imagecreatefromjpeg()で「marker 0xd9」エラーが出る問題について
PHPでユーザーからの画像ファイル投稿を受け付ける場合に、GDライブラリを利用したimagecreatefromjpeg()関数を使用すると、まれに以下のようなエラーが出てしまうことがあります。
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]:
gd-jpeg, libjpeg: recoverable error: Corrupt JPEG data: 233
extraneous bytes before marker 0xd9 in /***.php on line 94
Warning: imagecreatefromjpeg() [function.imagecreatefromjpeg]:
'/***.jpg' is not a valid JPEG file in /***.php on line 94
赤い数字の箇所は画像ファイルによって異なります。
要するに「画像ファイル中の0xd9マーカーより前の233バイト部分にゴミ情報がありますよ。」ということでJPEG画像が壊れてるらしいです。
しかし、この画像は画像ビューワーで見ると問題なく見られます。
おそらくメタデータ(EXIF等)部分をGDがチェックして独自判断を下しているのでしょう。
このエラーが発生した画像をPhotoshopの「ファイル情報」を調べてみると「Sumsung GALAXY S II SC-02C」で撮影された画像ファイルでした。
こうなるとGDライブラリではどうしようもないので、手動でやるのであれば一度ローカルPCにダウンロードしてPhotoshop等の編集ツールで開いて新規画像ファイルにコピペして再アップロードすることになります。
どうしてもサーバー上で解決したい!
jheadライブラリを導入
こういう場合はEXIF情報を除去してくれる「jhead」ライブラリを利用しましょう。
ただし、通常のLinuxサーバーではデフォルトでインストールされていないので、yumコマンドでインストールします。
yumコマンドでjheadパッケージが見つからない場合は、epelリポジトリを追加するとインストールできますよ。サーバーOSのバージョンとCPUの種類でインストールするパッケージが異なるので注意。
#yum install jhead ... Total download size: 54 k Is this ok [y/N]: (yキー+RETURNキー) ... Importing GPG key 0x217521F6 "Fedora EPEL <epel@fedoraproject.org>" from /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL Is this ok [y/N]: (yキー+RETURNキー) ... Installed: jhead.i386 0:2.90-2.el5 Complete!
PHPでWarning!を例外処理できるように変更
PHPでは通常「imagecreatefromjpeg()」で発生する警告エラー(Warning)を例外処理することはできませんが、set_error_handler()で独自関数を定義することで例外処理することができます。
/**
* 画像処理エラーを扱う関数
*
* @param integer $errno エラー番号
* @param string $errstr エラーメッセージ
* @param string $errfile エラーが発生したファイル名
* @param integer $errline エラーが発生した行番号
* @param array $errcontext エラーコンテキスト
*/
function imageErrorHandler($errno, $errstr, $errfile, $errline, array $errcontext) {
if (error_reporting()===0) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
この関数を以下のように「try~catch」の前に設定しておきます。
/**
* メイン処理
*/
$file_path = './corrupted_image.jpg';
//エラー処理系を一時的に変更
set_error_handler("imageErrorHandler");
try {
$img_rsrc = imagecreatefromjpeg($file_path);
} catch(ErrorException $e) {
//0xd9のエラー
if (strpos($e->getMessage(), '0xd9')!==false) {
//エラーが起こった際の処理系をここに書きます。
} else {
//その他のエラー処理系をここに書きます。
}
}
//エラー処理系を戻す
restore_error_handler();
エラーが発生したらjheadでEXIF情報を除去する
0xd9のバイトエラーが発生した場合、以下のような処理でEXIFデータを除去した画像ファイルに入れ替えることができます。
//0xd9のエラー
if (strpos($e->getMessage(), '0xd9')!==false) {
$cmd = escapeshellcmd("jhead -purejpg {$file_path}");
exec($cmd, $output);
...
(再度imagecreatefromjpeg()等を実行する)
}
これでエラーが発生しても問題なく変換できるようになります。
お役に立ちましたでしょうか?
2013-02-20