Способы извлечения путей в PHP: от файла до корня сайта
В веб-разработке часто требуется получить путь к текущему PHP-скрипту, его директории, корню сайта или URL страницы. Это необходимо для подключения файлов, создания ссылок, работы с файловой системой. В PHP существует несколько способов, каждый из которых подходит для конкретной задачи.
Основные подходы к получению путей
Как получить полный путь к текущему PHP-файлу?
Основное и наиболее надёжное решение - использование магической константы __FILE__. Она возвращает абсолютный путь к файлу, в котором была вызвана. Константа работает во всех версиях PHP и не зависит от внешних факторов, таких как web-сервер или текущая рабочая директория.
<?php echo __FILE__; ?>Php get path (получение текущего пути в php)
Пример вывода на сервере Linux: /var/www/html/site/index.php
Проблема: при использовании внутри файла, который был включён через include или require, __FILE__ указывает на сам включённый файл, а не на вызывающий скрипт. Для получения пути к главному скрипту запроса используется $_SERVER['SCRIPT_FILENAME']. Также __FILE__ может содержать символические ссылки; для их разрешения применяется realpath().
Как узнать директорию, где находится скрипт?
Для получения директории текущего файла можно использовать функцию dirname() в сочетании с __FILE__ или константу __DIR__ (доступна с PHP 5.3).
<?php
$dir1 = dirname(__FILE__);
$dir2 = __DIR__;
echo $dir1 . "\n" . $dir2;
?>
Результат: /var/www/html/site (без завершающего слеша). Для канонизации пути рекомендовано использовать realpath(__DIR__).
Типичная ошибка: забывают, что __DIR__ не содержит завершающего слеша. Это может привести к проблемам при конкатенации с последующими папками. Решение - добавлять DIRECTORY_SEPARATOR или использовать rtrim().
Как получить корень документа (Document Root)?
Для определения пути к корневой директории сайта (откуда сервер обрабатывает запросы) используется элемент суперглобального массива $_SERVER['DOCUMENT_ROOT'].
<?php
echo $_SERVER['DOCUMENT_ROOT'];
?>
Результат: /var/www/html (зависит от конфигурации).
Проблемы: настройка DOCUMENT_ROOT может быть отключена (если в php.ini register_globals выключено, но это не должно влиять). Может возвращать значение с завершающим слешем или без. При использовании виртуальных хостов или Chroot может быть неверное значение. Рекомендуется проверять и нормализовать с realpath().
Как получить URL текущей страницы?
Для полного URL (протокол + хост + URI) используется комбинация нескольких элементов $_SERVER.
<?php
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
$url = $protocol . '://' . $host . $uri;
echo $url;
?>
Результат: http://example.com/index.php?id=5.
Проблемы: при использовании нестандартного порта, отличного от 80 или 443, его необходимо явно добавлять. $_SERVER['HTTP_HOST'] может быть не задан в некоторых окружениях (CLI). Альтернатива - $_SERVER['SERVER_NAME'].
Как получить физический путь на основе URL?
Для преобразования запрошенного URL в файловый путь можно объединить $_SERVER['DOCUMENT_ROOT'] и $_SERVER['REQUEST_URI'], после чего обработать realpath().
<?php
$phys = realpath($_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI']);
if ($phys) {
echo $phys;
} else {
echo 'Путь не существует';
}
?>
Пример вывода: /var/www/html/article.php.
Ошибка: $_SERVER['REQUEST_URI'] может содержать query string, что надо отсекать (strtok()). При использовании mod_rewrite физического пути может не существовать. Также опасно для безопасности - возможен path traversal, если URI обрабатывается без проверки.
Как получить текущую рабочую директорию (CWD)?
Функция getcwd() возвращает текущую рабочую директорию процесса PHP.
<?php
echo getcwd();
?>
Результат: может быть /var/www/html или /tmp в зависимости от контекста.
Проблема: CWD изменяется после вызова chdir(). В CLI она часто совпадает с местом запуска скрипта, но не с путём самого скрипта. Для задач, где нужна директория скрипта, __DIR__ надёжнее.
Как получить путь к файлу, который вызвал include?
Если внутри инклуда требуется узнать путь к основному скрипту (который сделал запрос), используется $_SERVER['SCRIPT_FILENAME'] (имя исполняемого скрипта). Альтернативный способ - debug_backtrace().
<?php
// in included file
echo $_SERVER['SCRIPT_FILENAME'];
?>
Пример вывода: /var/www/html/index.php.
При использовании debug_backtrace() следует учитывать производительность и то, что глубина стека может быть ограничена. $_SERVER['SCRIPT_FILENAME'] не всегда доступен в CLI-сценариях (там может быть отсутствовать или содержать путь к php-бинарнику).
Расширенные примеры и редкие случаи
Разрешение символических ссылок с помощью realpath
Функция realpath() преобразует путь с симлинками и относительными сегментами в абсолютный канонический путь.
<?php
$path = __DIR__ . '/../config/db.php';
$canonical = realpath($path);
if ($canonical) {
echo $canonical;
} else {
echo 'Ошибка: путь не существует';
}
?>
/var/www/site/config/db.php
В случае, если симлинк ведёт на другую файловую систему, realpath() всё равно вернёт реальный путь.
Получение относительного пути от корня документа
Часто требуется преобразовать абсолютный путь скрипта в относительный URL. Это можно сделать, если известен $_SERVER['DOCUMENT_ROOT'].
<?php
$abs = __DIR__ . '/assets/image.jpg';
$docRoot = $_SERVER['DOCUMENT_ROOT'];
// Убираем корень документа из начала пути
if (strpos($abs, $docRoot) === 0) {
$relative = substr($abs, strlen($docRoot));
echo $relative;
} else {
echo 'Путь вне корня документа';
}
?>
/assets/image.jpg
Обратите внимание: после удаления корня может остаться начальный слеш, что нормально для URL.
Сравнение путей с учётом чувствительности регистра
На Linux файловая система чувствительна к регистру, на Windows - нет. Для надёжного сравнения путей рекомендуется привести их к единому регистру с помощью strtolower() после realpath().
<?php
$path1 = realpath('/var/www/html/File.php');
$path2 = realpath('/var/www/html/file.php');
if (strtolower($path1) === strtolower($path2)) {
echo 'Пути указывают на один файл (с точностью до регистра)';
}
?>
Вывод: строки могут совпадать или не совпадать в зависимости от реального существования файлов. Такой подход полезен для кэширования.
Получение списка всех включённых файлов с их путями
Для отладки или аудита может потребоваться массив всех файлов, подключенных через include/require. Для этого используется get_included_files().
<?php
// подключим несколько файлов
include 'config.php';
include 'functions.php';
$included = get_included_files();
print_r($included);
?>
Array
(
[0] => /var/www/html/index.php
[1] => /var/www/html/config.php
[2] => /var/www/html/functions.php
)
Функция возвращает абсолютные пути, уже нормализованные. Это работает и с require_once, и с include_once.
Кросс-платформенная обработка путей: DIRECTORY_SEPARATOR
Windows использует обратную косую черту (\), Linux - прямую (/). Для совместимости используйте константу DIRECTORY_SEPARATOR или просто /, так как PHP под Windows тоже понимает прямую черту.
<?php
$path = __DIR__ . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'file.txt';
echo $path;
// То же самое с /:
echo __DIR__ . '/data/file.txt';
?>
/var/www/html/data/file.txt
При работе с пользовательскими путями рекомендуется заменять обратные косые черты на прямые с помощью str_replace('\\', '/', $path).
Создание универсальной функции для получения пути скрипта
Иногда необходимо получить путь к папке, где лежит главный скрипт, даже если текущий файл является инклудом. Функция может использовать $_SERVER['SCRIPT_FILENAME'].
<?php
function getScriptDir() {
$script = $_SERVER['SCRIPT_FILENAME'];
if (!$script) {
// fallback для CLI
$script = $_SERVER['PHP_SELF'] ?? __FILE__;
}
return dirname(realpath($script));
}
echo getScriptDir();
?>
/var/www/html
Эта функция надёжна для веб-среды, но в CLI может дать неверный результат, поэтому требуется проверка.