CakeFest 2024: The Official CakePHP Conference

Büyük Veri Nesneleri (LOB'lar)

Uygulamanızın bir yerinde veritabanınızda büyük müktarda veri saklamanız gerekebilir. Burada büyük veriden kasıt 4kB civarı olsa da bazı veritabanları için büyük veri 32kB'tan başlar. Büyük veriler ikil veya dizgesel olabilir. PDOStatement::bindParam() ve PDOStatement::bindColumn() çağrılarında büyük verilerlerle çalışmak için PDO::PARAM_LOB veri türünü kullanabilirsiniz. PDO::PARAM_LOB, verinin bir akım olarak eşleneceği anlamına gelir. Dolayısıyla, bu veriler üzerinde PHP Akım işlevleri ile işlem yapabilirsiniz.

Örnek 1 - Veritabanındaki bir resmin gösterilmesi

Bu örnekte bir LOB, $lob değişkeni ile ilişkilendirilmekte ve fpassthru() üzerinden tarayıcıya gönderilmektedir. LOB bir akımla temsil edildiğinden fgets(), fread() ve stream_get_contents() gibi işlevlerle üzerinde işlem yapabilirsiniz.

<?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);
?>

Örnek 2 - Bir resmin veritabanına yerleştirilmesi

Bu örnekte bir dosya açılıp, bir LOB olarak veritabanına yerleştirilmek üzere, dosya tanıtıcısı PDO'ya aktarılmaktadır. PDO, dosya içeriğini veritabanına yerleştirme işlemini en verimli şekilde yapacaktır.

<?php
$db
= new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)");
$id = get_new_id(); // Yeni bir kimlik ayıran bir işlev

// Resmin bir dosya yükleme formundan geldiğini varsayıyoruz
// PHP belgelerinde bu konuda ayrıntılı bilgi bulabilirsiniz

$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();
?>

Örnek 3 - Oracle'da bir resmi veritabanına yerleştirmek

Oracle, bir LOB'u bir dosyadan alıp veritabanına yerleştirirken farklı bir sözdizimi kullanımını gerektirir. Esas olarak, yerleştirme işlemi bir toplu hareket olarak gerçekleştirilir. Böyle yapılmazsa oluşturulan LOB, sorgu çalıştırıldığında örtük olarak sıfır uzunluklu bir veri girişinin parçası haline gelir.

<?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(); // Yeni bir kimlik ayıran bir işlev

// Resmin bir dosya yükleme formundan geldiğini varsayıyoruz
// PHP belgelerinde bu konuda ayrıntılı bilgi bulabilirsiniz
$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();
?>

add a note

User Contributed Notes 7 notes

up
13
http://matts.org/
14 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
13
Jeremy Cook
14 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
10
diogoko at gmail dot com
14 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
4
knl at bitflop dot com
15 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
1
ben dot leiting at gmail dot com
7 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
5 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.
up
-15
xorinox at gmx dot ch
13 years ago
I find it easier to use stream_get_contens to fetch the data of a lob using the file handle.

<?php
$stmt
= $pdo->con->prepare( 'select * from filetable' );
$stmt->execute();
$res = $stmt->fetchAll( PDO::FETCH_ASSOC );

for(
$i=0; $i<count($res); $i++ ){
$filename = "C:/tmp/".$res[$i]['FILE_ID'].'.xml';
$content = stream_get_contents( $res[$i]['DATA_FILE'] );
file_put_contents( $filename, $content );
}
?>
To Top