MySQLに画像のバイナリデータを保存する方法メモ


画像アップロードを作る場合、通常のデータ登録の他に、ファイルアップロード機能を実装しなければならない。これがけっこうめんどい。

でも、画像をバイナリデータとして、直接MySQLに保存することもできる。

テーブル設計

--
-- データベース: `images`
--

-- --------------------------------------------------------

--
-- テーブルの構造 `posts`
--

CREATE TABLE IF NOT EXISTS `posts` (
  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `imgdat` blob NOT NULL,
  `mime` VARCHAR(64) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 ;

BLOBはバイナリデータを扱うデータ型
imgdatフィールドに画像のバイナリデータ、mimeフィールドにMIMEタイプを保存する。

ディレクトリ構造

blob

create_image.php ・・・バイナリデータを画像ファイルに変換するファイル
edit.php ・・・アップロードページ
view.php ・・・アップロードされた画像を表示するページ

アップロードページの作成(edit.php)

フォーム部

<form enctype="multipart/form-data" action="./edit.php" method="POST">
	<input type="hidden" name="MAX_FILE_SIZE" value="300000" />
	<input name="image" type="file" />
	<p><input type="submit" name="save" value="Submit" /><p>
</form>

formにはenctype=”multipart/form-data”を指定すること。
MAX_FILE_SIZEでアップロード可能なサイズを指定しておいた方がいい。

制御部

<?php
$url = "localhost";
$user = "root";
$pass = "root";
$db = "images";

if (!empty($_POST))
{
	// バイナリデータ
	$fp = fopen($_FILES["image"]["tmp_name"], "rb");
	$imgdat = fread($fp, filesize($_FILES["image"]["tmp_name"]));
	fclose($fp);
	$imgdat = addslashes($imgdat);
	
	// 拡張子
	$dat = pathinfo($_FILES["image"]["name"]);
	$extension = $dat['extension'];
	
	// MIMEタイプ
	if ( $extension == "jpg" || $extension == "jpeg" ) $mime = "image/jpeg";
	else if( $extension == "gif" ) $mime = "image/gif";
	else if ( $extension == "png" ) $mime = "image/png";
	
	// MySQL登録
	$link = mysql_connect( $url, $user, $pass ) or die("MySQLへの接続に失敗しました。");
	$sdb = mysql_select_db( $db, $link ) or die("データベースの選択に失敗しました。");
	$sql = "INSERT INTO `images`.`posts` (`imgdat`, `mime`) VALUES ('".$imgdat."', '".$mime."')";
	
	$result = mysql_query( $sql, $link ) or die("クエリの送信に失敗しました。");
	mysql_close($link) or die("MySQL切断に失敗しました。");
}
?>

アップロードされたファイルは、スーパーグローバル変数 $_FILES に連想配列として格納される。
そこからバイナリデータとMIMEタイプをMySQLに保存する。

表示ページの作成(view.php)

<?php
$url = "localhost";
$user = "root";
$pass = "root";
$db = "images";

$link = mysql_connect( $url, $user, $pass ) or die("MySQLへの接続に失敗しました。");
$sdb = mysql_select_db( $db, $link ) or die("データベースの選択に失敗しました。");
$sql = "SELECT * FROM images.posts";
$result = mysql_query( $sql, $link ) or die("クエリの送信に失敗しました。");
$rows = mysql_num_rows( $result );
mysql_close( $link ) or die("MySQL切断に失敗しました。");

if($rows){
	while($row = mysql_fetch_array($result)) {
		echo '<img src="./create_image.php?id='.$row["ID"].'" />';
	}
}
?>

ここで重要なのは、バイナリデータを描画するのは create_image.phpファイルであるということ。

create_image.php

<?php
$url = "localhost";
$user = "root";
$pass = "root";
$db = "images";

$id = $_GET['id'];

$link = mysql_connect( $url, $user, $pass ) or die("MySQLへの接続に失敗しました。");
$sdb = mysql_select_db( $db, $link ) or die("データベースの選択に失敗しました。");
$sql = "SELECT * FROM images.posts WHERE ID = '".$id."'";
$result = mysql_query( $sql, $link ) or die("クエリの送信に失敗しました。");
$rows = mysql_num_rows( $result );
mysql_close( $link ) or die("MySQL切断に失敗しました。");

if( $rows ){
	while($row = mysql_fetch_array($result)) {
		header( "Content-Type: ".$row['mime'] );
		echo $row['imgdat'];
	}
}
?>

このファイルにGETでidを渡すことにより、バイナリデータを画像として描画している。

  • PHP初心者

    大変参考になる、コードのご提示ありがとうございます。
    現在、参考にさせていただき、勉強させていただております。
    PHP初心者のため少しうまくいかないので、書き込みさせていただきました。
    アップロードページの作成(edit.php)では、アップロードすれば
    きちんとデータベースに反映しております。
    その後の表示ページの作成(view.php)でデータベースからの画像データの表示がうまくいきませんでした。
    たとえばデータベースに3つデータを入れていた場合、view.phpを実行させると
    画像1画像2画像3
    と表示されるべきとことが
    画像アイコン画像アイコン画像アイコン
    (×画像が3つ表示)
    という表示で、うまく画像データをひっぱってきてないのです。

    create_image.phpを参考にして、色々試行錯誤したところ
    たとえば、
    create_image.php?id=1
    と直接URL指定してやると
    エラーメッセージは出ますがデータはひっぱtってきているようなのです。
    Warning: Cannot modify header information – headers already sent by (output started at /home/users/1/lolipop.jp-91051b7cfdd9c77e/web/test2/create_image.php:5) in /home/users/1/lolipop.jp-91051b7cfdd9c77e/web/test2/create_image.php on line 25
    ����JFIFHH��C       ��C  ���c����A!1A”2Q#aq�B��3br�RS��$5CTc���������(!1A”Qa3q2B��� ?��`=�� ���g�I�(�ZXy�{,j ж�8����7G9�H���G���(1r��i�AE��,�45�����}�gG,�־ߦ9�J���3����’��T,�����Q�tĹȷj6�!Gc�R]ln��1>E��b�g5�,��)��܀G��Ov=���i�b Rqn`�nm dqü

    何か原因がわかればと思い、メールさせていただきました。

    • ななし

      あー・・自分も同じ現象ですね。
      厳密にえばview.phpで表示されない部分だけですが・・・
      create_img.phpもまったく何も表示されません。

    • 初心者PHP4ヶ月目

      初心者の私もソースのコピペで同様の現象が起きました。HTMLではMINEタイプではなくMIMEタイプですので。

      テーブル設計でSQLのCREATE TABLE文中の`mine`⇒`mime`に修正。

      MYSQLで作成後だったのでPhpMyAdminで修正。

      edit.phpファイルの22行目で$mine⇒$mimeに修正。

      27行目の$sql = 文中の`mine`⇒`mime`に修正。VALUESの$mine⇒$mimeに修正。

      create_image.phpファイルで18行目の$row[‘mine’]⇒$row[‘mime’]に修正。

      すべてのphpソースファイルのエンコードをUTF-8(BOMなし)に変換して保存。

      ブラウザもUTF-8にすると表示できました。

    • “mime” がすべて “mine” になっていましたね。。
      すみません、修正しました。

  • サイベリアン

    ずっとデータベースに接続されないので、どうしたらいいのか教えてもらいたいです