Π‘ΠΎΠ»ΡŒΡˆΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹

Иногда для Ρ€Π°Π±ΠΎΡ‚Ρ‹ прилоТСния трСбуСтся Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ «большиС» ΠΏΠΎΡ€Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π² Π±Π°Π·Π΅. Часто ΠΏΠΎΠ΄ большим ΠΏΠΎΠ½ΠΈΠΌΠ°ΡŽΡ‚ объСм Π΄Π°Π½Π½Ρ‹Ρ… Β«ΠΎΠΊΠΎΠ»ΠΎ 4 ΠΊΠΈΠ»ΠΎΠ±Π°ΠΉΡ‚ΠΎΠ² ΠΈΠ»ΠΈ большС», хотя ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… спокойно ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ Π΄ΠΎ 32 ΠΊΠΈΠ»ΠΎΠ±Π°ΠΉΡ‚ΠΎΠ², ΠΏΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ Π΄Π°Π½Π½Ρ‹Ρ… становится «большим». Π‘ΠΎΠ»ΡŒΡˆΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ (Π°Π½Π³Π». Large Objects, LOB) Π±Ρ‹Π²Π°ΡŽΡ‚ тСкстовыми ΠΈΠ»ΠΈ Π΄Π²ΠΎΠΈΡ‡Π½Ρ‹ΠΌΠΈ. ΠœΠΎΠ΄ΡƒΠ»ΡŒ PDO Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Ρ‚Π°ΠΊΠΈΠΌΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ ΠΏΡƒΡ‚Ρ‘ΠΌ установки Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ… PDO::PARAM_LOB Π² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°Ρ… PDOStatement::bindParam() ΠΈΠ»ΠΈ PDOStatement::bindColumn(). Π€Π»Π°Π³ PDO::PARAM_LOB сообщаСт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ PDO, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ трСбуСтся ΠΎΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ Π² Π²ΠΈΠ΄Π΅ ΠΏΠΎΡ‚ΠΎΠΊΠ°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ Ρ‡Π΅Ρ€Π΅Π· API-интСрфСйс PHP-ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ².

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 Π’Ρ‹Π²ΠΎΠ΄ изобраТСния, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ хранится Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…

Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ LOB-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΡΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‚ с ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ $lob, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ fpassthru(). ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ PDO-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ прСдставил LOB-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΊΠ°ΠΊ ΠΏΠΎΡ‚ΠΎΠΊ, с большим ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠΌ получится Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ функциями Π½Π°ΠΏΠΎΠ΄ΠΎΠ±ΠΈΠ΅ fgets(), fread() ΠΈ stream_get_contents().

<?php

$db
= new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');

$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);

header("Content-Type: $type");

fpassthru($lob);

?>

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 Вставка изобраТСния Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ Ρ„Π°ΠΉΠ» ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ дСскриптор Ρ„Π°ΠΉΠ»Π° Π² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ PDO для вставки Ρ„Π°ΠΉΠ»Π° Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²ΠΈΠ΄Π΅ LOB-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. ΠžΠ±ΡŠΠ΅ΠΊΡ‚ PDO ΠΈΠ·Π²Π»Π΅Ρ‡Ρ‘Ρ‚ содСрТимоС Ρ„Π°ΠΉΠ»Π° ΠΈ вставит Π΅Π³ΠΎ Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… самым эффСктивным способом.

<?php

$db
= new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');

$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // НСкоторая функция, которая Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ ID

// ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ находимся Π½Π° страницС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ² Π½Π° ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ сСрвСр

$fp = fopen($_FILES['file']['tmp_name'], 'rb');

$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);

$db->beginTransaction();
$stmt->execute();
$db->commit();

?>

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #3 Вставка изобраТСния Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…: Oracle

