アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

レンタルサーバーで PEL が動かない問題

以前の記事で PEL を利用した PHP による EXIF 読み込みを取り上げた。

動作は Windows Vista + Eclipse PDT で確認。また開発中の WordPress プラグインにもこの時の実装を元にした処理が組み込まれており XAMPP 上のプラグイン実行でも該当処理は問題なし。

しかし今日、プラグインをリリースするためレンタル サーバーに設置した本ブログでテストしたら EXIF 読み込みが動作しない。どうやら PEL の 処理が Fatal Error になるようだ。プラグインでは PEL による EXIF 読み込み部分を独立した CGI として設計しているため全体への影響はないが、かなり痛い問題である。

既に原因は判明しており対策を検討中だが PEL を利用したいと考えている人の役に立つかもしれないので、この問題の調査方法と原因をまとめておく。

調査方法

はじめに問題の再現する最小コードを作成。EXIF 読み込みが怪しいという目星は付いていたので、処理の各ステップと Fatal Error を echo で出力してみる。

<?php
// Fatal Error 用
register_shutdown_function( "shutdownHandler" );
function shutdownHandler()
{
	$error = error_get_last();
	if( $error[ "type" ] == E_ERROR )
	{
		echo $error[ "message" ];
	}
}

// スクリプト読み込み用
$include = include_once( "pel-0.9.1/PelJpeg.php" );
echo( $include ? "include_once [{$include}]" : "Error : include_once" );

// PEL 用
try
{
	$url = "/blog/2009/11/29.JPG";

	echo( class_exists( PelJpeg ) ? "class_exists( PelJpeg )" : "Error : class_exists( PelJpeg )" );

	$jpeg = new PelJpeg( $url );

	echo( "PelJpeg(url)" );
}
catch( Exception $e )
{
	echo( "Error : PelJpeg(url)" );
}
?>

PelJpeg のインスタンス生成まで成功すれば PEL 本体ではなく利用方法に問題があると切り分けられるだろう。これを test.php としてサーバーに配置して Web ブラウザーからアクセスしてみたところ以下のような結果が出力された。実際に出力されるテキストは詰まっているが、分かりやすくするため改行を入れている。

include_once [1]
class_exists( PelJpeg )
Call to undefined function unixtojd()

まず 1 ~ 2 行目の内容から include_once には成功して PelJpeg も定義されていることがわかる。しかし 3 行目に見慣れないエラーが。自前のメッセージではないため、これは Fatal Error であろう。そしてエラーは unixtojd という未定義の関数呼び出しを問題としている。

原因

問題の unixtojd とはカレンダー関数である。

カレンダー関数の説明を読むと使用条件が以下のように書かれている。

これらの関数を動作させるには、 --enable-calendar を指定して PHP をコンパイルする必要があります。 Windows 版の PHP にはこの拡張モジュールのサポートが組み込まれています。これらの関数を使用するために拡張モジュールを追加でロードする必要はありません。

2018/11/27 この引用文は記事を書いた当時、students.kiv.zcu.cz に掲載されていたもの。このページは消滅しているので jp2.php.net に変更。

この説明で合点がいった。

本記事の冒頭でも触れたように PEL を試した環境はすべて Windows の XAMPP。つまりカレンダー関数は始めから用意されていた。しかし他の環境では説明どおりに PHP をコンパイルする、またはカレンダー モジュールを導入して php.ini を書き換えなければならない。

私が利用しているレンタル サーバーはさくらインターネットのスタンダード コースだが、恐らくは他社のサービスでも発生するだろう。対策方法がサーバーの PHP をいじるしかなくて困った。プラグインにカレンダー系モジュールを同梱して side-by-side に実行する方法はないものだろうか?