Hudsonとphp
php用のHudsonの設定と言えば、
HudsonでPHPのユニットテスト
http://d.hatena.ne.jp/ssogabe/20081102/1225642743
の記事があったりしますが、こちらで紹介されてる設定をそのままコピペしたとしても
近頃(すくなくとも今年4月以降)のhudsonだとパスがうまくいかなかったりします(うろおぼえ)
なので、Phingプラグインを使う場合は、ビルドパスとか以下の感じにすると動くと思います。
というか、最近だったらSebastian Bergmann純正のテンプレートにそうのがトレンディーじゃないでしょうかね
http://github.com/sebastianbergmann/php-hudson-template
あ、PEAR的にはCruise Control&PHPUnderControlがナウでヤングですよ
http://wiki.php.net/pear/qa/ci
symfonyドキュメント翻訳温泉ツアーに参加してきました。
http://www.symfony.gr.jp/blog/20100801-symfony-translation-spa
symfonyドキュメントの翻訳は一切やってません(キリッ! (おいおい)
yudoufuさんの寝起きマル秘画像を激写はできなかったので、別の写真をお楽しみください。
やったことはちょっとgithubにプッシュしたり、温泉行ったり、vimperatorにeijiroプラグインまで入れてたのに電子辞書使ってて電池切れしてたり、
温泉に行ったり、オペラの発声練習を聞いたり、温泉に行ったりってことですね。参加者の皆さんお疲れ様でした。
強欲にHTTPレスポンスをUTF-8にエンコーディングするDiggin_Http_Response_Charsetについて
githubもしくはopenpearでのコミットログを見ていると気づいてるかと思われますが、
最近は、Diggin_Http_Response_Charsetというのを作成しました。
http://openpear.org/package/Diggin_Http_Response_Charset
http://github.com/sasezaki/Diggin_Http_Response_Charset
利用方法のわかりやすい例として、Zend_Http_Responseのラッパーを用意しました。
もともと、Htmlscrapingのエンコーディング部分だけを切り離して、Diggin_Http_Response_Encodingというクラスに置き換えてたのですが、
Http_Response_Encodingという名前は、「"content-encoding"などを無視していると弾言できる(Enjoy!)」*1と思い、ちょびっと手直ししたもの*2を作成しているところでした。
ですが、CharactorEncodingというのがタイポなのと、以下のisssueトラッカーにお寄せいただいたバグのために書き換えが必要だったという次第です。
http://code.google.com/p/diggin/issues/detail?id=1
バグの内容は、レスポンスのconten-typeが'Shift-JIS'だったために、
'SJIS-win'な○付き1とかが化けるという事象です。
細かくどう変更したかは、
Htmlscrapingクラス、Diggin_Http_Response_Encoding、
Diggin_Http_Response_Charset_Detector_Htmlをそれぞれ見比べてもらうとして、
・ mb_list_encodings()の中で、mb_preferred_mime_name()を通すと変更されるものは、 デフォルトでレスポンスボディ(HTML)をmb_detect_encoding()強制するようにした。 (SJIS-winなど) ・ デフォルトのdetectエンコーディングリストを 'ASCII, JIS, UTF-8, eucJP-win, EUC-JP, SJIS-win, SJIS'にした(かなり適当です)
という所です。
デフォルトのエンコード方法としては、上述のDetectorの結果をDiggin_Http_Response_Charset_Encoder_Htmlが用いてエンコードします。
使いかたの例としては、以下のような形で、レスポンスボディ(HTML)とレスポンスヘッダーのcontent-typeを渡します(conten-typeがない場合はnull)。
http://github.com/sasezaki/Diggin_Http_Response_Charset/blob/master/sandbox.php
デフォルトではDiggin_Http_Response_Charset_Encoder_Htmlである程度動作すると思われますが、特定のサイトにurlの正規表現などで、エンコード方法を細かく指定したい場合もあります。
そのために、Diggin_Http_Response_Charset_Front_UrlRegexというのを用意しました。
これは、addEncoderメソッドに対象のURL正規表現とDiggin_Http_Response_Charset_Encoder_EncoderAbstractを拡張したエンコーダーを設定し細かいエンコード設定ができます。使い方の例としては、
http://github.com/unpush/p2-php/blob/master/cookie.php
のように、ブラウザでも化けるようなHTMLの特定の一部についても、
http://github.com/sasezaki/Diggin_Http_Response_Charset/blob/master/sandbox_github.php
のような感じで、_initBody()という事前フィルタ処理を行うことで、HTMLすべてUTF-8変換というところまで試みてます。
なお、まだリリースしてないDiggin 0.7ではこのDiggin_Http_Response_Charsetを使います。すでに変更対応分のコミットはしてます。
http://openpear.org/repository/Diggin_Scraper_Adapter_Htmlscraping/trunk/library/Diggin/Scraper/Adapter/Htmlscraping.php
0.7では投入しようとした、robots.txtなどのハンドラー"Diggin_RobotRules"を一旦ギブアップしてもう近々リリースするつもりです。
たった1行のコードでHTML取得&解析をしたい場合はexthtmlが便利
たった*行のコードでHTML取得&解析をしたい場合はWeb::Scraperが便利をexthtmlを使った場合、こんな感じになります。
$ exthtml -x '//div[@id="topicsfb"]//li//text()' -a='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)' http://www.yahoo.co.jp/
詳しくは、exthtmlの解説ページで。
cpan分からないという方には、phpのインスパイア版(exthtml.php)があります。
extphp -x '#topicsfb li' -v text http://www.yahoo.co.jp -a 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)'
詳しくは、digginリファレンスで(あ、exthtml.phpのこと書いてないや)
某テンプレートエンジンの各HTTPクライアントで100リクエスト投げた時のベンチマーク
大体3,4回目の結果を載っけてます。
環境:
$ \php -v PHP 5.3.2-1ubuntu4 with Suhosin-Patch (cli) (built: Apr 9 2010 08:23:39) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
$ pear list | grep Net_Socket Net_Socket 1.0.9 stable $ pear list -a | grep HTTP HTTP_Client 1.2.1 stable HTTP_Request 1.4.4 stable HTTP_Request2 0.5.2 alpha $ pear list -a | grep ZF INSTALLED PACKAGES, CHANNEL PEAR.ZFCAMPUS.ORG: ZF 1.10.5 stable $ pecl list | grep http pecl_http 1.6.6 stable
file_get_contents
$ cat file_get.php <?php for ($i=1; $i <=100; $i++) { file_get_contents('http://localhost/favicon.ico'); } $ time \php file_get.php real 0m0.107s user 0m0.044s sys 0m0.036s
pear/HTTP_Request
$ cat pear_httpRequest.php <?php require_once 'HTTP/Request.php'; for ($i=1; $i <=100; $i++) { $req = new HTTP_Request('http://localhost/favicon.ico'); $req->sendRequest(); } $ time \php pear_httpRequest.php real 0m0.212s user 0m0.148s sys 0m0.044s
pear/HTTP_Request2
$ cat pear_httpRequest2.php <?php require_once 'HTTP/Request2.php'; for ($i=1; $i <=100; $i++) { $req2 = new HTTP_Request2('http://localhost/favicon.ico'); $req2->send(); } $ time \php pear_httpRequest2.php real 0m0.190s user 0m0.160s sys 0m0.012s
ZFのZend_Http_Client
$ cat zf_http.php <?php require_once 'Zend/Http/Client.php'; for ($i=1; $i <=100; $i++) { $client = new Zend_Http_Client('http://localhost/favicon.ico'); $client->request(); } $ time \php zf_http.php real 0m0.267s user 0m0.172s sys 0m0.036s
CURL(sudo apt-get php5-curlしたやつ)
$ cat cURL.php <?php for ($i=1; $i <=100; $i++) { $fh = fopen('/tmp/null', 'w'); $ch = curl_init('http://localhost/favicon.ico'); curl_setopt($ch, CURLOPT_FILE, $fh); curl_exec($ch); curl_close($ch); fclose($fh); } $ time \php cURL.php real 0m0.114s user 0m0.032s sys 0m0.052s
pecl_http(pecl installでウィザードは全部Enter)
$ cat pecl_http.php <?php for ($i=1; $i <=100; $i++) { http_get('http://localhost/favicon.ico'); } $ time \php pecl_http.php real 0m0.091s user 0m0.040s sys 0m0.032s
pecl_http(その2)
$ cat pecl_http_class.php <?php for ($i=1; $i <=100; $i++) { $r = new HttpRequest('http://localhost/favicon.ico', HttpRequest::METH_GET); $r->send(); } $ time \php pecl_http_class.php real 0m0.093s user 0m0.036s sys 0m0.040s
pecl_http(pool版 1回めと2回め以降で全然違う。。。)
$ cat pecl_http_pool.php <?php $pool = new HttpRequestPool; for ($i=1; $i <=100; $i++) { $pool->attach(new HttpRequest('http://localhost/favicon.ico')); } $pool->send(); $ time \php pecl_http_pool.php real 0m6.796s user 0m0.664s sys 0m1.580s $ time \php pecl_http_pool.php real 0m0.124s user 0m0.056s sys 0m0.044s
lithium0.9.5
$ cat lithium-095.php <?php require_once 'SplClassLoader.php'; $loader = new SplClassLoader(); $loader->setIncludePath(__DIR__ . '/libraries'); $loader->register(); for ($i=1;$i<=100;$i++) { $http = new lithium\net\http\Service(array('host' => 'localhost')); $r = $http->get('/favicon.ico'); } $ time \php lithium-095.php real 0m0.178s user 0m0.108s sys 0m0.040s
ただのsocket_clientだとかsfWebBrowserとかHordeだとかは誰かやってください。
参照:
LLごとの標準的なHTTPクライアントで100リクエスト投げた時のベンチマーク
http://subtech.g.hatena.ne.jp/mala/20100531/1275322139
ついき:ちなみに「そんなリクエストごとにクライアントオブジェクト生成しないわー」と思って、下のもやってみましたが、あんまりかわりませんでした。あれ。
<?php require_once 'Zend/Http/Client.php'; $client = new Zend_Http_Client(); for ($i=1; $i <=100; $i++) { $client->setUri('http://localhost/favicon.ico'); $client->request(); }
PHPとZend Frameworkでの前の例外
私の見てるマニュアルには載ってますよ!
http://framework.zend.com/manual/ja/zend.exception.previous.html
Zend Frameworkを使ってる方は、PHP5.2でもprevious exceptionを可能にするために以下のとおり変更が施されて、codeは(int)キャストしてることに注意。
http://framework.zend.com/code/browse/Standard_Library/standard/trunk/library/Zend/Exception.php
ちなみに、
<?php require_once 'Zend/Exception.php'; function throwing() { throw new InvalidArgumentException(); } function get() { throwing(); } try { try { get(); } catch (Exception $e){ throw new Zend_Exception("", 10, $e); } } catch (Exception $e) { echo $e; echo PHP_EOL.'----'.PHP_EOL; var_dump($e->getTraceAsString()); var_dump($e->getPrevious()->getTraceAsString()); }
を実行すると、
exception 'InvalidArgumentException' in /tmp/previous_test.php:5 Stack trace: #0 /tmp/previous_test.php(9): throwing() #1 /tmp/previous_test.php(14): get() #2 {main} Next exception 'Zend_Exception' in /tmp/previous_test.php:16 Stack trace: #0 {main} ---- string(9) "#0 {main}" string(87) "#0 /tmp/previous_test.php(9): throwing() #1 /tmp/previous_test.php(14): get() #2 {main}"
となる。で、これが実運用上ロギングとのかねあいでうんにゃこりゃがあると思いますが、僕Javaってなんじゃばなので一家言ありません。。(Zend Serverー?)
PHPマニュアルのException:
http://www.php.net/manual/ja/exception.construct.php