這個文件描述如何取得和安裝NuSOAP,然後提供一些實例來說明NuSOAP 的功能,這並不是一個全面的NuSOAP 的介紹,但是希望能夠然一些PHP 開發者可以有一個很好的入門。
NuSOAP 是一組PHP 類,它讓開發者可以建立和使用SOAP web services。它不需要安裝任何的PHP 擴充功能。它是在2004年12月3日被開發,目前的版本是NuSOAP(0.6.7) 。支援SOAP 1.1 規範,它能夠生產WSDL 1.1 ,當然也可以使用它,同時也支援rpc/encoded and document/literal service。但是,必須注意NuSOAP 沒有像.NET 和Apache Axis 那樣提供完全的實作。
Hello, World
我會以"Hello, World" 為實例做開始,編寫基本的NuSOAP 用戶端和伺服器端的程式碼。
我們先從伺服器端開始,應為沒有伺服器端,有客戶端也是沒有意義的。我們將編寫一個帶有單一參數並傳回一個字串,名叫Hello 的SOAP 方法,希望程式碼中的註解能夠提供有效的說明。
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the server instance
$server = new soap_server;
// Register the method to expose
$server->register('hello');
// Define the method as a PHP function
function hello($name) {
return 'Hello, ' . $name;
}
// 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);
?>
以下是客戶端的程式碼,有一些重要的事情要注意:首先,當建立實例soapclient 時,需要指定一個service 的URL 為參數,在這個實例中,helloworld.php 從http://localhost/phphack訪問的。當然,你要使用的services 放在不同的URL;第二,當呼叫service 時,第一個參數是service 的名字,必須匹配有效的方法名稱(有的伺服器是大小寫敏感的)。在這個實例,他必須匹配在helloworld.php 中已經註冊了的方法。最後,第二個參數是一個數組,它將是傳遞給SOAP service 方法作為參數。既然helloworld.php 中的方法hello 只有一個參數,那麼陣列就只有一個元素。
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/helloworld.php');
// Call the SOAP method
$result = $client->call('hello', array('name' => 'Scott'));
// Display the result
print_r($result);
?>
Debugging
程式設計時,當有問題出現的時候你都需要調試。 NuSOAP 提供了一組工具來幫助你做這個工作。 NuSOAP 偵錯的時候需要查看的資訊是傳送的請求資訊和回傳的對應資訊。 NuSOAP 的客戶端類別允許你透過它的兩個成員來查看這些資訊。例如,這裡是顯示請求和回應的helloworldclient.php 的修改版。在下一部分我會回顧顯示在客戶端程式碼的請求和回應訊息。
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/helloworld.php');
// Call the SOAP method
$result = $client->call('hello', array('name' => 'Scott'));
// Display the result
print_r($result);
// 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>';
?>
NuSOAP 也提供了一個方法使用它的類別就可以透過日誌來查看偵錯資訊。加入以下的程式碼將會顯示冗長的偵錯資訊。不幸的是輸出的說明必須留給讀者。
// Display the debug messages
echo '<h2>Debug</h2>';
echo '<pre>' . htmlspecialchars($client->debug_str, ENT_QUOTES) . '</pre>';
伺服器端能夠提供相似的調試信息,有趣的是,這些調試信息是在SOAP 的相應的末尾以xml格式顯示,因此它可以在客戶端中查看。伺服器端的調試看起來像這樣:
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Enable debugging *before* creating server instance
$debug = 1;
// Create the server instance
$server = new soap_server;
// Register the method to expose
$server->register('hello');
// Define the method as a PHP function
function hello($name) {
return 'Hello, ' . $name;
}
// 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);
?>
調試的第三個方法不算是真正的調試,它是很好的程式設計實踐。上面的實例在呼叫SOAP 的時候沒有做錯誤的檢查,比較健壯的客戶端會像這樣:
<?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the client instance
$client = new soapclient('http://localhost/phphack/helloworld.php');
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo '<p><b>Constructor error: ' . $err . '</b></p>';
// At this point, you know the call that follows will fail
}
// Call the SOAP method
$result = $client->call('hello', array('name' => 'Scott'));
// Check for a fault
if ($client->fault) {
echo '<p><b>Fault: ';
print_r($result);
echo '</b></p>';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo '<p><b>Error: ' . $err . '</b></p>';
} else {
// Display the result
print_r($result);
}
}
?>
為了測試程式碼,需要造成錯誤發生,例如,改變呼叫的方法名稱hello 為goodbye。
Request and Response
我在上面的範例中已經展示了顯示SOAP 的請求和回應資訊是如此的容易,在這裡hello2client.php 的請求資訊:
POST /phphack/helloworld2.php HTTP/1.0
Host: localhost
User-Agent: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: ""
Content-Length: 538
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:si=" http://soapinterop.org/xsd ">
<SOAP-ENV:Body>
<ns1:hello xmlns:ns1=" http://testuri.org ">
<name xsi:type="xsd:string">Scott</name>
</ns1:hello>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
在HTTP headers 裡,你會看到SOAPAction 是一個空的字串,這是它的預設值。你的service 方法可以設定SOAPAction 的值,你的客戶端程式碼可以指定SOAPAction 作為參數來呼叫方法。
在XML payload,你可以看到NuSOAP 使用和Latin-1一樣著名的ISO-8859-1 做為編碼,為了指定不同的編碼,你可以在客戶端soapclient 的實例設定soap_defencoding 屬性。使用指定的編碼來編碼參數的資料當然就是程式設計師的責任。幸運地,在SOAP 裡PHP提供了許多函數來編碼和解碼最通用的編碼數據,例如UTF-8。
另一件事情要注意的是,元素指定要呼叫的方法,名稱為hello 的元素被放在http://tempuri.org的網域下,指定真實的網域是最佳的實踐,對於許多services 也是很有必要的。這裡展示了一個未來的文件:
SOAP 服務的回應像以下:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Wed, 03 Nov 2004 21:32:34 GMT
X-Powered-By: ASP.NET
X-Powered-By: PHP/4.3.4
Server: NuSOAP Server v0.6.8
X-SOAP-Server: NuSOAP/0.6.8 (1.81)
Content-Type: text/xml; charset=ISO-8859-1
Content-Length: 556
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:si=" http://soapinterop.org/xsd ">
<SOAP-ENV:Body>
<ns1:helloResponse xmlns:ns1=" http://tempuri.org ">
<return xsi:type="xsd:string">Hello, Scott</return>
</helloResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>