[PEAR]HTML_CSS_MobileでUndefined index

Posted under php by uechoco on 木曜日 10 2月 2011 at 12 : 08 : 41

PC/mobile両対応のサイトを作ることになったので、初めてPEAR::HTML_CSS_Mobileを使わせていただきました。すばらしいライブラリを作ってくださった@yudoufuさんに感謝です。

さて、使い方は、ドコモだったら出力バッファ文字列に対してapply()するという単純なものなのですが、こんなエラーが発生しました。

TEXT:
  1. Notice (8): Undefined index:  h1, h2, h3, h4, h5, h6 [CORE/vendors/PEAR-1.9.0/HTML/CSS.php, line 2023]

ちなみにエラー部分で解析しようとしていたCSSはこんな感じです。いわゆるリセット用CSSの一部です。

TEXT:
  1. h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}

最初は複数指定が読み取れないのかと思ったのですが、そんなことも出来なければライブラリとして残念すぎるので、悩みつつ、とりあえずカンマが詰まりすぎていたのでスペースを入れました

TEXT:
  1. h1, h2, h3, h4, h5, h6{font-size:100%;font-weight:normal;}

・・・エラーがなくなりました。CSSの構文として間違っていたのでしょうか?とりあえず、まぁ、よしとするか。ちなみに、関連すると思われるバグチケットも発見しました

Bug #16544 :: HTML_CSS undefined index on malformed input

試した環境はphp5.1.6、PEAR 1.9.0、HTML_CSS 1.5.4(のはず)、HTML_CSS_Mobile 1.8.0です。


[Symfony2]PEAR::Net_UserAgent_MobileをDIコンテナから呼び出す

Posted under Symfony2 by uechoco on 木曜日 9 12月 2010 at 00 : 01 : 18

この記事は、Symfony アドベントカレンダー 2010 に参加しています。

Symfony2も先日PR4バージョンがリリースされて、ベータ版のリリースも近くなってきているようです。Symfony2はphp 5.3.2以上を必要とする新しいフレームワークに生まれ変わりますが、まだまだphp4時代の遺産にはお世話になるんではないかと思っています。特にお世話になるのはPEARですよね。今回は、Symfony2でのPEARライブラリを使用してみる例として、日本人phperの誰もがお世話になってる(言い過ぎか?)PEAR::Net_UserAgent_MobileをSymfony2で扱う方法を模索してみます。「模索」と言っているのは、私自身がSymfony2歴が非常に浅いという意味と、エラーをどのように回避していったかの軌跡をしっかりとお見せしようと思っているためです。対象バージョンはgithubの最新ではなく、Symfony2 PR4のsandboxです。

それでは進めていきましょう。

PEARライブラリの配置

まずはPEAR::Net_UserAgent_MobileとPEAR.phpをダウンロードし、以下のように/src/vendorにpearディレクトリを作成して中に配置します。

pearディレクトリの配置場所

pearディレクトリの中身の様子

autoload.phpの編集

PEARライブラリに対してパスを通すため、/src/autoload.phpを編集します。

// /src/autoload.php の下部

php:
  1. $loader->registerPrefixes(array(
  2.     'Swift_' => $vendorDir.'/swiftmailer/lib/classes',
  3.     'Twig_'  => $vendorDir.'/twig/lib',
  4.     'Net_'   => $vendorDir.'/pear', // added prefix for PEAR::Net_XXX libraries
  5. ));
  6. $loader->register();
  7.  
  8. // hack for some PEAR libraries
  9. set_include_path(get_include_path().PATH_SEPARATOR.$vendorDir.'/pear');

上のコードでは、「Net_」という文字から始まるクラス名の場合の起点ディレクトリをregisterPrefixes()メソッドで指定しています。PEARライブラリには「PEARである」という接頭辞がないため、ちょっと気持ちが悪い指定の仕方になっています(本当は接頭辞をNet_と指定したらNetディレクトリを起点に登録するか、PEARまるごと起点ディレクトリを登録できると嬉しい)。

また、多くのPEARライブラリは、PEARの起点ディレクトリからのパスを用いてrequire_onceすることが多いため、起点ディレクトリをinclude pathに登録する必要があります(「require_once 'Net/UserAgent/Mobile/Error.php';」といったインクルードに対応するためです)。

