PHP SOAP使用

簡介

PHP 的 SOAP 擴展能夠用來提供和使用 Web Services。換句話說,PHP 開發者能夠利用這個 PHP 擴展來寫他們本身的 Web Services,也能夠寫一些客戶端來使用給定的 Web Services。php

PHP5 中的這個 SOAP 擴展目的是爲了實現 PHP 對 Web Services 的支持。與其它實現 PHP 對 Web Services 的支持的方法不一樣,SOAP 擴展是用 C 寫的,所以它比其它方法具備速度優點。注:SOAP 擴展是在 PHP5 纔開始提供,因此在此以前人們要使用 SOAP 去調用 Web Services 時,通常是使用第三方提供的 SOAP 封裝庫來實現,好比:NuSOAPgit

SOAP 擴展支持如下規範:程序員

  • SOAP 1.1github

  • SOAP 1.2web

  • WSDL 1.1segmentfault

SOAP 擴展主要用來處理 RPC 形式的 Web Services。不過,你也可使用文本形式的 WSDL 文件配合 WSDL 模式的服務端和客戶端。數組

這個擴展使用 GNOME XML 庫來處理XML。緩存

擴展中的類

這個擴展實現了6個類。其中有三個高級的類,它們的方法頗有用,它們是 SoapClient、SoapServer 和SoapFault。另外三個類除了構造器外沒有其它別的方法,這三個是低級的類,它們是 SoapHeader、SoapParam 和 SoapVar。函數

SOAP 擴展關係圖:工具

上圖並非很準確,由於 SoapServer 也能夠在響應時發送 SoapHeader。全部會有下面這個更加準確的關係圖:

SoapClient 類

這個類用來使用 Web Services。SoapClient 類能夠做爲給定 Web Services 的客戶端。
它有兩種操做形式:

  • WSDL 模式

  • Non-WSDL 模式

在 WSDL 模式中,構造器可使用 WSDL 文件名做爲參數,並自動從 WSDL 中提取使用服務時所須要的信息。

Non-WSDL 模式中使用參數來設置使用服務時所須要的信息。這個類有許多能夠用來使用服務的有用的方法。其中 SoapClient::__soapCall() 是最重要的。這個方法能夠用來調用服務中的某個操做。

SoapServer 類

這個類能夠用來提供 Web Services。與 SoapClient 相似,SoapServer 也有兩種操做模式:WSDL 模式和 non-WSDL模式。這兩種模式的意義跟 SoapClient 的兩種模式同樣。在 WSDL 模式中,服務實現了 WSDL 提供的接口;在 non-WSDL 模式中,參數被用來管理服務的行爲。

在 SoapServer 類的衆多方法中,有三個方法比較重要。它們是 SoapServer::setClass()、SoapServer::addFunction() 和 SoapServer::handle()。

SoapServer::setClass()方法設定用來實現 Web Services 的類。SoapServer::setClass 所設定的類中的全部公共方法將成爲 Web Services 的操做(operation)。

SoapServer::addFunction() 方法用來添加一個或多個做爲 Web Services 操做(operation)的函數。

SoapServer:: handle() 方法指示 Web Services 腳本開始處理進入的請求。Web Services 腳本是用 PHP 腳本寫的一個或多個 SoapServer 對象的實例。儘管你能夠有不止一個的 SoapServer 對象,但一般的習慣是一個腳本只擁有一個 SoapServer 實例。在調用 SoapServer::handle() 方法以前,Web Services 腳本會使用設置在 SoapServer 對象實例上的任何信息來處理進入的請求和輸出相應的內容。

SoapFault 類

這個類從 Exception 類繼承而來,能夠用來處理錯誤。SoapFault 實例能夠拋出或獲取 Soap 錯誤的相關信息並按程序員的要求處理。

SoapHeader 類

這個類能夠用來描述 SOAP headers。它只是一個只包含構造器方法的數據容器。

SoapParam 類

SoapParam 也是一個只包含構造器方法的數據容器。這個方法能夠用來描述傳遞給 Web Services 操做的參數。在 non-WSDL 模式中這是一個頗有用的類,能夠用來傳遞所指望格式的參數信息。

SoapVar 類

SoapVar 也是一個只包含構造器的低級類,與 SoapHeader 和 SoapParam 類類似。這個類能夠用來給一個Web Services 操做傳遞編碼參數。這個類對 non-WSDL 中傳遞類型信息是很是有用的。


注:SoapParam 和 SoapVar 主要用來封裝用於放入 SOAP 請求中的數據,他們主要在 non-WSDL 模式下使用。事實上,在 WSDL 模式下,SOAP 請求的參數能夠經過數組方式包裝,SOAP 擴展會根據 WSDL 文件將這個數組轉化成爲 SOAP 請求中的數據部分,因此並不須要這兩個類。而在 non-WSDL 模式下,因爲沒有提供 WSDL 文件,因此必須經過這兩個類進行包裝。

SoapHeader 類用來構造 SOAP 頭,SOAP 頭能夠對 SOAP 的能力進行必要的擴展。SOAP 頭的一個主要做用就是用於簡單的身份認證。

