Techracho

IXRライブラリの使い方

このエントリーをはてなブックマーク Share
2010.06.09    CakePHP, PHP, 馬場   タグ: —    baba   

PHPでXML-RPCサーバを作るには、IXRのライブラリが簡単です。

PEAR::XML_RPC2も良いですが、こっちの方がCakePHPで使うには良さそうですね。

以下のページで、CakePHPでの使い方もまとまっています。
http://bakery.cakephp.org/articles/view/how-to-create-an-xml-rpc-server-with-cakephp

基本的に、インデックスアクションでレシーバを登録するだけで、後は各アクションでPHPのオブジェクトをreturnできます。

あまりに簡単すぎて、基本的なことを調べるのがめんどくさくなります。

たとえば、base64やdateTimeで囲んだ値を返したいときはどうしたら良いでしょうか?

このようにやればOKです。

function _hogeAction($data) {
  return new IXR_Base64($bytedata);
}
function _piyoAction($data) {
  return new IXR_Date(time());
}

Base64は、内部でbase64_encodeが呼ばれるので、バイトデータを直接渡すようにします。
dateは、タイムスタンプ値かISO形式を渡します。

dateのパースは、あまり柔軟性は無いので気をつけてください。

function parseIso($iso) {
    $this->year = substr($iso, 0, 4);
    $this->month = substr($iso, 4, 2);
    $this->day = substr($iso, 6, 2);
    $this->hour = substr($iso, 9, 2);
    $this->minute = substr($iso, 12, 2);
    $this->second = substr($iso, 15, 2);
}

WordPress XML-RPCライブラリ

このエントリーをはてなブックマーク Share
2010.06.03    PHP, 馬場   タグ: , —    baba   

WordPressはXML-RPC対応で、地味に色々な対応プログラムが出ていますね。

XML-RPCのライブラリを使ってAPIをたたけば、たいていの操作はできますが、
お手軽に使うならライブラリを使いたいです。

PHPのライブラリでは、↓のものがシンプルにまとまっていて使いやすかったです。
http://sourceforge.jp/projects/wpapiclient1/

ただし、WordPress 2.9.2 + PHP5.3 で試したところ、
日付がおかしくなる(1999年11月になってしまう)問題が発生したため、以下のように修正しました。

wordpress/core/Util.class.php
static function createDateTime($timestamp)
{
    $timestamp = date('Ym\TH:i:s', $timestamp); //'c' を 'Ymd\TH:i:s' に置換する
    xmlrpc_set_type($timestamp, 'datetime');
    return $timestamp;
}

date()の結果の違いが原因です。

‘c’ → 20100510T10:00:00+09:00
‘Ymd\TH:i:s’ → 20100510T10:00:00

このように、「c」だとタイムゾーンを表す値が入ってしまいます。
date関数

しかし、XML-RPC で dateTime.iso8601 形式を使う場合、タイムゾーンの指定はできない仕様のため、不正な日時と見なされてしまうようです。
Ymd\TH:i:s のように手動で指定することで、正しいフォーマットに指定できますね。

XMLRPCでhttps

このエントリーをはてなブックマーク Share
2009.07.30    PHP, 馬場   タグ: , —    baba   

XML-RPCで、サーバ側にhttpsを使用する場合、クライアント側でcURLがSSLを認証できないとエラーになることがあります。
これは、cURLにSSLの証明書が入っていないのが原因です。

(Curl returned non-null errno 60:SSL certificate problem, verify that the CA cert is OK.
Details:error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed)

そこで、証明書のチェックを無効化します。
生PHPでcurlをたたく場合、以下のようにします。

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

PEAR::XML_RPC2を使う場合、以下のように、’sslverify’をfalseに指定します。

$options = array('debug' => false, 'sslverify' => false);
$url = "http://example.com/xmlrpc.php";
$this->client = XML_RPC2_Client::create($api, $options);

