Индексный файл PHP для вывода элемента

Раздел: Разработка на PHP -> Работа с записями (items) в PHP

Индексный файл PHP для работы с одним элементом

Как создать PHP скрипт, который выводит запись из базы данных по её идентификатору?

Наиболее надёжное и безопасное решение основано на использовании PDO с подготовленными запросами. Такой подход защищает от SQL инъекций и позволяет легко переключаться между разными СУБД. Ниже приведён полный пример файла index.php, который принимает параметр id через URL и отображает соответствующую запись из таблицы items.


<?php
// Настройки подключения
define('DB_HOST', 'localhost');
define('DB_NAME', 'mydb');
define('DB_USER', 'root');
define('DB_PASS', '');

// Подключение к БД
try {
    $pdo = new PDO(
        "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
        DB_USER,
        DB_PASS,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]
    );
} catch (PDOException $e) {
    die('Ошибка подключения: ' . $e->getMessage());
}

// Проверка наличия id
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if ($id <= 0) {
    http_response_code(400);
    exit('Неверный идентификатор элемента');
}

// Запрос
$stmt = $pdo->prepare('SELECT * FROM items WHERE id = :id');
$stmt->execute(['id' => $id]);
$item = $stmt->fetch();

if (!$item) {
    http_response_code(404);
    exit('Элемент не найден');
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Просмотр элемента</title>
</head>
<body>
    <h2><?= htmlspecialchars($item['title']) ?></h2>
    <p><?= nl2br(htmlspecialchars($item['content'])) ?></p>
</body>
</html>
  

Пояснение шагов:

  1. Создаётся подключение через PDO с указанием кодировки и режима ошибок.
  2. Параметр id извлекается из $_GET и приводится к целому числу (intval) для дополнительной безопасности.
  3. Если идентификатор отсутствует или невалиден, возвращается код 400.
  4. Подготовленный запрос с плейсхолдером :id выполняется подстановкой значения.
  5. Если запись не найдена, отправляется 404 ответ.
  6. Данные выводятся с использованием htmlspecialchars для защиты от XSS.

Типичные ошибки и их решение:

  • Исключение PDOException при неверных данных подключения. Решение: проверить имя хоста, базы, логин и пароль.
  • Пустой вывод при наличии записи: вероятно, неверное имя поля в выводе. Проверить структуру таблицы.
  • Ошибка при передаче id как строки: использование intval обнуляет строку. Если id нечисловой, лучше применять регулярное выражение.

Как реализовать тот же функционал с помощью расширения MySQLi?

MySQLi также поддерживает подготовленные запросы. Пример:


<?php
$mysqli = new mysqli('localhost', 'root', '', 'mydb');
if ($mysqli->connect_error) {
    die('Ошибка подключения: ' . $mysqli->connect_error);
}

$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if ($id <= 0) {
    http_response_code(400);
    exit();
}

$stmt = $mysqli->prepare('SELECT * FROM items WHERE id = ?');
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$item = $result->fetch_assoc();

if (!$item) {
    http_response_code(404);
    exit();
}
?>
  

Проблемы: MySQLi привязан только к MySQL, в то время как PDO поддерживает множество СУБД. Кроме того, синтаксис MySQLi считается менее удобным.

Как организовать код с использованием объектно ориентированного подхода?

Создайте класс ItemRepository, который инкапсулирует логику работы с записями. Это упрощает тестирование и повторное использование.


class ItemRepository {
    private PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function findById(int $id): ?array {
        $stmt = $this->pdo->prepare('SELECT * FROM items WHERE id = :id');
        $stmt->execute(['id' => $id]);
        return $stmt->fetch() ?: null;
    }
}

// Использование
$repo = new ItemRepository($pdo);
$item = $repo->findById($id);
  

Проблема: при неправильной инициализации PDO (например, без режима исключений) методы репозитория могут возвращать ложные значения. Решение: всегда настраивать PDO на выбрасывание исключений.

Как сделать URL вида /item/5 без прямого указания index.php?

Для получения чистых URL используется серверная перезапись через .htaccess. Создайте правило, направляющее запрос к index.php с параметром id.


RewriteEngine On
RewriteRule ^item/([0-9]+)$ index.php?id=$1 [L,QSA]
  

Теперь по адресу /item/5 будет вызван index.php?id=5.

Ошибка: если модуль mod_rewrite не включён, правило не сработает. Решение: проверить настройки Apache или использовать встроенный PHP сервер с простым роутингом.

Как обрабатывать ситуацию, когда элемент не найден, с помощью HTTP-статусов?

Важно не только выводить текст ошибки, но и устанавливать корректный код ответа:


if (!$item) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Not found']);
    exit;
}
  

