Скрипт PHP для поиска на сайте

Здравствуйте, друзья. Хочу с вами поделиться скриптом, который вы можете использовать по своему усмотрению. Я уверен, что вы сможете легко его усовершенствовать под свои нужды. В конце статьи вы найдете ссылку на скачивание этого скрипта. В исходниках скрипта вы найдёте необходимые файлы для его встраивания на свой сайт. Также в конце статьи вас ждет ссылка на один неплохой материал, который, я надеюсь, поможет вам усовершенствоваться как разработчику. А теперь к делу! Для начала создадим таблицу, в которой будут хранится найденные статьи:

CREATE TABLE `searchers` (
  `id` int(5) NOT NULL,
  `title` varchar(255) NOT NULL DEFAULT "",
  `text` text NOT NULL,
  `description` text NOT NULL,
  `mini_img` varchar(255) NOT NULL DEFAULT "",
  `relevation` int(5) NOT NULL,
  KEY `id` (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=104 DEFAULT CHARSET=cp1251;

Для работы с таблицой «searchers» будем использовать класс «Search» из файла «Search.class.php»:

<?php
require_once "DB.class.php";

class Search {
    public $id;
    public $title;
    public $text;
    public $description;
    public $mini_img;
    public $relevation;

    //Конструктор создаёт новый поисковый объект
    function __construct($data) {
        $this->id = (isset($data["id"])) ? $data["id"] : "";
        $this->title = (isset($data["title"])) ? $data["title"] : "";
        $this->text = (isset($data["text"])) ? $data["text"] : "";
        $this->description = 
        (isset($data["description"])) ? $data["description"] : "";
        $this->mini_img = 
        (isset($data["mini_img"])) ? $data["mini_img"] : "";
        $this->relevation = (
        isset($data["relevation"])) ? $data["relevation"] : "";
    }

    public function save($isNewArticle = FALSE) {
        //Создаём новый объект БД
        $db = new DB();
        // Заменям все апострофы в тексте на двойные кавычки, 
        // чтобы данные записались в БД без ошибок.
        $text = str_replace(""", """, $this->text);

        // Если статья присутствует в БД, то обновляем
        if(!$isNewArticle) {
            $data = array(
            "title" => ""$this->title"",
            "text" => """.$text.""",
            "description" => ""$this->description"",
            "mini_img" => ""$this->mini_img"",
            "relevation" => ""$this->relevation""
            );
            //обновим строку в БД
            $db->update($data, "searchers", "id = ".$this->id );
        }else{ // Если статьи ещё нет в БД, то добавляем
            $data = array(
            "id" => ""$this->id"",
            "title" => ""$this->title"",
            "text" => """.$text.""",
            "description" => ""$this->description"",
            "mini_img" => ""$this->mini_img"",
            "relevation" => ""$this->relevation""
            );
            //добавим строку в БД
            $this->id = $db->insert($data, "searchers");
        }
            return true;
    }
}
?>


Как видите мы подключаем еще один класс «DB» из файла «DB.class.php» для работы с базой:

<?php

class DB {
   // Свойства класса
   protected $db_name = "mydbname"; // Имя Вашей базы
   protected $db_user = "mydbuser"; // Имя пользователя Вашей базы
   protected $db_pass = "mypassword"; // Пароль к Вашей базе
   protected $db_host = "myhostname"; // Имя хоста, может быть "localhost"
    
    // Методы класса
    public function GetHost() {
        return $_SERVER["HTTP_HOST"];
    }

    public function connect() {
        $db=mysql_connect($this->db_host,$this->db_user,$this->db_pass);
        mysql_select_db($this->db_name,$db);
        return $db;
    }

    //Обновляет таблицу БД
    public function update($data, $table, $where) {
        foreach ($data as $column => $value) {
            $sql = "UPDATE $table SET $column = $value WHERE $where";
            mysql_query($sql) or die(mysql_error());
        }
        return true;
    }

    //Удаляет строки из таблицы БД
    public function delete($table, $where) {
        $sql = "DELETE FROM $table WHERE $where";
        mysql_query($sql) or die(mysql_error());
        return true;
    }

    //Вставляет новую строку в таблицу БД
    public function insert($data, $table) {
        $columns = "";
        $values = "";
        foreach ($data as $column => $value) {
            $columns .= ($columns == "") ? "" : ", ";
            $columns .= $column;
            $values .= ($values == "") ? "" : ", ";
            $values .= $value;
        }
        $sql = "insert into $table ($columns) values ($values)";
        mysql_query($sql) or die(mysql_error());
        //Выводит ID
        return mysql_insert_id();
    }
}

?>

Измените свойства класса «DB», добавив информацию о Вашей базе.

Теперь напишем основные строки кода из файла «view_search.php»:

<?php
// Подключаем поисковый класс
require_once "classes/Search.class.php";

// Объявляем переменные
$endings = "ых|ый|ы|ой|ое|ые|ому|ом|ами|ам|ая|ат|ать|а|
овый|ов|ого|ох|о|у|ему|ей|е|ство|ия|ий|и|ять|ь|я|он|ют|";
//Ставим окончания с большим количеством символов вперед, 
//например, если первая "е", то "|ему|ей|е|".
$endings_arr = explode("|",$endings);

// Получаем массив из слов в нижнем регистре
$search_arr = explode(" ",strtolower($search));
// Получаем массив слов со всеми имеющимися у нас окончаниями
$SearchArray = GetSearchArrayX($search);

//Удалим все строки из таблицы
$db1 = new DB();
$db = $db1->connect();
$db1->delete("searchers", "id<>0");

if ($SearchArray <> "") 
{
    echo "<p class=".p_class.">
    Результаты для <strong><em>".$search."</em></strong>
    </p>";
        // Укажите здесь название таблицы, в которой нужно искать
        $tbl ="NameOfYourTable"; 
        // Найдём слова в заголовке статьи
        SearchWords($SearchArray, "title", $db, $tbl);
        // Найдём слова в тексте статьи
        SearchWords($SearchArray, "text", $db, $tbl);
        // Выведем статьи из таблицы поиска
        ViewArticles($SearchArray, $db);
}else{
echo "<p class=".p_class.">Информация по Вашему запросу не найдена.</p>";}

?>


Теперь по порядку покажем описание функций, используемых здесь. Описание функции «GetSearchArrayX»:

<?php

// функция добавления слов с окончаниями в массив
function GetSearchArrayX($query) {  
    global $endings_arr;
    // Заносим слова, разделенные пробелом в массив
    $words = explode(" ",$query);
    //создаем пустой массив
    $SearchArray = array();
    //создаем пустую строку
    $SearchArray_str = "";
    foreach ($words as $word) {     
        $j=0;
        $word = trim($word);
        //пропускаем, если слово короче трёх символов
        if (strlen($word)<3) { unset($word); } else { if (strlen($word)>2) {
                $WithoutEnding = DeleteEndings($word); 
                // первым ставим слово без окончания
                if ($j == 0) { 
                    if ($word != $WithoutEnding) {
                        $SearchArray_str=$SearchArray_str." ".$WithoutEnding;
                    }
                    $SearchArray_str=$SearchArray_str." ".$word;
                }
                $j++;
                foreach ($endings_arr as $ending){
                    // Если находим слово с таким же окончанием продолжаем
                    if ($word == $WithoutEnding.$ending) {
                        continue;
                    }
                    $SearchArray_str=$SearchArray_str." "
                    .$WithoutEnding.$ending;    
                }
            }
            else {
                $SearchArray_str=$SearchArray_str." ".$word;
            }
        }
    }
    $SearchArray = explode(" ",trim($SearchArray_str));
    return $SearchArray; //возвращаем полученный массив
} // GetSearchArrayX

?>

Описание функции «DeleteEndings»:

<?php

// Функция удаления окончаний
function DeleteEndings($word) { 
    global $endings;
    $reg = "/(".$endings.")$/i"; 
    $word = preg_replace($reg,"",$word); //удаляем окончания
    return $word;
}

?>

Описание функции «SearchWords»:

<?php

function SearchWords($SearchArray, $column, $db, $tbl = "data")
{
    global $search;

    $query_str = 
    "SELECT id,text,mini_img,title,description FROM ".$tbl." WHERE ";

    $SearchArray_ = GetSearchArray($search);
    foreach ($SearchArray_ as $word) {
    // ищем вхождение слова
        $result1 = mysql_query($query_str."(".$column." LIKE "%$word%")",$db);
        if (!$result1)
        {
            echo "<p align="center">
            Запрос на выборку данных из базы не прошел. 
            Напишите об этом администратору сайта. 
            <br> <strong>Код ошибки:</strong></p>";
            exit(mysql_error());
        }

        if (mysql_num_rows($result1) > 0)
        {
            while($row = mysql_fetch_assoc($result1))
            {
                 if (isset($row)) {
                    // проверим есть ли запись с таким id
                    $check_id = check_id($row[id], $db);
                    if($check_id) { // если да, пропускаем
                        continue;
                    }
                    //создать новый объект поиска
                    $newSearch = new Search($row);
                    //сохранить новый поиск в БД
                    $newSearch->Save(TRUE);
                }
            }
        }
    }
} // SearchWords()

?>

Описание функции «check_id»:

<?php

// Проверяем есть ли запись в таблицы с таким id
function check_id($id, $db)
{
    $result = mysql_query ("
    SELECT id FROM searchers WHERE (id=".$id.")",
    $db);
    if (!$result)
    {
        echo "<p align="center">Запрос на выборку данных из базы не прошел. 
        Напишите об этом администратору сайта. 
        <br> <strong>Код ошибки:</strong></p>";
        exit(mysql_error());
    }

    if (mysql_num_rows($result) > 0)
    {   
        return TRUE;
    }
    else
    {
        return FALSE;
    }
} // check_id

?>

Описание функции «ViewArticles»:

<?php

// Функция вывода найденных статей из таблицы поиска
function ViewArticles($SearchArray, $db){
    SearchArticles($SearchArray);
    $arts = mysql_query ("
    SELECT * FROM searchers WHERE relevation <> 0 ORDER BY relevation DESC",
    $db);
    if (!$arts)
    {
        echo "<p align="center">Запрос на выборку данных из базы не прошел. 
        Напишите об этом администратору сайта. 
        <br> <strong>Код ошибки:</strong></p>";
        exit(mysql_error());
    }

    if (mysql_num_rows($arts) > 0)
    {   
        while($articles = mysql_fetch_assoc($arts))
        {
            $text = $articles["description"];
            $id = $articles["id"];
            print <<<HERE
            <br>
            <table align="center" class="post">
            <tr>
                <td class="post_title">
                    <p class="post_name"><img class="mini" 
                    align="left" src="https://site.softmaker.kz/files/a></p>
                 </td>
            </tr>
            <tr>
                <td>$text
                <p class="post_view"><span style="background-color: #ffec82;">
                Число вхождений: $articles[relevation]</span></p>
                </td>
            </tr>
            </table>   
HERE;
        }
    }
    else
    {
    print <<<HERE
        <p class="post_title2">Информация по Вашему запросу не найдена.</p>
HERE;
    }
 } // ViewArticles

?>

Описание функции «SearchArticles»:

<?php

// Функция для добавления выделенных слов в таблицу searchers
function SearchArticles($SearchArray) {
    global $db, $search;
    // Эта переменная нужна, чтобы узнать были ли совпадения
    $was = 0;
    // Выбираем все статьи из таблицы поиска
    $arts = mysql_query (
    "SELECT * FROM searchers ORDER BY relevation DESC",
    $db);
    if (!$arts)
    {
        echo "<p align="center">
        Запрос на выборку данных из базы не прошел. 
        Напишите об этом администратору сайта. 
        <br> <strong>Код ошибки:</strong></p>";
        exit(mysql_error());
    }

    if (mysql_num_rows($arts) > 0)
    {   
        while($article = mysql_fetch_assoc($arts)){
            
            $title = $article[title]; 
            // можно так: 
            // $title = htmlspecialchars(strip_tags($material[title]));
            $text = $article[text]; 
            // можно так: 
            // $text = htmlspecialchars(strip_tags($material[text]));
            $description = $article[description];
            $CountOfEntry =0; //число вхождений слова
            $relevation = 0;
            $SearchArray_ = GetSearchArray($search); 
            // Цикл по массиву слов без окончаний
            foreach ($SearchArray_ as $word) {
                $word_l = strtolower($word);
                $WithoutEnding = DeleteEndings($word_l);
                //Создадим маску для поиска с помощью регулярной функции
                $reg = "/(".$word_l.")/"; 
                if ($word_l == $WithoutEnding) {
                    // подсчитываем количество вхожений в заголовке, 
                    // тексте и описании
                    $CountOfEntry = 
                    preg_match_all($reg, strtolower($title), $out); 
                    $CountOfEntry += 
                    preg_match_all($reg, strtolower($text), $out);  
                    $CountOfEntry += 
                    preg_match_all($reg, strtolower($description), $out);

                    $article[relevation] += $CountOfEntry; 
                    // увеличиваем число вхождений слова
                    // окрашиваем совпадения в заголовке, тексте и описании
                    $title = MarkAll($word_l, $title);
                    $text = MarkAll($word_l, $text);
                    $description = MarkAll($word_l, $description);
                }
            }
            //Добавляем в таблицу только те статьи, 
            //которые имеют хотя бы одно вхождение
            if($article[relevation]!=0) {
                $was = 1;
                $article[title] = $title;
                $article[text] = $text;
                $article[description] = $description;
                //создать новый объект поиска
                $newSearch = new Search($article);
                //обновить поиск в БД
                $newSearch->Save();
            }
            else {
                unset($article);
            }
        }
    }
    // Если не было совпадений, выводим сообщение   
    if ($was == 0) {
    echo "<p align="center">
    Информация в статьях по Вашему запросу не найдена.
    </p>";
    }
    return $article; 
}

?>

Описание функции «GetSearchArray»:

<?php

//функция добавления слов без окончаний в массив
function GetSearchArray($query) {   
    global $endings_arr;
    //Заносим слова, разделенные пробелом в массив
    $words = explode(" ",$query);
    //создаем пустой массив
    $SearchArray = array();
    //создаем пустую строку
    $SearchArray_str = "";
    foreach ($words as $word) {     
        $word = trim($word);
        //пропускаем, если слово короче трёх символов
        if (strlen($word)<3) { unset($word); } else { if (strlen($word)>2) {
                $WithoutEnding = DeleteEndings($word); 
                $SearchArray_str=$SearchArray_str." ".$WithoutEnding;
            }
            else {
                $SearchArray_str=$SearchArray_str." ".$word;
            }
        }
    }
    $SearchArray = explode(" ",trim($SearchArray_str));
    return $SearchArray; //возвращаем полученный массив
} // GetSearchArray

?>

Описание функции «MarkAll»:

<?php

// Функция для выделения найденных слов в тексте
function MarkAll($word, $string) {
    global $endings_arr, $search_arr;
    // если не находим слова без окончания, значит не найдём ничего
    if (stristr ($string, $word) == FALSE) { 
        return $string;
    }
    //  Сначала окрашиваем целые слова с окончаниями
    foreach ($search_arr as $search){
        if (stristr($search, $word) == FALSE) {
            continue;
        }
        $pattern = "/b".$search."b/i";
        $replacement = "<mark>".$search."</mark>";
        $string = preg_replace($pattern, $replacement, $string);
    }
    // Находим слово без окончания и окрашиваем его
    if (in_array($word, $search_arr))
    {
        $pattern = "/b".$word."b/i";
        $replacement = "<mark>".$word."</mark>";
        $string = preg_replace($pattern, $replacement, $string);
    }
    // Добавляем к слову без окончания все окончания и окрашиваем
    foreach ($endings_arr as $ending){
        $pattern = "/b".$word.$ending."b/i";
        $replacement = "<mark>".$word.$ending."</mark>";
        $string = preg_replace($pattern, $replacement, $string); 
    }
    return $string;
} // MarkAll

?>
4 ответы
  1. Сергей говорит:

    Это что получается данные к базе сможет увидить каждый кто откроет DB.class.php(имя базы,имя пользователя,пароль?

  2. Softmaker говорит:

    Здравствуйте, Сергей!
    Даже, если смогут открыть, что мало вероятно, то увидят текст, который видите вы. А не данные из базы.

  3. serj011 говорит:

    Отличный скрипт, спасибо! Есть конечно к чему придраться, но это лучшее что есть в сети-))
    Немного доработал, прикрутил постраничную навигацию…
    У меня вот только пока ни как не получилось настроить подсветку для русского текста, т.е. латиницу подсвечивает, а кириллицу нет((
    Если знаете, подскажите пожалуйста.
    И у меня еще вопрос, я так лр конца и не понял принцип работы в целом…. При поиске данные временно заносятся в таблицу, может быть накладка обращения к таблице, если например несколько пользователей будут использовать скрипт?

    • softmaker говорит:

      Спасибо, я думаю, что второй запрос будет ожидать завершение первого.

Комментарии закрыты.