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

Функция pg_lo_read: чтение больших объектов в PostgreSQL из PHP
Раздел: Базы данных (PostgreSQL)
pg_lo_read(PgSql\Lob $lob, int $length = 8192): string|false

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

Назначение функции

Функция pg_lo_read предназначена для чтения содержимого большого объекта (Large Object) из базы данных PostgreSQL. Она является частью модуля работы с большими объектами (LO), которые позволяют хранить данные размером до 4 ТБ, например, изображения, документы или мультимедийные файлы.

Синтаксис и параметры

Синтаксис функции: pg_lo_read(resource $large_object, int $length = 8192): string|false

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

  • $large_object — ресурс большого объекта, полученный с помощью функций pg_lo_open или pg_lo_create.
  • $length (необязательный) — максимальное количество байтов для чтения. По умолчанию равно 8192. Если передать 0, функция будет считывать данные до достижения конца файла.

Возвращаемые значения: строка с прочитанными данными или false в случае ошибки.

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

Базовое чтение объекта

Пример чтения большого объекта с размером блока по умолчанию:

$conn = pg_connect('dbname=mydb');
$oid = 12345; // Идентификатор большого объекта
$handle = pg_lo_open($conn, $oid, 'r');
if ($handle) {
    $data = pg_lo_read($handle);
    echo 'Прочитано ' . strlen($data) . ' байт';
    pg_lo_close($handle);
} else {
    echo 'Ошибка открытия объекта';
}
Прочитано 8192 байт
Чтение с указанием размера блока

Пример с явным указанием размера читаемого блока:

$handle = pg_lo_open($conn, $oid, 'r');
$data = pg_lo_read($handle, 4096); // Чтение 4 КБ
pg_lo_close($handle);
Чтение всего объекта

Чтение содержимого большого объекта целиком:

$handle = pg_lo_open($conn, $oid, 'r');
$content = '';
while ($chunk = pg_lo_read($handle, 32768)) {
    $content .= $chunk;
}
pg_lo_close($handle);
echo 'Общий размер: ' . strlen($content) . ' байт';
Общий размер: 24576 байт

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

Функции для работы с большими объектами
  • pg_lo_get — читает весь большой объект и возвращает его содержимое в виде строки. Удобна для объектов небольшого размера.
  • pg_lo_export — экспортирует большой объект в файл на сервере. Позволяет сохранить объект непосредственно в файловую систему.
  • pg_lo_read_all — отправляет содержимое большого объекта непосредственно в браузер или другой вывод. Полезна для потоковой передачи данных.
Выбор подходящей функции

pg_lo_read используется для поточного чтения больших объектов с контролем размера блока. pg_lo_get подходит для объектов, которые полностью помещаются в память. pg_lo_export применяется при необходимости сохранения объекта в файл.

Аналоги в других языках и СУБД

Python (psycopg2)

В Python для чтения больших объектов используется метод read объекта LargeObject:

import psycopg2
conn = psycopg2.connect('dbname=mydb')
conn.autocommit = True
lo = conn.lobject(12345, 'rb')
data = lo.read(8192)  # Чтение 8 КБ
lo.close()
JavaScript (node-postgres)

В Node.js с использованием библиотеки pg:

const { Client } = require('pg');
const client = new Client();
await client.connect();
const stream = client.query(new Client.QueryStream('SELECT loread(12345, 8192)'));
stream.on('data', chunk => {
    console.log(chunk);
});
MySQL

В MySQL аналогом является тип данных BLOB и функции работы с ним:

SELECT SUBSTRING(blob_column, 1, 8192) FROM table WHERE id = 1;
Отличия от PHP реализации

В Python и JavaScript часто используются потоковые интерфейсы, тогда как в PHP требуется ручное управление чтением по блокам. MySQL использует совершенно другую модель хранения бинарных данных.

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

Некорректный ресурс объекта

Ошибка возникает при передаче неверного ресурса в функцию:

$data = pg_lo_read(false, 8192);
var_dump($data);
bool(false)

Решение: проверять результат pg_lo_open перед чтением.

Чтение после закрытия ресурса

Попытка чтения из закрытого большого объекта:

$handle = pg_lo_open($conn, $oid, 'r');
pg_lo_close($handle);
$data = pg_lo_read($handle, 1024);
if ($data === false) {
    echo 'Ресурс объекта недействителен';
}
Ресурс объекта недействителен
Превышение доступной памяти

Чтение очень большого объекта целиком может привести к исчерпанию памяти:

$handle = pg_lo_open($conn, $large_oid, 'r');
$content = '';
while ($chunk = pg_lo_read($handle, 0)) { // Чтение всего объекта
    $content .= $chunk; // Потенциальная проблема с памятью
}

Решение: использовать ограниченный размер блока или экспорт в файл.

Изменения в последних версиях PHP

PHP 8.0 и новее

В PHP 8.0 были улучшены сообщения об ошибках для функций работы с большими объектами. Сама функция pg_lo_read не претерпела значительных изменений в поведении, но теперь более строго типизирована.

Устаревание и совместимость

Модуль больших объектов PostgreSQL в PHP остается стабильным. В будущих версиях планируется улучшение интеграции с современными методами работы с бинарными данными, но обратная совместимость сохраняется.

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

Потоковая передача файла в браузер

Пример передачи большого объекта непосредственно в ответ HTTP:

Пример php
$handle = pg_lo_open($conn, $oid, 'r');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="file.bin"');
while ($chunk = pg_lo_read($handle, 65536)) {
    echo $chunk;
    flush();
}
pg_lo_close($handle);
Построчное чтение текстового файла

Чтение и обработка текстового файла, хранящегося как большой объект, по строкам:

Пример php
$handle = pg_lo_open($conn, $text_oid, 'r');
$buffer = '';
while ($chunk = pg_lo_read($handle, 1024)) {
    $buffer .= $chunk;
    $lines = explode("\n", $buffer);
    $buffer = array_pop($lines);
    foreach ($lines as $line) {
        echo 'Строка: ' . htmlspecialchars($line) . '<br>';
    }
}
if ($buffer !== '') {
    echo 'Последняя строка: ' . htmlspecialchars($buffer);
}
pg_lo_close($handle);
Сравнение двух больших объектов

Пример пошагового сравнения содержимого двух больших объектов:

Пример php
$handle1 = pg_lo_open($conn, $oid1, 'r');
$handle2 = pg_lo_open($conn, $oid2, 'r');
$are_equal = true;
$block_size = 4096;
do {
    $data1 = pg_lo_read($handle1, $block_size);
    $data2 = pg_lo_read($handle2, $block_size);
    if ($data1 !== $data2) {
        $are_equal = false;
        break;
    }
} while ($data1 !== false && $data2 !== false);
pg_lo_close($handle1);
pg_lo_close($handle2);
echo $are_equal ? 'Объекты идентичны' : 'Объекты различаются';
Шифрование данных при чтении

Пример чтения и одновременного расшифрования данных:

Пример php
$handle = pg_lo_open($conn, $encrypted_oid, 'r');
$key = 'my-secret-key';
$method = 'AES-256-CBC';
$content = '';
while ($chunk = pg_lo_read($handle, 8192)) {
    $content .= $chunk;
}
pg_lo_close($handle);
$decrypted = openssl_decrypt($content, $method, $key);
file_put_contents('decrypted.txt', $decrypted);

PHP pg_lo_read function comments

En
Pg lo read Read a large object