Это необходимо для правильной работы REST-клиентов и поисковых систем.

Ошибка: после вызова header() может возникнуть ошибка, если уже был выведен какой либо текст. Решение: убедиться, что до вызова header нет вывода (проверьте пробелы перед <?php).

Расширенные примеры использования

Ниже представлены дополнительные сценарии и более сложные реализации индексного файла для элемента.

Пример с кэшированием результата запроса

Для снижения нагрузки на БД кэшируйте запрос на несколько секунд. Используйте memcached или файловое кэширование.

Пример

// Файловый кэш на 60 секунд
$cacheFile = __DIR__ . '/cache/item_' . $id . '.cache';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 60)) {
    $item = unserialize(file_get_contents($cacheFile));
} else {
    $stmt = $pdo->prepare('SELECT * FROM items WHERE id = :id');
    $stmt->execute(['id' => $id]);
    $item = $stmt->fetch();
    file_put_contents($cacheFile, serialize($item));
}
  
Файл cache/item_5.cache будет содержать сериализованный массив записи.
  

Особенности: необходимо создать папку cache с правами на запись. Кэш аннулируется при удалении файла.

Пример с поддержкой разных форматов вывода (HTML, JSON, XML)

Индексный файл может возвращать данные в формате, зависящем от параметра format или заголовка Accept.

Пример

$format = $_GET['format'] ?? 'html';

if (!$item) {
    http_response_code(404);
    if ($format === 'json') {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Not found']);
        exit;
    }
}

switch ($format) {
    case 'json':
        header('Content-Type: application/json');
        echo json_encode($item);
        break;
    case 'xml':
        header('Content-Type: application/xml');
        $xml = new SimpleXMLElement('<item/>');
        array_walk($item, [$xml, 'addChild']);
        echo $xml->asXML();
        break;
    default:
        // HTML вывод
        ?>
        <!DOCTYPE html>...
        <?php
}
  
При запросе /index.php?id=5&format=json возвращается JSON:
{"id":5,"title":"Заголовок","content":"Текст"}
  

Пример с использованием шаблонизатора (Twig)

Для отделения логики от представления используйте шаблонизатор, например Twig.

Пример

require_once '/vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
$twig = new \Twig\Environment($loader, ['cache' => __DIR__ . '/compilation_cache']);

echo $twig->render('item.html.twig', ['item' => $item]);
  

Шаблон item.html.twig:

Пример

<h2>{{ item.title|e }}</h2>
<p>{{ item.content|nl2br }}</p>
  
Результат: HTML с защищёнными данными.
  

Пример с обработкой нескольких идентификаторов (массив id)

Иногда требуется вывести несколько записей по идентификаторам, переданным через запятую.

Пример

$ids = isset($_GET['ids']) ? explode(',', $_GET['ids']) : [];
$ids = array_map('intval', array_filter($ids, 'is_numeric'));

if (empty($ids)) {
    exit('Нет корректных id');
}

$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT * FROM items WHERE id IN ($placeholders)");
$stmt->execute($ids);
$items = $stmt->fetchAll();
  
При запросе /index.php?ids=1,2,3 возвращается массив всех трёх записей.
  

Важно: не используйте динамическую подстановку id в SQL напрямую, только через плейсхолдеры.

Индексный файл PHP для элемента - comments

En
Index php item (php)