PEL のカレンダー関数依存を解決する
PHP 用の EXIF 操作ライブラリ PEL は PHP の拡張モジュールに含まれるカレンダー関数に依存している。Windows 版の PHP は初めから拡張モジュールを提供しているが、その他の仕向けでは -enable-calendar
オプション付きでコンパイルするか自前で拡張モジュールを入れて php.ini を編集しなければならない。
サーバー運営者ならこれらの対応を行う事も可能だろう。しかしレンタル サーバー利用者では対応は難しいか不可能。そこで PEL 自体のカレンダー関数依存を解決する方法を検討してみる。
PEL 内でカレンダー関数に依存している部分
PEL のソース コードに対してカレンダー関数名で grep したところ、依存しているファイルは PelEntryAscii.php のみ。使用している関数も以下の 4 種類だった。
gregoriantojd
...グレゴリウス日をユリウス積算日に変換するjdtogregorian
...ユリウス積算日をグレゴリウス日に変換するjdtounix
...ユリウス歴を Unix タイムスタンプに変換するunixtojd
...Unix タイムスタンプをユリウス歴に変換する
これらの関数は PelEntryTime
クラスの getValue
、setValue
メソッドで呼び出されている。
依存解決の方針
- カレンダー関数が有効の場合は、それを使用する
- カレンダー関数が無効の場合は、代用処理を使用する
- 代用処理はカレンダー関数の C 言語による実装を PHP に移植する
- これらを実装した
PelCalendarUtility
というユーティリティ クラスを用意する PelEntryTime
はカレンダー関数の代りにPelCalendarUtility
を使用する
カレンダー関数の C 言語実装
PHP 本体と拡張モジュールはオープンソースとなるので、まずは以下のページからソースコードを入手する。
ダウンロードした圧縮イメージを展開したフォルダのパスが C:\php
ならばカレンダー関数のソース コードは C:\php\ext\calendar
に格納されている。カレンダー関数はシンプルな C 言語の処理として実装されており依存する処理も少ない。よって必要な箇所だけ抜粋して単体動作できるようにするとよいだろう。
PHP への移植
基本的に C 言語の処理をそのまま移植し、言語間の表現や型解決の差異を解決してゆく。
また PelCalendarUtility
は PEL の PelEntryAscii.php に記述するので違和感のないようにコーディング ルールは PEL に合わせる。
参考資料として本記事にソース コードを掲載しようとしたものの処理がそれなりに長く、実装は PelEntryAscii.php だけで完結している。そのためソース コードをファイルとして公開することにした。
PEL 0.9.1 の PelEntryAscii.php をこのファイルに置き換える事で、カレンダー関数用の拡張モジュールが無効でも、PEL が動作するようになる。本ソースにより問題が発生しても私は一切の責任を負わないので使用は自己責任で。ライセンスはカレンダー関数が PHP License だけど PEL は GPL なので GPL としておく。
さくらインターネットのレンタル サーバー上では今回の対策で PEL が動くようになり、EXIF から GPS や撮影日が正しく取得できる事を確認した。
Comments from WordPress
- makoto_kw 2009-12-02T07:30:29Z
ちゃんと内容を理解してないんだけど、
if (!function_exists('unixtojd')) { function unixtojd() {...} }
っていうのを作ればPELいじんなくて良くない?
- akabeko 2009-12-02T08:22:11Z
@makoto_kw
unixtojd などの有無で分岐する処理を「PEL 以外の部分で定義した方が良い」という事でしょうか?今回のような実装にした理由としては、PEL 内のファイル ( 今回は PelEntryAscii.php ) だけ置き換えれば利用側はカレンダー関数の有無を気にする必要がない、という状態にする為となります。
- makoto_kw 2009-12-03T07:04:34Z
@akabeko
そうです。PEL以外で定義して(php_calender.patch.php)とかをつくれば利用者側はPELをおきかえなくても
include('php_calender.patch.php'); include(PEL); // オリジナル
で済みます。
PELそのものを置き換える方法だとPELのバージョンが変わる度にメンテナンスしないといけません。 - akabeko 2009-12-03T07:17:22Z
@makoto_kw
先にインクルードされる方に Wrapper を定義する事で、以降の呼び出しをそちらに変更するのですね。確かにこの方法なら PEL への影響はなく、今後、他の拡張モジュール関数に依存した時も、PEL 外でパッチを定義すれば OK ですね。ありがとうございます。試してみます。