デベロッパー
デベロッパー
AJAXでPHP Webサービスを利用する
はじめに
本稿では、NuSOAPライブラリを使用してPHP Webサービスを構築する方法と、AJAX技術およびSOAPプロトコルを使用してPHP Webサービスを利用するJavaScriptクライアントを構築する方法を中心に説明します。まずは、Webサービスの用語について少し説明しましょう。SOAPおよびWebサービスに関する概略
SOAP(Simple Object Access Protocol)は、XMLベースの要求/応答メッセージングプロトコルです。SOAPの重要な特徴は、特定のトランスポートプロトコルに依存せず(最も頻繁に使用されるのはHTTPですが、SMTP、MIMEなども使用できます)、特定のオペレーティングシステムやプログラミング言語にも依存しないという点です。そのため、さまざまなソフトウェアアーキテクチャ上で高い柔軟性を発揮するだけではなく、非常に使いやすくなっています。Webサービスとは、ネットワーク上でリモートに呼び出されるよう設計されたソフトウェアシステムの一般的な名称です。これらのサービスで実行されるタスクは多岐にわたり、実装もそれぞれに異なりますが、一般的なWebサービスは次のことを前提としています。
- Webサービスは、一連の操作に基づいて問い合わせを受けるサーバとして公開されます。
- 利用可能な操作を、WSDL(Webサービス記述言語)ドキュメントと呼ばれるXMLドキュメントを使用して「パブリッシュ」します。通常、このドキュメントは、人間の手ではなく機械によって生成され、解析(分析)されます。
- Webサービスにアクセスするエンティティは、Webサービスクライアントと呼ばれます。
- クライアントとサーバ間の通信プロトコルはSOAPです。
PHPでSOAPを使用する
Webサービスはまたたく間にさまざまな分野で利用されるようになったため、一般的なプログラミング言語のほとんどは、Webサービスの構築と利用に対するサポートを提供し、より強化すべく取り組んできました。例えば、PHPには、Webサービスのサポートを追加するいくつかの拡張機能(PEARとライブラリ)があります。PHP5以降は、このようなサポートはNuSOAPと呼ばれるライブラリとして、PHPに標準装備されています。NuSOAPライブラリは操作性と性能に優れているため、本稿では、このライブラリを使用して完全なWebサービスを開発する方法を説明します。もし読者が他の拡張機能/ライブラリに精通していて、本稿の後半部分(JavaScript AJAXクライアントの開発方法)にのみ関心がある場合は、お好みの技術を使用して、サーバ側Webサービスを再構築することももちろん可能です。
NuSOAPライブラリは、HTTPプロトコルを使用してSOAPメッセージの送受信をサポートするPHPクラスの集合です。NuSOAPライブラリは、別名「SOAPx4」とも呼ばれるNuSphere社の製品で、公式サイトからダウンロードできます。NuSOAPクラスを使用するには、PHPソースファイル内に次のコードスニペットを含めます。
require_once('{NuSOAPフォルダパスおよびフォルダ名}/lib/nusoap.php');
TriangleAreaとRectangleAreaという2つのメソッドを公開します。これらのメソッドは、その名のとおり、それぞれ三角形と長方形の面積を求めます。次に、Webサービスを開発する手順を紹介します。1、メソッドの記述
まず、2つのメソッドを記述します。お分かりのように単純な作業です。
// Define the TriangleArea method as a PHP function
function TriangleArea($b, $h) {
return 'The triangle area is:' .((b*h)/2);
}
// Define the RectangleArea method as a PHP function
function RectangleArea($L, $l) {
return 'The rectangle area is:' .($L*$l);
TriangleAreaメソッドは三角形の底辺と高さの整数値、RectangleAreaメソッドは長方形の幅と高さです。どちらのメソッドも、計算において求められた面積の値を含む文字列を返します。これら2つのメソッドを記述したら、メソッドを公開するためのWebサービスが必要になります。
2、Webサービスインスタンスを取得
NuSOAPは、Webサービスの詳細を1つのクラスにカプセル化しているので、次のように空のコンストラクタsoap_serverを呼び出すだけで、Webサービスインスタンスを取得できます。// Create the server instance $server = new soap_server();
3、WSDLファイルの名前と名前空間を指定
Webサービスサーバに対応するWSDLファイルの名前と名前空間を指定します。これを行うには、名前と名前空間のみを必要とするnusoap.phpクラスのconfigureWSDLメソッドを呼び出します。
// Initialize WSDL support
$server->configureWSDL('mathwsdl', 'urn:mathwsdl');
4、メソッドを登録
次に、メソッドを登録します(この例では2つあります)。メソッドを登録することで、そのメソッドの名前、引数、戻り値の型、SOAPアクション、スタイル、エンコーディング、説明をWebサービスサーバに認識させます。これらのプロパティはすべて、registerという1つのメソッドで指定できます。例えば、TriangleAreaとRectangleAreaメソッドを登録するには、次のように行います。
// Register the TriangleArea method
$server->register('TriangleArea', // method name
array('b' => 'xsd:int', 'h' => 'xsd:int'), // input parameters
array('area_t' => 'xsd:string'), // output parameters
'urn:mathwsdl', // namespace
'urn:mathwsdl#TriangleArea', // soapaction
'rpc', // style
'encoded', // use
'Calculate a triangle area as (b*h)/2' // documentation
);
// Register the RectangleArea method to expose
$server->register('RectangleArea', // method name
array('L' => 'xsd:int', 'l' => 'xsd:int'), // input parameters
array('area_r' => 'xsd:string'), // output parameters
'urn:mathwsdl', // namespace
'urn:RectangleAreawsdl#RectangleArea', // soapaction
'rpc', // style
'encoded', // use
'Calculate a rectangle area as (L*l)' // documentation
);
※注
この登録内容は、NuSOAP固有のものです。
5、Webサービスを起動
最後に、次のようにしてNuSOAPのserviceメソッドを呼び出し、Webサービスを起動します。// Use the request to (try to) invoke the service $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : ''; $server->service($HTTP_RAW_POST_DATA);
リスト1 シンプルなWebサービス
<?php
// Pull in the NuSOAP code
require_once('./nusoap-php5-0.9/lib/nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL('mathwsdl', 'urn:mathwsdl');
// Register the TriangleArea method to expose it
$server->register('TriangleArea', // method name
array('b' => 'xsd:int', 'h' => 'xsd:int'), // input parameters
array('area_t' => 'xsd:string'), // output parameters
'urn:mathwsdl', // namespace
'urn:mathwsdl#TriangleArea', // soapaction
'rpc', // style
'encoded', // use
'Calculate a triangle area as (b*h)/2' // documentation
);
// Register the RectangleArea method to expose it
$server->register('RectangleArea', // method name
array('L' => 'xsd:int', 'l' => 'xsd:int'), // input parameters
array('area_r' => 'xsd:string'), // output parameters
'urn:mathwsdl', // namespace
'urn:RectangleAreawsdl#RectangleArea', // soapaction
'rpc', // style
'encoded', // use
'Calculate a rectangle area as (L*l)' // documentation
);
// Define the TriangleArea method as a PHP function
function TriangleArea($b, $h) {
return 'The triangle area is: ' .((b*h)/2);
}
// Define the RectangleArea method as a PHP function
function RectangleArea($L, $l) {
return 'The rectangle area is: ' .($L*$l);
}
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>
Webサービスを確認する
NuSOAPの優れた点の1つとして、Webサービスの存在を確認できることと、クライアントを構築しなくても必要なメソッドを確実に公開できることが挙げられます。例えば、サーバのURLにアクセスすると、先ほど作成したWebサービスのWebサービスWSDLと(WSDLを明示的に記述または生成しなくても、このWSDLは存在します)、サービスメソッドの詳細を確認できます。各メソッドの詳細では、適切なWebサービスクライアントを記述するために必要となる情報を見ることができます。図1に、サンプルWebサービス(nusoap_server.php)のWSDLとメソッドに関する画面キャプチャを示します。Webサービスクライアントを記述する
サーバを作成して確認したら、次はNuSOAP Webサービスクライアントを作成します。以降の説明を読めば分かるように、これはサーバを作成するよりも単純な作業です。手順は次のとおりです。1、soapclientNusoapクラスをインスタンス化
まず、soapclientNusoapクラスをインスタンス化してクライアントインスタンスを作成します。このとき、通常はWSDLのURLと、WSDLファイルを使用することを示すブール値をクラスコンストラクタに渡します(NuSOAPでは、WSDLがなくてもWebサービスを作成できますが、これについては、ここでは論じません)。// Create the client instance $client = new soapclientNusoap( 'http://localhost/php/webservice/nusoap_server.php?wsdl', true);
2、エラーチェック
この時点でエラーをチェックすると良いでしょう。例えば、次のようにします。
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Constructor error</h2><pre>' .$err .'</pre>';
// At this point, you know any calls to
// this web service's methods will fail
}
3、Webサービスメソッドの呼び出し
最後に、NuSOAPのcallメソッドを使用して、Webサービスメソッドを呼び出します。次の例では、TriangleAreaおよびRectangleAreaメソッドを呼び出しています(潜在的なエラーもチェックしていることに留意してください)。
// Call the TriangleArea SOAP method
$result = $client->call('TriangleArea',
array('b' => 10, 'h' => 15));
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' .$err .'</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
// Call the RectangleArea SOAP method
$result = $client->call('RectangleArea',
array('L' => 40, 'l' => 20));
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' .$err .'</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
4、要求/応答の表示
必要であれば、次のようにして要求/応答を表示することもできます。// Display the request and response echo '<h2>Request</h2>'; echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) .'</pre>'; echo '<h2>Response</h2>'; echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) .'</pre>';
リスト2 Webサービスクライアント
<?php
// Pull in the NuSOAP code
require_once('./nusoap-php5-0.9/lib/nusoap.php');
// Create the client instance
$client = new soapclientNusoap('http://localhost/php/webservice/nusoap_server.php?wsdl', true);
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
// At this point, you know the call that follows will fail
}
// Call the TriangleArea SOAP method
$result = $client->call('TriangleArea', array('b' => 10, 'h' => 15));
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' . $err . '</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
// Call the RectangleArea SOAP method
$result = $client->call('RectangleArea', array('L' => 40, 'l' => 20));
// Check for a fault
if ($client->fault) {
echo '<h2>Fault</h2><pre>';
print_r($result);
echo '</pre>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<h2>Error</h2><pre>' . $err . '</pre>';
} else {
// Display the result
echo '<h2>Result</h2><pre>';
print_r($result);
echo '</pre>';
}
}
// Display the request and response
echo '<h2>Request</h2>';
echo '<pre>' . htmlspecialchars($client->request, ENT_QUOTES) . '</pre>';
echo '<h2>Response</h2>';
echo '<pre>' . htmlspecialchars($client->response, ENT_QUOTES) . '</pre>';
?>
図2 Webサービスクライアント:nusoap_client.phpクライアントページを見ると、そのページから呼び出されたTriangleAreaおよびRectangleAreaの呼び出しと、要求/応答の詳細が表示される
JavaScript Webサービスクライアントを記述する
以降では、RectangleAreaメソッドを題材として、JavaScriptとAJAX技術を使ってブラウザWebサービスクライアントを作成する方法について説明します(TriangleAreaメソッドの呼び出しも基本的には同じです)。まず、
RectangleAreaメソッドの幅および高さの引数値を指定するための、シンプルなHTMLインターフェースを記述することから始めます。インターフェースに入力された値は、myAjaxというJavaScript関数に渡します(この関数は、ajaxSOAPという名前の独立したJavaScriptモジュールに書かれています)。このHTMLには空白の<div>タグが含まれており、AJAXはここにWebサービスサーバから受信した応答を入れます。最小限のインターフェースを以下に示します(これをwebserviceフォルダに保存してください)。
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>Web Service SOAP and AJAX</title>
</head>
<script type="text/javascript" src="./ajaxSOAP.js"></script>
<body>
<div style="position:relative;left:0px;
top:-12px;background-color:#1D3968;margin:0px;">
<h2 align="center"><font color="#ffffff">
Consume WebServices through SOAP-AJAX calls</font></h2></div>
<table align="center" cellpading="0px" cellspacing="3px"
bordercolor="#000000" border="0"
style="position:relative;width:300px;height:200px;">
<tr>
<td colspan="2" align="center"><h1>Rectangle Area</h1></td>
</tr>
< tr>
<td valign="center"><font color="#cc0000" size="3">
Insert value for l:</font></td>
<td><input id="l_id" type="text"></td>
</tr>
<tr>
<td><font color="#cc0000" size="3">Insert value for L:</font></td>
<td><input id="L_id" type="text"></td>
</tr>
<tr>
<td><input type="button" value="Calculate Area" onclick="myAjax();"></td>
</tr>
<tr>
<td colspan="2">
<div id="resultDiv"></div>
</td>
</tr>
</table>
</body>
</html>
myAJAX関数の実装が含まれていませんが、心配は無用です。これについては次に行います。空のJavaScriptモジュールを作成し、「ajaxSOAP.js」と名づけます。このモジュールを、前のHTMLコードと同じwebserviceフォルダに保存します。MyAJAX関数では、まず、Webサービスサーバに渡す必要がある引数を抽出します。前述のとおり、引数の値はHTMLインターフェースを通じて提供されるので、l_idとL_idというIDで識別される2つのテキストフィールドにアクセスします。
var l_var = document.getElementById("l_id").value;
var L_var = document.getElementById("L_id").value;
RectangleAreaメソッドを呼び出して、面積の計算に必要な2つの値を渡します。今回の例では、このSOAPメッセージをJavaScript変数に格納しておきます。
soapMessage = '
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="urn:mathwsdl">
<SOAP-ENV:Body>
<tns:RectangleArea xmlns:tns="urn:mathwsdl">
<L xsi:type="xsd:int">' +L_var+'</L>
<l xsi:type="xsd:int">'+l_var+'</l>
</tns:RectangleArea>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
callbackAjaxというAJAXコールバック関数を参照するようにします。
if(window.XMLHttpRequest) {
httpRequest=new XMLHttpRequest();
}
else if (window.ActiveXObject) {
httpRequest=new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open("POST",url,true);
if (httpRequest.overrideMimeType) {
httpRequest.overrideMimeType("text/xml");
}
httpRequest.onreadystatechange=callbackAjax;
httpRequest.setRequestHeader("Man", "POST
http://localhost/php/webservice/nusoap_server.php HTTP/1.1")
httpRequest.setRequestHeader("MessageType", "CALL");
httpRequest.setRequestHeader("Content-Type", "text/xml");
httpRequest.send(soapMessage);
下記の
callbackAjax関数は、Webサービス応答を取得し、書式化を行い、HTMLで作成したresultDivタグに結果を表示します。応答もSOAPメッセージの形をしていますが、ほとんどのブラウザはSOAPメッセージの解析方法を把握しているので、ペイロード(有益な情報)のみを抽出できます。しかし、相手側がWebサービスであり、SOAP XMLのチャンクを含む応答を取得する場合には、SOAPメッセージパーサーを実装する必要があります(responseTextではなくresponseXMLプロパティを使用して応答を抽出し、XML DOMパーサーを使用して必要な情報のみを抽出します)。
function callbackAjax(){
try {
if(httpRequest.readyState==4) {
if(httpRequest.status==200) {
clearTimeout(xhrTimeout);
resultDiv=document.getElementById("resultDiv");
resultDiv.style.display='inline';
resultDiv.innerHTML='<font color="#cc0000"
size="4"><b>'+httpRequest.responseText+'</b></font>';
}
}
} catch(e) {
alert("Error!"+e);
}
}
リスト3 ajaxSOAP.jsのコード(全体)
var httpRequest = null;
var xhrTimeout = null;
var url = "http://localhost/php/webservice/nusoap_server.php";
var soapMessage = null;
function myAjax()
{
var l_var = document.getElementById("l_id").value;
var L_var = document.getElementById("L_id").value;
soapMessage = '
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="urn:mathwsdl">
<SOAP-ENV:Body>
<tns:RectangleArea xmlns:tns="urn:mathwsdl">
<L xsi:type="xsd:int">' +L_var+'</L>
<l xsi:type="xsd:int">'+l_var+'</l>
</tns:RectangleArea>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
if(window.XMLHttpRequest) {
httpRequest=new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest=new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open("POST",url,true);
if (httpRequest.overrideMimeType) {
httpRequest.overrideMimeType("text/xml");
}
httpRequest.onreadystatechange=callbackAjax;
httpRequest.setRequestHeader("Man",
"POST http://localhost/php/webservice/nusoap_server.php HTTP/1.1")
httpRequest.setRequestHeader("MessageType", "CALL");
httpRequest.setRequestHeader("Content-Type", "text/xml");
httpRequest.send(soapMessage);
xhrTimeout=setTimeout("ajaxTimeout(httpRequest);",120000);
}
function callbackAjax(){
try {
if(httpRequest.readyState==4) {
if(httpRequest.status==200) {
clearTimeout(xhrTimeout);
resultDiv=document.getElementById("resultDiv");
resultDiv.style.display='inline';
resultDiv.innerHTML='<font color="#cc0000" size="4"><b>' +
httpRequest.responseText+'</b></font>';
}
}
}catch(e) {
alert("Error!"+e); }
}
function ajaxTimeout(ajaxOBJ) {
ajaxOBJ.abort();
}
※注
リスト3の前半にある
xhrTimeout変数とajaxTimeout関数はオプションです。これらはAJAXの堅牢性を高める目的で用意したもので、要求/応答にかかる時間が120,000ミリ秒を超えた場合はコールバックメカニズムを停止します。通常は、120,000秒あれば十分に応答を得ることができます。要求/応答に120,000秒以上かかる場合は、サーバのクラッシュや、通信の使用不可など、何らかの支障があることをクライアントに通知します。JavaScript/AJAXクライアントをテストする
お楽しみはここからです。JavaScript/AJAXクライアントをテストしましょう。ブラウザを開き、Webサービステストページにアクセスします。図3のような画面が開くはずです。2つのテキストフィールドに2つの整数を入力し(例えば、[l]には40、[L]には120など)、[Calculate Area]ボタンをクリックします。図4のような画面が表示されるはずです。
SOAP要求/応答メカニズムをモニタリングする
舞台裏で送信されるHTMLヘッダーとSOAPメッセージの内容を確認したい場合は、そのための専用アプリケーションを使用します。簡単なのは、Firefox用のフリーのプラグインであるFirebugを使用することです。例えば図5は、AJAXクライアントとWebサービス(nusoap_server.php)との間で送受信されたHTML要求/応答ヘッダーを表示しています。同様に、完全なSOAP要求(図6を参照)と応答(図7を参照)をモニタリングすることもできます。
Webサービスは一般的に文字列メッセージ、数値、各種形式の画像(SVGなど)を応答として返し、開発者は一般的にWebページ内でAJAXを使用して文字列、数値、画像を取得して表示します。つまり、両者はまったく同じ種類の情報を扱っているわけで、そのことを考えれば、AJAXからWebサービスを呼び出すことは興味深く、自然なアプローチであると言えます。これら2つを組み合わせれば、クールなインタラクティブWebサイトを構築できるでしょう。
著者紹介
Octavia Andreea Anghel(Octavia Andreea Anghel)
経験豊富なPHP開発者。現在は、国内外のソフトウェア開発コンテストに参加するプログラミングチームの主任トレーナーを務める。国レベルの教育プロジェクト開発のコンサルティングも担当している。共著書に『XML technologies?XML in Java』があり、XML部分の執筆を担当。PHPやXMLのほか、ソフトウェアアーキテクチャ、Webサービス、UML、ハイパフォーマンスな単体テストについても関心を寄せている。
New Topics
Special Ad
| “超高速無線 LAN 時代”の幕開け--新規格 11ac(Draft)に対応したバッファロー最新ルーターの潜在能力を試す | |
![]() |
バッファローは次世代無線 LAN 規格 IEEE802.11ac(Draft)通信速度最大 1,300Mbps 対応無線 LAN ルーター「WZR-1750DHP」を3月下旬に販売開始。今回、同機器を入手できたので、使用感や便利な機能についてレポートしたい。⇒詳細記事へ |
Hot Topics
IT Job
今週のIT求人情報
Interviews / Specials
Follow japan.internet.com
Popular
Access Ranking
Partner Sites



![図4 長方形の面積:2つの整数値を入力して[Calculate Area]ボタンを押すと、ボタンの下に面積が表示される](http://d16vxhzt0fcu59.cloudfront.net/developer/img/article/3939/04s.gif)













