Результаты PHP: эффективные решения для вывода поисковых данных
Результаты PHP: реализация поиска и вывода данных
Наиболее эффективное решение для вывода результатов поиска на PHP подразумевает использование подготовленных запросов PDO с пагинацией и кэшированием. Это обеспечивает безопасность, производительность и гибкость.
Как организовать защищённый поиск с постраничным выводом?
Пример структуры:
// config.php
$host = 'localhost';
$db = 'search_db';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
// search.php
$query = isset($_GET['q']) ? trim($_GET['q']) : '';
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$perPage = 10;
$offset = ($page - 1) * $perPage;
if ($query !== '') {
$stmt = $pdo->prepare('SELECT * FROM articles WHERE title LIKE :q OR content LIKE :q2 ORDER BY created_at DESC LIMIT :lim OFFSET :off');
$likeQuery = '%' . $query . '%';
$stmt->bindParam(':q', $likeQuery, PDO::PARAM_STR);
$stmt->bindParam(':q2', $likeQuery, PDO::PARAM_STR);
$stmt->bindParam(':lim', $perPage, PDO::PARAM_INT);
$stmt->bindParam(':off', $offset, PDO::PARAM_INT);
$stmt->execute();
$results = $stmt->fetchAll();
// Подсчёт общего количества для пагинации
$countStmt = $pdo->prepare('SELECT COUNT(*) FROM articles WHERE title LIKE :q OR content LIKE :q2');
$countStmt->execute([':q' => $likeQuery, ':q2' => $likeQuery]);
$total = $countStmt->fetchColumn();
$totalPages = ceil($total / $perPage);
}
Типичная ошибка: использование mysql_* функций, которые удалены в PHP 7. Решение - переход на PDO или mysqli.
Другая проблема - SQL-инъекции при конкатенации строк. Подготовленные запросы исключают эту уязвимость.
Как выполнить поиск по файлам на сервере с помощью PHP?
Используется рекурсивный обход директорий и поиск подстроки в содержимом файлов.
function searchFiles($dir, $needle) {
$results = [];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'txt') {
$content = file_get_contents($file->getPathname());
if (stripos($content, $needle) !== false) {
$results[] = $file->getPathname();
}
}
}
return $results;
}
Ошибка: при большом количестве файлов скрипт может превысить лимит времени выполнения. Решение - ограничить глубину или использовать генераторы.
Как реализовать полнотекстовый поиск через MySQL FULLTEXT?
Для больших объёмов текста лучше использовать полнотекстовые индексы.
ALTER TABLE articles ADD FULLTEXT(title, content);
$stmt = $pdo->prepare('SELECT *, MATCH(title, content) AGAINST(:q IN BOOLEAN MODE) AS relevance FROM articles WHERE MATCH(title, content) AGAINST(:q2 IN BOOLEAN MODE) ORDER BY relevance DESC');
$stmt->execute([':q' => $query, ':q2' => $query]);
$results = $stmt->fetchAll();
Проблема: минимальная длина слова для индекса (по умолчанию 4 символа). Изменяется через параметр ft_min_word_len. Необходим ребилд индекса.
Как сделать поиск с использованием регулярных выражений (regex)?
Применяется для сложных шаблонов, например, поиск email или ссылок.
$pattern = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/';
preg_match_all($pattern, $content, $matches);
print_r($matches[0]);
Ошибка: неверный синтаксис регулярного выражения приводит к предупреждениям. Нужно проверять корректность через preg_match с заведомо валидным шаблоном.
Как организовать AJAX-поиск с динамической подгрузкой результатов?
Клиент отправляет запрос к PHP-скрипту, который возвращает JSON.
// search_ajax.php
header('Content-Type: application/json');
$query = $_GET['term'] ?? '';
$results = [];
if (strlen($query) > 2) {
$stmt = $pdo->prepare('SELECT id, title FROM articles WHERE title LIKE :q LIMIT 5');
$stmt->execute([':q' => '%' . $query . '%']);
$results = $stmt->fetchAll();
}
echo json_encode($results);
Проблема: частые запросы при вводе - необходимо добавить debounce на стороне клиента. Нагрузка на сервер возможна при большом количестве пользователей.
Расширенные примеры работы с результатами PHP
Пример 1: Поиск с пагинацией и подсветкой совпадений
function highlight($text, $query) {
return preg_replace('/(' . preg_quote($query, '/') . ')/iu', '$1', $text);
}
// в цикле вывода
foreach ($results as $row) {
$title = highlight($row['title'], $query);
$content = highlight(substr($row['content'], 0, 200), $query);
echo "<article><h3>$title</h3><p>$content...</p></article>";
}
Результат: заголовок "Как начать с PHP" при поиске "php" превращается в "Как начать с PHP".
Пример 2: Поиск по нескольким таблицам с UNION
$stmt = $pdo->prepare('
SELECT 'post' AS type, id, title, created_at FROM posts WHERE title LIKE :q
UNION
SELECT 'comment' AS type, id, content AS title, created_at FROM comments WHERE content LIKE :q
ORDER BY created_at DESC
LIMIT 20
');
$stmt->execute([':q' => '%' . $query . '%']);
$combined = $stmt->fetchAll();
Результат: массив записей с полем type, по которому можно определить источник.
Пример 3: Использование Elasticsearch через PHP (официальный клиент)
require 'vendor/autoload.php';
$client = Elastic\Elasticsearch\ClientBuilder::create()->build();
$params = [
'index' => 'articles',
'body' => [
'query' => [
'multi_match' => [
'query' => $query,
'fields' => ['title^3', 'content']
]
],
'highlight' => [
'fields' => [
'content' => ['fragment_size' => 150, 'number_of_fragments' => 1]
]
]
]
];
$response = $client->search($params);
$hits = $response['hits']['hits'];
foreach ($hits as $hit) {
echo $hit['_source']['title'];
echo $hit['highlight']['content'][0] ?? '';
}
Выводятся заголовки и подсвеченные фрагменты контента. Elasticsearch требует установки и индексации.
Пример 4: Поиск с учётом опечаток (soundex)
// Поиск похожих по звучанию имён
$qSoundex = soundex($query);
$stmt = $pdo->prepare('SELECT * FROM users WHERE soundex(name) = :s');
$stmt->execute([':s' => $qSoundex]);
$users = $stmt->fetchAll();
При поиске "Jon" найдутся "John", "Jon" - функция soundex даёт одинаковый код.
Пример 5: Результаты поиска в формате JSON для SPA
// api/search.php
$query = $_GET['q'] ?? '';
if (strlen($query) < 2) {
http_response_code(400);
echo json_encode(['error' => 'Запрос слишком короткий']);
exit;
}
$stmt = $pdo->prepare('SELECT id, title, excerpt FROM articles WHERE MATCH(title, content) AGAINST(:q IN NATURAL LANGUAGE MODE) LIMIT 20');
$stmt->execute([':q' => $query]);
$data = $stmt->fetchAll();
echo json_encode(['data' => $data, 'total' => count($data)]);
Ответ: {"data":[{"id":1,"title":"PHP примеры","excerpt":"..."}],"total":1}