Бяка способ. На каждый узел дерева по одному запросу - жирновато, как мне кажется. Всё дерево целиком можно получить одним запросом, а потом рекурсией (которая и в этом примере используется, правда, довольно бездарно) его перестроить...
Навскидку код будет выглядеть примерно так. Пишу навскидку прямо в форуме, без проверки. Надеюсь, ошибок не наляпаю, но будьте к ним готовы :). Впрочем, понять суть метода, думаю, можно.
define('NODE_BEGINS', '<ul>'); // html-код, который будет вставляться в начале узла define('NODE_ENDS', '</url>'); // html-код, который будет вставляться в начале узла define('LEAF_BEGINS', '<li>'); // html-код, который будет вставляться в начале листа ветви define('LEAF_ENDS', '</li>'); // html-код, который будет вставляться в конце ветви $res = mysql_query('SELECT id, parent_id, title FROM catalogue '); $tree = array(); while ($row = mysql_fetch_object($res)) { $tree[$row->parent_id][$row->id] = $row->title; } print _recurse($tree); /** * Рекурсивно обходит дерево и возвращает HTML * * @param array $tree * @param integer $parent_id * @return string */ function _recurse($tree, $parent_id = 0) { $code = NODE_BEGINS; foreach ($tree as $id => $root) { if ($parent_id != $id) { continue; } if (count($root)) { foreach ($root as $key => $title){ $code.= LEAF_BEGINS; // Нужна ссылка? Измените строчку ниже. Как - догадайтесь сами ;) $code.= $title; if (count($tree[$key])) { $code.= _recurse($tree, $key); } $code.= LEAF_ENDS; } } } $code.= NODE_ENDS; return $code; }
Не знаю, будет ли работать на PHP4, меня провидение миловало, не пришлось с ним работать :) Я просто попытался максимально примитизировать идею, поэтому код получился грязноватым. Если кому интересно, могу "правильно" (т.е. с ООП :)) переписать этот же код на PHP5.
Думаю, не в суровости перла дело, а в его умении грамотно и оптимально использовать ресурсы системы. А PHP для CLI слабоват, да
Можно и даже нужно ;). Я сам, как перловщик с 8-летним стажем пытаюсь это донести до своих собратьев по перу ;). До кого-то даже удаётся достучаться :).
Не знаю, как так получилось... Быть может, система кеширует часто изменяемые файлы, держит в памяти их потоки; быть может, дело в том, что винты SCSI. Может, обе причины. Как бы то ни было, замеры производились не наручными часами, а запуском парсеров через time ;)
Постоянно :) Не всегда HTTP (случается и за сквидом следить, к примеру), не всегда двухгигабайтные (бывает и больше, но обычно меньше :)), но очень большие - постоянно.
Код у перла нечитабелен только в том случае, если его писать так, как пишут большинство перловщиков. Процедурное программирование, использование пакетов не более чем неймспейсы, названия переменных и подпрограмм а-ля $hz, a(), b(), hz(). Как бы парадоксально это ни звучало, код на перле может быть очень красивым. :)
...или воспользоваться tail, sed, grep и средствами операционной системы. ;)
Но перл, тем не менее сбрасывать со счётов я бы не стал.
А Вы проверьте, попробуйте (я про загнать большой файл в файл) ;)
Только как человек, в своё время наступавший на эти грабли, не советую играться на сервере, где крутятся важные проекты.
Разумеется, всё зависит от реализации. Регекспы, разумеется, спользовались, какой же без них парсинг. А насчёт их тормознутости - не совсем верно. Да, разумеется, строковое сравнение быстрее регулярного. Но тут есть один ньюанс: это справедливо для одного сравнения паттерна.
Все последующие регулярные совпадения будут обработаны существенно быстрее (PCRE кеширует выражения), чем первое, поэтому при обработке больших объёмов текста регулярные выражения могут быть существенно быстрее строкового поиска...
Конкретно тех скриптов нет и чего там выпарсилось, я уже и не помню. Поэкспериментируйте :)
Вот перловый скрипт:
#!/usr/bin/perl open LOG, '<', 'access.log'; while (my $line = <LOG>) { if ($line =~ /(GoogleBot|Slurp)/i) { # do something } } close LOG;
Вот на php:
#!/usr/local/bin/php <?php $fp = fopen('access.log', 'r'); while ($line = fgets($fp)) { if (preg_match('/(GoogleBot|Slurp)/i', $line)) { # do something } } ?>
Попробуйте поменять паттерны на свои, добавить какую-то логику... В общем, пофантазируйте ;)
Неверно Вам кажется :)
Зачем загонять огромный файл в память, когда можно открыть поток и просто читать его построчно? Для запоминания текущей позиции курсора в потоке нужно гораздо меньше памяти, чем 8М.
Использовать php для парсинга большого объёма текста не очень желательно. Скорее даже очень нежелательно. Нет, я помимаю, что и микроскопом можно забивать гвозди, но для этого существуют гораздо более подходящие средства.
Для примера:двухигабайтный лог апача перлом парсился уть больше двух секунд. А пхп скрипел почти три минуты =)
Не знаю, если честно, где Вы общие моменты у MZZ и CI нашли... Разве что оба - MVC-фреймворки ;)
На всякий случай: в Zend Framework есть пакет Zend_Acl, который с этой задачей весьма и весьма справляется. Из автономных готовых решений phpGACL, но он требует ADODB.
Есть отечественная разработка - CMF\CMS MZZ (http://mzz.ru), в которой тоже есть неплохая реализация ACL. Если потратить некоторое время на изучение и поход, то сможет помочь.
Скаффолдинг? :)
Всё остальное писать придётся в любом случае :). Но фреймворки позволяют свести нудятину к минимуму.
Проще всего через wget в режиме зеркалирования :)
А потом уже локальную копию и парсить можно. По желанию.