| |
которая будет заниматься поиском и обработкой
файлов на каждом этапе обхода сайта. Листинг 33.1 содержит код библиотеки, в
ко-
торой описана эта функция. Чтобы не "привязываться" к специфике конкретной
зада-
чи, сделаем функцию универсальной. Будем передавать ей имя процедуры-
обработчика, умеющего "вытаскивать" из указанного файла всю информацию, необ-
ходимую для построения карты (например, название страницы, ее размер и т. д.),
сама же WalkSite() будет просто вызывать этот обработчик в нужный момент вре-
мени, следя за тем, чтобы квант времени, отведенный на данный этап построения
карты, не истек. Если это произойдет, текущее состояние обхода сервера (включая
всю собранную информацию) будет сохранено в специальном файле, а при следую-
щем запуске — восстановлено, с тем чтобы обход продолжился с того же места, где
он завершился в прошлый раз.
Листинг 33.1. Библиотека для обхода дерева сайта: SiteWalker.phl
// Функция выполняет один этап обхода всех каталогов и файлов сайта.
// Если обход нужно продолжить, загружается предыдущее состояние
// из файла $cache. Если этого файла не существует, значит,
// необходимо начать новый обход, начиная с каталога $Root.
// Этап будет длиться не более $time секунд (если 0, то за один
// раз обрабатывается ровно один файл или каталог).
// Для каждого обнаруженного файла или каталога вызывается функция,
// имя которой передано в $Func.
// Формат функции: function FWalker(string $fname, array &$Result)
// Эта функция должна обрабатывать найденный файл $fname
// соответствующим образом и добавлять данные в массив $Result
// (в любом формате). Состояние массива $Result будет автоматически
// сохранено сразу по истечении кванта времени и восстановлено
// перед началом нового этапа.
// Возвращает true, если процесс не был закончен на этом этапе,
// и false, если только что были обработаны последние файлы на сервере.
function WalkSite($Root,$Func,$cache,$time,&$Result)
{ $Start=time();
// Состояние в самом начале работы. Нужно обработать
// корневой каталог $Root.
Часть V. Приемы программирования на PHP 498
$Prg=array(
"Todo" => array($Root), // для накопления путей необработанных файлов
"Res" => array() // результат обработки всех файлов
);
// Пытаемся загрузить текущее состояние. Если не получается,
// значит, обход только что начался.
if($f=@fopen($cache,"rb")) {
if(@flock($f,LOCK_SH)) {
$Prg=Unserialize(fread($f,filesize($cache)));
fclose($f);
}
}
// Обходим сайт — по одной итерации цикла на каждый файл или
// каталог. Найденные файлы добавляются в конец массива
// $Prg['Res'], а подвергающиеся обработке — извлекаются из его
// начала. Таким образом, мы продолжаем процесс до тех пор,
// пока не будут "пройдены" все файлы на сервере.
do {
// очередное полное имя файла
$fname=array_shift($Prg['Todo']);
// если это не файл и не каталог, пропускаем
if(!@is_file($fname) && !@is_dir($fname)) continue;
// если это каталог, добавляем все его содержимое
if(@is_dir($fname)) {
$Files=array();
for($d=openDir($fname); $e=readDir($d); ) {
if($e=="."||$e=="..") continue;
$Files[]="$fname/$e";
}
closeDir($d);
// вставляем в начало массива, чтобы на следующей итерации
// цикла обрабатывались именно эти файлы
$Prg['Todo']=array_merge($Files,$Prg['Todo']);
}
// вызываем функцию для обработки очередного файла или каталога
$Func($fname,$Prg['Res']);
// выходим, если время истекло, или же необработанных
// файлов не осталось.
Глава 33. Разные советы 499
} while(time()-$Start<$time && count($Prg['Todo']));
// Вернуть текущий результат в $Result.
$Result=$Prg['Res'];
// Если еще есть файлы для обработки, сохранить состояние.
if(count($Prg['Todo'])) {
// Сохраняем текущее состояние. В следующий раз мы начнем с него.
$f=fopen($cache,"a+b");
flock($f,LOCK_EX);
ftruncate($f,0);
fwrite($f,Serialize($Prg));
fflush($f); fclose($f);
return true; // процесс продолжается
}
// Иначе процесс закончился. Удалить файл состояния.
@unlink($cache);
return false;
}
?>
Я не буду приводить здесь реальный сценарий для построения карты сервера,
потому
что он слишком велик и, к тому же, довольно однообразен и неинтересен. Вся
"изю-
минка" заключена именно в функции WalkSite(). Листинг 33.2 содержит неболь-
шую "демонстрацию" е
|
|