Определяем корень сайта на php
Часто возникает необходимость подгрузить из одного скрипта другой. Всё хорошо, когда эти скрипты физически расположены в одном каталоге. Делаем include
и нет проблем. Проблемы возникают при развитой системе скриптов. Когда исполняемые файлы сгруппированы по каталогам и нужно настроить взаимодействие между ними.
Для себя я решил, что проще всего понять где находится корневой каталог и уже от него подгружать другие скрипты.
Способ 1. Некрасивый
Способ, которым я пользовался более трех лет. Основная идея: получить путь к каталогу текущего файла и относительно этого каталога подгружать другие скрипты.
В переменной $_SERVER["SCRIPT_FILENAME"]
содержится абсолютный путь к скрипту. С помощью функций mb_strrpos
и mb_substr
мы вырезаем из исходной строки имя файла. В итоге в константе PATH
будет содержаться текущий каталог.
define ('PATH', mb_substr($_SERVER["SCRIPT_FILENAME"], 0, mb_strrpos($_SERVER["SCRIPT_FILENAME"], "/"))); require_once(PATH."/../connect.php"); |
Плюсы данного решения
– Должен работать даже на самых древних версиях PHP.
– Инициализация константы происходит в одну строку.
Минусы данного решения
– В зависимости от вложенности скрипта, необходимо менять количество "../"
. То есть, если вложенность один каталог:
require_once(PATH."/../connect.php"); |
Если вложенность 4 каталога:
require_once(PATH."/../../../../connect.php"); |
– Весь этот код вообще не нужен ведь, начиная с PHP 5.3, появилась константа __DIR__
, которая содержит путь к каталогу.
– При запуске скрипта с консоли в $_SERVER["SCRIPT_FILENAME"]
будет содержаться относительный путь. То есть, если вы запускаете скрипт так:
php /var/www/sites/lgnd.ru/public_html/parser/test.php |
В $_SERVER["SCRIPT_FILENAME"]
будет содержаться полный путь.
Но если вы сначала перейдете в каталог скрипта, а затем запустите его:
cd /var/www/sites/lgnd.ru/public_html/parser/test.php php test.php |
то в $_SERVER["SCRIPT_FILENAME"]
будет содержаться только test.php
– На некоторых конфигурациях содержимое $_SERVER["SCRIPT_FILENAME"]
может быть пустым.
Способ 2. Элегантный, но не идеальный
В какой-то момент мне надоело постоянно менять вложенность. И я решил переписать этот говнокод.
Начиная с PHP 5.3, появилась удобная константа __DIR__
. Почему бы не воспользоваться ею?
Для начала определим: какое название имеет корневой каталог. В зависимости от настроек вашего веб-сервера, это может быть public_html
, public
, www
или что-то другое. В константе __DIR__
будет такой путь:
/var/www/sites/lgnd.ru/public_html/parser
При помощи функции explode
мы разобьем этот путь на две части. Разделителем будет служить название корневого каталога (в моем случае — public_html
). В итоге в $dir[0]
будет содержаться левая часть (всё, что было до public_html
):
/var/www/sites/lgnd.ru/
К этой строке мы добавляем название корневого каталога и слэш.
$root_dir = 'public_html'; $dir = explode($root_dir, __DIR__); define ('PATH', $dir[0].$root_dir.'/'); require_once(PATH."/connect.php"); |
Плюсы
– Будет корректно определён путь до корневого каталога, вне зависимости от вложенности скрипта.
– Нет проблем с относительным/абсолютным путем при работе из командной строки или при запуске в экзотических конфигурациях
– Не нужно постоянно указывать дополнительные "../"
при переносе скрипта в другой каталог.
Минусы
– Требует PHP 5.3+
– Инициализация занимает больше строк и её нельзя сократить (записать три строки в одну не комильфо)
– Требует указания корневого каталога, а значит скрипт нельзя просто скопировать с одного сервера на другой
Способ 3. Нет предела совершенству
Дальнейшие улучшения способа номер 2.
В PHP 5.4 появилось разыменование массивов. Эта штука позволяет обращаться к результатам работы функции explode
без создания временной переменной:
PHP 5.3
$dir = explode('public_html', __DIR__); echo dir[0]; |
PHP 5.4
echo explode('public_html', __DIR__)[0]; |
В итоге код из способа 2 становится более компактным:
$root_dir = 'public_html'; define ('PATH', explode($root_dir, __DIR__)[0].$root_dir.'/'); |
А если очень хочется всё записать в одну строку:
define ('PATH', explode('public_html', __DIR__)[0].'public_html'.'/'); |
А DOCUMENT_ROOT чем не устраивает суперглобальный массив $_SERVER доступен всегда.
$_SERVER[DOCUMENT_ROOT] = /home/userdomen/www/gamatic.ru/public_html/dmx1
@Vladimir
При запуске скрипта из консоли (напрямую или по CRON) эта переменная пуста:
простой файл с одной строкой:
Запускаем файл из консоли:
string(0) ""
Запускаем файл из браузера:
string(35) "/var/www/sites/lgnd.ru/public_html/"
Ну таки из консоли и $_SERVER[«SCRIPT_FILENAME»] пуста, и от константы __DIR__ тот же прок !
@Pilotka
Даже сейчас не на всех хостингах доступна PHP 5.3, а 2 года назад ситуация была еще хуже.
В 2015 году принято делать автозагрузку по стандарту PSR-4 (или хотя бы PSR-0)