PHPプロ!TIPSメーリングリスト

┏┏┏―― PHPプロ!Tipsメーリングリスト――――――――――――――
┏┏    
http://www.phppro.jp/ 2007/8/10 号

―――――――――――――――――――――――――――――――――

こんにちは、アシアル株式会社の亀本です。

すっかり猛暑の様相を呈してきていますが、皆様いかがお過ごしでしょうか。
業種が業種だけに、冷房と外の暑さのギャップに中てられている方もいらっしゃ
るかもしれません。夏風邪は怖いので、こういうときには健康には十分注意した
いですね。

TIPSも今回で50回目を迎え、一つの節目を迎えた感じでスタッフ一同感慨も一入
です。それでは今回のTIPSをお楽しみください。

━ 目次 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 1. PHPの「魔法の杖」runkitを使ってみよう
 2. ffmpeg-phpで動画のデータを取得しよう
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. PHPの「魔法の杖」runkitを使ってみよう

PHPのこの関数が、あともうちょっとこんな挙動をしてくれたらなぁ。。。
デバッグのために、一時的にここだけ動作を変更させたいんだけどなぁ。。。
そんな風に思うこと、ありませんか?

今回は、そんなかゆい所に手が届く一風変わったPHPエクステンション、「runkit」をご紹介します。

runkitは、PHPの定数や関数、クラス、メソッドを追加・変更・削除したり、独自のスーパーグローバル変数を定義したりできるPHPのエクステンションです。

基本的な関数などの追加・変更機能はPHP4と5の全てのバージョンで使用することができ、独自のスーパーグローバル変数定義はPHP4.2以上で使用可能となります。

加えて、PHP5以上では、「サンドボックス」という独自のPHP実行空間を持つスレッドを生成する機能も利用することができます。

このライブラリはPECL拡張モジュールとして提供されています。以下のようにpeclコマンド(もしくはpearコマンド)を使用しすることでインストールすることができます。 runkitは現在まだベータ版なので、モジュール名の指定には「-beta」表記をつけてください。

# pecl install runkit-beta

また、PHP5.2以上を利用している場合は現在リリース版として配布されているソース(執筆時点のバージョンは0.9)ではmake時にエラーが発生してしまうため、上記の方法ではインストールできません。

そのため、ソースをダウンロードした後、エラーの原因となるソースコードの修正を行ってからマニュアルでインストールをする必要があります。

$ wget http://pecl.php.net/get/runkit-0.9.tgz
$ tar xvzf
$ cd runkit-0.9

runkit_import.c 内で使用されているzend_unmangle_property_name()関数(バージョン0.9では230行目にあります)の引数を

zend_unmangle_property_name(key, &cname, &pname);

から

zend_unmangle_property_name(key, key_len, &cname, &pname);

に変更した上で、インストール作業を行ってください。

$ phpize
$ ./configure --enable-runkit --enable-maintainer-zts
$ make
$ sudo make install

あとは、extension=runkit.soの記述をphp.iniに追記してください。

※なお、この問題は既にCVSリポジトリ上のソースでは修正されているので、そちらをチェックアウトしてきて使用すれば修正の必要はありません。

では、早速使ってみましょう。

<?php

function test ($data){
  echo 
"foo $data \n";
}

test("bar");

runkit_function_redefine('test''$data, $data2 = "huni"'
                         
'echo "baz $data $data2 \n";');

test("hoge""huga");
test("hoge");
?>

結果:
foo bar 
baz hoge huga 
baz hoge huni 

上はもっとも単純な例ですが、runkitの関数を使用する前後で、test関数の挙動が変わっていることがわかります。。

runkit_function_redefine関数を使うと、既に定義済みの関数の内容を丸ごと再定義することができます。

第1引数に再定義したい関数名、第2引数にその関数で新たに与える引数定義、第3引数に実際のコードを、それぞれ指定します。

もちろんこの例だけだと「それ関数の定義書き換えれば。。。?」と思ってしまうかもしれません。

ですが実際の開発では、共通ライブラリで使用されているせいで勝手に変えられないけど、テストや拡張のために一時的にこの関数を変更したい。。。という要求が出ることがことがあります。

そういった場合などには、この関数を利用することで他の人には迷惑をかけずに共通関数の拡張が行えますので、ちょこっと便利です。 redefine以外にもrenamecopyなど色々な操作をする関数があり、また関数だけでなく定数やクラスのメソッドにも同様の操作が可能です。

