Help us understand the problem. What is going on with this article?

PHP(PDO)でファイルをMySQLに保存するときに変更しなければいけない点

More than 3 years have passed since last update.

ファイルを物理ファイルではなく、データベースに保存する

tableの設計

  • おそらく2択

MEDIUMBLOB

  • およそ 16MB(2^24 - 1)
  • 常識的な添付ファイルで使えるサイズ。

LONGBLOB

  • およそ 4GB(2^32 - 1)
  • 本当に4GBを格納するつもりならば考え直した方が良い。
  • とはいえ、16MB以上であれば必然的にこのサイズ。

TINYBLOB

  • およそ 255B
  • テキストくらいしかないだろうし、それならバイナリで持たせる必要ないかな。

BLOB

  • およそ 64KB
  • プロフィール画像とか?
  • 昔、BLOBってんだからバイナリ無制限に入るんだろうとか思ってた。そもそも無制限とかありえないし実際全然入らなかった死にたい。

MySQLの設定

max_allowed_packet

確認

show variables like 'max_allowed_packet';
| max_allowed_packet | 1048576 |

  • クライアントからサーバに送ることができるパケットの最大値設定
  • この値を超えるとエラーを吐くので、割とすぐ気付く。
  • デフォルトでは1MB
  • 最大値でも1GB
    • なので、LONGBLOBの最大の4GBは保存できない。

変更

  • 設定変更と一時変更の2種類があり、一時変更にはさらに一時全体変更と、一時一部変更の2種類がある。
  • 設定変更はMySQLサーバーとしての設定を変更する。
  • 一時全体変更は、変更以後接続する場合に適用される。ただし、再起動するとリセットされる
  • 一時一部変更は、今接続している自分自身にのみ適用される。PHPから使うのでこの設定を使うことは多分無い。
設定変更
  • my.cnfを変更
my.cnf
[mysqld]
max_allowed_packet=16MB
  • 反映には再起動が必要。
一時全体変更

set global max_allowed_packet = 10475520;

  • 変更直後はSESSIONの値が適用されているので、一度接続しなおす必要がある。
一時一部変更

set max_allowed_packet = 10475520;

  • 省略。

まとめ

  • 運用環境で突然再起動なんてできないだろうし、かといって一生再起動しないというパターンもあり得ないので、結局set globalで一時的に変更して、再起動した時用にmy.cnfも修正する必要に迫られると思われる。

PHP(PDO)の設定

MYSQL_ATTR_MAX_BUFFER_SIZE

  • PDOが読み出すバッファの最大サイズ。デフォルト1MB。
  • 最大サイズを超えていてもエラーは出ない。
  • 1MBを超えているファイルをダウンロードする場合にキッチリ1MBになっていたらこれが原因の可能性大。

変更

  • 接続後の変更は不可で、PDOのコンストラクタに渡す必要がある。
new PDO("mysql:host=$host; dbname=$dbname", $user, $password,
           array(PDO::MYSQL_ATTR_MAX_BUFFER_SIZE=>1024*1024*10));//バイトで指定

出力時の設定

  • BLOBでファイルデータのみ格納している状態では適切なmime-typeを判別することは不可能なので、DB格納時に調べてファイル情報としてファイル名他と共に保存するのが良いと思う。

まとめ

  • ファイルは物理ファイルとして保存して、パス情報等のみ保存する方法は、SQLアンチパターン「ファントムファイル」としても挙げられているので、じゃあDBにファイルを保存しようとした結果がこの有様です。

  • 実装さえ終われば、二度目以降は同じ失敗しないだろうし、トランザクション管理もバックアップもほぼ何も考えなくて良いので、今後もファイルは積極的にDBに持たせていきたい。

smzk
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした