MySQLでこういうデータを保存したい場合、
- PNGとかJPEGとかの画像
- 圧縮されたデータ
- その他バイナリなど
こういうバイナリ保存の方法は難しくありません。
ただいくつか注意すべきことも多いです。
そこで PHPの mysqli からバイナリ保存する方法 をまとめました。
※ 画像を直にMySQL保存するケースでの話
このページの目次
手順1.まず画像バイナリを保存するテーブルを作る
例えばこんなテーブルを作ったとします。
▼ 例えば画像名とデータを記録するテーブル的な
1 2 3 4 5 6 |
CREATE TABLE thumbnails { id INT AUTO_INCREMENT, name VARCHAR(256), data MEDIUMBLOB, PRIMARY KEY (id) }; |
画像データそのものは data カラムに保存するとしましょう。
そのとき大事なのは、型を次の4ついずれか にすること
型名 | 最大容量(bytes) | 補足 |
TINYBLOB | 255 | どういう用途で使うんだろ |
BLOB(M) | 65535 | 約64KB。長さをMで指定可 |
MEDIUMBLOB | 16777215 | 約15MB。そこそこ大きい |
LONGBLOB | 4294967295 | 約4GB。動画でもギリ保存可能 |
画像とかなら MEDIUMBLOB で十分なはず
4GB容量の LONGBLOB もあるけど、さすがに必要ないですね。そもそもそんな大容量データは ファイルとして保存 した方がベストです。
もし LONGBLOB で考えているなら、テーブル設定の見直しが必要かもしれません。
手順2.PHPの mysqli から画像データをinsertしてみる
今作った画像テーブル
そこに次のレコードを挿入したいとしましょう。
- idカラム : オートインクリメント
- nameカラム : image.jpeg
- dataカラム : 10KBほどの画像データ
その場合、以下のPHPを書けば画像データごとinsert可能です。
▼ 実際のPHPコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// 保存する画像の名前 $jpeg_name = 'image.jpeg'; /// 保存したい画像バイナリ(仮) $jpeg_data = hex2bin("FFD8DDE0..."); /// データカラム用のダミーデータ $DUMMY_NULL = null; $sql = " INSERT INTO thumbnails ( data, name ) VALUES ( ?, ? ) "; $stmt = $mysqli->prepare( $sql ); $stmt->bind_param( 'bs', $DUMMY_NULL, $jpeg_name ); $stmt->send_long_data( 0, $jpeg_data ); $stmt->execute(); $stmt->close(); |
大事なポイントは次の3つ
- プリペアステートメントを使う(当然)
バイナリを渡すので mysqli::prepare を使う。当然ながらMySQLインジェクションを防ぐためでもある
- BLOB型のバインド変数は null にする
なぜか bind_param ではバイナリデータを直に渡せない。そのため $DUMMY_NULL というダミー変数を作り、セットしている。
- バイナリは send_long_data から送信
肝心のバイナリデータは send_long_data( 0, $jpeg_data ); のように送信。1つめの引数がパラメーターのインデックス位置、2つめがデータそのもの
上コードみたいに send_long_data を使うのが必須みたいです。
てっきり bind_params から渡せると勘違いしていた・・・
安全にバイナリデータを渡すなら、こっちの方を使う方がいいみたいですね。
蛇足.バイナリをMySQLに直保存する是非について...
補足ではなく蛇足
バイナリをMySQLに直接保存する是非についてです。
この話題については 賛否両論いろいろあります。
▼ バイナリ保存に肯定的な意見
- 小さいデータだったら別にいいんじゃない?
- MySQLに保存した方が便利な場合もあるし、、、
▼ バイナリ保存に否定的な意見
- 直接バイナリ保存とかありえない!
- 普通にファイルで保存すれば、、、?
まあ絶対的な答えはないですね。
実際 LONGBLOB を使えば、バイナリでも4GBまで保存できる訳で・・・
仕様的にバイナリ保存がダメな理由はないです。
あとバイナリ保存も次の場合は許されるかな、と思ってます。
- 容量が決まっている場合
=> たとえば最大1KBまでとか制限があるとか - MySQL保存の方が便利な場合
=> 条件を指定いして絞り込みとかしたいケース
でも画像に関しては、どちらかといえばファイル保存ですね。
CMS(WordPressなど)でもデータベースに画像保存されてないし、
そもそもデータベース容量は 500MB とかの制限があるサーバーも多いです。
だから容量固定以外はファイル保存が基本かなという感じ。
まあケースバイケースで判断すればいいのかなと思います。
ここまでのまとめ
PHPで mysqli でバイナリ保存するのは少し面倒です。
でもやり方さえ間違えなければ、意外と簡単だと思いました。
もしコード的な誤りがあるならご指摘ください。ではでは($・・)/~~~