脳みそスワップアウト

揮発性なもので。おもにPHPのこととか。

Zend_Http_Clientのすすめ

PHPでちょっとしたHTTPリクエストを送る必要がでてきた。
どうせGETだし単純だし file_get_contents() でいいやーと実装。
度重なる改修・機能追加,要件が膨らみ,
なにやら複雑なコードになってしまっていることは少なくない。

file_get_contents() はPHPのお手軽さの象徴のような関数だし,
加えてstream関数を駆使すればけっこうなんでもできてしまうのだけど
どう考えても複雑なことをするのに向いたインタフェイスではない。

そうなる可能性があるのなら初めから3rd partyのライブラリの利用を検討した方がいい。

一昔前はPEAR::HTTP_Requestがよく使われていたけど,PHP4互換コードなのでアレである。
PEAR::HTTP_Request2とやらはひそかにバージョンアップがなされているがどうなのやら。


で,個人的におすすめなのが Zend_Http_Client。
ZendFrameworkに含まれるライブラリだが,
frameworkは使わずともライブラリは単体で利用することができる。



いいところ

  • PHP5(5.2ベース)なので,コードがきれい
  • 設計もきれい
  • PEARと違ってクラス名の衝突が起こりづらい(Zend_のprefixがある)
  • 高機能(redirect追跡,backendはfsockopen/curl両対応,認証対応,Cookie対応...一通り揃っている)
  • 日本語マニュアルもなかなか充実

悪いところ

  • DRYになるようよく設計されているため,依存するZendFrameworkのライブラリが多い。全部を置くことができないなら自分で選別が必要になる。
  • PHP5.2ベースのコードなので,namespaceがなくクラス名が長くなりがち


使い方は,ライブラリ群の親ディレクトリ(Zend)のひとつ上までinclude_pathを通しておいてrequireすればいい。

GETでリクエストして,HTTPステータスを取得,
proxy設定の例をざっくり書いてみた。

$zendBaseDir = dirname(__FILE__) . '/../../ZF/';
$includePath = get_include_path();
$includePath .= PATH_SEPARATOR . $zendBaseDir;
set_include_path($includePath);

require_once 'Zend/Http/Client.php';

$client = factory();

// 正常系
$uri = 'http://localhost/apiMock/http200.php';
$client->setUri($uri);
$objRes = $client->request('GET');
var_dump($objRes->getStatus());


// 500
$uri = 'http://localhost/apiMock/http500.php';
$client->setUri($uri);
$objRes = $client->request('GET');
var_dump($objRes->getStatus());


// timeoutは例外になる
$uri = 'http://localhost/apiMock/slowResponse.php';
$client->setUri($uri);
$client->setParameterGet('time', 5);
try {
    $objRes = $client->request('GET');
} catch(Exception $e) {
    var_dump(get_class($e));
    var_dump($e->getMessage());
}

// 正常系
$client = factory_withProxy();
$uri = 'http://localhost/apiMock/http200.php';
$client->setUri($uri);
try {
    $objRes = $client->request('GET');
} catch(Exception $e) {
    var_dump(get_class($e));
    var_dump($e->getMessage());
}

/**
 * @return Zend_Http_Client
 */
function factory() {
    $client = new Zend_Http_Client();
    $client->setConfig(array(
        'maxredirects' => 0,
        'timeout' => 3)
    );

    return $client;
}

/**
 * proxy設定をする場合
 * @return Zend_Http_Client
 */
function factory_withProxy() {
    $config = array(
        'adapter' => 'Zend_Http_Client_Adapter_Proxy',
        'proxy_host' => 'localhost',
        'proxy_port' => 8888,
        'timeout' => 3,
//         'proxy_user' => 'user',
//         'proxy_pass' => 'pass',
    );

    $client = new Zend_Http_Client();
    $client->setConfig($config);

    return $client;
}


上記のコードで必要になるライブラリ群は以下。
より高度な機能を使う場合はもっと増えるのだろう。

  1. Zend_Http_Client
  2. Zend_Loader
  3. Zend_Uri
  4. Zend_Http_Response
  5. Zend_Http_Response_Stream
  6. Zend_Uri_Http
  7. Zend_Validate_Abstract
  8. Zend_Validate_Ip
  9. Zend_Validate_Hostname
  10. Zend_Registry
  11. Zend_Http_Cient_Adapter_Socket
  12. Zend_Exception
  13. Zend_Http_Client_Exception
  14. Zend_Http_Cient_Adapter_Exception
  15. Zend_Http_Cient_Adapter_Proxy

それにしても私はZendFrameworkのライブラリの設計が好み。
惚れ惚れするドメイン分けだにゃ。