PostgreSQLで画像をバイナリデータで格納・出力する

PostgreSQLでDBのテーブルのbytea型の列にデータを格納し、表示する簡単なサンプルです。
Smartyというテンプレートエンジンも使用していますが、使用しなくても良いです。

  

この記事は1年以上前に書かれたものです。
情報が古い可能性があります。

検証バージョンはPostgreSQLが9.2、PHPが5.4.7です。PDOは今回使用していません。

注意:

bytea 型を SELECT した場合、PostgreSQL は ‘\’ で 始まる 8 進数のバイト値(例: \032)を返します。これをユーザーが手動で コンバートすることを期待されています。

とかPHP Manualに書いてるんですけどそもそもPHP Manualに書いてある例がちゃんと動いてくれなかったのでENCODEでコンバートしましたよ(‘A`)

PHP: pg_unescape_bytea – Manual

フォルダ構成はこんな感じ。
フォルダ構成

テーブルの作成

CREATE TABLE image
(
  byte_data bytea,
  id serial NOT NULL,
  CONSTRAINT id PRIMARY KEY (id)
);

ソース

image.php

<?php
/**
 * UTF-8 BOM なしで保存しています。
 *
 * <img src="image.php?id=画像ID" />
 * という形で画像出力を行う
 */
 
//イメージIDを取得 
if( !isset( $_GET['id'] ) ) exit;
$id = $_GET['id'];

//数値チェック
if( !is_numeric( $id ) ) exit;
else $id = intval( $id );

//DB接続
$conn = pg_connect( 'host=localhost port=5432 dbname=sample user=postgres password=passwd' );
if( $conn == false ) exit;

//bytea 型を SELECT した場合、PostgreSQL は '\' で 始まる 8 進数のバイト値(例: \032)を返します。これをユーザーが手動で コンバートすることを期待されています。 
// bytea データを取得する(ENCODEでコンバート)
$sql = "SELECT ENCODE( byte_data::bytea, 'escape' ) byte_data FROM image WHERE id= {$id} ";
$res = pg_query( $sql );
if( $res == false ) exit;

//クエリ結果をオブジェクトして取得
$data = pg_fetch_object( $res );
if( $data == false ) exit;

//クエリ 結果 resource に関するメモリとデータを開放
pg_free_result( $res );

//DB切断
pg_close( $conn );

//画像の情報を取得する(※要GDライブラリ有効)
$img = base64_encode( pg_unescape_bytea( $data->byte_data ) );  
$scheme = 'data:application/octet-stream;base64,';  
$size = getimagesize( $scheme . $img );
if( $size == false ) exit;

//バイナリに変換し、ブラウザに送信する
header( 'Content-type: ' . $size['mime'] );
echo pg_unescape_bytea( $data->byte_data );
exit;

index.php

<?php
/**
 * UTF-8 BOM なしで保存しています。
 */

//Smartyのlibフォルダがinclude_pathに入っていること
require_once( 'Smarty.class.php' );

//Smarty初期設定
$smarty = new Smarty();

//PHP5.3.0以上では dirname( __FILE__ ) => __DIR__ でも可能
$smarty->template_dir = dirname( __FILE__ ) . '/';
$smarty->compile_dir  = dirname( __FILE__ ) . '/compile/';
$smarty->config_dir   = dirname( __FILE__ ) . '/configs/';

//DBへの接続を行う
$conn = pg_connect( 'host=localhost port=5432 dbname=sample user=postgres password=passwd' );


//取り敢えずのデータ生成
$images = array( 'img/cat.jpg', 'img/php.gif', 'img/children.png' );

for( $i =0; $i < count( $images ); $i++ ) { 
	
	//バイナリファイルを読み込む
	$data = file_get_contents( $images[ $i ] );

	//バイナリデータをエスケープする
	$esc = pg_escape_bytea( $data );

	//DBに登録
	pg_query( "INSERT INTO image (byte_data) VALUES ('{$esc}')" );
}


//テンプレートを表示する
$smarty->assign( 'msg', '画像出力テスト' );
$smarty->display( 'index.tpl' );

index.tpl

<!DOCTYPE html>

<html>
<head>
	<meta charset="UTF-8" />
	<title>{$msg}</title>
	<meta name="viewport" content="width=device-width" />
	<meta name="description" content="" />
	<meta name="keywords" content="" />
</head>

<body>
	<h1>{$msg}</h1>
	
	<img src="image.php?id=1" alt="猫" />
	<img src="image.php?id=2" alt="PHP" />
	<img src="image.php?id=3" alt="子供" />
</body>
</html>

実行例

実行例

  

共有やブックマークなど