Пишем поиск по сайту на PHP и MySQL

7 ответ(ов) в теме
Stanislavovich
не в сети давно
На сайте с 19.12.2013
Участник
0
20:23

Сегодня мы напишем собственный поиск по сайту с использованием PHP и MySQL. Первым делом рассмотрим краткий алгоритм.
Пользователь выполняет POST запрос из формы поиска, этот запрос передается специальному скрипту-обработчику, который должен обработать поисковый запрос пользователя и возвратить результат.
Сначала скрипт должен обработать должным образом запрос пользователя для обеспечения безопасности, затем выполняется запрос к базе данных, который возвращает в ассоциативном массиве результаты, которые должны будут выводиться на экран. Итак, приступим.
Для начала создадим форму поиска на нужной нам странице:

<form name="search" method="post" action="search.php"><br> <input type="search" name="query" placeholder="Поиск"><br> <button type="submit">Найти</button> <br></form>

Эта форма и будет отправлять сам поисковый запрос скрипту search.php. Теперь создадим сам скрипт-обработчик.

<?php <br>define('DB_HOST', 'localhost');<br>define('DB_USER', 'имя пользователя бд');<br>define('DB_PASS', 'пароль');<br>define('DB_NAME', 'имя базы данных');<br><br>if (!mysql_connect(DB_HOST, DB_USER, DB_PASS)) {<br> exit('Cannot connect to server');<br>}<br>if (!mysql_select_db(DB_NAME)) {<br> exit('Cannot select database');<br>}<br><br>mysql_query('SET NAMES utf8');<br><br>function search ($query) <br>{ <br> $query = trim($query); <br> $query = mysql_real_escape_string($query);<br> $query = htmlspecialchars($query);<br><br> if (!empty($query)) <br> { <br> if (strlen($query) < 3) {<br> $text = '<p>Слишком короткий поисковый запрос.</p>';<br> } else if (strlen($query) > 128) {<br> $text = '<p>Слишком длинный поисковый запрос.</p>';<br> } else { <br> $q = "SELECT `page_id`, `title`, `desc`, `title_link`, `category`, `uniq_id`<br> FROM `table_name` WHERE `text` LIKE '%$query%'<br> OR `title` LIKE '%$query%' OR `meta_k` LIKE '%$query%'<br> OR `meta_d` LIKE '%$query%'";<br><br> $result = mysql_query($q);<br><br> if (mysql_affected_rows() > 0) { <br> $row = mysql_fetch_assoc($result); <br> $num = mysql_num_rows($result);<br><br> $text = '<p>По запросу <b>'.$query.'</b> найдено совпадений: '.$num.'</p>';<br><br> do {<br> // Делаем запрос, получающий ссылки на статьи<br> $q1 = "SELECT `link` FROM `table_name` WHERE `uniq_id` = '$row[page_id]'";<br> $result1 = mysql_query($q1);<br><br> if (mysql_affected_rows() > 0) {<br> $row1 = mysql_fetch_assoc($result1);<br> }<br><br> $text .= '<p><a> href="'.$row1['link'].'/'.$row['category'].'/'.$row['uniq_id'].'" title="'.$row['title_link'].'">'.$row['title'].'</a></p><br> <p>'.$row['desc'].'</p>';<br><br> } while ($row = mysql_fetch_assoc($result)); <br> } else {<br> $text = '<p>По вашему запросу ничего не найдено.</p>';<br> }<br> } <br> } else {<br> $text = '<p>Задан пустой поисковый запрос.</p>';<br> }<br><br> return $text; <br>} <br>?>

Естественно, данные таблиц БД нужно задать собственные. Рассмотрим, что делает эта функция. Первые 4 строчки обрабатывают запрос, чтобы он стал безопасным для базы. Такую обработку нужно делать обязательно, т. к. любая форма на Вашем сайте — это потенциальная уязвимость для злоумышленников.
Затем идет проверка, не пустой ли запрос. Если запрос пустой, то возвращаем соответствующее сообщение пользователю. Если запрос не пустой, проверяем его на размер.
Если поисковый запрос имеет длину менее 3 или более 128 символов, также выводим соответствующие сообщения пользователю. Иначе, выполняем запрос к базе данных, который делает выборку идентификатора страницы, ее заголовка, описания, описания ссылки, категорию, если она есть и идентификатор самой статьи, в которой найдены совпадения нужных нам полей с поисковым запросом.
В данном случае мы делаем сравнение с текстом статьи, ее заголовком, ключевыми словами и описанием. Если ничего не найдено, выводим пользователю сообщение об этом. Если запрос возвратил хотя бы одну запись, выполняем в цикле еще один запрос, который делает выборку из таблицы со страницами ссылку на страницу, на которой находится статья.
Если у Вас все статьи на одной странице, вы можете опустить этот шаг. После выполнения запроса при каждой итерации цикла в переменную $text Дозаписываем одну найденную статью.
После завершения цикла, возвращаем переменную $text, Которая и будет выводиться на нашей странице пользователю.
Теперь осталось на этой же странице search.php сделать вызов этой функции и вывести ее результат пользователю.

<?php <br>if (!empty($_POST['query'])) { <br> $search_result = search ($_POST['query']); <br> echo $search_result; <br>}<br>?>

Также вы можете упростить скрипт поиска по Вашему усмотрению. Желательно создать стиль в таблице css для выводимой информации, чтобы выводимая информация смотрелась более красиво и читабельно. Все замечания вопросы по скрипту можете задавать в комментариях.

Редакции сообщения
0
Y2K
не в сети давно
На сайте с 21.11.2014
Участник
0
09:28

Небольшие комментарии:
1. Не указано, в какой кодировке нужно хранить скрипт, в коде есть только
mysql_query('SET NAMES utf8');
Эта команда, устанавливающая кодировку для работы в UTF8. Многие начинающие разработчики сначала используют CP1251 в своих проектах, а это не очень хорошо 😛
Поэтому, или сохраняем все ваши скрипты в UTF8, или меняем внутреннюю кодировку в скрипте командами, например, mb_internal_encoding, mb_external_encoding. Или, в крайнем случае, дописываем к запросам типа SELECT
COLLATE latin1_german2_ci в нужное место, это зависит от типа запроса. Лучше почитать в самой документации MySQL: http://dev.mysql.com/doc/refman/5.0/en/charset-collate.html
2. В запросах не используются placeholder'ы. Это неоптимально и небезопасно:) Легче и лучше использовать готовые PHP-библиотеки, созданные для этого или, как например, класс PDO, вместо mysql_* функций. mysql_* функции уже на момент написания этой статьи были запрещены. Но их все так же можно скачать отдельно к вашему серверу, если это так необходимо:)

Редакции сообщения
0
Y2K
не в сети давно
На сайте с 21.11.2014
Участник
0
09:33

А еще!
В коде слишком много конкатенаций в цикле. В случае с PHP это очень и очень грозит утечками памяти:
$text .= '<p><a> href="'.$row1['link'].'/'.$row['category'].'/'.$row['uniq_id'].'" title="'.$row['title_link'].'">'.$row['title'].'</a></p>
<p>'.$row['desc'].'</p>';
Вместо этого перед циклом нужно объявлять $text = array() (или, для новых версий PHP - $text = [];), выделяя ему определенный размер в памяти вместо размера для текста-контейнера.
Далее в цикле вместо $text.= нужно использовать $text[]=
И, наконец, после завершения цикла, текст получать командой implode('', $text), собирающей массив воедино:)

Редакции сообщения
0
Phoenix
не в сети давно
На сайте с 15.02.2015
Участник
0
16:46

В целом код полезный, и со своей задачей справляется, только новичкам будет сложно его понять. Слишком много условий, в них легко запутаться. Я не вижу чтобы Вы выводили из таблицы поля text, meta_k, и meta_d, хотя производите по ним поиск. Почему не выводится meta я могу понять, но текст где? Если полный текст статьи вывести нельзя, то нужно показывать хотя бы отрезок с совпадением, чтобы пользователь его видел. Я на своем сайте, чтобы результаты поиска были нагляднее, подсвечивал совпадение светло-зеленым фоном. Очень красиво получалось.

Очень огорчает наличие всего одного комментария, и того в самом очевидном месте. Хороший программист знает как сделать поиск на сайте, а в такие темы попадают в основном новички (коим и я был не так давно). Не понимая что происходит, они просто копируют весь код, и, осознав что ничего не работает, опускают руки.

Редакции сообщения
0
igrok1908
не в сети давно
На сайте с 10.02.2015
Участник
0
00:37

Может, код и полезен... Но это под вопросом. Например, функция mysql_real_escape_string() просто не сработает, так как она устарела и вскоре будет вообще заменена. Когда данной функцией пытался защититься от инъекций, то в браузере возникала ошибка, которая не позволяла обрабатывать и последующий код — эта функция срабатывала с выдачей практически фатальной ошибки. А если уж придерживаться функционального стиля, то и подключение к базе следует выводить в отдельной функции, либо вообще выносить в отдельный файл с необходимостью его последующего подключения. А лучше, если константы DB_HOST и другие окажутся также в отдельном файле.

В php, хоть и оставили возможность программирования в функциональном стиле, все же отдают теперь предпочтение объектно-ориентированному, а потому приведенный пример немного устарел и не совсем полезен. Не совсем понятно зачем в коде используется вот эта часть: "mysql_query('SET NAMES utf8');". Для примера, на мой взгляд, она совершенно лишняя, ведь по условиям не сказано, что БД и таблицы, к которым обращаемся, в utf-8 кодировке, а, вдруг, у меня БД в кодировке "1251-windows"! :terminator

Редакции сообщения
0
Форум
Гость
0
17:38

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

Редакции сообщения
0
Root
не в сети давно
На сайте с 11.03.2015
Участник
0
13:17

женя сказал(а)
для чего нужна база данных для поиска? он что так просто по странице не может искать?

А вы подумали, сколько времени уйдет на просмотр всех страниц для поиска необходимого слова (фразы) с проверкой всех условий? Что же теперь, поисковую базу данных создавать для ускорения поиска, как это делают поисковые системы? И зачем это нужно, когда у нас уже есть база данных сайта, в которой все содержимое сайта заранее структурировано и отсортировано? Очевидно же, что искать проще и быстрее по базе данных, чем просматривая страницы одну за другой 🙂

Редакции сообщения
0

Ваше имя *

Ваш E-mail *

не публикуется

Текст сообщения *