Для рекурсивной итерации по файлам RecursiveDirectoryIterator
очень удобен (относится: Путь к рекурсивной директории PHP ).Он также предлагает простой доступ к FileSystemObject
, что выглядит полезным в вашем случае, так как вы хотите получить содержимое файлов.
Кроме того, можно выполнить одно регулярное выражение для разбора первых двух строк файла., поскольку шаблоны кэшируются, когда вы выполняете их чаще, это должно быть хорошо.Преимущество одного шаблона в том, что код более структурирован, но недостаток в том, что шаблон более сложный.Конфигурация может выглядеть следующим образом:
#
# configuration
#
$path = 'md';
$fileFilter = '~\.(md|markdown)$~';
$pattern = '~^(?:Title: (.*))?(?:(?:\r\n|\n)(?:Description: (.*)))?~u';
На всякий случай, если файлы разметки на самом деле кодируются в UTF-8, я добавил модификатор u
(PCRE8).
Обрабатывающая частьзатем код использует рекурсивный итератор каталога над $path
, пропускает файлы, не соответствующие $fileFilter
, а затем анализирует первые две строки каждого файла (если файл по крайней мере читаем и имеет хотя бы одну строку) и сохраняет его вхеш-таблица на основе каталога / массив $result
:
#
# main
#
# init result array (the nice one)
$result = array();
# recursive iterator for files
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO),
RecursiveIteratorIterator::SELF_FIRST);
foreach($iterator as $path => $info)
{
# filter out files that don't match
if (!preg_match($fileFilter, $path)) continue;
# get first two lines
try
{
for
(
$maxLines = 2,
$lines = '',
$file = $info->openFile()
;
!$file->eof() && $maxLines--
;
$lines .= $file->fgets()
);
$lines = rtrim($lines, "\n");
if (!strlen($lines)) # skip empty files
continue;
}
catch (RuntimeException $e)
{
continue; # files which are not readable are skipped.
}
# parse md file
$r = preg_match($pattern, $lines, $matches);
if (FALSE === $r)
{
throw new Exception('Regular expression failed.');
}
list(, $title, $description) = $matches + array('', '', '');
# grow result array
$result[dirname($path)][] = array($path, $title, $description);
}
Осталось только вывод.Поскольку хеш-таблица предварительно упорядочена хешем каталога, она довольно проста, сначала перебирая каталоги, а затем файлы внутри:
#
# output
#
$dirCounter = 0;
foreach ($result as $name => $dirs)
{
printf("Directory %d %s\n", ++$dirCounter, basename($name));
foreach ($dirs as $entry)
{
list($path, $title, $description) = $entry;
printf("<a href='%s'>%s from line 1 of Markdown %s</a> <br>\n%s\n\n",
htmlspecialchars($path),
htmlspecialchars($title),
htmlspecialchars(basename($path)),
htmlspecialchars($description)
);
}
}