SQLite в PHP: PDO, SQLite3 и ORM — полное руководство с примерами

SQLite встроен в PHP по умолчанию — никаких серверов, никакой установки. Файл базы данных лежит рядом с проектом, и этого достаточно для большинства задач: лендинги, парсеры, кеш, небольшие API. В этой статье — всё что нужно для работы с SQLite в PHP: два способа подключения, основные запросы, ORM, оптимизация производительности и удалённый доступ.

PDO vs SQLite3: какой интерфейс выбрать

В PHP есть два способа работать с SQLite: через универсальный PDO и через специализированный класс SQLite3. Оба входят в стандартную поставку PHP.

КритерийPDOSQLite3
Переносимость✅ Работает с MySQL, PostgreSQL, SQLite — один интерфейс❌ Только SQLite
ПроизводительностьЧуть медленнее из-за абстракции✅ Быстрее на прямых запросах
Prepare/execute✅ Полноценно✅ Полноценно
Транзакции
Подходит дляПроект может переехать на MySQL; командная разработкаТолько SQLite, максимальная скорость

Рекомендация: используйте PDO если есть шанс переехать на другую СУБД. Используйте SQLite3 если нужна максимальная скорость в SQLite-only проекте.

Подключение к SQLite через PDO

Убедитесь что расширение включено в php.ini:

extension=pdo_sqlite

Подключение к файлу базы данных:

<?php
$pdo = new PDO('sqlite:' . __DIR__ . '/database.db');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

Для базы только в памяти (например в тестах):

$pdo = new PDO('sqlite::memory:');

Важно: путь к файлу должен быть абсолютным. Используйте __DIR__ чтобы путь не зависел от рабочей директории скрипта.

Подключение через класс SQLite3

Расширение в php.ini:

extension=sqlite3
<?php
$db = new SQLite3(__DIR__ . '/database.db');

// Включить исключения вместо предупреждений
$db->enableExceptions(true);

База в памяти:

$db = new SQLite3(':memory:');

SELECT: выборка данных

Через PDO

<?php
// Все записи
$stmt = $pdo->query('SELECT * FROM users');
$users = $stmt->fetchAll(); // массив ассоциативных массивов

// С параметром (защита от SQL-инъекций)
$stmt = $pdo->prepare('SELECT * FROM users WHERE city = :city AND age > :age');
$stmt->execute([':city' => 'Москва', ':age' => 18]);
$users = $stmt->fetchAll();

// Одна запись
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch();

Через SQLite3

<?php
// Все записи
$result = $db->query('SELECT * FROM users');
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
    echo $row['name'] . "\n";
}

// С параметром
$stmt = $db->prepare('SELECT * FROM users WHERE city = :city');
$stmt->bindValue(':city', 'Москва', SQLITE3_TEXT);
$result = $stmt->execute();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
    var_dump($row);
}

INSERT, UPDATE, DELETE

INSERT через PDO

<?php
$stmt = $pdo->prepare(
    'INSERT INTO users (name, email, city) VALUES (:name, :email, :city)'
);
$stmt->execute([
    ':name'  => 'Алексей',
    ':email' => 'alex@example.com',
    ':city'  => 'Москва',
]);

$lastId = $pdo->lastInsertId(); // ID вставленной записи

UPDATE и DELETE через PDO

<?php
// UPDATE
$stmt = $pdo->prepare('UPDATE users SET city = :city WHERE id = :id');
$stmt->execute([':city' => 'СПб', ':id' => 5]);
$affected = $stmt->rowCount(); // количество затронутых строк

// DELETE
$stmt = $pdo->prepare('DELETE FROM users WHERE id = :id');
$stmt->execute([':id' => 5]);

INSERT через SQLite3

<?php
$stmt = $db->prepare(
    'INSERT INTO users (name, email) VALUES (:name, :email)'
);
$stmt->bindValue(':name', 'Мария', SQLITE3_TEXT);
$stmt->bindValue(':email', 'maria@example.com', SQLITE3_TEXT);
$stmt->execute();

$lastId = $db->lastInsertRowID();

Создание таблиц из PHP

