Do You PHP?    
Search Engine Optimization  php5 powerd  Valid XHTML 1.0!  Valid CSS!  このサイトのはてなブックマーク数 



last updated
2005/06/11

counter hits
since 1999/11/06


SOAP extensionでSOAP Server

memoサンプルは、EXPERIENCEで実際に確認できるようにしてますので、気になる方は見てみてください。

以前にPHP4+PEAR SOAP+Google Web APIsでGoogle検索とかPHP5のSOAP extension+Google Web APIsでGoogle検索といったSOAP Clientとしての使い方を確認してきましたが、「Clientと来ればServer」ということ(?)で今度はSOAP Serverを試してみます。PHP5.0.0で導入されてまだ枯れていない(と思われる)extensionですが、2005/06/10にリリースされたPHP5.1.0β1でもかなりの修正がされているようですので今後が楽しみです。

SOAPServerに関してのドキュメントは、やはりPHP日本語マニュアルを参照してください。

今回のサンプルですが、次の4つのサービスを提供するSOAP Serverを作ってみました。

  • add:数値を2つ受け取り、加算した結果を返す
  • addByArray:数値を格納した配列を受け取り、合算した結果を返す
  • hello:文字列を1つ受け取り、メッセージを返す
  • helloByObj:オブジェクトを受け取り、メッセージを返す

どれもありがちな(?)サービスですが、数値・文字列(日本語も含む)などの基本型、配列、オブジェクトを引数とする場合での動作を確認したかったのでサービス内容はかなり単純にしてあります。

さて、このSOAP ServerのPHPコードは以下のようになります。

●SoapServer_test.php
  
<?php
/**
 * SOAPレスポンスをutf-8で返すため
 */
mb_internal_encoding('utf-8');
mb_http_output('utf-8');

/**
 * 提供するサービス(関数の場合)
 */
function add($x, $y)
{
    return (int)$x + (int)$y;
}
function addByArray($vars)
{

    return array_sum($vars);
}
function hello($nm)
{
    return 'こんにちは、' . $nm . ' さん!';
}
function helloByObj($obj)
{
    return 'こんにちは、<a href="' . $obj->url . '">' . $obj->name . '</a> さん!';
}

/**
 * SOAPサーバオブジェクトの作成
 */
$server = new SoapServer(null, array('uri' => 'http://www.doyouphp.jp/xp/soap/'));

/**
 * サービスの追加
 */
$server->addFunction('add');
$server->addFunction('addByArray');
$server->addFunction('hello');
$server->addFunction('helloByObj');

/**
 * サービスを実行
 */
$server->handle();
?>

説明するほどのものでもないですが、「サービス用関数で定義し、それをSoapServerオブジェクトに追加していく」といった手順になります。それぞれのサービスに相当する関数は全くひねりも何もないソースですね。。。ちなみに、SOAPメッセージのエンコーディングはutf-8になりますので、マルチバイト文字列を使用する可能性がある場合は結果をutf-8に変換する必要があります。今回のサンプルではmb_convert_encoding関数をあちこちに書きたくなかった(手抜き)ため、

  • ソースのエンコーディングをutf-8
  • 内部エンコーディングをutf-8(php.iniの設定はeuc-jp)
  • 出力エンコーディングをutf-8(php.iniの設定はsjis)

としています。

また、SoapServerクラスではWSDLを生成する機能は持っていないようです。残念。。。

一方、これに対するクライアントですが、以下のような感じになります。

●SoapClient_test.php
  
