Безопасный и удобный поиск MostInfo.net (http://mostinfo.net/article/3/42.htm) Главное, с чем сталкиваешься при написании скрипта для поиска - то, что все кажется простым, но объем кода быстро нарастает... |
||||
infocity.kiev.ua 10-05-2004 |
||||
Главное, с чем сталкиваешься при написании скрипта для поиска - то, что все кажется простым, но объем кода быстро нарастает. Обработка строки Первым делом надо порезать ручками строку. $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("[ ]%2B", " "," $search ")));А после замены плохих слов - надо сжать двойные пробелы (они были сделаны специально для корректного поиска коротких слов). $good = ereg_eplace("[ ]%2B", " ", $good);Логика Допустим, мы хотим предоставить пользователю возможность выбирать логику поиска - искать все слова или только одно из нескольких. Если вы хотите сделать как в Яндексе [2] [1] - два амперсанта означают "И" (слово1&&слово2&&слово3) или как-то еще, то я не советчик. Шаманство со строками на небольшом сайте imho не оправдывает затраченного времени. Поэтому форму для поиска рисуем так: А в поисковом скрипте лишний раз проверяем, что пользователь ввел:if ($logic!="AND" && $logic!="OR") $logic = "OR"; Как будет использоваться логика — ниже. Релевантность Наверное, в том же Яндексе [2] [1] все видели ссылочку "сортировать по релевантности". Это оно и есть. Сортировка результатов по количеству совпадений слов. Статистика поиска Неплохо будет сразу информировать пользователя, сколько он нашел строк таблицы. Для этого делается дополнительный запрос в базу: $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). $request .= "LIMIT $rows_in_page"; else $request .= "LIMIT ". $page*$rows_in_page. ",". $rows_in_page; (синтаксис: LIMIT <кол-во строк> либо LIMIT <кол-во строк отступа>, <кол-во строк>) 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%2B1). ">следующая страница</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 тысяч раз лазил в базу) в) увидеть сообщение об ошибке в результате попадания в строку спецсимволов языка запросов. Во-вторых, некоторое удобство для пользователя - постраничный вывод и подсветка. Оригинал статьи находится по адресу http://mostinfo.net/article/3/42.htm | ||||