k-holyのPHPとか諸々メモ

Webで働くk-holyがPHP(スクリプト言語)とか諸々のことをメモしていきます。ソースコードはだいたいWindowsで動かしてます。

filesize()関数における2GBの壁と4GBの壁

filesize()関数におけるというか、要は32bit整数の話なのですが。
マニュアルにもある通り、filesize()関数は2GBを越えるファイルについては期待通りの値を返さない場合があります。
PHP filesize - Manual

今まで2GB超のファイルに対してファイルシステム関数を使う機会はなかったんですが、アップロードファイルのサイズチェック処理を書いてて改めて検証してみたのでメモ。

(以下、環境は32bit Windows7、XAMPP1.7.7のPHP 5.3.8)

  • 2GBの壁

32bit int (-2147483648 から 2147483647)の上限を越えるため、2GB以上の場合filesize()関数はマイナスの値を返す。
sprintf('%u')(引数を整数として扱い、符号無しの10進数として表現)で4GBまでは対応可能。

  • 4GBの壁

32bit unsigned int (0 から 4294967295)の上限を越えるため、4GB以上の場合filesize()関数は0を返す。
マニュアルの記述では falseが返ってE_WARNINGが発生するようなことを期待したけどそんなことはなかった…。
Linuxだと stat -c%s ファイル名 で取得できるけどWindowsだと…?(dirコマンドという話もあったけどそんなのやだ…)

今回の要件では4GB以上のファイルは扱わないので、単位付きバイト数の変換はBCMath関数使ってYB(10の24乗、ヨタバイト)まで対応するとして、サイズチェックの方はfilesize()関数任せでダメっぽい場合のみ例外スローしておくことにしました。

ちなみに、手元に2GB以上の巨大ファイルがなかったんですが、Windowsではこんなコマンドでサクッと一瞬で作成できました。

fsutil file createnew C:\Users\k-holy\Documents\Projects\test\2GB.dat 2147483648
fsutil file createnew C:\Users\k-holy\Documents\Projects\test\3GB.dat 3221225472
fsutil file createnew C:\Users\k-holy\Documents\Projects\test\4GB.dat 4294967296

バイト数に「1208925819614629174706176」(1YB)指定してみたかったけど、仕事中だったのでやめときました。

(参考)巨大なサイズのファイルを簡単に作る方法 - @IT