Войны между программистами php и perl кажется давно уже позади. Даже я стал программировать на php, напрочь забыв perl. Но это не значит, что меня всё устраивает в php. Например то, что скрипты на php могут не только легко содержать куски html-разметки, но и запускаться из любой папки на сервере, я до сих пор считаю серьёзной уязвимостью, накладывающей дополнительные обязательства на программиста, пишущего код. Наверняка, можно озадачится и серверными средствами ограничить запуск php-скриптов из всех директорий, кроме выбранной, (или, по крайней мере, прописать в правах доступа к папкам запрет на исполнение с наследованием этого свойства файлами), но я пока не встречал кода, который показал бы, что этим кто-то озадачивался. Как использовать эту особенность php, я для себя решил. А в этой статье рассмотрим, как подняться по всему дереву каталогов в корневую директорию с помощью php-скрипта, который, как увидим, может спокойно лазить по всему серверу и что-то там себе в делать тихим сапом (в зависимости от развитости и извращённости фантазии программиста, его написавшего).
Основные переменные и функции php для определения папки, в которой находится программа
Для начала рассмотрим две глобальные переменные php и одну функцию, которые позволяют быстро с помощью языка программирования определить место, где находится скрипт в дереве каталогов на сервере. Эксперимента ради, я загрузил скрипт глубоко в папки установленной Joomla, на которой работает этот сайт.
Итак, скрипт с названием delete.php
(потому что после написания статьи будет удалён) лежит в папке \www\mb4.ru\templates\protostar\html\layouts\joomla\html\batch\
, если рассматривать его путь от домашней директории пользователя.
В php версиях: PHP 4 >= 4.1.0, PHP 5, PHP 7 есть переменная $_SERVER
, содержащая в себе массив с заголовками, путями и местоположениями скриптов. Записи в этом массиве создаются веб-сервером. Нет гарантии, что каждый веб-сервер предоставит любую информацию, но по умолчанию, рассматриваемые ниже два пути, хранящиеся в этом массиве, отдаются сервером «на ура».
$_SERVER['DOCUMENT_ROOT']
- в этой переменной содержится директория корня документов, в которой выполняется текущий скрипт, в точности та, которая указана в конфигурационном файле сервера.
$_SERVER['SCRIPT_FILENAME']
- в этой переменной содержится абсолютный путь к исполняемому скрипту.
Для проверки, как это работает, достаточно запустить php-скрипт, который выдаст на экран содержимое этих переменных:
<?php
echo "$_SERVER['DOCUMENT_ROOT'] . "<br>";
echo "$_SERVER['SCRIPT_FILENAME']";
?>
В результате получим нечто подобное:
/var/www/mb4/data/www/mb4.ru
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts/joomla/html/batch/delete.php
То есть корневую папку пользователя, под которым запущен на выполнение скрипт и ВНИМАНИЕ (!) — полный путь к исполняемому скрипту от корня дерева каталогов сервера (!). Красота ;)
В php есть ещё одна полезная функция, которой мы воспользуемся ниже для подъёма к корню файловой системы сервера, которая получает имя текущего рабочего каталога. Это функция getcwd()
, работающая во всех версиях php (PHP 4, PHP 5, PHP 7).
То есть, запустив код:
<?php
echo "getcwd()";
?>
Получим в качестве выполнения:
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts/joomla/html/batch
Всё тот же путь, по которому можно подняться до корня файловой системы.
Как получить список папок ветки дерева каталога, в котором лежит php-скрипт
Самый простой способ получить список папок ветки дерева каталога, в котором лежит php-скрипт, это воспользоваться стандартной функций php preg_split()
, работающей во всех версиях этого языка (PHP 4, PHP 5, PHP 7). Эта функция разбивает строку по регулярному выражению и помещает результаты разбиения в массив. В нашем случае, в качестве разделителей папок однозначно используется /
, так что и думать особо не нужно, используя для вывода функцию print_r()
так, подробно описано в → этой статье:
<?php
echo '<pre>';
print_r( preg_split ( '/\//', getcwd() ) );
echo '</pre>';
?>
В итоге получим вывод этого массива, в котором будут содержаться все папки, встречающиеся по пути от файла до корня файловой системы:
Array ( [0] => [1] => var [2] => www [3] => mb4 [4] => data [5] => www [6] => mb4.ru [7] => templates [8] => protostar [9] => html [10] => layouts [11] => joomla [12] => html [13] => batch )
Если в этот массив нужно включить и имя файла, то вместо getcwd()
нужно использовать глобальную переменную $_SERVER['SCRIPT_FILENAME']
.
Как подняться к корню каталога с помощью php, заходя в каждую папку
Вот тут мы и добрались до ответа на основой вопрос: «Как подняться к корню каталога с помощью php?» Для этого достаточно знать, что в операционных системах типа *nix ссылкой на предыдущую папку служит ..
, а в php есть функция, позволяющая менять каталог chdir()
. То есть, для перехода на каталог выше, нужно указать скрипту: chdir ( '..' )
. В итоге получим такой скрипт, который поднимается к корню каталога файловой системы, последовательно заходя во все встречные родительские папки:
<?php
while ( getcwd() != '/' ) {
echo getcwd() . "<br/>";
chdir ( '..' );
}
?>
Для того, чтобы программа не пыталась выйти за пределы операционной системы в открытый космос (всё равно не получится), в цикле while нужно указать ограничение, что дальше корня /
даже не пытаться заходить: getcwd() != '/'
. Иначе будет бесконечный цикл и программа будет тупо биться в конечную папку, пытаясь выйти за её пределы.
В результате наш скрипт бодро откроет все папки (и даже сможет по ним полазить, если нужно) и выдаст список того, в каких директориях он побывал:
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts/joomla/html/batch
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts/joomla/html
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts/joomla
/var/www/mb4/data/www/mb4.ru/templates/protostar/html/layouts
/var/www/mb4/data/www/mb4.ru/templates/protostar/html
/var/www/mb4/data/www/mb4.ru/templates/protostar
/var/www/mb4/data/www/mb4.ru/templates
/var/www/mb4/data/www/mb4.ru
/var/www/mb4/data/www
/var/www/mb4/data
/var/www/mb4
/var/www
/var
Резюме
Таким образом, разместив короткую программу на php в любое место на сервере, можно попасть в любую родительскую директорию. Что с этим делать и как можно использовать, как-нибудь в другой раз.
Напоследок полный работающий код для тестирования и дописывания этого php-скрипта. Скрипт безобидный: ничего не дописывает и не меняет на сервере, так что его можно использовать в качестве заготовки для написания более осмысленной программы, выполняющей определённые действия. ;)
<?php
echo "Текущая папка: <b>" . getcwd() . "</b><br/><br/>";
echo '<pre>';
print_r( preg_split ( '/\//', getcwd() ) );
echo '</pre>';
while ( getcwd() != '/' ) {
echo getcwd() . "<br/>";
chdir ( '..' );
}
echo "<br>\$_SERVER['DOCUMENT_ROOT'] = <b>" . $_SERVER['DOCUMENT_ROOT'] . "</b><br>";
echo "\$_SERVER['SCRIPT_FILENAME'] = <b>" . $_SERVER['SCRIPT_FILENAME'] . "</b>";
?>
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)