実はこれだけでもうクラスパスが通ったので使えるようになりました。おめでとう!これにて一件落着!
...というところで終わってしまったらこの記事の価値は全くありません(笑 Symfony2らしく、DIコンテナからNet_UserAgent_Mobileクラスのインスタンスを取り出せるようにHelloBundleを拡張してみます。(ここからちょっとハードルが上がります)

HelloExtensionの作成

Symfony2のDI機構には、Extensionと呼ばれる仕組みがあり、バンドル毎にDIコンテナに対する初期設定などを行うことができます。HelloBundleであれば、以下のようにHelloBundleディレクトリ直下にDependencyInjectionディレクトリを作成しHelloExtension.phpを配置すると、設定ファイルに記載があれば自動的に読み込まれるようになっています。

// /src/Application/HelloBundle/DependencyInjection/HelloExtension.php

php:
  1. <?php
  2.  
  3. namespace Application\HelloBundle\DependencyInjection;
  4.  
  5. use Symfony\Component\DependencyInjection\Extension\Extension;
  6. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  7. use Symfony\Component\DependencyInjection\ContainerBuilder;
  8.  
  9. use Symfony\Component\DependencyInjection\Definition;
  10. use Symfony\Component\DependencyInjection\Reference;
  11.  
  12. /*
  13.  * This source file is subject to the MIT license that is bundled
  14.  * with this source code in the file LICENSE.
  15.  */
  16.  
  17. /**
  18.  * HelloExtension.
  19.  *
  20.  * @author uechoco
  21.  */
  22. class HelloExtension extends Extension
  23. {
  24.     /**
  25.      * Loads the Hello Bundle configuration.
  26.      *
  27.      * @param array            $config    An array of configuration settings
  28.      * @param ContainerBuilder $container A ContainerBuilder instance
  29.      */
  30.     public function configLoad($config, ContainerBuilder $container)
  31.     {
  32.         $def = new Definition('Net_UserAgent_Mobile');
  33.         $def->setFactoryMethod('factory');
  34.         $container->setDefinition('net.useragent.mobile', $def);
  35.     }
  36.  
  37.     /**
  38.      * Returns the base path for the XSD files.
  39.      *
  40.      * @return string The XSD base path
  41.      */
  42.     public function getXsdValidationBasePath()
  43.     {
  44.         return __DIR__.'/../Resources/config/schema';
  45.     }
  46.  
  47.     public function getNamespace()
  48.     {
  49.         return 'http://labs.uechoco.com/schema/dic/hello';
  50.     }
  51.  
  52.     public function getAlias()
  53.     {
  54.         return 'hello';
  55.     }
  56. }

このコードが何をしているのかを一言で言えば、DIコンテナがNet_UserAgent_Mobileを勝手に管理してくれるように登録しています。Net_UserAgent_Mobileクラスのサービスを定義し、ファクトリメソッドとして、factoryを設定し、net.useragent.mobileという識別子で登録しています。

また、getAlias()メソッドでHelloExtensionのエイリアスとしてhelloを指定していますが、これは次のconfig設定で使用されます。

config.ymlの修正

さきほど作成したHelloExtensionが自動的に読み込まれるには、/app/config/config.ymlにHelloExtensionの設定を記述する必要があります。

// /app/config.config.yml に追記

TEXT:
  1. # HelloBundle Configuration
  2. hello.config: ~

最後のチルダも忘れずに。

設定ファイルの読み込みの仕組みをここで詳しく説明はしませんが、例えばhello.configという記述があると、「hello」エイリアスのExtensionの、「config」Load()メソッドが自動的に呼び出される仕組みにあっています。これで先程のサービス定義のconfigLoad()メソッドが呼ばれるように成ります。

HelloContorllerから使ってみる

HelloControllerのindexActionを以下のように修正して、Net_UserAgent_Mobileクラスでモバイルかどうかを判定した真偽値をテンプレートに渡してあげます。

// /src/Application/HelloBundle/Controller/HelloController.php

php:
  1. public function indexAction($name)
  2.     {
  3.         $agent = $this->container->get('net.useragent.mobile');
  4.  
  5.         return $this->render('HelloBundle:Hello:index.twig', array('name' => $name, 'non_mobile' => $agent->isNonMobile()));
  6.  
  7.         // render a PHP template instead
  8.         // return $this->render('HelloBundle:Hello:index.php', array('name' => $name));
  9.     }

そして、twigテンプレートにも少し修正を加えます。

// /src/Application/HelloBundle/Resources/views/Hello/index.twig

TEXT:
  1. {% extends "HelloBundle::layout.twig" %}
  2.  
  3. {% block content %}
  4.     {% if non_mobile %}
  5.     <strong>non mobile!</strong>
  6.     {% else %}
  7.     <strong>mobile!</strong>
  8.     {% endif %}
  9.  
  10.     Hello {{ name }}!
  11. {% endblock %}

Webからアクセスしてみる

これで本来なら動くはずです。Webからアクセスしてみましょう。私の場合は以下のようなURLです。

http://sandbox-pr4.localweb02/app_dev.php/hello/uechoco

※uechocoの部分は、好きな英数字に置き換えても構いません。

すると、以下のようなエラーが発生して動きません。

「call_user_func() expects parameter 1 to be a valid callback, non-static method Net_UserAgent_Mobile::factory() should not be called statically」

原因を探る

困りました。何がいけなかったのか、エラーが発生したDIコンテナの該当部分を見てみます。

// /app/cache/dev/appDevDebugProjectContainer.php

php:
  1. protected function getNet_Useragent_MobileService()
  2.     {
  3.         return $this->services['net.useragent.mobile'] = call_user_func(array('Net_UserAgent_Mobile', 'factory'));
  4.     }

どうやらstatic宣言していないメソッドを静的に呼ぼうとしているのがいけないようです。php4自体のコードを引き継いでいるのでしょうがないですよね。static宣言をしていないメソッドを静的に呼び出すための一番容易な解決策は、エラー制御演算子付きで呼び出すことです。call_user_func()の前に@マークが付けられれば問題ないのですが、このコードはSymfony2の内部で自動的に生成されるコードなのですが、エラー制御演算子をつけるオプションはないようです。

※今回はエラー制御演算子の使用の是非の議論はしません。単純かつ分かりやすい解決策として採用しています。

Net_UserAgent_Mobile::factory()メソッドを呼び出すラッパークラスを作成

幸いにも、Symfony2のサービス定義には、別のサービスのメソッドを用いてインスタンスを生成するような指定方法があります。つまり、ラッパークラスを作ってエラー制御演算子付きでfactory()メソッドを呼び出すようなメソッドを持たせて、そのラッパークラス経由でNet_UserAgent_Mobileのインスタンスを生成するようにしてやります。言葉だと分かりにくいと思うので、ソースコードで語りますw

まずはラッパークラスを作成します。Utilディレクトリはつくってください。
// /src/Application/HelloBundle/Util/PEARClassLoader.php

php:
  1. <?php
  2.  
  3. namespace Application\HelloBundle\Util;
  4.  
  5. /*
  6.  * This source file is subject to the MIT license that is bundled
  7.  * with this source code in the file LICENSE.
  8.  */
  9.  
  10. /**
  11.  * class loader for PEAR classes
  12.  *
  13.  * @author uechoco
  14.  */
  15. class PEARClassLoader
  16. {
  17.     /**
  18.      * Load the Net_UserAgent_Mobile class.
  19.      *
  20.      * @return Net_UserAgent_Mobile
  21.      */
  22.     public function factoryNet_UserAgent_Mobile()
  23.     {
  24.         return @\Net_UserAgent_Mobile::factory();
  25.     }
  26. }

気をつけなければならないのは、Symfony2にとってNet_UserAgent_Mobileクラスはデフォルト名前空間で定義されています。このラッパークラスの名前空間とは異なりますので、エラー制御演算子とクラス名の間にバックスラッシュを入れるのを忘れないでください。

HelloExtensionの修正

続いて、DIコンテナがラッパークラスからインスタンスを生成するようにHelloExtensionのサービス定義を修正します。

php:
  1. /**
  2.      * Loads the Hello Bundle configuration.
  3.      *
  4.      * @param array            $config    An array of configuration settings
  5.      * @param ContainerBuilder $container A ContainerBuilder instance
  6.      */
  7.     public function configLoad($config, ContainerBuilder $container)
  8.     {
  9.         $def = new Definition('Application\\HelloBundle\\Util\\PEARClassLoader');
  10.         $def->setFile(__DIR__.'/../Util/PEARClassLoader.php');
  11.         $container->setDefinition('pear.classloader', $def);
  12.  
  13.         $def = new Definition('Net_UserAgent_Mobile');
  14.         $def->setFactoryService('pear.classloader');
  15.         $def->setFactoryMethod('factoryNet_UserAgent_Mobile');
  16.         $container->setDefinition('net.useragent.mobile', $def);
  17.     }

新たにラッパークラスのサービス定義を追加しています。またNet_UserAgent_Mobileクラスのサービス定義は、ラッパークラスのfactoryNet_UserAgent_Mobile()メソッドからインスタンスを作成するように変更しています。

ちなみに、どうやってこれらのメソッドを見つけ出したかというと、DIコンテナのphpファイルを吐き出すPhpDumperクラスとDefinitionクラスと交互に見て、どのように定義すればどのようにDIコンテナが吐き出されるのかを追って見つけ出しました。

再びWebからアクセスしてみる

これで動くはずです。Webからアクセスしてみましょう。私の場合は以下のようなURLです。

http://sandbox-pr4.localweb02/app_dev.php/hello/uechoco

※uechocoの部分は、好きな英数字に置き換えても構いません。

PCから見ると「non mobile」と表示されます

FirefoxでFireMobileSimulatorでP903iをシミュレートすると「mobie」と表示されます

おまけ:自動生成されたDIコンテナのサービス定義を見る

一応インスタンス生成部分のコードを再確認しておきましょう。

// /app/cache/dev/appDevDebugProjectContainer.php

php:
  1. /**
  2.      * Gets the 'pear.classloader' service.
  3.      *
  4.      * This service is shared.
  5.      * This method always returns the same instance of the service.
  6.      *
  7.      * @return Application\HelloBundle\Util\PEARClassLoader A Application\HelloBundle\Util\PEARClassLoader instance.
  8.      */
  9.     protected function getPear_ClassloaderService()
  10.     {
  11.         require_once '/mnt/hgfs/localweb02/sandbox-pr4/src/Application/HelloBundle/DependencyInjection/../Util/PEARClassLoader.php';
  12.  
  13.         return $this->services['pear.classloader'] = new \Application\HelloBundle\Util\PEARClassLoader();
  14.     }
  15.  
  16.     /**
  17.      * Gets the 'net.useragent.mobile' service.
  18.      *
  19.      * This service is shared.
  20.      * This method always returns the same instance of the service.
  21.      *
  22.      * @return Net_UserAgent_Mobile A Net_UserAgent_Mobile instance.
  23.      */
  24.     protected function getNet_Useragent_MobileService()
  25.     {
  26.         return $this->services['net.useragent.mobile'] = $this->get('pear.classloader')->factoryNet_UserAgent_Mobile();
  27.     }

ラッパークラスのインスタンス生成部分と、そのインスタンスを用いてfactoryNet_UserAgent_Mobile()メソッドを呼び出す部分がちゃんと動いていそうです。

まとめ

こんな感じでSymfony2でもPEARライブラリを使うことができそうです。使用するPEARライブラリが増えても、ある程度まではPEARClassLoaderのメソッドを増やして対応していくことで対応できそうです。

今回は既存のBundleに組み込む形で対応しました。PEARライブラリごとにBundleを作れば楽なんじゃないかという思いもあったのですが、それだとset_include_path()に登録するディレクトリが増えてしまいますので、PEARBundleとかでまとめてしまったほうが賢いかも知れません。

また繰り返しになりますが、私自身のSymfony2歴が浅いので、こんな方法もあるんだよというくらいで捉えてもらえると助かります。

次のアドベントカレンダーの記事は再びchobi_eさんの予定です。よろしくお願いします!

Symfony Advent 2010であなたの記事を公開してみませんか?

Symfony Advent 2010では12月1日から12月24日までを使って日替わりでsymfonyでイイなと思った小さなtipsから内部構造まで迫った解説などをブログ記事にし て公開していくイベントです。参加についてはATNDで参加表明の上、Google GroupのSymfony Advent 2010に追加リクエストを送信ください。Symfony Advent 2010チーム一同、あなたの参加をお待ちしております。

日本Symfonyユーザー会
Symfonyアドベントカレンダー 2010

※Syfony Advent 2010はsymfony好きな有志で集まったチームです。


[php][pear]HTTP_Request2のサンプル#5

Posted under php by uechoco on 水曜日 21 1月 2009 at 23 : 43 : 36

この記事は、HTTP_Requestのマニュアルに載っている全サンプルコードをHTTP_Request2対応で書き換えてみる企画の最終回(5回目)です。HTTP_Request2クラスの概要を知りたい方は、下記リンクの#1を参照ください。

全記事へのリンク:

#13 ダウンロード進捗バー(コマンドラインのみ)

php:
  1. <?php
  2. /**
  3.  * 例 48-13 ダウンロード進捗バー(コマンドラインのみ)
  4.  *
  5.  * @link http://pear.php.net/manual/ja/package.http.http-request.listeners.php
  6.  * @see  http://www.php.net/~helly/php/ext/spl/interfaceSplObserver.html
  7.  */
  8. require_once 'HTTP/Request2.php';
  9. require_once 'Console/ProgressBar.php';
  10.  
  11.  
  12. class HTTP_Request2_Observer_Progress implements SplObserver
  13. {
  14.     /**
  15.      * 対象となるファイルのハンドル
  16.      * @var int
  17.      */
  18.     protected $fp;
  19.  
  20.     /**
  21.      * インジケータの表示に使用する Console_ProgressBar のインスタンス
  22.      * @var Console_ProgressBar
  23.      */
  24.     protected $bar;
  25.  
  26.     /**
  27.      * 対象となるファイルの名前
  28.      * @var string
  29.      */
  30.     protected $target = "filename";
  31.  
  32.     /**
  33.      * 受信したファイルのバイト数
  34.      * @var int
  35.      */
  36.     protected $size;
  37.  
  38.     /**
  39.      * 対象となるファイルをオープンする
  40.      * @param string ファイル名
  41.      * @throws HTTP_Request2_Exception
  42.      */
  43.     function setTarget($target)
  44.     {
  45.         $this->target = $target;
  46.         $this->fp = @fopen($target, 'wb');
  47.         if (!$this->fp) {
  48.             throw new HTTP_Request2_Exception("'{$target}' をオープンできません");
  49.         }
  50.     }
  51.  
  52.     /**
  53.      * HTTP_Request2から呼ばれる (例えば、値が変わった時)
  54.      *
  55.      * @param SplSubject $subject
  56.      */
  57.     public function update(SplSubject $subject)
  58.     {
  59.         $event = $subject->getLastEvent();
  60.  
  61.         switch ($event['name']) {
  62.             case 'connect':
  63.                 $this->target = basename($subject->getUrl()->getPath());
  64.                 break;
  65.             case 'receivedHeaders':
  66.                 $headers = $event['data']->getHeader();
  67.                 if (isset($headers['content-disposition']) &&
  68.                     preg_match('/filename="([^"]+)"/', $headers['content-disposition'], $matches)) {
  69.                     $this->setTarget(basename($matches[1]));
  70.                 } else {
  71.                     $this->setTarget($this->target);
  72.                 }
  73.                 $this->bar = new Console_ProgressBar(
  74.                     '* ' . $this->target . ' %fraction% KB [%bar%] %percent%', '=>', '-',
  75.                     79, (isset($headers['content-length'])? round($headers['content-length'] / 1024): 100)
  76.                 );
  77.                 $this->size = 0;
  78.                 break;
  79.             case 'receivedEncodedBodyPart':
  80.             case 'receivedBodyPart':
  81.                 $this->size += strlen($event['data']);
  82.                 $this->bar->update(round($this->size / 1024));
  83.                 fwrite($this->fp, $event['data']);
  84.                 break;
  85.             case 'receivedBody':
  86.                 fclose($this->fp);
  87.                 break;
  88.         }
  89.     }
  90. }
  91.  
  92. try {
  93.     $req = new HTTP_Request2("http://pear.php.net/get/HTML_QuickForm-stable");
  94.  
  95.     $observer = new HTTP_Request2_Observer_Progress();
  96.     $req->attach($observer);
  97.  
  98.     $response = $req->send();
  99.  
  100. } catch (HTTP_Request2_Exception $e) {
  101.     die($e->getMessage());
  102. } catch (Exception $e) {
  103.     die($e->getMessage());
  104. }
  105.  
  106. /*****************************
  107.  * HTTP_Request_Listenerクラスを派生する代わりにSplObserverインターフェースを実装します。
  108.  *
  109.  * このとき、update(SplSubject $subject)メソッドを実装する必要があります。
  110.  * $subjectにはHTTP_Request2が代入されています(HTTP_Request2はSplSubjectの実装クラス)。
  111.  *
  112.  * たいていの場合、HTTP_Request2::getLastEvent()メソッドを呼び出して、イベントを取得します。
  113.  * 使用するアダプタによってはイベントを発生させないことがあります。
  114.  * 例えば、Mockアダプタはイベント発生させません。
  115.  *
  116.  * getLastEvent()メソッドの返り値はarray('name' => string, 'data' => mixed)の配列です。
  117.  * イベントは以下の8種類が用意されています。
  118.  *  - connect
  119.  *  - sentHeaders
  120.  *  - sentBodyPart
  121.  *  - receivedHeaders
  122.  *  - receivedBodyPart
  123.  *  - receivedEncodedBodyPart
  124.  *  - receivedBody
  125.  *  - disconnect
  126.  * イベントの種類によって、データの種類は異なります。
  127.  *****************************/
  128.  
  129. /*
  130.  
  131. // HTTP_Request でのリスナーの使用例です。これは、ファイルの
  132. // ダウンロードと保存を行うと同時に、処理の進捗状況をバーで表示します
  133. //
  134. // 注意すべき点は以下のとおりです
  135. // 1) ブラウザでなく、コンソールから実行しないといけません
  136. // 2) 出力バッファリングを OFF にしないと正常に動作しません
  137.  
  138. require_once 'HTTP/Request.php';
  139. require_once 'HTTP/Request/Listener.php';
  140. require_once 'Console/ProgressBar.php';
  141.  
  142. PEAR::setErrorHandling(PEAR_ERROR_DIE);
  143.  
  144. set_time_limit(0);
  145.  
  146. class HTTP_Request_DownloadListener extends HTTP_Request_Listener
  147. {
  148.     // 対象となるファイルのハンドル
  149.     // @var int
  150.     var $_fp;
  151.  
  152.     // インジケータの表示に使用する Console_ProgressBar のインスタンス
  153.     // @var object
  154.     var $_bar;
  155.  
  156.     // 対象となるファイルの名前
  157.     // @var string
  158.     var $_target;
  159.  
  160.     // 受信したファイルのバイト数
  161.     // @var int
  162.     var $_size = 0;
  163.  
  164.     function HTTP_Request_DownloadListener()
  165.     {
  166.         $this->HTTP_Request_Listener();
  167.     }
  168.  
  169.     // 対象となるファイルをオープンする
  170.     // @param string ファイル名
  171.     // @throws PEAR_Error
  172.     function setTarget($target)
  173.     {
  174.         $this->_target = $target;
  175.         $this->_fp = @fopen($target, 'wb');
  176.         if (!$this->_fp) {
  177.             PEAR::raiseError("'{$target}' をオープンできません");
  178.         }
  179.     }
  180.  
  181.     function update(&$subject, $event, $data = null)
  182.     {
  183.         switch ($event) {
  184.             case 'sentRequest':
  185.                 $this->_target = basename($subject->_url->path);
  186.                 break;
  187.  
  188.             case 'gotHeaders':
  189.                 if (isset($data['content-disposition']) &&
  190.                     preg_match('/filename="([^"]+)"/', $data['content-disposition'], $matches)) {
  191.  
  192.                     $this->setTarget(basename($matches[1]));
  193.                 } else {
  194.                     $this->setTarget($this->_target);
  195.                 }
  196.                 $this->_bar =& new Console_ProgressBar(
  197.                     '* ' . $this->_target . ' %fraction% KB [%bar%] %percent%', '=>', '-',
  198.                     79, (isset($data['content-length'])? round($data['content-length'] / 1024): 100)
  199.                 );
  200.                 $this->_size = 0;
  201.                 break;
  202.  
  203.             case 'tick':
  204.                 $this->_size += strlen($data);
  205.                 $this->_bar->update(round($this->_size / 1024));
  206.                 fwrite($this->_fp, $data);
  207.                 break;
  208.  
  209.             case 'gotBody':
  210.                 fclose($this->_fp);
  211.                 break;
  212.  
  213.             default:
  214.                 PEAR::raiseError("イベント '{$event}' が処理できません");
  215.         } // switch
  216.     }
  217. }
  218.  
  219. // 別のパッケージを使用してもかまいませんが、できるだけ大き目のものを
  220. // 選ばないと進捗バーが見えません
  221. $url = 'http://pear.php.net/get/HTML_QuickForm-stable';
  222.  
  223. $req =& new HTTP_Request($url);
  224.  
  225. $download =& new HTTP_Request_DownloadListener();
  226. $req->attach($download);
  227. $req->sendRequest(false);
  228. */
  229. ?>

最後のサンプルになりましたが、昔のHTTP_Request_Listenerに当たるSplObserver派生クラスのサンプルとなりました。HTTP_Request2のパッケージにはHTTP_Request2_Observer_Logが同梱されているので、そちらを参考にすると、SplObserver派生クラスについての理解が深められます。

全サンプルコードを載せましたが、0.2.0(alpha)の時点でだいたいの機能はそろっている気がしますね。


[php][pear]HTTP_Request2のサンプル#4

Posted under php by uechoco on 水曜日 21 1月 2009 at 23 : 37 : 03

この記事は、HTTP_Requestのマニュアルに載っている全サンプルコードをHTTP_Request2対応で書き換えてみる企画の4回目です。HTTP_Request2クラスの概要を知りたい方は、下記リンクの#1を参照ください。

全記事へのリンク:

#10 レスポンスコードをチェックする

php:
  1. <?php
  2. /**
  3.  * 例 48-10 レスポンスコードをチェックする
  4.  *
  5.  * @link http://pear.php.net/manual/ja/package.http.http-request.response-eval.php
  6.  */
  7. require_once 'HTTP/Request2.php';
  8.  
  9. $urls = array(
  10.     "http://www.example.com/",
  11.     "http://example.com/thisdoesnotexist.html"
  12.     );
  13.  
  14. try {
  15.     $req = new HTTP_Request2();
  16.     foreach ($urls as $url) {
  17.         $req->setUrl($url);
  18.         $response = $req->send();
  19.  
  20.         $code = $response->getStatus();
  21.         switch ($code) {
  22.             case 404:
  23.                 echo "Document not foundn";
  24.                 break;
  25.  
  26.             case 200:
  27.                 echo "Everything's okn";
  28.                 break;
  29.         }
  30.     }
  31.  
  32. } catch (HTTP_Request2_Exception $e) {
  33.     die($e->getMessage());
  34. } catch (Exception $e) {
  35.     die($e->getMessage());
  36. }
  37.  
  38. /*****************************
  39.  * HTTP_Request::getResponseCode()はHTTP_Request2_Response::getStatus()に変更されました。
  40.  *****************************/
  41.  
  42. /*
  43. require_once "HTTP/Request.php";
  44.  
  45. $urls = array(
  46.     "http://www.example.com/",
  47.     "http://example.com/thisdoesnotexist.html"
  48.     );
  49.  
  50. $req =& new HTTP_Request("");
  51. foreach ($urls as $url) {
  52.     $req->setURL($url);
  53.     $req->sendRequest();
  54.  
  55.     $code = $req->getResponseCode();
  56.     switch ($code) {
  57.     case 404:
  58.         echo "Document not foundn";
  59.         break;
  60.  
  61.     case 200:
  62.         echo "Everything's okn";
  63.         break;
  64.  
  65.     }
  66. }
  67.  
  68. */
  69. ?>

#11 レスポンスからの全てのヘッダを取得する

php:
  1. <?php
  2. /**
  3.  * 例 48-11 レスポンスからの全てのヘッダを取得する
  4.  *
  5.  * @link http://pear.php.net/manual/ja/package.http.http-request.response-eval.php
  6.  */
  7. require_once 'HTTP/Request2.php';
  8.  
  9. try {
  10.     $req = new HTTP_Request2("http://example.com/");
  11.     $response = $req->send();
  12.     foreach ($response->getHeader() as $name => $value) {
  13.         echo $name . " = " . $value . "n";
  14.     }
  15.  
  16. } catch (HTTP_Request2_Exception $e) {
  17.     die($e->getMessage());
  18. } catch (Exception $e) {
  19.     die($e->getMessage());
  20. }
  21.  
  22. /*****************************
  23.  * HTTP_Request::getResponseHeader()はHTTP_Request2_Response::getHeader()に変更されました。
  24.  *****************************/
  25.  
  26. /*
  27. require_once "HTTP/Request.php";
  28.  
  29. $req =& new HTTP_Request("http://example.com/");
  30. $req->sendRequest();
  31.  
  32. foreach ($req->getResponseHeader() as $name => $value) {
  33.     echo $name . " = " . $value . "n";
  34. }
  35.  
  36. */
  37. ?>

#12 特定のヘッダを取得する

php:
  1. <?php
  2. /**
  3.  * 例 48-12 特定のヘッダを取得する
  4.  *
  5.  * @link http://pear.php.net/manual/ja/package.http.http-request.response-eval.php
  6.  */
  7. require_once 'HTTP/Request2.php';
  8.  
  9. try {
  10.     $req = new HTTP_Request2("http://example.com/");
  11.     $response = $req->send();
  12.     echo $response->getHeader('Date');
  13.  
  14. } catch (HTTP_Request2_Exception $e) {
  15.     die($e->getMessage());
  16. } catch (Exception $e) {
  17.     die($e->getMessage());
  18. }
  19.  
  20. /*****************************
  21.  * HTTP_Request::getResponseHeader()はHTTP_Request2_Response::getHeader()に変更されました。
  22.  *****************************/
  23.  
  24. /*
  25. require_once "HTTP/Request.php";
  26.  
  27. $req =& new HTTP_Request("http://example.com/");
  28. $req->sendRequest();
  29.  
  30. echo $req->getResponseHeader("Date");
  31.  
  32.  
  33. */
  34. ?>


[php][pear]HTTP_Request2のサンプル#3

Posted under php by uechoco on 水曜日 21 1月 2009 at 23 : 34 : 32

この記事は、HTTP_Requestのマニュアルに載っている全サンプルコードをHTTP_Request2対応で書き換えてみる企画の3回目です。HTTP_Request2クラスの概要を知りたい方は、下記リンクの#1を参照ください。

全記事へのリンク:

#6 PDF 文章をアップロードする

php:
  1. <?php
  2. /**
  3.  * 例 48-6 PDF 文章をアップロードする
  4.  *
  5.  * この例では、/home/johndoe/text.pdf というファイルが
  6.  * リモートにあるマシン upload.example.com に johndoe-text.pdf という名前で
  7.  * アップロードされます。 さらに、ジョンが何かをアップロードする事を許可されていることを
  8.  * 保証するために、Basic 認証が使用されています。
  9.  *
  10.  * @link http://pear.php.net/manual/ja/package.http.http-request.file-upload.php
  11.  */
  12. require_once 'HTTP/Request2.php';
  13.  
  14. try {
  15.     $req = new HTTP_Request2("http://upload.example.com/upload.php", HTTP_Request2::METHOD_POST);
  16.     $req->setAuth("johndoe", "foo", HTTP_Request2::AUTH_BASIC);
  17.     $req->addUpload("johndoe-txt.pdf", "/home/johndoe/text.pdf");
  18.     $response = $req->send();
  19.     echo $response->getBody();
  20. } catch (HTTP_Request2_Exception $e) {
  21.     die($e->getMessage());
  22. } catch (Exception $e) {
  23.     die($e->getMessage());
  24. }
  25.  
  26. /*****************************
  27.  * HTTP_Request::addFile()はHTTP_Request2->addUpload()に変更されました。
  28.  *****************************/
  29.  
  30. /*
  31. require_once "HTTP/Request.php";
  32.  
  33. $req =& new HTTP_Request("http://upload.example.com/upload.php");
  34. $req->setBasicAuth("johndoe", "foo");
  35. $req->setMethod(HTTP_REQUEST_METHOD_POST);
  36.  
  37. $result = $req->addFile("johndoe-txt.pdf", "/home/johndoe/text.pdf");
  38. if (PEAR::isError($result)) {
  39.     echo $result->getMessage();
  40. } else {
  41.  
  42.     $response = $req->sendRequest();
  43.  
  44.     if (PEAR::isError($response)) {
  45.         echo $response->getMessage();
  46.     } else {
  47.         echo $req->getResponseBody();
  48.     }
  49. }
  50. */
  51. ?>

#7 カスタムリクエストヘッダの追加

php:
  1. <?php
  2. /**
  3.  * 例 48-7 カスタムリクエストヘッダの追加
  4.  *
  5.  * 以下の例では、HTTP ヘッダ X-PHP-Version が HTTP リクエストに追加されます。
  6.  * このヘッダの値は、 HTTP_Request  インスタンスが動作している PHP インタプリタのバージョン文字列です。
  7.  *
  8.  * @link http://pear.php.net/manual/ja/package.http.http-request.headers.php
  9.  */
  10. require_once 'HTTP/Request2.php';
  11.  
  12. try {
  13.     $req = new HTTP_Request2("http://example.com/");
  14.     $req->setHeader("X-PHP-Version", phpversion());
  15.  
  16.     $response = $req->send();
  17.     echo $response->getBody();
  18.  
  19. } catch (HTTP_Request2_Exception $e) {
  20.     die($e->getMessage());
  21. } catch (Exception $e) {
  22.     die($e->getMessage());
  23. }
  24.  
  25. /*****************************
  26.  * HTTP_Request::addHeader()はHTTP_Request2->setHeader()に変更されました。
  27.  * 配列での一括指定や"header:value"形式の文字列でも受け付けるようになりました。
  28.  *****************************/
  29.  
  30. /*
  31. require_once "HTTP/Request.php";
  32.  
  33. $req =& new HTTP_Request("http://example.com/");
  34. $req->addHeader("X-PHP-Version", phpversion());
  35.  
  36. $response = $req->sendRequest();
  37.  
  38. if (PEAR::isError($response)) {
  39.     echo $response->getMessage();
  40. } else {
  41.     echo $req->getResponseBody();
  42. }
  43.  
  44. */
  45. ?>

#8 匿名アクセスでプロキシサーバを利用する

php:
  1. <?php
  2. /**
  3.  * 例 48-8 匿名アクセスでプロキシサーバを利用する
  4.  *
  5.  *  この例では、プロキシサーバがポート 8080  で待機しており、
  6.  * example.com への外向き接続の代理(プロキシ)を行っている
  7.  * proxy.example.com というホスト名のマシンを 利用しようとしている、と想定しています。
  8.  *
  9.  * setProxy() の二番目のパラメータはオプションで、 デフォルトは 8080 です。
  10.  *
  11.  * @link http://pear.php.net/manual/ja/package.http.http-request.proxy-auth.php
  12.  */
  13. require_once 'HTTP/Request2.php';
  14.  
  15. try {
  16.     $req = new HTTP_Request2("http://example.com/");
  17.     $req->setConfig(array(
  18.         'proxy_host' => 'proxy.example.com',
  19.         'proxy_port' => '8080',
  20.     ));
  21.     // $req->setConfig('proxy_host', 'proxy.example.com');
  22.     // $req->setConfig('proxy_port', '8080');
  23.  
  24.     $response = $req->send();
  25.     echo $response->getBody();
  26.  
  27. } catch (HTTP_Request2_Exception $e) {
  28.     die($e->getMessage());
  29. } catch (Exception $e) {
  30.     die($e->getMessage());
  31. }
  32.  
  33. /*****************************
  34.  * HTTP_Request::setProxy()に対応するメソッドはありません。
  35.  * 代わりにHTTP_Request2::setConfig()メソッドで1つ1つ設定するか、配列でまとめて設定します。
  36.  *****************************/
  37.  
  38. /*
  39. require_once "HTTP/Request.php";
  40.  
  41. $req =& new HTTP_Request("http://example.com/");
  42. $req->setProxy("proxy.example.com", 8080);
  43. */
  44. ?>

#9 プロキシ認証の利用

php:
  1. <?php
  2. /**
  3.  * 例 48-9 プロキシ認証の利用
  4.  *
  5.  * これは、プロキシサーバでのユーザー認証のためのユーザー名/パスワードの
  6.  * タプルが提供されていることを除いて、上記と同じ例です:
  7.  * ユーザー名は johndoe で付随するパスワードは foo です。
  8.  *
  9.  * @link http://pear.php.net/manual/ja/package.http.http-request.proxy-auth.php
  10.  */
  11. require_once 'HTTP/Request2.php';
  12.  
  13. try {
  14.     $req = new HTTP_Request2("http://example.com/");
  15.     $req->setConfig(array(
  16.         'proxy_host' => 'proxy.example.com',
  17.         'proxy_port' => '8080',
  18.         'proxy_user' => 'johndoe',
  19.         'proxy_password' => 'foo',
  20.     ));
  21.     // $req->setConfig('proxy_host', 'proxy.example.com');
  22.     // $req->setConfig('proxy_port', '8080');
  23.     // $req->setConfig('proxy_user', 'johndoe');
  24.     // $req->setConfig('proxy_password', 'foo');
  25.  
  26.     $response = $req->send();
  27.     echo $response->getBody();
  28.  
  29. } catch (HTTP_Request2_Exception $e) {
  30.     die($e->getMessage());
  31. } catch (Exception $e) {
  32.     die($e->getMessage());
  33. }
  34.  
  35. /*****************************
  36.  * HTTP_Request::setProxy()に対応するメソッドはありません。
  37.  * 代わりにHTTP_Request2::setConfig()メソッドで1つ1つ設定するか、配列でまとめて設定します。
  38.  *****************************/
  39.  
  40. /*
  41. require_once "HTTP/Request.php";
  42.  
  43. $req =& new HTTP_Request("http://example.com/");
  44. $req->setProxy("proxy.example.com", 8080, "johndoe", "foo");
  45.  
  46. */
  47. ?>


次ページへ »

Copyright © 2012 うえちょこ@ぼろぐ. WP Theme created by Web Top.