PEAR::SOAP

まるごとPHP vol.1」で紹介されていたPEARSOAPライブラリ。自分はNuSOAPを使ってきて、PEARのものは知らなかった。中を見てみるとNuSOAPをPEARに持ってきたもののようでOriginal AuthorはNuSOAPの人になっている。ただ、NuSOAPの方はNuSOAPとして開発は継続されている。逆にPEAR::SOAPの最新版が0.8RC3=>2004-01月で、NuSOAP 0.6.7=>2004-05の方が新しく活動が活発な印象を受ける。
試しに使ってみると

  • クライアントがPEAR::SOAP→サーバがNuSOAP→OK(当たり前?)
  • クライアントがPEAR::SOAP→サーバがAxis→OK(NuSOAPでもつながっていたし)
  • NuSOAPでは復帰値は連想配列だったが、PEAR::SOAPではstdClassのObjectになっているようだった。といってもその中は連想配列だからあまり変わらないみたいだ。
  • 添付ファイルでMIMEDIMEにも対応しているようだ。
  • エンコーディングは実質UTF-8のみ。NuSOAPの場合にはShift_JISも指定しようと思えばできた(ただレスポンス中の日本語は化けた)。UTF-8を使っていれば日本語もOKのようだ。
  • デバッグ用にHTTPのトレースを出力したい場合にはオプションに「'trace' => 1」を指定してから、「$soapclient->__get_wire()」で参照する。
require_once("SOAP/Client.php");

$soapclient = new SOAP_Client('myservice.wsdl');

// 必要なら文字コードをUTF-8にしておく。
$text = mb_convert_encoding($text, 'UTF-8', 'Shift_JIS');

$parameters = array(
    'param1' => "value1",
    'param2' => "value2",
    'param3' => $text,
);

$options = array(
    'namespace' => 'urn:myservice_namespace',
    'trace' => 1,
);

$ret = $soapclient->call("method_name", $parameters, $options);

if (PEAR::isError($ret))
{
    print("Error: " . $ret->getMessage() . "<br>\n");
    print $soapclient->__get_wire();echo "<br>\n";
}
else
{
    print("Success: ");
    var_dump($ret);
    print("<br>\n");
}

PEAR::SOAP サーバ側

PEAR::SOAPSOAPサービスを作成するのはNuSOAPよりちょっとだけ手間がかかる。

  • classを作成する。そのクラスでは提供したいメソッドのほかに__dispatch()という名前のメソッドを実装する。といってもサンプルにあるようにパラメタでメソッド名が渡ってくるので、同じ名前のメソッドを呼ぶようにしておけばほとんどの場合問題ないと思う。
  • HTTP GETで来たらDISCOやWSDLを返却するようにできる。これもサンプルの通りに書いておけばOKみたい。
  • NuSOAPで復帰値を連想配列で返却していた場合、SOAP_Valueクラスの配列に修正する必要があるようだ。
  • 後はexample/server.phpを参照

このあたりがちょっと面倒なので、標準のものを拡張するだけで、後は自分が提供したいメソッドだけ書けばいいようにできると便利なのにと感じた。(そういう風に自分で作ればいいんだけど)

それでclassを作成するのが面倒な場合にはexample/server2.phpにあるように自分でハンドラを書いてしまえばいいようだ。

require_once('SOAP/Server.php');

/**
 * 自分の提供するサービス
 */
function myService($param1, $param2, $param3)
{
    $result = array(
        new SOAP_Value('resutl1', 'string', 'foo'),
        new SOAP_Value('result2', 'string', 'bar'),
        new SOAP_Value('result3', 'string', 'baz'),
    );
    
    return $result;
}

/**
 * 来たメソッド名をそのまま呼び出す。
 */
function myCallHandler($methodname, $args)
{
    return @call_user_func_array($methodname, $args);
}

$server = new SOAP_Server;
$server->setCallHandler('myCallHandler', false);

if (isset($_SERVER['REQUEST_METHOD']) &&
    $_SERVER['REQUEST_METHOD']=='POST') {
    $server->service($HTTP_RAW_POST_DATA);
} else {
    require_once 'SOAP/Disco.php';
    $disco = new SOAP_DISCO_Server($server,'ServerExample');
    header("Content-type: text/xml");
    if (isset($_SERVER['QUERY_STRING']) &&
       strcasecmp($_SERVER['QUERY_STRING'],'wsdl')==0) {
        echo $disco->getWSDL();
    } else {
        echo $disco->getDISCO();
    }
    exit;
}
  • しかし、上記の方法ではWSDLを生成することができない。WSDLのためにはexample/server2.phpにあるようにclassでやる必要があるようだ。(少なくとも、PEAR::SOAPの0.8RC3では)

DISCO

ref. id:drambuie:20040622#p1
WSDLを取得する方法についての規約はまだ分かりませんが、これはWSDL(のようなもの)を取得するためのやり取りが結構具体的に書いてありますね。といっても草案レベルのようです。タイムスタンプも2001年と古いし。google:DISCO SOAPでひっかかった他のWebページも読んでみるとWSDLより前のアイデアらしい。