| |
лог и выходим в случае ошибки
$d=@opendir(".");
if(!$d) return;
while(($e=readdir($d))!==false) {
// Игнорируем элементы .. и .
if($e=='.'||$e=='..') continue;
// Нам нужны только подкаталоги
if(!@is_dir($e)) continue;
// Печатаем пробелы, чтобы сместить вывод
for($i=0; $i<$level; $i++) echo " ";
// Выводим текущий элемент
echo "$e\n";
// Входим в текущий подкаталог и печатаем его
if(!chdir($e)) continue;
PrintTree($level+1);
// Возвращаемся назад
chdir("..");
// Отправляем данные в браузер, чтобы избежать видимости зависания
// для больших распечаток
flush();
}
closedir($d);
}
// Выводим остальной текст фиксированным шрифтом
echo "";
echo "/\n";
// Входим в корневой каталог и печатаем его
chdir("/");
PrintTree();
echo "";
?>
Часть IV. Стандартные функции PHP 272
Сразу хочу предупредить, что результат работы этого сценария представляет собой
довольно длинную распечатку. Кроме того, программа работает медленно, т. к. ей
нужно будет обойти тысячи каталогов вашей системы.
Последний факт делает метод рекурсивного обхода каталогов совершенно не-
пригодным для автоматического построения карты сервера. В случае приме-
нения технологии кэширования информации между запусками сценариев для
больших сайтов построение карты даже, скажем, раз в час, выглядит довольно
плачевно. Как обойти эту трудность (фактически, используя кэш и разделен-
ные вычисления) рассказано в части V этой книги.
Глава 17
Каналы
и символические ссылки
Вообще-то, каналы и символические ссылки — совершенно разные вещи. Однако у
меня есть по крайней мере два веских основания для того, чтобы сгруппировать их
описания в одном месте.
r И то и другое сколько-нибудь результативно можно использовать лишь в системах
на основе Unix, в других же операционных системах функции либо не реализова-
ны, либо просто не работают.
r Примерно лишь один сценарий на PHP из тысячи может нуждаться в создании и
использовании каналов и символических ссылок.
Каналы
Давайте начнем с каналов. Мы уже привыкли, что можем открыть какой-то файл для
чтения при помощи fopen(), а затем читать или писать в него данные. Теперь
пред-
ставьте себе немного отвлеченную ситуацию: вы хотите из сценария запустить
какую-
то внешнюю программу (скажем, утилиту mail для отправки или приема почты).
Вам нужен будет механизм, посредством которого вы могли бы передать этой утили-
те данные (например, E-mail и текст письма), а затем получить результат работы
про-
граммы.
Можно, конечно, заранее сохранить данные для запроса в отдельном временном фай-
ле, затем запустить программу, передав ей этот файл в параметрах и направив ре-
зультат в другой файл, а затем считать его и таким образом решить задачу. Этот
спо-
соб вполне приемлем (хотя и несколько медлителен), если вы используете утилиту,
которая работает не в режиме диалога (а только читает запрос и возвращает
ответ).
Однако, если после ответа программы-утилиты ей нужно будет послать какой-то
дру-
гой запрос, не перезапускаясь, то задача становится на этом уровне неразрешимой.
Как раз в такой ситуации и удобно использовать межпроцессные каналы. И вот как
это работает.
// Запускаем процесс /bin/ls (параллельно работе сценария) в режиме
// чтения. Эта утилита Unix просто распечатывает содержимое текущего
// каталога, а ключ -l заставляет ее детализировать распечатку.
Часть IV. Стандартные функции PHP 274
$fp=popen("/bin/ls -l","r");
// Теперь мы можем работать с $fp как с обычным файловым
// идентификатором. То есть выполнять функции чтения.
for($Lines=array(); !eof($fp);)
$Lines[]=fgets($fp,1000);
// Не забудем также закрыть канал.
pclose($fp);
Теперь более подробно. По команде popen() запускается указанная в первом пара-
метре программа, причем выполняется она параллельно сценарию. Соответственно,
управление сразу возвращается на следующую строку, и сценарий не ждет, пока за-
вершится наша утилита (в отличие от функции system(), которая будет вскоре рас-
смотрена). Второй параметр задает режим работы: чтение или запись, точно
|
|