<?php
echo phpversion();
?>
<hr>
<?php
function showTrace($result, $client)
{
    echo '<h1>result=' . mb_convert_encoding(
                         $result, mb_internal_encoding(), 'utf-8')
                   . '</h1><br/>';

    echo "●REQUEST:<br/><pre>"
        . $client->__getLastRequestHeaders()
        . mb_convert_encoding(
              htmlspecialchars(
                  mb_ereg_replace("><", ">\n<", $client->__getLastRequest())),
                  mb_internal_encoding(), 'utf-8')
        . "</pre>";

    echo "●RESPONSE:<br/><pre>"
        . $client->__getLastResponseHeaders()
        . mb_convert_encoding(
              htmlspecialchars(
                  mb_ereg_replace("><", ">\n<", $client->__getLastResponse())),
                  mb_internal_encoding(), 'utf-8')
        . "</pre><hr/>";
}
?>
<?php
    /**
     * $location:エンドポイントURI
     */
    $location = 'http://www.doyouphp.jp/xp/soap/SoapServer_test.php5';
    $uri = 'http://www.doyouphp.jp/xp/soap/';

    try {
        /**
         * location:エンドポイント
         */
        $client = new SoapClient(
                     null,
                     array(
                         'location'=> $location,
                         'uri' => $uri,
                         'trace' => 1            // トレース
                     ));

        $result = $client->add(3, 5);
        showTrace($result, $client);

        $result = $client->addByArray(array(1, 3, 5, 9));
        showTrace($result, $client);

        $result = $client->hello("Hideyuki Shimooka");
        showTrace($result, $client);

        $result = $client->hello(mb_convert_encoding("ソフト", 'utf-8'));
        showTrace($result, $client);

        $user = new stdClass();
        $user->name = mb_convert_encoding("はろーわーるど", 'utf-8');
        $user->url = "http://www.doyouphp.jp/";
        $result = $client->helloByObj($user);
        showTrace($result, $client);

    }
    catch (Exception $e) {
        showTrace(null, $client);
        echo '<pre>';
        var_dump($e);
        echo '</pre>';
        exit;
    }


?>
<hr>
<?php
    show_source($_SERVER['SCRIPT_FILENAME']);
?>

実際の動作はEXPERIENCEのページで確認できるようにしましたのでどうぞ。また、上記サンプルを適当な名前を付けて保存し実行してもOKです。なお、Proxyサーバ経由でのアクセスの場合、

        $client = new SoapClient(
                     null,
                     array(
                         'location'=> $location,
                         'uri' => $uri,
                         'trace' => 1            // トレース
                     ));

        $client = new SoapClient(
                     null,
                     array(
                         'location'=> $location,
                         'uri' => $uri,
                         'trace' => 1,           // トレース
                         'proxy_host' => 'proxy_server.example.com',
                         'proxy_port' => 8080
                     ));

のようにProxyサーバのIPアドレス or ホスト名とポート番号を指定することでOKです。その他オプションについては、PHP日本語マニュアルを参照してください。

さて、「サービス用関数で定義し、それをSoapServerオブジェクトに追加していく」といった手順なんですが、サービスを提供するのがメソッドの場合でもOKです。以下は、ServeByClassクラスのauthenticate、validateUserの各メソッドをサービスとして提供するSOAP Serverの例です。実際の動作とクライアント側のコードはEXPERIENCEのページで確認してみてください。

●SoapServer_test2.php
  
<?php
/**
 * SOAPレスポンスをutf-8で返すため
 */
mb_internal_encoding('utf-8');
mb_http_output('utf-8');

/**
 * 提供するサービス(クラスの場合)
 */
class ServeByClass
{
    /**
     * 認証メソッド
     *
     * @param ユーザーID
     * @return ダミーのユーザーオブジェクト(stdClass)
     */
    public function authenticate($id)
    {
        /**
         * ダミーのユーザークラス
         */
        $user = new stdClass();
        $user->id = $id;
        $user->name = 'user_' . $id;
        $user->isAuthenticated = true;

        return $user;
    }

    /**
     * ユーザー検証メソッド
     *
     * @param ダミーのユーザーオブジェクト(stdClass)
     * @return true:有効なユーザー、false:無効なユーザー
     */
    public function validateUser($obj)
    {
        return ($obj->name == 'user_' . $obj->id);
    }
}

/**
 * SOAPサーバオブジェクトの作成
 */
$server = new SoapServer(null, array('uri' => 'http://www.doyouphp.jp/xp/soap/'));

/**
 * サービスの追加
 */
$server->setClass('ServeByClass');


/**
 * サービスを実行
 */
$server->handle();
?>

この場合、SoapServerクラスのsetClassメソッドでServeByClassクラスの全メソッドをサービスとして登録しています。なお、SoapServerクラスのaddFunctionメソッドとsetClassメソッドを同時に使用するとaddFunctionメソッドで追加したサービスが使用できなくなってしまいます。バグなのか仕様なのか。。。

ふふふ。。。またまたいろいろと遊べそうです(^-^;



About This Site |  Privacy Policy |  Contact
Copyright © 1999 - 2005 by Hideyuki SHIMOOKA all rights reserved.