95% бесплатных
Именно так это и происходит.
Сегодня опять ковырялся в каталогах бесплатных скриптов, главным образом из
любопытства, но еще и в тайной надежде найти
забавное. В прошлый раз из «забавных» скриптов я нашел, например, «скрипт
вывода текстового файла в php». Думал — парсер. Оказалось -
да… почти что парсер. Привожу скрипт целиком: <?php include ("text.txt");
?>
. Или вот вижу скрипт, написано «This script will reverse the text
you give it. reversed: .ti evig uoy txet eht esrever lliw tpircs siht It isn’t
very useful, it’s just funny. Try it out :)», то есть скрипт переворачивает
строку
Нашел скрипт поиска по сайту: он обшаривает директории, которые вы указали,
открывает все
В общем, решил я
Итак, начали…
Самое первое — скрипт индексации. Для чего он нужен?.. Вот у меня
278 заметок. Если мы будем открывать каждый файл и искать совпадения, то нам
надо будет открыть 278 файлов. А это ой как долго… Более того, нам надо будет
278 раз провести хитрые манипуляции с этими файлами (про манипуляции — ниже).
Если же у нас есть индекс, то
Алгоритм индексирующего скрипта такой:
1. Открываем очередной файл
2. Убираем из него «мусор» ( зачем убирается мусор — понятно, чем мусора
меньше, тем ищется быстрее… ):
а) переводы строк
б)
в) знаки препинания
г) слова, короче трех букв (а зачем они там?)
3. Делаем заглавные буквы строчными.
4. Убираем повторяющиеся слова. (Действительно, зачем нам вся это тавтология?)
5. Записываем все в индекс.
6. Если еще есть файлы, переходим к пункту 1.
Реализуется это все на php — легко!
<?php
// Spectator's Indexing Script
// (C) Spectator.ru
// Для работы требуется PHP 4 или выше.
// Если вы будете использовать этот скрипт, ссылка на Spectator.ru крайне
желательна. Спасибо.
// ставим скрипт "на счетчик" (чтобы знать, как долго он выполнялся
$ttt=microtime();
$ttt=((double)strstr($ttt, ' ')+(double)substr($ttt,0,strpos($ttt,' ')));
$indexdir="text"; #индексируемая директория
$indexfile="indexfile.txt"; #файл, в котором будет лежать индекс
// если вы хотите индексировать файлы в нескольких директориях, надо внести
несколько махоньких добавлений...
// делаем так, чтобы не было таймаута из-за того, что скрипт будет долго
выполняться (на всякий случай)
// и из-за того, что пользователь нажмет кнопку "стоп" в браузере
$abort = ignore_user_abort(1);
set_time_limit(600);
// Функция, удалающая слова, короче 3х букв. Пригодится дальше.
function sw (&$item1, $key) { if (strlen($item1)<3) $item1=""; }
// по очереди открываем все файлы в директории и проверяем, можно ли их
индексировать
// у меня можно индексировать только файлы, которые имеют вид "число.txt"
// то есть && (is_numeric(str_replace (".txt","", $file))) - это вам наверняка
не понадобится.
$handle=opendir('./'.$indexdir);
while (false!==($file = readdir($handle))):
if ($file != "." && $file != ".." && (is_numeric(str_replace (".txt","", $file)))
):
// открываем очередной файл
$fd = fopen ($indexdir."/".$file, "r");
$contents = fread ($fd, filesize ($indexdir."/".$file));
Fclose ($fd);
// убираем переводы строк
$contents=str_replace ("n"," ", $contents);
$contents=str_replace ("r","", $contents);
// убираем хтмл-тэги
$contents=str_replace ('<br>', ' ', $contents);
$contents=str_replace ('<p>', ' ', $contents);
$contents=strip_tags ($contents);
// убираем знаки препинания и цифры
// все эти строки работают быстрей, чем один eregi_replace!
$contents=str_replace (' -', ' ', $contents);
$contents=str_replace ('.', ' ', $contents);
$contents=str_replace (',', ' ', $contents);
$contents=str_replace ('!', ' ', $contents);
$contents=str_replace ('?', ' ', $contents);
$contents=str_replace (':', ' ', $contents);
$contents=str_replace (';', ' ', $contents);
$contents=str_replace (')', ' ', $contents);
$contents=str_replace ('(', ' ', $contents);
$contents=str_replace ('"', ' ', $contents);
// убираем заглавные буквы
$contents=strtolower ($contents);
// разбиваем на слова, убираем слова, короче 3х букв
$contents=explode (" ", $contents);
// вот и функция пригодилась...
array_walk ($contents, 'sw');
// убираем повторяющиеся слова
$contents=array_unique ($contents);
// соединяем слова
$contents=implode (" ", $contents);
// формируем соответствующую строку в индексе.
$fullfile.=$file."| ".$contents." n";
// индекс-файл будет иметь вид:
// имя_файла|индекс_для_данного_файла n
// имя_файла|индекс_для_данного_файла n
// имя_файла|индекс_для_данного_файла n
echo ($file." проиндексирован<br>");
// переходим к следующему файлу
endif;
endwhile;
closedir($handle);
// убираем двойные пробелы
while (stristr($fullfile, " ")) $fullfile=str_replace (" "," ",$fullfile);
// индекс готов, сохраняем его
$fp = fopen($indexfile, "w+");
fwrite($fp, $fullfile);
fclose($fp);
// считаем, как долго работал скрипт
$ddd=microtime();
$ddd=((double)strstr($ddd, ' ')+(double)substr($ddd,0,strpos($ddd,' ')));
echo ("<br>Время индексации: ".(number_format(($ddd-$ttt),3))." секунд<br>");
echo ("Размер индекса: ".(number_format((round ((filesize($indexfile))/1024))
, 0, ".",".")))." Kb";
?>
Итак, у нас есть индекс. Дальше — просто. Так ведь?.. Надо просто произвести поиск в нем. Берем функцию eregi, например…
Хотя я делал совсем
Лирическое отступление: часто, когда надо проверить, если в строке
if (eregi(’this must be found’,$string)) echo ’found!!’; else echo ’нифига не found!’;
Способ хороший, но тормозной —
Ок, вот пример с php.net:
$email = 'sterling@designmultimedia.com';
$domain = strstr ($email, '@');
print $domain;
// выводит: @designmultimedia.com
Теперь понятно? Функция ищет, где в строке встречается подстрока «@» и выводит все после нее (включительно). Что самое главное — если ничего на найдено, то функция возвращает false. Именно поэтому ее можно использовать вот так:
if (stristr($string, ’this must be found’)) echo ’found!!’; else echo ’нифига не found!’;
У меня в скрипте для поиска в индексе используется stristr. Кроме того,
поиск понимает простейший синтаксис: «+» (слово должно быть найдено, aka AND),
В моем поиске всеми этими значками никто не пользуется, как бы я ни
распинался. Хотя, когда мне надо найти у себя
Скрипт простой, но работает надежно. Если правильно составить запрос — то находит все с первого раза. В принципе, можно еще сделать сортировку по релевантности, сделать так, чтобы из найденного файла показывался кусок с текстом, где искомое слово было бы выделено, и прочее… Но это вы делайте сами…
<?php
// Spectator's Site Search Script
// (C) Spectator.ru
// Для работы требуется PHP 4 или выше.
// Если вы будете использовать этот скрипт, ссылка на Spectator.ru крайне
желательна. Спасибо.
// файл с индексом
$indexfile="indexfile.txt";
// обрабатываем запрос
$total=0;
$qu2=str_replace ("+","&",$words);
// убираем заглавные буквы
$qu2=strtolower ($qu2);
// обрубаем в конце лишние пробелы
$qu2=chop($qu2);
// убираем двойные пробелы
while (stristr($qu2," ")) $qu2=str_replace (" "," ",$qu2);
echo ('Запрос: '.$qu2);
echo ('<p><p><p>');
// разбиваем запрос на слова
$words = explode (' ', $qu2);
// удаляем в запросе все лишнее (знаки препинания, и прочее)
$qu2=eregi_replace ('[.?,!()#":;|]', '', $qu2);
// проверяем длинну запроса
if (strlen($qu2)>2):
// открываем индекс
$index=file ($indexfile);
$num= (count($index)-1);
// для каждой сточки из индекса (одна строчка=один файл) выполняем:
for ($i=1; $i<$num+2; $i++):
$contents=$index[$i-1];
$wordcount =0;
$mustfound=1;
// выполняем для каждого их запрошенных слов:
$mustntfound=1;
for ($q=0; $q<count($words); $q++):
// обработка знаков *, + и -
// знак *
if (stristr($words[$q], "*")) {$search=str_replace ("*","",$words[$q]); } else
{ $search=" ".$words[$q]." ";}
// если в слове есть звездочка, то убираем звездочку и добавляем в начало и
конец слова по пробелу
// если нет проблелов, то слово будет искаться не целиком, а "вообще",
// то есть на запрос "чай" будет выводиться и слово "случайный".
// bug: скрипт не учитывает, где в слове стоит звездочка и считает, что в любом случае она стоит в конце (!!)
// знак & (или +)
if (stristr($search, "&")) {$search=str_replace ("&","",$search); $mustfound++;
}
// если стоит знак +, то количество слов, которые _должны_ быть найдены, увеличиваются на 1
// знак -
if (stristr($search, "-")) {$search=str_replace ("-","",$search); $mustntfound=0;
}
// если стоит знак +, то если слово найдено, весь результат умножается на 0 (смотри дальше).
// если слово найдено, считаем его и умножаем на $mustntfound, то есть на
1,
// если найдено "правильное" слово и на 0, если найдено слово, помеченное
знаком -
if (stristr($contents, $search)) { $wordcount++; $wordcount=$wordcount*$mustntfound;}
endfor;
// проверяем, все ли слова, помеченные знаком + найдены,
// либо (если таких слов нет), найдено ли вообще хоть одно слово
if ($wordcount >= $mustfound):
// находим имя файла, в котором это найдено
$file=explode ("|",$contents);
$file=$file[0];
// выводим имя файла, в котором это найдено с ссылкой
// (этот кусочек вам надо будет переделать под собственные нужды).
$file=str_replace (".txt", "", $file);
$file=str_replace ("_", ".", $file);
echo ("<a href=".$file.">".$file."</a><br>");
// считаем, колько всего файлов надено
$total++;
endif;
// переходим к следующемуу файлу
endfor;
// выводим результаты
if ($total!=0) echo ('<br><br>Всего найдено страниц: '.$total); else echo ("<b>Ничего
не найдено!</b><p>Возможно, вы просто не правильно составили запрос. Как это
сделать правильно - смотрите <a href=search>вот здесь</a>.");
else:
echo ("<br>Слишком короткий запрос!");
endif;
?>
<!-- Форма для поиска: -->
<form method=get action=search.php>
<input type=text size=19 name=words value="" maxlength=150> <input type=submit
class=frm value=Go>
</form>
PS. PHP.net — очень хороший сайт. 99%
того, что мне надо, я нахожу там. Все просто: если вам не понятно, как
работает