WSDL VS. non-WSDL 模式

Web Services 有兩種實現模式:契約先行(Contract first)模式和代碼先行(Code first)模式。

契約先行模式使用了一個用 XML 定義的服務接口的WSDL文件。WSDL 文件定義了服務必須實現或客戶端可使用的接口。SoapServer 和 SoapClient 的 WSDL 模式就基於這個概念。

在代碼先行模式中,首先要先寫出實現服務的代碼。而後在大多數狀況下,代碼會產生一個契約(能夠藉助一些工具生成),換種說法,一個 WSDL 文件。接着客戶端在使用服務的時候就可使用那個 WSDL 來得到服務的接口及其餘信息。儘管如此,PHP5 的擴展並無從代碼輸出一個 WSDL 的實現,考慮到這種狀況,能夠在 non-WSDL 模式下使用 SoapServer 和 SoapClient。

使用 SOAP 擴展實現 Hello World

這一節介紹如何使用 WSDL 模式和 non-WSDL 模式來實現服務和客戶端。相對而言,使用 WSDL 模式來實現服務和客戶端會比較容易,假定已經有一個定義好了接口的 WSDL 文件。所以這一節會先介紹如何使用 WSDL 模式實現一個 Web Service。

安裝 SOAP 擴展

對於 Windows 平臺,須要在 php.ini 中加入以下代碼:

extension = php_soap.dll

上面的工做完成以後,還須要注意的是 SOAP 擴展在配置文件中有獨立的代碼片斷:

[soap]
; Enables or disables WSDL caching feature.
; http://php.net/soap.wsdl-cache-enabled
soap.wsdl_cache_enabled=1

; Sets the directory name where SOAP extension will put cache files.
; http://php.net/soap.wsdl-cache-dir
soap.wsdl_cache_dir="D:/wamp/tmp"

; (time to live) Sets the number of second while cached file will be used
; instead of original one.
; http://php.net/soap.wsdl-cache-ttl
soap.wsdl_cache_ttl=86400

; Sets the size of the cache limit. (Max. number of WSDL files to cache)
soap.wsdl_cache_limit = 5

這些配置項主要是用來指定 PHP 處理 WSDL 文件時使用緩存的行爲。這幾個配置項分別說明:是否開啓 WSDL 文件緩存、文件緩存位置、緩存時間、以及最大緩存文件數量。啓用緩存會加快 PHP 處理 WSDL 文件的速度,但最好在調試代碼時關閉緩存,以免一些因緩存行爲而出現的問題。

WSDL 文件

在這個 Hello World 例子的服務中有一個被命名爲 greet 的操做。這個操做有一個字符串形式的名字參數並返回一個字符串形式的 Hello + 名字。所用到的 WSDL 以下:

<wsdl:definitions
    xmlns:impl='http://localhost/php-soap/wsdl/helloService'
    xmlns:intf='http://localhost/php-soap/wsdl/helloService'
    xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
    xmlns:wsdlsoap='http://schemas.xmlsoap.org/wsdl/soap/'
    xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
    targetNamespace='http://localhost/php-soap/wsdl/helloService'>
    <wsdl:types>
        <schema elementFormDefault='qualified'
            xmlns:impl='http://localhost/php-soap/wsdl/helloService'
            xmlns:intf='http://localhost/php-soap/wsdl/helloService'
            xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
            xmlns="http://www.w3.org/2001/XMLSchema" 
            targetNamespace='http://localhost/php-soap/wsdl/helloService' >
            <element name='greet'>
                <complexType>
                    <sequence>
                        <element name='name' type='xsd:string' />
                    </sequence>
                </complexType>
            </element>
            <element name='greetResponse'>
                <complexType>
                    <sequence>
                        <element name='greetReturn' type='xsd:string' />
                    </sequence>
                </complexType>
            </element>
        </schema>
    </wsdl:types>
    <wsdl:message name='greetRequest'>
        <wsdl:part name='parameters' element='impl:greet' />
    </wsdl:message>
    <wsdl:message name='greetResponse'>
        <wsdl:part name='parameters' element='impl:greetResponse' />
    </wsdl:message>
    <wsdl:portType name='helloService'>
        <wsdl:operation name='greet'>
            <wsdl:input name='greetRequest' message='impl:greetRequest' />
            <wsdl:output name='greetResponse' message='impl:greetResponse' />
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name='helloServiceSoapBinding' type='impl:helloService'>
        <wsdlsoap:binding transport='http://schemas.xmlsoap.org/soap/http' style='document' />
        <wsdl:operation name='greet'>
            <wsdlsoap:operation soapAction='helloService#greet' />
            <wsdl:input name='greetRequest'>
                <wsdlsoap:body use='literal' />
            </wsdl:input>
            <wsdl:output name='greetResponse'>
                <wsdlsoap:body use='literal' />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name='helloService'>
        <wsdl:port binding='impl:helloServiceSoapBinding' name='helloService'>
            <wsdlsoap:address location='http://localhost/php-soap/wsdl/hello_service_wsdl.php' />
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

