アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

PHP で EXIF を読む 3

PHP で EXIF を読むシリーズその 3。これまでの記事で PHP による EXIF 読み込み方法として PEL というライブラリを紹介し、使用上の問題点と解決策を検討した。

しかし本日、「PEL のカレンダー関数依存を解決する」のコメントとして makoto_kw 氏に「PEL へ変更を加えないで済む方法」についてアドバイスをいただいた。

新しい対策の有効性を確認したので、前の記事を修正しようと思ったが、以前に公開した EXIF 読み込みのサンプルも修正したくなったので、これらをまとめて新しい記事にする事にした。

PEL による EXIF 読み込み

PEL とは、オープンソースの PHP 向け EXIF 編集ライブラリ。現在は GitHub から入手できる。

PEL のフォルダーを pel とした場合、EXIF 読み込みの処理は以下のようになる。

<?php
require_once( "pel/PelJpeg.php"  );

/**
 * 画像から読み取った IFD 情報を取得します。
 *
 * @param $url 画像の URL。
 *
 * @return 成功時は IFD 情報。失敗時は false。
 */
function getIfd( $url )
{
    try
    {
        $jpeg = new PelJpeg( $url );
        $app1 = $jpeg->getExif();
        if( !$app1 ) { return false; }

        $tiff = $app1->getTiff();
        if( !$tiff ) { return false; }

        return $tiff->getIfd();
    }
    catch( Exception $e )
    {
        return false;
    }
}

/**
 * 画像から読み取った撮影日時を取得します。
 *
 * @param $url 画像の URL。
 *
 * @return 成功時は撮影日時。失敗時は false。
 */
function readDateTime( $url )
{
    $ifd = getIfd( $url );
    if( !$ifd ) { return false; }

    $v = $ifd->getEntries();
    if( !isset( $v[ PelTag::DATE_TIME ] ) ) { return false; }

    return $v[ PelTag::DATE_TIME ]->getText();
}

// 撮影日時を出力
$datetime = readDateTime( "http://***/test.jpg" );
echo $datetime;

?>

基本的に IFD や GPS を表すエントリのオブジェクトを参照し、それらの持つデータを getEntries メソッドで配列として取得。配列の添え字は PelTag クラスに定数として定義されているので、これを使用する。

添え字でアクセスした要素はデータ種別により文字列やバイナリ、配列などに分かれる。これらは EXIF の規格や Eclipse のデバッガなどで構造を確認しながら操作する。

PEL のカレンダー関数依存

PHP 用の EXIF 操作ライブラリ PEL は PHP の拡張モジュールに含まれるカレンダー関数に依存している。Windows 版の PHP は初めから拡張モジュールを提供しているが、その他の仕向けでは -enable-calendar オプション付きでコンパイルするか自前で拡張モジュールを入れて php.ini を編集しなければならない。

サーバー運営者ならこれらの対応を行う事も可能だろう。しかしレンタル サーバー利用者では対応は難しいか不可能。そこでカレンダー関数の Wrapper となる PHP スクリプトを作成して PEL よりも先にインクルードすることで依存を吸収する。

まず Wrapper となるスクリプトを作成する。php-calender-patch.php というファイル名で以下のように実装。

<?php
class CalendarUtility
{
    static public function gregoriantojd( $month, $day, $year )
    {
        // gregoriantojd 相当の処理
    }
}

if( !function_exists( gregoriantojd ) )
{
    function gregoriantojd( $month, $day, $year )
    {
        return CalendarUtility::gregoriantojd( $month, $day, $year );
    }
}
?>

CalendarUtility というクラスにカレンダー関数の代替メソッドを定義する。処理は PHP 拡張モジュールのカレンダー関数 (C 言語) を移植。クラスにした理由は以下。

  • 同一目的を持つ処理を局所化したかった
  • 移植元の処理を見ると理解しやすいのだが public にしなくても済む処理がある

これを前提にグローバル スコープでカレンダー関数の定義を判定、未定義なら CalendarUtility の代替メソッドを呼び出すようにする。この処理がなされると以降のカレンダー関数に対する呼び出しが以下のように変化する。

  • カレンダー関数が定義されている場合はそれを使用
  • カレンダー関数が未定義なら新たに定義された代替メソッドを使用

このスクリプトを PEL インクルードの前に置くことで PEL を変更せずにカレンダー関数への依存を解決できる。

サンプル プログラム

今回の記事で取り上げた処理の完全なソースを以下に公開する。

カレンダー関数の代替メソッド実装は PHP 拡張モジュールから移植したので、ライセンスはこれを踏襲して PHP License としておく。

サンプル プログラムの動作手順は以下のようになる。

  1. ダウンロードしたファイルを展開
  2. 展開されたファイルが php-calender-patch.php と test-read-exif.php の 2 つの PHP スクリプトである事を確認
  3. test-read-exif.php 内の readExif 関数の "http://***/test.JPG" という部分を、EXIF 情報を取得したい画像の URL に変更する
  4. PHP が動作するサーバー上にスクリプトを配置する
  5. PEL を格納した pel というフォルダをスクリプトと同じ階層に配置する
  6. test-read-exif.php へアクセスし、スクリプトを実行する

手順 3 の画像にアクセス可能で、EXIF 情報 ( このサンプルの場合、GPS と撮影日時 ) が設定されていれば、手順 6 を実行した時に画像情報が出力される。

Comments from WordPress

  • anonymous 2010-03-20T14:35:34Z

    サンプルファイルにアクセス出来ないようです...

    再アップをお願いしてもよいでしょうか。

  • akabeko akabeko 2010-03-20T15:04:18Z

    恐らくサンプル プログラム ZIPのことだと思いますが、今、アクセスしたらダウンロードできました。もう一度、試してみてください。