Главная страница статей --> Хитрости при программировании php, заметки по базам данных

Безопасный и удобный поиск на PHP

Источник: realcoding.net

Главное, с чем сталкиваешься при написании скрипта для поиска - то, что все кажется простым, но объем кода быстро нарастает.

Обработка строки


Первым делом надо порезать ручками строку.

$search = substr($search, 0, 64); 64 символов пользователю будет достаточно для
поиска. Теперь каленым железом выжжем все "ненормальные" символы.

$search = preg_replace("/[^(w)(x7f-xff)(s)]/", " ", $search); По идее, нельзя
давать пользователю возможности искать по слишком коротким словам - кроме всего
прочего, это сильно загружает сервер. Итак, разрешим искать только по словам, которые
длиннее двух букв (если ограничение больше, надо заменить "{1,2}" на "{1, кол-во
символов}").

$good = trim(preg_replace("/s([^s]{1,2})s/", " ", ereg_replace("[ ]+", " "," $search
"))); А после замены плохих слов - надо сжать двойные пробелы (они были сделаны
специально для корректного поиска коротких слов).

$good = ereg_eplace([ ]+, , $good);

Логика


Допустим, мы хотим предоставить пользователю возможность выбирать логику поиска -
искать все слова или только одно из нескольких. Если вы хотите сделать как в Яндексе
[2] [1] - два амперсанта означают "И" (слово1&&слово2&&слово3) или как-то еще, то я не
советчик. Шаманство со строками на небольшом сайте imho не оправдывает затраченного
времени. Поэтому форму для поиска рисуем так:

искать любое из словискать все слова

А в поисковом скрипте лишний раз проверяем, что пользователь ввел:

if ($logic!="and" && $logic!="or") $logic = "or"; Как будет использоваться логика —
ниже.

Релевантность


Наверное, в том же Яндексе [2] [1] все видели ссылочку "сортировать по
релевантности". Это оно и есть. Сортировка результатов по количеству совпадений слов.

Отчасти, кстати, такая сортировка снимает проблему обработки логики поиска. Но с БД
mysql делать такую сортировку очень сложно. Надо сперва выбрать, где есть все слова,
потом записи, где разные слова (исключив предыдущие). Если у вас постраничный вывод -
то вообще дело труба!

Статистика поиска


Неплохо будет сразу информировать пользователя, сколько он нашел строк таблицы. Для
этого делается дополнительный запрос в базу:

$query = select id from table where field like %. str_replace( , % or field
like %
, $good). %;

Для статистики по отдельным словам можно сделать следующее:

$word = explode( , $search); while (list($k, $v) = each($word)) { if (strlen($v)>2)
$stat[]=$v:. mysql_num_rows(mysql_query(select id from table where field like
%$v%
)); else $stat[]=$v: <font color=#cc0000>короткое</font>; }; $word_stats =
Статистика слов: . implode(, $stat). <br>; unset($stat);

Постраничный вывод результатов


Ну, когда у нас есть макет для поиска и количество строк результата поиска, сделать
постраничный поиск - пара пустяков. Проверяем переменную $page (не меньше 0, не больше
$results_amount/$rows_in_page).

В запрос, который подсчитывает количество строк (смотри выше), пишем нужные нам поля
и поля для сортировки. А потом дописываем

if ($page==0) $request .= limit $rows_in_page; else $request .= limit .
$page*$rows_in_page. ,. $rows_in_page; (синтаксис: limit <кол-во строк> либо limit
<кол-во строк отступа>, <кол-во строк>)

В результате выполнения подобного запроса мы получим именно те самые строки, которые
надо выводить на странице.

Для навигации можно либо рисовать ссылки на следующую и предыдущую страницы, либо,
что сложнее, делать панель навигации на несколько страниц.

if ($page>0) print (<a href=search.php?search=. rawurlencode($good). &page=.
(
$page-1). >предыдущая страница</a>);

if (
$page<$results_amount/$rows_in_page) print (<a href=search.php?search=.
rawurlencode($good). &page=. ($page+1). >следующая страница</a>);

Подсветка

Чтобы подсвечивать светом или жирным шрифтом искомые слова в тексте, надо сделать
всего лишь следующее:

$highlight = "(". str_replace(" ", "", $good). ")"; Пробелы (а они у нас между
словами стоят поодиночке, и нигде двойной пробел не встречается, к тому же с концов
строки мы их тоже вырезали) достаточно заменить на вертикальную черту - разделитель
вариантов в регулярных выражениях. "Плохие" слова мы не подсвечиваем, потому что в базе
их не ищем :).

В коде, который выводит текст пишем:

$row["text"] = ereg_replace($highlight, "<font color=#cc0000>1</font>",
$row["text"]); После написания выпуска я кинулся, было, писать и себе "подсветку". Не
тут-то было! У меня в тексте встречаются теги html, поэтому пришлось много подумать...
Получилась вот такая вещь (строка со словами для подсветки есть):

$text = eregi_replace(>([^<]*)$words, >1<font color=#cc0000>2</font>3<, $text);

Приходится смотреть, нет в теге ли это слово. Однако тут встает проблема ресурсоемкости
такой замены (мой k6-266 над текстом в 5 килобайт думал целых семь секунд). Печально.

Итог


Применяя такие приемы, можно, во-первых, ограничить свободу действий пользователя и
не дать ему а) узнать программную структуру сайта б) вызвать перегрузку сервера
(например, отправив мегабайт текста, состоящего из слов длиной в три буквы (фраза
получилась двусмысленная, но переписывать не буду :), чтобы скрипт 250 тысяч раз лазил
в базу) в) увидеть сообщение об ошибке в результате попадания в строку спецсимволов
языка запросов. Во-вторых, некоторое удобство для пользователя - постраничный вывод и
подсветка.



Похожие статьи:
- Язык программирования Ruby
- HTMLchecklist – проверь свой HTML
- Rails SCGI Install
- Тестирование в Rails
- Звериный оскал информационной безопасности
- Абсолютный и относительный путь к файлам
- Как заставить Apache понимать SSI?
- Веб-сайт: сборка по кирпичикам
- Кэшируем свой сайт
- Создание вкладок средствами HTML.
- CGI на Perl. Первые шаги.
- Документ изменен
- Как сделать эффективный баннер


Оглавление | Обсудить на форуме | Главная страница сайта | Карта сайта |

Контакты
Редакция:
[0.002]