Π‘Π” Oracle Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π΄Ρ€ΡƒΠ³ΠΎΠΉ синтаксис для извлСчСния содСрТимого Ρ„Π°ΠΉΠ»Π° Π² Π²ΠΈΠ΄Π΅ LOB-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΈ вставки большого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…. Вставку Π±ΠΎΠ»ΡŒΡˆΠΈΡ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² Π‘Π” Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ, ΠΈΠ½Π°Ρ‡Π΅ Π‘Π” зафиксируСт LOB-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ вставила, с Π½ΡƒΠ»Π΅Π²ΠΎΠΉ Π΄Π»ΠΈΠ½ΠΎΠΉ β€” ΠΊΠ°ΠΊ Ρ‡Π°ΡΡ‚ΡŒ нСявной фиксации, которая Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ запроса.

<?php

$db
= new PDO('oci:', 'scott', 'tiger');

$stmt = $db->prepare("insert into images (id, contenttype, imagedata) " .
"VALUES (?, ?, EMPTY_BLOB()) RETURNING imagedata INTO ?")
;

$id = get_new_id(); // НСкоторая функция, которая Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ Π½ΠΎΠ²Ρ‹ΠΉ ID

// ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ находимся Π½Π° страницС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ² Π½Π° ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ сСрвСр

$fp = fopen($_FILES['file']['tmp_name'], 'rb');

$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['type']);
$stmt->bindParam(3, $fp, PDO::PARAM_LOB);

$db->beginTransaction();
$stmt->execute();
$db->commit();

?>
οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 6 notes

up
13
http://matts.org/ ΒΆ
16 years ago
A big gotcha exists for Oracle users.

You have to save CLOB objects using PDO::PARAM_STR, not PDO::PARAM_LOB.

But you MUST send the 4th argument, usually strlen($subject) or you get a LONG error.
up
10
diogoko at gmail dot com ΒΆ
17 years ago
PDOStatement's methods bindParam and bindValue also work with strings, as in:

<?php
  $data = file_get_contents($filename);
  $stmt->bindValue(1, $data, PDO::PARAM_LOB);
  //...
?>

This was the only way I could make it work with PostgreSQL.
up
11
Jeremy Cook ΒΆ
16 years ago
There seems to be a bug that affects example 1 above. PDO::PARAM_LOB when used with pdo::bindColumn() is supposed to return a stream but it returns a string. Passing this string to fpassthru() then triggers an error with the message 'supplied argument is not a valid stream resource'. This has been reported in bug #40913. The work around is to do the following:

<?php
$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);

header("Content-Type: $type");
echo($lob);
?>

Since the browser is expecting an image after the call to header() writing the string representation of the binary output with echo() has the same affect as calling fpassthru().
up
5
knl at bitflop dot com ΒΆ
17 years ago
I spend a lot of time trying to get this to work, but no matter what I did PDO corrupted my data.

I finally discovered that I had been using:

$pdo->exec('SET CHARACTER SET utf8');

in the TRY part of my connection script.

This off course doesn't work when you feed binary input to PDO using the parameter lob.
up
2
ben dot leiting at gmail dot com ΒΆ
9 years ago
For selecting data out of Postgres, the data type of the column in the table determined if the parameter bound with PARAM_LOB returned a string or returned a resource.

<?php

// create table log ( data text ) ;
$geth = $dbh->prepare('select data from log ');
$geth->execute();
$geth->bindColumn(1, $dataString, PDO::PARAM_LOB);
$geth->fetch(PDO::FETCH_BOUND);

echo ($dataString); // $dataString is a string

// create table log ( data bytea ) ;
$geth = $dbh->prepare('select data from log');
$geth->execute();
$geth->bindColumn(1, $dataFH, PDO::PARAM_LOB);
$geth->fetch(PDO::FETCH_BOUND);

fpassthru($dataFH); // $dataFH is a resource
up
-1
phpcoder at gmail dot com ΒΆ
7 years ago
The DBMSs that are listed above have these (default) limits on the maximum size of a char string. The maximum is given in bytes so the number of characters storable can be smaller if a multibyte encoding is used.

CUBRID:    16kB
SQL Server: 2GB
Firebird:  32kB
IBM Db2:   32kB
Informix:  32kB
MySQL:     16kB
Oracle:     2kB
PostgreSQL: 1GB
SQLite:     1 billion bytes
4D: Unknown, but LOBs are limited to 2GB.