技術・開発

【MySQL】PHPから巨大なBLOBデータを登録する方法|メモリ不足を回避するLOAD_FILE()の活用と注意点

2010年12月26日

MySQLのテーブルには、画像やバイナリデータを保存するための BLOB型 を作成することができます。

PHPからMySQLのBLOBカラムにデータを INSERT する際、一般的にはファイルの中身を文字列として読み込んでSQLに埋め込む方法がとられますが、ファイルサイズが大きくなると「メモリ不足」のエラーに悩まされることがあります。

今回は、巨大なファイルを扱う際に有効な LOAD_FILE() 関数 を使った登録方法と、その際に必須となる権限設定、そしてセキュリティ上の注意点について解説します。

一般的な方法とメモリ消費の問題

通常、PHPからBLOBデータを登録する場合は、以下のようなSQLを構築します。

// 一般的な実装イメージ(※擬似コード)
$fileData = file_get_contents('ファイルパス'); // ファイルを全てメモリに読み込む
$sql = "INSERT INTO TEST (TITLE, FILEDATA) VALUES ('タイトル名', '" . エスケープ処理($fileData) . "')";

この方法では、file_get_contents() でファイルの中身をすべてPHPのメモリ上に展開します。 さらに、エスケープ処理やSQL文の生成によって、実際のファイルサイズの数倍のメモリ を消費することになります(例:700MBのファイルで約3GB近いメモリを消費するなど)。

これでは、PHPの memory_limit 設定に引っかかるか、物理メモリの上限に達して処理が停止してしまいます。

解決策:LOAD_FILE() を使用する

メモリ不足を回避するためには、PHPを経由せず、MySQL側に直接ファイルを読み込ませる FILE 権限 を利用した方法が有効です。

1. FILE権限の付与

まず、MySQLユーザーに対して、サーバー上のファイルを読み込むための権限(FILE権限)を付与する必要があります。

GRANT FILE ON *.* TO 'ユーザー名'@'ホスト';

注意: FILE権限は特定のデータベースに対してではなく、サーバー全体に対する「グローバル権限」となります(後述のセキュリティリスクに注意)。

2. SQLの書き換え

権限を付与したら、INSERT文を以下のように書き換えます。PHP側でファイルの中身を展開するのではなく、ファイルパスを渡して LOAD_FILE() 関数を実行させます。

-- PHP側で構築するSQLのイメージ
INSERT INTO TEST (TITLE, FILEDATA) VALUES ('タイトル名', LOAD_FILE('サーバー上の絶対パス'));

これにより、PHPは「ファイルパスという短い文字列」を送信するだけで済み、実際のファイルの読み込みと書き込みはMySQL(HDD ⇔ DB)が直接行います。 物理メモリを圧迫せず、処理速度も向上します。

重要なセキュリティ上の注意

非常に便利な LOAD_FILE() ですが、利用には慎重な判断が必要です。

FILE権限の危険性 FILE権限を持つユーザーは、MySQLサーバー上の読み取り可能なすべてのファイルを読み取ることができます。 例えば、サーバーの設定ミスやSQLインジェクション脆弱性があった場合、/etc/passwd などのシステム重要ファイルを盗み見られるリスクがあります。

  • 特定のフォルダのみ許可するという設定は(標準機能では)できません。
  • MySQLを root 権限で動かしている場合は特に危険です。

まとめ

  • 小規模なファイル: PHPで読み込んでINSERTしても問題ありません。
  • 大規模なファイル: メモリ不足になる場合は LOAD_FILE() を検討してください。ただし、FILE権限の付与はセキュリティリスクを伴うため、ネットワーク制限やユーザー権限の管理を厳重に行う必要があります。

-技術・開発
-, , , , , , ,