Поиск на php
// 28 июня 2001 года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 isnt very useful, its just funny. Try it out :)», то есть скрипт переворачивает строку
Нашел скрипт поиска по сайту: он обшаривает директории, которые вы указали, открывает все
В общем, решил я
Итак, начали…
Самое первое скрипт индексации. Для чего он нужен?.. Вот у меня 278 заметок. Если мы будем открывать каждый файл и искать совпадения, то нам надо будет открыть 278 файлов. А это ой как долго… Более того, нам надо будет 278 раз провести хитрые манипуляции с этими файлами (про манипуляции ниже). Если же у нас есть индекс, то
Алгоритм индексирующего скрипта такой:
1. Открываем очередной файл
2. Убираем из него «мусор» ( зачем убирается мусор понятно, чем мусора меньше, тем ищется быстрее… ):
а) переводы строк
б)
в) знаки препинания
г) слова, короче трех букв (а зачем они там?)
3. Делаем заглавные буквы строчными.
4. Убираем повторяющиеся слова. (Действительно, зачем нам вся это тавтология?)
5. Записываем все в индекс.
6. Если еще есть файлы, переходим к пункту 1.
Реализуется это все на php легко!
// Spectator's Indexing Script // ставим скрипт "на счетчик" (чтобы знать, как долго он выполнялся // Функция, удалающая слова, короче 3х букв. Пригодится дальше. // по очереди открываем все файлы в директории и проверяем, можно ли их индексировать $handle=opendir('./'.$indexdir); // открываем очередной файл $contents=str_replace (' -', ' ', $contents); // убираем заглавные буквы // разбиваем на слова, убираем слова, короче 3х букв echo ($file." проиндексирован<br>"); endif; // убираем двойные пробелы // индекс готов, сохраняем его // считаем, как долго работал скрипт echo ("<br>Время индексации: ".(number_format(($ddd-$ttt),3))." секунд<br>"); ?><?php
// (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);
function sw (&$item1, $key) { if (strlen($item1)<3) $item1=""; }
// у меня можно индексировать только файлы, которые имеют вид "число.txt"
// то есть && (is_numeric(str_replace (".txt","", $file))) - это вам наверняка не понадобится.
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=strtolower ($contents);
$contents=explode (" ", $contents);
// вот и функция пригодилась...
array_walk ($contents, 'sw');
// убираем повторяющиеся слова
$contents=array_unique ($contents);
// соединяем слова
$contents=implode (" ", $contents);
// формируем соответствующую строку в индексе.
$fullfile.=$file."| ".$contents." n";
// индекс-файл будет иметь вид:
// имя_файла|индекс_для_данного_файла n
// имя_файла|индекс_для_данного_файла n
// имя_файла|индекс_для_данного_файла n
// переходим к следующему файлу
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 ("Размер индекса: ".(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),
В моем поиске всеми этими значками никто не пользуется, как бы я ни распинался. Хотя, когда мне надо найти у себя
Скрипт простой, но работает надежно. Если правильно составить запрос то находит все с первого раза. В принципе, можно еще сделать сортировку по релевантности, сделать так, чтобы из найденного файла показывался кусок с текстом, где искомое слово было бы выделено, и прочее… Но это вы делайте сами…
// Spectator's Site Search Script // обрабатываем запрос $total=0; // убираем заглавные буквы // обрубаем в конце лишние пробелы // убираем двойные пробелы // разбиваем запрос на слова // удаляем в запросе все лишнее (знаки препинания, и прочее) // проверяем длинну запроса // для каждой сточки из индекса (одна строчка=один файл) выполняем: $contents=$index[$i-1]; $wordcount =0; // выполняем для каждого их запрошенных слов: for ($q=0; $q<count($words); $q++): // обработка знаков *, + и - // знак * // если в слове есть звездочка, то убираем звездочку и добавляем в начало и конец слова по пробелу // bug: скрипт не учитывает, где в слове стоит звездочка и считает, что в любом случае она стоит в конце (!!) // знак & (или +) // если стоит знак +, то количество слов, которые _должны_ быть найдены, увеличиваются на 1 // знак - // если стоит знак +, то если слово найдено, весь результат умножается на 0 (смотри дальше). // если слово найдено, считаем его и умножаем на $mustntfound, то есть на 1, if (stristr($contents, $search)) { $wordcount++; $wordcount=$wordcount*$mustntfound;} endfor; // проверяем, все ли слова, помеченные знаком + найдены, if ($wordcount >= $mustfound): // находим имя файла, в котором это найдено // выводим имя файла, в котором это найдено с ссылкой $file=str_replace (".txt", "", $file); // переходим к следующемуу файлу // выводим результаты else: <!-- Форма для поиска: --><?php
// (C) Spectator.ru
// Для работы требуется PHP 4 или выше.
// Если вы будете использовать этот скрипт, ссылка на Spectator.ru крайне желательна. Спасибо.
// файл с индексом
$indexfile="indexfile.txt";
$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++):
$mustfound=1;
$mustntfound=1;
if (stristr($words[$q], "*")) {$search=str_replace ("*","",$words[$q]); } else { $search=" ".$words[$q]." ";}
// если нет проблелов, то слово будет искаться не целиком, а "вообще",
// то есть на запрос "чай" будет выводиться и слово "случайный".
if (stristr($search, "&")) {$search=str_replace ("&","",$search); $mustfound++; }
if (stristr($search, "-")) {$search=str_replace ("-","",$search); $mustntfound=0; }
// если найдено "правильное" слово и на 0, если найдено слово, помеченное знаком -
// либо (если таких слов нет), найдено ли вообще хоть одно слово
$file=explode ("|",$contents);
$file=$file[0];
// (этот кусочек вам надо будет переделать под собственные нужды).
$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>.");
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% того, что мне надо, я нахожу там. Все просто: если вам не понятно, как работает