|
ここにある情報はかなり古くなっており、正しくなくなっている可能性があります。掲載しているサンプルコードiなどは、最新のPHPでは動作しない、もしくは、別途設定・調整が必要になるかも知れません。情報を鵜呑みにせず、あなたの手を動かして、あなたの目で確認してください。
Oracle8 から追加されたBLOB型の扱いについてまとめています。BLOB型を使えば、データベースに直接バイナリファイルを格納しておくことが可能です。なお、BLOBの詳細については、適宜Oracleのマニュアルを読んでください(^-^;
まず、INSERTの簡単にサンプルのフローを説明すると、以下のような感じです。
- LOBロケータを定義する
- 空のBLOBをINSERTして、BLOB型のカラムを返す
- LOBロケータのsaveメソッドでファイルを格納する
注意点としては、以下の通りです。私は、2番目でハマりました(-"-;
- BINDする前に、OCIDescriptorを実行し、LOBロケータに記憶領域を確保する
- SQL実行時に、自動 commit させないこと。でないと、BLOBの格納時に、「ORA-22990: LOBロケータは複数のトランザクションにまたがることはできません」というエラーが発生する
ここでは、アップロードされたファイルをBLOB型のカラムにINSERTするサンプルを作ってみました。なお、以下のPHPスクリプトはPHP4.3.11+Oracle10g Release1の組み合わせで確認しています。また、ファイルアップロードの詳細については、PHPマニュアルの「ファイルアップロードの処理」を参照してください。
●テスト用テーブル定義:create_lob_tbl.sql
CREATE TABLE lob_tbl(
filename VARCHAR2(100),
filesize NUMBER(7),
content_type VARCHAR2(100),
binary BLOB
);
●lob_ins.php
<?php
function loadfile($filename){
$fp = fopen( $filename, 'r' );
$buf = fread( $fp, filesize($filename) );
fclose($fp);
return $buf ;
}
if (!isset($_FILES['fname']) || $_FILES['fname']['error'] != UPLOAD_ERR_OK) {
?>
<form action='./lob_ins.php' method='post' enctype='multipart/form-data'>
ファイル名: <input type='file' name='fname'>
<input type='submit' value='アップロード'>
</form>
<?php
}
else {
$tmp_file_name = $_FILES['fname']['tmp_name'];
$file_name = $_FILES['fname']['name'];
$file_size = $_FILES['fname']['size'];
$content_type = $_FILES['fname']['type'];
echo 'テンポラリファイル名=' . $tmp_file_name . '<br>';
echo '元のファイル名=' . $file_name . '<br>';
echo 'サイズ=' . $file_size . '<br>';
echo 'Content-type=' . $content_type . '<br>';
$conn = OCILogon('scott', 'tiger', 'orcl');
$lob = OCINewDescriptor($conn, OCI_D_LOB);
$sql = 'INSERT INTO lob_tbl (filename, filesize, content_type, binary) '
. 'VALUES(:fn, :fs, :ct, EMPTY_BLOB()) '
. 'RETURNING binary INTO :bin ';
$sql = OCIParse($conn, $sql);
OCIBindByName($sql, ':FN', $file_name);
OCIBindByName($sql, ':FS', $file_size);
OCIBindByName($sql, ':CT', $content_type);
OCIBindByName($sql, ':BIN', $lob, -1, OCI_B_BLOB);
OCIExecute($sql, OCI_DEFAULT);
if ($lob->save(loadfile($tmp_file_name))) {
OCICommit($conn);
echo 'アップロード成功<br>';
}
else {
echo 'アップロード失敗<br>';
}
OCIFreeStatement($sql);
OCILogoff($conn);
}
?>
次に、INSERTしたデータを取り出すサンプルです。基本的には、通常のSELECTと変わりませんが、BLOB型データの出力の部分に特徴があります。モジュールは2つあり、テーブルのリストを作成する部分と、ダウンロードを実行する部分に分かれています。ダウンロードする部分では、以下のようなフローになっています。
- データをFETCH
- HeaderでContent-typeを出力
-
loadメソッドを使ってBLOB型データをLoadし、そのままechoで出力
なお、パラメータとしてOracleの行ID(ROWID)を渡していますが、ROWIDは「+」を含む可能性があるのでrawurlencode関数を使用してエンコードして渡すようにしています。
●lob_sel.php
<?php
$conn = OCILogon("scott", "tiger", "orcl");
$sql = "SELECT ROWIDTOCHAR(ROWID) rid, filename, filesize "
. "FROM lob_tbl ";
$sql = OCIParse($conn, $sql);
OCIExecute($sql, OCI_DEFAULT);
?>
<table border=1>
<tr>
<th>No.</th>
<th>ファイル名</th>
<th>サイズ</th>
</tr>
<?php
$cnt = 0;
while(OCIFetchInto($sql, $arr, OCI_ASSOC)){
$cnt++;
?>
<tr>
<th>
<a href="lob_sel2.php?rid=<?php echo rawurlencode($arr["RID"]); ?>">
<?php echo $cnt; ?>
</a></th>
<td><?php echo $arr["FILENAME"]; ?></td>
<td><?php echo $arr["FILESIZE"]; ?></td>
</tr>
<?php
}
?>
</table>
<?php
OCIFreeStatement($sql);
OCILogoff($conn);
?>
●lob_sel2.php
<?php
if (!isset($_GET['rid'])) {
die('invalid parameter');
}
$rid = $_GET['rid'];
$conn = OCILogon('scott', 'tiger', 'orcl');
$sql = 'SELECT filename, content_type, binary '
. 'FROM lob_tbl '
. 'WHERE ROWID = ROWIDTOCHAR(:rid) ';
$stmt = OCIParse($conn, $sql);
OCIBindByName($stmt, ':RID', $rid);
OCIExecute($stmt, OCI_DEFAULT);
OCIFetchInto($stmt, $arr, OCI_ASSOC);
$filename = $arr['FILENAME'];
$content_type = $arr['CONTENT_TYPE'];
$data = $arr['BINARY'];
if (ereg(' MSIE ', $_SERVER['HTTP_USER_AGENT'])) {
$encoding = 'sjis';
}
else {
$encoding = mb_http_output(); }
$filename = mb_convert_encoding(
$filename,
$encoding,
mb_internal_encoding());
mb_http_output('pass');
header('Content-Type: ' . $content_type);
header('Content-Disposition: attachment; filename=' . $filename);
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0,pre-check=0');
header('Pragma: public');
echo $data->load();
OCIFreeStatement($stmt);
OCILogoff($conn);
?>
|