肉とビールとパンケーキ by @sotarok

少し大人になった「肉とご飯と甘いもの」

Phar の仕組みを利用した PEAR モジュールのもっと便利な使い方

別にPEARに限った話ではないんですが,ここからが PHP の本気です!!

ってことで,tar などで圧縮されたファイルをそのまま読むことが出来るようになったので,その使い方をちょっと紹介.

Phar

PHP 5.3 から標準搭載された Phar (PHP Archive *1 ) の仕組み(の一部)を使うと,tar や zip で固められたバイナリデータの中身を直接ファイルとして読み込むことができます.phar:// ストリートがストリームラッパーに登録されているので,それを利用して require などをするだけです.

で,これを利用して PEAR ライブラリなどをさらに簡単に利用できるようにしてあげられるよねーと思ったので,利用してみました.

Phar ってなに

その前に Phar ってなにって話をしたいとおもったんですけど,面倒なのでぐぐればいいと思いましたので省略.phar 形式のファイルは,zlib で圧縮されたデータ *2+スタブ(そのデータを扱うためのプログラム)だと思ってもらえれば大丈夫です.
で,今回は特にその Phar 形式のファイルは使いません.

Phar ストリームラッパーのおかげで,tgz/zip で固められたデータの中身を解凍せずにそのままファイルとして読み込めるようになったので,それを利用してライブラリを使おうって話です.

とりあえずなにか適当に PEAR のファイルを用意する

とりあえず,こっから HTTP_Request2-0.5.1.tgz をダウンロードしてきます.

そうすると,今,ディレクトリは,

% ls
HTTP_Request2-0.5.1.tgz  load_library.php

みたいなかんじになっている状態です.

PharData で中身を確認

あとは普段どおり + phar:// ストリームをつかいます.
と,その前に,PharData クラスを使って,中身がどういう構成かを確認したいとおもいます.

<?php

foreach (new RecursiveIteratorIterator(new PharData('HTTP_Request2-0.5.1.tgz')) as $f) {
    echo $f, PHP_EOL;
}

そうすると,

phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Adapter/Curl.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Adapter/Mock.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Adapter/Socket.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Adapter.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Exception.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/MultipartBody.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Observer/Log.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2/Response.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/docs/examples/upload-rapidshare.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/AllTests.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/ObserverTest.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2/Adapter/AllTests.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2/Adapter/MockTest.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2/AllTests.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2/MultipartBodyTest.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2/ResponseTest.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/Request2Test.php
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/bug_15305
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/empty.gif
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/plaintext.txt
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/response_cookies
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/response_deflate
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/response_gzip
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/response_gzip_broken
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/tests/_files/response_headers
phar:///home/sotarok/git/sandbox/php/phar_pear/HTTP_Request2-0.5.1.tgz/package.xml

のように,中身を見ることができます.RecursiveIterator を実装しているので RecursiveIteratorIterator が役に立ちますね.(参考: モダンPHP勉強会を開催しました & 資料 - 肉とご飯と甘いもの @ sotarok)

phar:// ストリームでファイルの中身を require

目的のファイルをrequireして,あとはいつもどおりに使うだけです.先程出力をされたものは phar:// ストリーム+ファイルの絶対パスになっていますが,もちろん相対パスでも指定可能です.HTTP_Request2-0.5.1.tgz に続けて普通にファイルにアクセスするようにパスを指定します.

<?php

require_once 'phar://HTTP_Request2-0.5.1.tgz/HTTP_Request2-0.5.1/Request2.php';

$r = new HTTP_Request2('http://nequal.jp/');
$response = $r->send();
echo $response->getBody();

Request2.php 内でほかのファイルを require しているはずですが,このあたりは相対パスでよしなにやっているのでしょうか.(未調査)
依存ライブラリがあったときに困りそうだなあ.

まとめ

pharストリームを使えば,圧縮されたファイルでも,解凍せずに中身のPHPファイルを直接ロードして使うことができるます.file_get_contents などもできますし,画像データなども圧縮しておいたものをそのまま使うこともできます.


今回は,PharData を使って中身を確認してからファイルをロードしましたが,このあたりは自動化できるはずですね.例えば,PEAR 形式に関して言えば, package.xml を探し出して,その中身をチェックし,例えば,Loader::load('HTTP/Request2.php'); のようにしたら自動でその中身を読み込んできてくれるものを作ったり.
XOOPSWordPress のような CMSで,ユーザにプラグインをインストールさせる際,pear コマンドを使わずに,tgz をアップロードするだけでライブラリを使うことができる,そんな仕組みを実現することもできます.

このあたりに対応したフレームワークとかもそのうち出てくるんじゃないでしょうかねー.

Phar データのスタブを使えばもっと色々できますし,Phar はまだまだ活躍の幅を広げられそうです.


#次回,モダンPHP勉強会のテーマの1つが Phar になりそうだw *3

*1:jar のぱk(r

*2:無圧縮もできたはず.

*3:というかそれはもはやモダンPHPっていうか新機能PHP ... ?