また、上記の例ではユーザー定義関数を変更しましたが、runkitは強力な機能としてPHPの組み込み関数に対しても変更を加えることができます。

php.iniに

runkit.internal_override = On

という設定を加えてやる事でrunkitの機能が広がり、PHPの組み込み関数に対しても変更を加えられるようになります。例として、以下のようにstrlen関数を変更してみます。

test_runkit.php:
<?php
runkit_function_copy
('strlen''hoge');
runkit_function_remove('strlen');
runkit_function_add('strlen''$str''
echo $_SERVER["PHP_SELF"] . "\n";
return hoge($str);
'
);
?>

test.php:
<?php
$string 
"1234567";
include_once(
"test_runkit.php");
echo 
strlen($string) . "\n";
?>

結果:
test.php
7

strlen関数を文字列の長さを返すだけでなく、呼び出されたPHPのソースコード名も返すようにしてみました。

これを応用することで、PHPの組み込み関数の処理に対してLoggingを挟み込むことができ、デバッグやデータの流れを把握したい時などにもちょっと便利です。他にも、使い方はいろいろでしょう。

このように、runkitはPHPの各種挙動をダイナミックに変更することが出来ます。そういう意味では使い方を間違うと諸刃の剣にもなりますが、うまく使えばPHPをとても便利に拡張できます。

開発時のちょっとしたテストやデバッグなどであれば、「かゆい所に手が届く」使い方ができると思います。デフォルトのままだと色々細かいところで不便だな、と感じるところがある人は、一度試してみてはいかがでしょうか。

PECLパッケージ・runkit:http://pecl.php.net/package/runkit

マニュアル:http://www.phppro.jp/phpmanual/php/ref.runkit.html

2. ffmpeg-phpで動画のデータを取得しよう

オープンソースで動画や音声を変換するツールと言えば、ffmpegがあります。多彩なコーデックに対応しており、いろいろなものに使われています。

このffmpegの機能の一部をPHPで簡単に使えるようにしたエクステンションがffmpeg-phpです。これを使えば、少ないコードで簡単に、動画のプロパティや画像を取得できます。

では、早速使い方の解説です。

ffmpeg-phpのインストールには、ffmpeg本体が必要で、ffmpegのコンパイル時に

--enable-shared

をつけておく必要があるのでご注意ください。

ffmpegの準備ができたら、ffmpeg-phpのソースコードを

http://ffmpeg-php.sourceforge.net/

からダウンロード、解凍して、

phpize
./configure
make 
make install

とするだけでインストールは終了です。

動作の確認は、解凍したffmpeg-phpのディレクトリにあるtests と test_ffmpeg.phpをドキュメントルートにコピーしてアクセスし、テスト用ファイルのデータが出力されれば正常です。

次に、実際の使い方です。

dl("ffmpeg." . PHP_SHLIB_SUFFIX);    //エクステンションをロード

$movie_path = 'tests/test_media/test.avi';  //画像のパス

$movie = new ffmpeg_movie($movie_path);    //インスタンス生成

echo $movie->getFileName();  //ファイル名取得、表示
echo "
"; echo $movie->getFrameRate(); //フレームレート表示
/*  実行結果

tests/test_media/test.avi
24

*/

以上、わずか数行書くだけで、test.aviのプロパティが取得できます。

次に、画像の取得と表示方法です。(GDが必要です)

$frame = $movie->getFrame(100);
$image = $frame->toGDImage();

getFrameで取得するフレームを指定し、toGDImageでresouseを返しますので、

ob_end_clean();
header('Content-Type: image/jpeg');
imageJpeg($image,null,100);
imageDestroy($image);

とすると、画像を表示することができます。

これらを応用すると、例えば、あるディレクトリに画像を置くだけで、動的に画像のタイトルを取得し、画像を出力してサムネイルを作成したり、動画のデータを自動的にデータベースに入力するなどの使い方がでます。

また、ここで紹介したものはほんの一部ですので、他に使用できるメソッドなどは、公式のAPIドキュメント

http://ffmpeg-php.sourceforge.net/apidoc.php

をご覧ください。

ffmpeg-phpは面倒な画像取得などを少しのコードで実現できるので、機会があれば使ってみてはいかがでしょうか。