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.
À un moment dans votre application, vous pourriez avoir besoin de stocker de
grosses données dans votre base de données. « Gros » signifie typiquement
des données d'environ 4 ko ou plus, bien que certaines bases de données peuvent
gérer plus de 32 ko avant que les données deviennent « grosses ». Les gros objets
peuvent être de nature textuelle ou binaire. PDO vous permet de travailler
avec ce type de grosses données en utilisant le code type
PDO::PARAM_LOB
dans vos appels aux fonctions
PDOStatement::bindParam() ou
PDOStatement::bindColumn().
PDO::PARAM_LOB
demande à PDO de transformer les données
en un flux que vous pourrez manipuler en utilisant
l'API PHP des flux.
Exemple #1 Affichage d'une image depuis une base de données
Cet exemple lie un LOB dans une variable nommée $lob et l'envoie au navigateur en utilisant la fonction fpassthru(). Étant donné qu'un LOB est représenté en un flux, les fonctions comme fgets(), fread() et stream_get_contents() peuvent être utilisées sur ce flux.
<?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);
?>
Exemple #2 Insertion d'une image dans une base de données
Cet exemple ouvre un fichier et passe le pointeur de fichier à PDO pour l'insérer en tant que LOB. PDO fera son possible pour récupérer le contenu du fichier et l'insérer dans la base de données de la manière la plus efficace possible.
<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // fonction pour allouer un nouvel ID
// assumons que nous récupérons un fichier depuis un formulaire
// vous pouvez trouver plus de détails dans la documentation de PHP
$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();
?>
Exemple #3 Insertion d'une image dans une base de données Oracle
Oracle requiert une syntaxe légèrement différente pour y insérer un LOB depuis un fichier. Il est également essentiel d'effectuer votre insertion au sein d'une transaction, sinon, votre nouveau LOB sera inséré avec une longueur de zéro :
<?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(); // fonction pour allouer un nouvel ID
// assumons que nous récupérons un fichier depuis un formulaire
// vous pouvez trouver plus de détails dans la documentation de PHP
$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();
?>
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.
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.
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().
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.
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
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.