Реализация просмотра раздела PHP на сайте
Основные подходы к просмотру раздела PHP
Как организовать страницу просмотра списка записей с пагинацией, защитой от SQL-инъекций и минимальным потреблением памяти?
Наиболее эффективное решение использует PDO с подготовленными запросами, пагинацию на стороне базы данных и передачу параметров через GET. Это снижает нагрузку на сервер и предотвращает уязвимости.
// index.php
$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$limit = 10;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$offset = ($page - 1) * $limit;
$totalStmt = $pdo->query('SELECT COUNT(*) FROM articles');
$total = $totalStmt->fetchColumn();
$stmt = $pdo->prepare('SELECT * FROM articles ORDER BY created_at DESC LIMIT :limit OFFSET :offset');
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
Section php url (url раздела php)
Пояснение: запрос на получение общего количества записей выполняется отдельно, а затем выбирается только нужная страница. Параметры привязываются с указанием типа данных.
Типичная ошибка: забыть привести $_GET['page'] к целому числу, что может привести к SQL-инъекции через нечисловой параметр. Решение: использовать (int) или ctype_digit.
Проблема: большое количество записей может замедлить COUNT(*). Решение: использовать приблизительные оценки или кеширование.
Как сделать простой вывод без пагинации с использованием mysqli?
Классический способ на mysqli для небольших объёмов данных.
$mysqli = new mysqli('localhost', 'user', 'pass', 'mydb');
$result = $mysqli->query('SELECT * FROM articles');
while ($row = $result->fetch_assoc()) {
echo '<div>' . $row['title'] . '</div>';
}
Indices php section (индексы разделов php)
Ошибка: отсутствие проверки на ошибки подключения и запроса. Решение: использовать $mysqli->connect_error и $result === false.
Как выводить данные с фильтрацией по категории через GET-параметр?
Добавление фильтра с помощью подготовленного запроса в PDO.
$categoryId = $_GET['cat'] ?? 0;
$stmt = $pdo->prepare('SELECT * FROM articles WHERE category_id = :cat ORDER BY id DESC');
$stmt->execute([':cat' => $categoryId]);
$articles = $stmt->fetchAll();
Catalog php section id (каталог разделов по id php)
Ошибка: если $categoryId не существует в БД, запрос вернёт пустой результат. Решение: проверить существование категории или выводить сообщение.
Как реализовать просмотр одной записи (детальный вид)?
Параметр id в URL, выборка одной строки.
$id = (int)$_GET['id'];
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = ?');
$stmt->execute([$id]);
$article = $stmt->fetch();
if (!$article) { echo 'Статья не найдена'; }
Ошибка: передача строки вместо числа, хотя приведение к (int) решает проблему, но может привести к некорректному идентификатору. Лучше проверять $_GET['id'] на валидность с filter_var($id, FILTER_VALIDATE_INT).
Расширенные примеры с кодом и результатом
Пример 1: Пагинация с ссылками на страницы и выводом номеров
// pagination.php
$limit = 5;
$page = isset($_GET['p']) && is_numeric($_GET['p']) ? (int)$_GET['p'] : 1;
$offset = ($page - 1) * $limit;
$pdo = new PDO('mysql:host=localhost;dbname=blog;charset=utf8', 'root', '');
$total = $pdo->query('SELECT COUNT(*) FROM posts')->fetchColumn();
$pages = ceil($total / $limit);
$stmt = $pdo->prepare('SELECT id, title FROM posts ORDER BY id DESC LIMIT :lim OFFSET :off');
$stmt->bindParam(':lim', $limit, PDO::PARAM_INT);
$stmt->bindParam(':off', $offset, PDO::PARAM_INT);
$stmt->execute();
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<ul>';
foreach ($posts as $row) {
echo '<li>' . htmlspecialchars($row['title']) . '</li>';
}
echo '</ul>';
echo '<div class="pagination">';
for ($i = 1; $i <= $pages; $i++) {
echo '<a href="?p=' . $i . '">' . $i . '</a> ';
}
echo '</div>';
Результат (при 3 записях на 1 странице):
- Заголовок 5
- Заголовок 4
- Заголовок 3
Пояснение: используется ceil для определения числа страниц, ссылки формируются с параметром p. Текст заголовков экранируется через htmlspecialchars.
Пример 2: Вывод с группировкой по дате (с использованием PDO и вложенного цикла)
$stmt = $pdo->query('SELECT DATE(created_at) as day, id, title FROM posts ORDER BY day DESC, id DESC');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$byDay = [];
foreach ($rows as $row) {
$byDay[$row['day']][] = $row;
}
foreach ($byDay as $day => $posts) {
echo '<h3>' . $day . '</h3>';
echo '<ul>';
foreach ($posts as $post) {
echo '<li>' . $post['title'] . '</li>';
}
echo '</ul>';
}
Результат (пример):2025-04-10
- Новость 1
- Новость 2
2025-04-09
- Новость 3
Пояснение: данные сначала собираются в массив по дням, затем выводятся с заголовками.
Пример 3: Поиск с LIKE и подготовленными запросами
$search = $_GET['q'] ?? '';
$searchTerm = '%' . $search . '%';
$stmt = $pdo->prepare('SELECT id, title FROM articles WHERE title LIKE :search OR content LIKE :search2');
$stmt->execute([':search' => $searchTerm, ':search2' => $searchTerm]);
$results = $stmt->fetchAll();
Ошибка: если пользователь вводит символ подчёркивания _ или знак процента %, они интерпретируются в LIKE. Решение: экранировать через addcslashes($search, '%_') или использовать регулярные выражения.
Пример 4: Использование ORM Eloquent (Laravel) для просмотра раздела
// В контроллере
$articles = Article::paginate(10);
return view('articles.index', compact('articles'));
В шаблоне (blade):
@foreach ($articles as $article)
<div>{{ $article->title }}</div>
@endforeach
{{ $articles->links() }}
Пояснение: Eloquent автоматически подставляет LIMIT и OFFSET, пагинация генерирует ссылки. Для простых проектов такое решение избыточно, но ускоряет разработку.