Oracle 使用者有個很大的陷阱。
您必須使用 PDO::PARAM_STR 來儲存 CLOB 物件,而不是 PDO::PARAM_LOB。
但是您必須傳送第四個參數,通常是 strlen($subject),否則會收到 LONG 錯誤。
在您的應用程式中,您可能會發現需要將「大型」資料儲存在資料庫中。大型通常表示「約 4kb 或更多」,儘管某些資料庫可以在資料變成「大型」之前輕鬆處理高達 32kb 的資料。大型物件可以是文字或二進制性質。PDO 允許您使用 PDO::PARAM_LOB
類型代碼在 PDOStatement::bindParam() 或 PDOStatement::bindColumn() 呼叫中使用這種大型資料類型。PDO::PARAM_LOB
會告知 PDO 將資料對應為資料流,以便您可以使用 PHP 資料流 API 處理它。
範例 #1:從資料庫顯示圖片
此範例將 LOB 繫結到名為 $lob 的變數中,然後使用 fpassthru() 將其傳送到瀏覽器。由於 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 的函式
// 假設我們正在檔案上傳表單中執行
// 您可以在 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();
?>
範例 #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 的函式
// 假設我們正在檔案上傳表單中執行
// 您可以在 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();
?>
Oracle 使用者有個很大的陷阱。
您必須使用 PDO::PARAM_STR 來儲存 CLOB 物件,而不是 PDO::PARAM_LOB。
但是您必須傳送第四個參數,通常是 strlen($subject),否則會收到 LONG 錯誤。
PDOStatement 的方法 bindParam 和 bindValue 也適用於字串,如下所示
<?php
$data = file_get_contents($filename);
$stmt->bindValue(1, $data, PDO::PARAM_LOB);
//...
?>
這是我在 PostgreSQL 中使其運作的唯一方法。
似乎有個錯誤會影響上面的範例 1。當與 pdo::bindColumn() 一起使用時,PDO::PARAM_LOB 應該會傳回串流,但它會傳回字串。然後將此字串傳遞給 fpassthru() 會觸發錯誤,訊息為「提供的引數不是有效的串流資源」。這已在錯誤 #40913 中回報。解決方法是執行下列操作
<?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);
?>
由於瀏覽器在呼叫 header() 後預期會有圖片,因此使用 echo() 寫入二進位輸出的字串表示法與呼叫 fpassthru() 的效果相同。
我花了很多時間試圖讓它運作,但是無論我怎麼做,PDO 都會損壞我的資料。
我終於發現我一直在使用
$pdo->exec('SET CHARACTER SET utf8');
在我的連線指令碼的 TRY 部分中。
當您使用參數 lob 將二進位輸入饋送到 PDO 時,這當然無法運作。
為了從 Postgres 中選取資料,資料表中欄位的資料類型決定了使用 PARAM_LOB 綁定的參數是傳回字串還是資源。
<?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 是一個字串
// 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 是一個資源
上面列出的 DBMS 在字元字串的最大大小上都有這些(預設)限制。最大值以位元組為單位,因此如果使用多位元組編碼,則可儲存的字元數可能會較小。
CUBRID:16kB
SQL Server:2GB
Firebird:32kB
IBM Db2:32kB
Informix:32kB
MySQL:16kB
Oracle:2kB
PostgreSQL:1GB
SQLite:10 億位元組
4D:未知,但 LOB 限制為 2GB。