WSDL 模式服務端

下面是 WSDL 模式的服務使用 SOAP 擴展來實現提供服務的代碼:

<?php
function greet($param)
{
    $value  = 'Hello ' . $param->name;
    $result = [
        'greetReturn' => $value
    ];
    return $result;
}

$server = new SoapServer('hello.wsdl');
$server->addFunction('greet');
$server->handle();

在這個服務的實現過程當中,函數實現了WSDL所定義的服務操做 greet,greet 操做有一個 WSDL 指定的參數,按照 greet 操做的語義,這個參數是一個用戶的名字。最後 handle 調用了觸發處理請求的服務對象。

WSDL 模式客戶端

客戶端代碼以下:

try {
    $client = new SoapClient('hello.wsdl');
    $result =  $client->__soapCall('greet', [
        ['name' => 'Suhua']
    ]);
    printf("Result = %s", $result->greetReturn);
} catch (Exception $e) {
    printf("Message = %s",$e->__toString());
}

客戶端代碼中,首先建立一個使用 WSDL 文件做參數的 SoapClient 實例。接着使用 __soapCall() 調用 greet 方法,並傳入參數。

下面是客戶端所發送的 SOAP 請求:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns1="http://localhost/php-soap/wsdl/helloService">
    <SOAP-ENV:Body>
        <ns1:greet>
            <ns1:name>Suhua</ns1:name>
        </ns1:greet>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

下面是服務端響應上訴請求而發送的 SOAP 響應:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns1="http://localhost/php-soap/wsdl/helloService">
    <SOAP-ENV:Body>
        <ns1:greetResponse>
            <ns1:greetReturn>Hello Suhua</ns1:greetReturn>
        </ns1:greetResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

上面的 SOAP 消息都是利用 WSDL 模式下的服務端和客戶端來獲取的(可使用 __getLastResponse 和 __getLastRequest 這兩個方法獲取,前提是客戶端初始化時,要把 trace 參數設置爲 true)。也能夠利用 non-WSDL 模式的服務端和客戶端來產生與上面相同的 SOAP 消息。可是,PHP 代碼必須有一點改變。下一節會說明如何使用 non-WSDL 模式。

non-WSDL 模式服務端

function greet($param)
{
    $value = 'Hello '.$param;
    return new SoapParam($value, 'greetReturn');
}

$server = new SoapServer(null, [
    'uri' => 'http://localhost/php-soap/non-wsdl/helloService'
]);

$server->addFunction('greet');
$server->handle();

在 non-WSDL 模式中,像 WSDL 模式同樣首先實現 greet 函數的功能,可是函數實現的方式跟 WSDL 模式稍稍有所不一樣。在 non-WSDL 模式中,咱們必須返回一個 SoapParam 對象做爲響應,而不是一個數組。建立服務時,第一個參數設爲 null,說明沒有提供 WSDL;接着傳遞一個選項做爲參數,這個選項參數是服務的 URI。最後像 WSDL 模式同樣調用剩下的方法。

non-WSDL 模式客戶端

try {
    $client = new SoapClient(null, [
        'location' => 'http://localhost/php-soap/non-wsdl/hello_service_non_wsdl.php',
        'uri' => 'http://localhost/php-soap/non-wsdl/helloService'
    ]);

    $result =  $client->__soapCall('greet', [
        new SoapParam('Suhua', 'name')
    ]);

    printf("Result = %s", $result);
} catch (Exception $e) {
    printf("Message = %s",$e->__toString());
}

在 non-WSDL 模式中,由於沒有使用 WSDL,傳遞了一個包含服務所在位置(location)和服務 URI 的參數數組做爲參數。而後像 WSDL 模式中同樣調用 __soapCall() 方法,可是使用了 SoapParam 類用指定格式打包參數。返回的結果將獲取 greet 方法的響應。

注:客戶端實例化時所傳入的服務 URI,實際上,咱們能夠把它看做該服務的一個命名空間(namespace)。客戶端所傳入的 URI 必與服務端所命名的 URI 同樣。

結論

這篇文章介紹了 SOAP 擴展,能夠在 PHP 中經過它來提供和使用 Web Services。PHP SOAP 擴展的強項是它的簡單和快速。使用 C 寫的 SOAP 擴展來運行服務端和客戶端是很是簡單的。雖然 SOAP 擴展在處理一些簡單的 Web Services 時頗有用,可是當用它來處理全部的 Web Services 時就表現出它的侷限性。WSO WSF/PHP 就是爲了彌補 PHP 擴展的缺陷而開發的,它是開源的,能夠實現 SOAP 相似的功能而且支持 MTOM,WS-Addressing,WS- Security 和 WS-RelaiableMessaging。WSO2 WSF/PHP 支持與 SOAP 擴展相似的 API。咱們正計劃將 API 打包起來提供跟 SOAP 擴展同樣的 API,會用 C 來寫。

轉自" : http://www.javashuo.com/article/p-dpmimprf-d.html

相關文章
相關標籤/搜索