/**
* Приведение ссылки к абсолютному URI
*
* @param string $link ссылка (абсолютный URI, абсолютный путь на сайте, относительный путь)
* @param string $base базовый URI (можно без "http://")
* @return string абсолютный URI ссылки
*/
function uri2absolute($link, $base)
{
if (!preg_match('~^(http://[^/?#]+)?([^?#]*)?(\?[^#]*)?(#.*)?$~i', $link.'#', $matchesLink)) {
return false;
}
if (!empty($matchesLink[1])) {
return $link;
}
if (!preg_match('~^(http://)?([^/?#]+)(/[^?#]*)?(\?[^#]*)?(#.*)?$~i', $base.'#', $matchesBase)) {
return false;
}
if (empty($matchesLink[2])) {
if (empty($matchesLink[3])) {
return 'http://'.$matchesBase[2].$matchesBase[3].$matchesBase[4];;
}
return 'http://'.$matchesBase[2].$matchesBase[3].$matchesLink[3];
}
$pathLink = explode('/', $matchesLink[2]);
if ($pathLink[0] == '') {
return 'http://'.$matchesBase[2].$matchesLink[2].$matchesLink[3];
}
$pathBase = explode('/', preg_replace('~^/~', '', $matchesBase[3]));
if (sizeOf($pathBase) > 0) {
array_pop($pathBase);
}
foreach ($pathLink as $p) {
if ($p == '.') {
continue;
} elseif ($p == '..') {
if (sizeOf($pathBase) > 0) {
array_pop($pathBase);
}
} else {
array_push($pathBase, $p);
}
}
return 'http://'.$matchesBase[2].'/'.implode('/', $pathBase).$matchesLink[3];
}
Одна из областей применения - вытаскивание ссылок из html-кода. Ссылки, как известно, могут указываться разными способами. Это может быть абсолютный URI (http[nobbc]://[/nobbc]site.ru/path), либо абсолютный путь на текущем сайте (/path/to/file.php), либо путь относительно текущего документа (./../path/to/file). Данная функция позволяет привести их все к абсолютному виду.
Примеры (базовым URI обычно является адрес текущей страницы):
// Путь от корня. Результат: http://site.com@user:password/path/to/file.php?x=10
print uri2absolute('/path/to/file.php?x=10', 'http://site.com@user:password/one/two/three.html?y=20#fragment');
print '<br />';
// Тот же сценарий с другими параметрами. Результат: http://site.com/one/two/three.html?x=10
print uri2absolute('?x=10', 'site.com/one/two/three.html?y=20#fragment');
print '<br />';
// Пустая ссылка (возможно с js-обработчиком). Результат: http://site.com/one/two/three.html?y=20
print uri2absolute('#', 'site.com/one/two/three.html?y=20#fragment');
print '<br />';
// Файл в том же каталоге. Результат: http://site.com/one/two/file.php
print uri2absolute('file.php', 'site.com/one/two/three.html?y=20#fragment');
print '<br />';
// Так же, но в базовом пути последний элемент - каталог. Результат: http://site.com/one/two/three/file.php
print uri2absolute('file.php', 'site.com/one/two/three/?y=20#fragment');
print '<br />';
// Выход из текущего каталога. Результат: http://site.com/one/new/path/file.php?x=10
print uri2absolute('./../../new/path/file.php?x=10', 'site.com/one/two/three/?y=20#fragment');
print '<br />';
// Ссылка является абсолютной. Базовый путь ни на что не влияет. Результат: http://domain.com/path
print uri2absolute('http://domain.com/path', 'site.com');
Так же при подобном разборе ссылок не стоит забывать о теге BASE. Обработать его можно следующим образом:
/**
* Получение базового пути для относительных ссылок в html-документа
*
* @param string $htmlCode код страницы
* @param string $url адрес страницы
* @return string базовый путь
*/
function getBaseHref($htmlCode, $url)
{
if (!preg_match('~<base\s+href\s*=\s*[\'"]?([^\'">]+).*?>~is', $htmlCode, $matches)) {
return $url;
}
return uri2absolute(htmlSpecialChars_decode($matches[1]), $url);
}
[/php]
Посылаем на вход функции код html-страницы и её адрес, на выходе получаем базовый адрес для всех относительных ссылок внутри документа. Если тега <BASE> в документе нет, базовым адресом будет адрес самого документа.
Еще uri2absolute() может быть удобна для переадресации сценария (что часто делается, после обработки формы). Обычно делается это с помощью header + exit(). В соответствии со стандартами в http-заголовке location может быть указан только aбсолютный URI. Большинство браузеров, правда, ест всё что угодно, но все равно это неправильно. Кроме того, постоянно писать header и exit, тоже надоедает:
[php]
/**
* Переадресация браузера
*
* @param string $path [optional]
*/
function location($path = false)
{
$base = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
if ($path === false) {
$path = $base;
} elseif ($path === true) {
$path = preg_replace('~\?.*$~', '', $base);
} else {
$path = uri2absolute($path, $base);
}
header('Location: '.$path);
exit();
}
[/php]
Где нужно вызываем:
[php]
location('http://php.net/'); // Идите почитайте мануал
location('/script.php'); // Переадресуем на тот же сайт
location('./../script.php'); // Используем относительную переадресацию
location(); // На самого же себя
location(true); // На самого себя, с отрезанием GET-параметров
[/php]