<?php
// PDO — создать таблицу если не существует
$pdo->exec('
    CREATE TABLE IF NOT EXISTS users (
        id    INTEGER PRIMARY KEY AUTOINCREMENT,
        name  TEXT    NOT NULL,
        email TEXT    UNIQUE,
        city  TEXT,
        created_at TEXT DEFAULT (datetime("now"))
    )
');

// SQLite3
$db->exec('
    CREATE TABLE IF NOT EXISTS products (
        id    INTEGER PRIMARY KEY AUTOINCREMENT,
        name  TEXT NOT NULL,
        price REAL,
        stock INTEGER DEFAULT 0
    )
');

Транзакции: массовая вставка данных

Транзакции критически важны при массовой вставке. Без транзакции SQLite делает fsync на каждый INSERT — это катастрофически медленно. В транзакции 10 000 записей вставляются в 100–300 раз быстрее.

<?php
// PDO — вставка 10 000 строк в транзакции
$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare('INSERT INTO log (message, created_at) VALUES (?, ?)');
    for ($i = 0; $i < 10000; $i++) {
        $stmt->execute(["Запись $i", date('Y-m-d H:i:s')]);
    }
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}
<?php
// SQLite3 — то же самое
$db->exec('BEGIN TRANSACTION');
$stmt = $db->prepare('INSERT INTO log (message) VALUES (:msg)');
for ($i = 0; $i < 10000; $i++) {
    $stmt->bindValue(':msg', "Запись $i", SQLITE3_TEXT);
    $stmt->execute();
    $stmt->reset();
}
$db->exec('COMMIT');

Результат: 10 000 записей без транзакции — ~30 секунд. В транзакции — ~0.1 секунды.

PHP SQLite ORM: ORM::for_table и альтернативы

Популярный минималистичный ORM для PHP — Paris/Idiorm. Именно его методы ORM::for_table() и ORM::close() чаще всего ищут разработчики.

Установка Idiorm через Composer

composer require j4mie/idiorm

Подключение к SQLite

<?php
require 'vendor/autoload.php';

ORM::configure('sqlite:' . __DIR__ . '/database.db');

ORM::for_table() — основные операции

<?php
// SELECT — все записи
$users = ORM::for_table('users')->find_many();
foreach ($users as $user) {
    echo $user->name . "\n";
}

// SELECT — с условием
$user = ORM::for_table('users')
    ->where('email', 'alex@example.com')
    ->find_one();

// SELECT — несколько условий
$results = ORM::for_table('products')
    ->where('category', 'Книги')
    ->where_gt('price', 500)
    ->order_by_asc('price')
    ->find_many();

// INSERT
$user = ORM::for_table('users')->create();
$user->name  = 'Алексей';
$user->email = 'alex@example.com';
$user->save();

// UPDATE
$user = ORM::for_table('users')->find_one(5);
$user->city = 'Москва';
$user->save();

// DELETE
$user = ORM::for_table('users')->find_one(5);
$user->delete();

ORM::close() — закрытие соединения

<?php
// Явно закрыть соединение (например в CLI-скриптах)
ORM::get_db()->close(); // через PDO
// или через сброс конфигурации:
ORM::reset_config();
ORM::reset_db();

Примечание: в веб-запросах закрывать соединение вручную не нужно — PHP закрывает его автоматически по завершении скрипта.

Альтернативы Idiorm для SQLite

ORMРазмерОсобенность
Idiorm/ParisМикроМинималистичный, только Active Record
Eloquent (Laravel)СреднийПолноценный ORM, работает вне Laravel через illuminate/database
RedBeanPHPСреднийСоздаёт таблицы автоматически при первой вставке
Doctrine DBALБольшойПромышленный ORM, избыточен для SQLite-проектов

Оптимизация производительности PHP + SQLite

SQLite работает быстро «из коробки», но несколько настроек дают кратный прирост производительности.

1. WAL-режим — ускорить параллельное чтение

<?php
// Включить WAL сразу после подключения
$pdo->exec('PRAGMA journal_mode = WAL');

// WAL позволяет одновременно читать и писать в БД
// По умолчанию: DELETE journal — блокирует чтение при записи

2. Кеш в памяти — ускорить чтение

<?php
// Размер кеша страниц: 64 МБ (по умолчанию ~2 МБ)
$pdo->exec('PRAGMA cache_size = -64000'); // отрицательное число = КБ

// Хранить временные таблицы в памяти
$pdo->exec('PRAGMA temp_store = MEMORY');

3. Индексы — ускорить SELECT

<?php
// Создать индекс на часто используемое поле
$pdo->exec('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');
$pdo->exec('CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status)');

// Проверить план выполнения запроса
$stmt = $pdo->query('EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = "x@x.com"');
var_dump($stmt->fetchAll());

4. Synchronous OFF — для некритичных данных

<?php
// Отключить синхронизацию с диском (быстро, но риск потери данных при краше ОС)
// Подходит для: логи, кеш, временные данные
$pdo->exec('PRAGMA synchronous = OFF');

// Для продакшн-данных оставьте NORMAL (по умолчанию)

5. Итоговый набор PRAGMA для PHP-проекта

<?php
function connectSQLite(string $path): PDO {
    $pdo = new PDO('sqlite:' . $path);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

    // Оптимальные настройки для большинства PHP-проектов
    $pdo->exec('PRAGMA journal_mode = WAL');   // параллельное чтение/запись
    $pdo->exec('PRAGMA cache_size = -32000');  // 32 МБ кеша
    $pdo->exec('PRAGMA temp_store = MEMORY');  // временные таблицы в RAM
    $pdo->exec('PRAGMA synchronous = NORMAL'); // баланс скорость/надёжность

    return $pdo;
}

Удалённый доступ к SQLite через PHP

SQLite — встраиваемая база данных без сервера, поэтому прямого сетевого подключения у неё нет. Удалённый доступ реализуется через PHP-скрипт как HTTP-API.

Вариант 1 — простой REST API на чистом PHP

<?php
// api.php — простой HTTP-API для чтения из SQLite
// Защита: токен в заголовке Authorization

define('API_TOKEN', 'ваш-секретный-токен');
define('DB_PATH',   __DIR__ . '/database.db');

header('Content-Type: application/json; charset=utf-8');

// Проверка токена
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if ($token !== 'Bearer ' . API_TOKEN) {
    http_response_code(401);
    echo json_encode(['error' => 'Unauthorized']);
    exit;
}

$pdo   = new PDO('sqlite:' . DB_PATH);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

$action = $_GET['action'] ?? '';

switch ($action) {
    case 'users':
        $stmt = $pdo->query('SELECT id, name, city FROM users ORDER BY id DESC LIMIT 100');
        echo json_encode($stmt->fetchAll());
        break;

    case 'user':
        $id   = (int)($_GET['id'] ?? 0);
        $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        echo json_encode($stmt->fetch() ?: null);
        break;

    default:
        http_response_code(400);
        echo json_encode(['error' => 'Unknown action']);
}

Вызов из другого сервера:

curl -H "Authorization: Bearer ваш-секретный-токен" \
     "https://ваш-сайт.ru/api.php?action=users"

Вариант 2 — PHPLiteAdmin (веб-интерфейс)

PHPLiteAdmin — однофайловый веб-интерфейс для SQLite, аналог phpMyAdmin. Загрузите phpliteadmin.php на сервер, установите пароль в начале файла и откройте в браузере.

<?php
// Настройки в начале phpliteadmin.php
$password = 'ваш_пароль';   // обязательно измените!
$directory = './';           // папка с .db файлами
$allowed_extensions = ['db', 'sqlite', 'sqlite3'];

Важно: закройте доступ к PHPLiteAdmin по IP или через .htaccess после использования. Не оставляйте его открытым на продакшн-сервере.

Практический пример: сохранение заявок с лендинга

Типичный сценарий: форма на лендинге сохраняет заявки в SQLite. Никакого MySQL, никакой настройки сервера — файл leads.db рядом с проектом.

<?php
// leads.php — обработчик формы

define('DB_PATH', __DIR__ . '/data/leads.db');

function getDb(): PDO {
    $pdo = new PDO('sqlite:' . DB_PATH);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->exec('PRAGMA journal_mode = WAL');
    $pdo->exec('
        CREATE TABLE IF NOT EXISTS leads (
            id         INTEGER PRIMARY KEY AUTOINCREMENT,
            name       TEXT NOT NULL,
            phone      TEXT,
            email      TEXT,
            source     TEXT,
            created_at TEXT DEFAULT (datetime("now", "localtime"))
        )
    ');
    return $pdo;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name  = trim(strip_tags($_POST['name']  ?? ''));
    $phone = trim(strip_tags($_POST['phone'] ?? ''));
    $email = trim(strip_tags($_POST['email'] ?? ''));

    if ($name === '') {
        http_response_code(400);
        echo json_encode(['error' => 'Имя обязательно']);
        exit;
    }

    $pdo  = getDb();
    $stmt = $pdo->prepare(
        'INSERT INTO leads (name, phone, email, source) VALUES (?, ?, ?, ?)'
    );
    $stmt->execute([$name, $phone, $email, $_SERVER['HTTP_REFERER'] ?? '']);

    header('Content-Type: application/json');
    echo json_encode(['ok' => true, 'id' => $pdo->lastInsertId()]);
    exit;
}

Просмотр накопленных заявок:

<?php
// admin-leads.php — простой просмотр заявок (закройте Basic Auth!)
$pdo   = new PDO('sqlite:' . __DIR__ . '/data/leads.db');
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$leads = $pdo->query('SELECT * FROM leads ORDER BY created_at DESC')->fetchAll();

foreach ($leads as $lead) {
    echo "{$lead['created_at']} | {$lead['name']} | {$lead['phone']}\n";
}

Когда SQLite не подходит для PHP-проекта

SQLite отлично работает в PHP, но есть сценарии где лучше выбрать MySQL или PostgreSQL:

  • Высокая конкурентная запись — SQLite блокирует запись на уровне файла. При 50+ одновременных записях появятся ошибки SQLITE_BUSY. Решение: WAL-режим снижает проблему, но не устраняет полностью.
  • Несколько серверов — SQLite-файл должен быть на одном сервере. Если у вас балансировщик нагрузки с несколькими PHP-серверами — нужна сетевая СУБД.
  • Размер базы больше 10 ГБ — SQLite поддерживает до 281 ТБ технически, но производительность деградирует. При размере больше 10 ГБ рассмотрите миграцию на PostgreSQL.
  • Сложные права доступа — SQLite не поддерживает пользователей и роли на уровне БД.

SQLite идеален для PHP когда: лендинг/портфолио, парсер, кеш, CLI-утилита, прототип, тесты, небольшое API до 10 000 запросов/сутки.

Изучите SQLite подробнее

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

1 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Vova Gendel
Vova Gendel
21 дней назад

Благодарю! Несколько недель искал и не мог найти примеры — а тут всё подробно. Делаю Аналитикуна сайт и в библиотеку базу книг на SQLite.

1
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x