31
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【PHP】serializeの落とし穴

Last updated at Posted at 2018-05-20

配列や独自クラスをDBに入れておいて、それを後から使うようなこと、したくなりますよね。
そんな時に便利なのがserializeです。(serializeとは?)
JSONと言う手もありますが、型の情報が失われてしまうので、serializeを使うことも多くあると思います。
ですが、そのserializeした情報、DBに入れる時どうしてますか?
もしかして、text型のカラムに直接突っ込んだりしていませんか?(私はtext型のカラムに突っ込んでいました)
戻り値がstringだからと言って、text型のカラムに入れるのはNGです。

以前趣味で作っていたwebアプリではまったので、その際のポイントをかいつまんでまとめてみました。

何がいけないのか

実はtext型のカラムにserializeされた文字列を入れると、unserializeする際に上手くいかないことがあります。
insert自体に問題はなく、そこでエラーが出たりexceptionがthrowされることもありません。
でも、その時点でDBに格納されるデータは壊れており、unserializeすることができないため復旧も不可能となります。

何故こんなことが起きるのか、ですが、簡単に言うとinsert時にデータが欠損してしまい、unserialize時に正しく元に戻せなくなってしまうことが原因でした。
insert時にデータが欠損してもinsert自体には問題がないため、DBには中途半端な状態でinsertされてしまい、気付くのはunserializeのタイミング、と言うなんとも悲しい状態の出来上がりです。

解決策

serializeメソッドではstringが返ってくるのに、DBにはtextで入れてはいけません。ではどうしたらいいのか。
実は答えは簡単で、PHPのマニュアルに記載があります。

これはバイナリ文字列であり、null バイトを含む可能性もあることに注意しましょう。 保存したり利用したりするときも、null バイトが含まれることを想定しておかないといけません。 たとえば、serialize() の出力をデータベースに格納するときには、 通常は CHAR 型や TEXT 型ではなく BLOB 型を使わないといけません。

上記の通り、serializeメソッドの戻り値はバイナリ文字列であるため、BLOB型のカラムを用意してそこに入れる必要があります。(参考:BLOBとは?)
serializeメソッドの戻り値はstringなんですが、中身はバイナリ文字列なので、普通に文字列として扱うとデータが欠損することがあるようでした。
考えてみれば単純なことなんですが、戻り値がstringであることに惑わされ、解決までに結構時間を費やしてしまいました。

この時はこれで解決できましたが、正直なところデータの検証をしたわけではないので、正確には別の原因があった可能性もあります。
もし別の原因をご存知の方がいらっしゃれば、是非お教えいただければと思います。

補足

実はMySQLのBLOB型にはいくつか種類があり、バイナリデータによっては格納しきれない場合があります。
参考:MySQLのBLOBについて

BLOB はさまざまな容量のデータを保持できる大きなバイナリオブジェクトです。BLOB 型は、TINYBLOB、BLOB、MEDIUMBLOB、および LONGBLOB の 4 つがあります。これらの違いは、保持できる値の最大長だけです。

保持できる値の最大長が違うだけで4種類あり、格納したいデータのサイズを見積もった上でテーブルを作る必要があります。
格納したいデータによってはカラムのサイズを超えてしまい、BLOB型でも欠損が起こる場合があるので、テーブルを作る際はデータサイズの確認を怠らないよう気をつけたいと思います。

31
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?