Pg lo import: примеры (PHP)

Импорт больших объектов в PostgreSQL с помощью pg_lo_import
Раздел: Базы данных (PostgreSQL)
pg_lo_import(PgSql\Connection $connection, string $filename, $object_id = ?): int|false

Основы функции pg_lo_import

Функция pg_lo_import в PHP предназначена для импорта содержимого файла в базу данных PostgreSQL в качестве большого объекта (Large Object, BLOB).

Аргументы функции

Функция имеет два варианта сигнатуры:

  1. pg_lo_import($connection, $pathname, $object_id = null)
  2. pg_lo_import($pathname, $object_id = null, $connection = null) (устаревший с PHP 8.1)

Параметры:

  • $connection (ресурс или PgSql\Connection) - соединение с базой данных PostgreSQL.
  • $pathname (string) - путь к файлу на сервере, содержимое которого будет загружено.
  • $object_id (int) - необязательный идентификатор для создаваемого большого объекта. Если не указан, будет сгенерирован сервером.

Возвращает OID (целочисленный идентификатор) созданного большого объекта или false при ошибке.

Простые примеры использования

Базовый пример
$conn = pg_connect("dbname=test user=postgres");
if ($conn) {
    $oid = pg_lo_import($conn, '/tmp/document.pdf');
    if ($oid) {
        echo "Файл загружен с OID: $oid";
    } else {
        echo "Ошибка загрузки";
    }
    pg_close($conn);
}
Файл загружен с OID: 123456
Пример с указанием OID
$conn = pg_connect("dbname=test user=postgres");
$oid = pg_lo_import($conn, '/tmp/image.jpg', 987654);
echo $oid ? "Объект создан с OID: $oid" : "Ошибка";
Объект создан с OID: 987654
Обработка ошибок
$oid = pg_lo_import($conn, '/nonexistent/file.txt');
if ($oid === false) {
    echo "Ошибка импорта файла";
    // pg_last_error($conn) можно использовать для получения деталей
}
Ошибка импорта файла

Альтернативные функции в PHP

pg_lo_import с ресурсом

Функция pg_lo_import также может принимать строковый путь, что является основным способом.

Чтение файла и вставка как BYTEA

Вместо больших объектов можно хранить данные в колонке типа BYTEA:

$data = file_get_contents('/tmp/file.pdf');
$escaped = pg_escape_bytea($conn, $data);
$result = pg_query($conn, "INSERT INTO files (content) VALUES ('$escaped')");
Использование потоков

Для больших файлов можно использовать комбинацию pg_lo_open, pg_lo_write и pg_lo_close для потоковой передачи.

Реализации в других языках

Python (psycopg2)
import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
with conn.cursor() as cur:
    with open('/tmp/file.pdf', 'rb') as f:
        oid = conn.lobject().import(f)
    print(f"OID: {oid}")
conn.commit()
OID: 123456
JavaScript (Node.js, pg)
const { Client } = require('pg');
const fs = require('fs');
const client = new Client();
await client.connect();
const stream = fs.createReadStream('/tmp/file.pdf');
const oid = await client.query('BEGIN');
const lo = new LargeObject(client, oid);
await lo.write(stream);
await client.query('COMMIT');
console.log(`OID: ${oid}`);

Pg lo import в MySQL

В MySQL обычно используют тип BLOB:

INSERT INTO files (data) VALUES (LOAD_FILE('/tmp/file.pdf'));
PostgreSQL (SQL)
INSERT INTO files (data) VALUES (pg_read_binary_file('/tmp/file.pdf'));

Распространенные ошибки

Файл не существует или недоступен
// Файл отсутствует
$oid = pg_lo_import($conn, '/tmp/notfound.txt');
var_dump($oid);
bool(false)
Отсутствие прав на запись в БД
// Пользователь БД не имеет прав на создание больших объектов
$oid = pg_lo_import($conn, '/tmp/file.pdf');
if ($oid === false) {
    echo "Ошибка: " . pg_last_error($conn);
}
Ошибка: ERROR: permission denied for large object 123456
Использование устаревшей сигнатуры
// В PHP 8.1+ этот вызов может вызвать предупреждение
$oid = pg_lo_import('/tmp/file.pdf', null, $conn);
Неверный тип соединения
// Передача не ресурса и не объекта PgSql\Connection
$conn = null;
$oid = pg_lo_import($conn, '/tmp/file.pdf');
Warning: pg_lo_import(): supplied resource is not a valid PostgreSQL link resource

Изменения в версиях PHP

PHP 8.1

Функция pg_lo_import стала принимать объект PgSql\Connection вместо ресурса. Сигнатура с соединением в качестве третьего параметра устарела.

PHP 8.0

Добавлена поддержка именованных аргументов при вызове функции.

PHP 7.0+

Рекомендуется использовать первую сигнатуру с соединением в качестве первого параметра.

Расширенные примеры

Импорт с сохранением метаданных
Пример php
$conn = pg_connect("dbname=test");
$file_path = '/tmp/report.pdf';
$oid = pg_lo_import($conn, $file_path);
if ($oid) {
    $file_name = basename($file_path);
    $file_size = filesize($file_path);
    $mime_type = mime_content_type($file_path);
    $result = pg_query_params(
        $conn,
        'INSERT INTO documents (oid, name, size, mime_type) VALUES ($1, $2, $3, $4)',
        [$oid, $file_name, $file_size, $mime_type]
    );
    echo "Документ '$file_name' сохранен с OID: $oid";
}
Документ 'report.pdf' сохранен с OID: 234567
Транзакционная загрузка
Пример php
pg_query($conn, 'BEGIN');
try {
    $oid = pg_lo_import($conn, '/tmp/important.dat');
    if (!$oid) {
        throw new Exception('Ошибка импорта');
    }
    // Связываем с записью в таблице
    pg_query_params($conn, 'UPDATE data SET file_oid = $1 WHERE id = 1', [$oid]);
    pg_query($conn, 'COMMIT');
    echo "Файл загружен в транзакции, OID: $oid";
} catch (Exception $e) {
    pg_query($conn, 'ROLLBACK');
    echo "Ошибка: " . $e->getMessage();
}
Файл загружен в транзакции, OID: 345678
Загрузка из временного файла
Пример php
// Предположим, файл загружен через форму
if ($_FILES['userfile']['error'] === UPLOAD_ERR_OK) {
    $tmp_path = $_FILES['userfile']['tmp_name'];
    $conn = pg_connect("dbname=test");
    $oid = pg_lo_import($conn, $tmp_path);
    if ($oid) {
        // Связываем OID с пользователем
        $user_id = 42;
        pg_query_params($conn, 'UPDATE users SET avatar_oid = $1 WHERE id = $2', [$oid, $user_id]);
    }
}
Массовый импорт файлов
Пример php
$files = ['/tmp/file1.pdf', '/tmp/file2.jpg', '/tmp/file3.txt'];
$conn = pg_connect("dbname=test");
$oids = [];
foreach ($files as $file) {
    if (file_exists($file)) {
        $oid = pg_lo_import($conn, $file);
        if ($oid) {
            $oids[basename($file)] = $oid;
        }
    }
}
print_r($oids);
Array
(
    [file1.pdf] => 456789
    [file2.jpg] => 456790
    [file3.txt] => 456791
)
Использование с PDO и большими объектами
Пример php
// PDO не имеет прямой поддержки pg_lo_import, но можно использовать так:
$pdo = new PDO('pgsql:dbname=test');
$pdo->beginTransaction();
$stmt = $pdo->query("SELECT lo_import('/tmp/file.pdf') as oid");
$oid = $stmt->fetchColumn();
$pdo->commit();
echo "OID: $oid";
OID: 567890

PHP pg_lo_import function comments

En
Pg lo import Import a large object from a file