EthnaでXML-RPCの引数を連想配列にする

このエントリーをはてなブックマーク Share
2009.03.04    PHP, Web, ネットワーク, 馬場   タグ: , —    baba   

Ethnaは標準でXML-RPCに対応しているので、
# ethna add-action-xmlrpc hoge
とやるだけで app/action-xmlrpc にActionのテンプレートが作れますし、クライアントからHogeメソッドをコールすると、自動的にHogeアクションが実行されます。
(エントリポイントはindex.phpではなくxmlrpc.phpになります)

しかし、デフォルトでは引数がActionFormのform定義と順番に1対1で対応するため、引数が多くなると使いづらくなります。

ここは、PHPらしく引数名をキーにした連想配列にしたいところ。
(プロジェクト名)_Controller に以下のメソッドを定義(オーバーライド)することで、XMLRPCの第一引数を連想配列として扱い、対応する名前のformに値がセットされるようになります。

function trigger_XMLRPC($method, $param)
{
    // アクション定義の取得
    $action_obj =& $this->_getAction($method);
    if (is_null($action_obj)) {
        return Ethna::raiseError("undefined xmlrpc method [%s]", E_APP_UNDEFINED_ACTION, $method);
    }

    // オブジェクト生成
    $backend =& $this->getBackend();

    $form_name = $this->getActionFormName($method);
    $this->action_form =& new $form_name($this);
    $def = $this->action_form->getDef();
    
    /***** ここから変更 *****/
    if (isset($param[0]) && is_array($param[0]))
    {
        foreach ($param[0] as $key => $value)
        {
            if (isset($def[$key]))
            {
                $this->action_form->set($key, $value);
            }
        }
    }
    /***** ここまで変更 *****/

    // バックエンド処理実行
    $backend->setActionForm($this->action_form);

    $session =& $this->getSession();
    $session->restore();
    $r = $backend->perform($method);

    return $r;
}

これで、クライアント側では引数の順番を気にせずに済みます。

XML-RPC

このエントリーをはてなブックマーク Share
2009.02.27    Linux, PHP, Web, 馬場   タグ: , , —    baba   

PHPでXML-RPCを使った記録です。
PEAR::XML_RPC2を使うことにしました。PHP5専用で使いやすそうです。

  • PHP5以上
  • cURLのエクステンション

が必須です。

クライアント側では、

require_once './XML/RPC2/Client.php';
$options = array('debug' => true);
$client = XML_RPC2_Client::create('http://www.bpsinc.jp/xmlrpc.php', $options); //URLはダミー
try {
    $result = $client->Version(); //関数名はサーバ側で定義したもの
    print_r($result);
} catch (XML_RPC2_FaultException $e) {
    var_dump($e);
} catch (Exception $e) {
    var_dump($e);
}

のように使えます。

しかし、これだとなぜか結果が全部NULLになることがあります。
debugメッセージを見ると、Server Responseは正常なのに、Decoded ResultがNULLになっているように見えます。

この問題、Server側かHttpRequestの実装の問題だと思うのですが、Server ResponseのBodyの最初に改行が入っているのが原因でした。
"\n<?xml version="1.0"?><methodResponse> …"

PEAR/XML/RPC2/Backend/Xmlrpcext/Client.php の112行目付近で、
$result = xmlrpc_decode($body, $this->encoding);
となっているところを、
$result = xmlrpc_decode(trim($body), $this->encoding);
とすれば直ります。(マルチバイト対応のtrimを書いた方が良いかもしれません)
※XMLRPCEXT拡張モジュールが入っていない場合は、PEAR/XML/RPC2/Backend/PHP/Client.phpになります。

ライブラリを書き換えるのは強引ですが、xmlrpc_decode関数自体がEXPERIMENTALのままですし、あとはHttpRequestやサーバ側を変更しなければ行けないので、スマートな解決方法は思いつきません。
とりあえずresultがnullになる問題は回避できました。

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.