PHP使用SOAP

目录
  1. 简介
  2. 扩展中的类
    1. SoapClient 类
    2. SoapServer 类
    3. SoapFault 类
    4. SoapHeader 类
    5. SoapParam 类
    6. SoapVar 类
  3. 扩展安装
    1. php.ini配置
  4. WSDL 模式测试
    1. hello.wsdl文件
    2. WSDL 服务端
    3. WSDL 客户端
  5. non-WSDL 模式
    1. non-WSDL 模式服务端
    2. non-WSDL 模式客户端

简介

PHP 的 SOAP 扩展可以用来提供和使用 Web Services。换句话说,PHP 开发者可以利用这个 PHP 扩展来写他们自己的 Web Services,也可以写一些客户端来使用给定的 Web Services。

PHP5 中的这个 SOAP 扩展目的是为了实现 PHP 对 Web Services 的支持。与其它实现 PHP 对 Web Services 的支持的方法不同,SOAP 扩展是用 C 写的,因此它比其它方法具有速度优势。

扩展中的类

SoapClient 类

这个类用来使用 Web Services。SoapClient 类可以作为给定 Web Services 的客户端。
它有两种操作形式:

  • WSDL 模式
  • Non-WSDL 模式

在 WSDL 模式中,构造器可以使用 WSDL 文件名作为参数,并自动从 WSDL 中提取使用服务时所需要的信息。

Non-WSDL 模式中使用参数来设置使用服务时所需要的信息。

这个类有许多可以用来使用服务的有用的方法。其中__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 头的一个主要作用就是用于简单的身份认证。

扩展安装

php.ini配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
extension=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="G:/xampp/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.wsdl文件

在这个 Hello World 例子的服务中有一个被命名为 greet 的操作。这个操作有一个字符串形式的名字参数并返回一个字符串形式的 Hello + 名字。

所用到的 WSDL 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<wsdl:definitions
xmlns:impl='http://localhost/test/php-soap/wsdl/helloService'
xmlns:intf='http://localhost/test/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/test/php-soap/wsdl/helloService'>
<wsdl:types>
<schema elementFormDefault='qualified'
xmlns:impl='http://localhost/test/php-soap/wsdl/helloService'
xmlns:intf='http://localhost/test/php-soap/wsdl/helloService'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace='http://localhost/test/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/test/php-soap/wsdl/hello_service_wsdl.php' />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

WSDL 服务端

下面是 WSDL 模式的服务使用 SOAP 扩展来实现提供服务的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function greet($param)
{
$value = 'Hello ' . $param->name;
$result = [
'greetReturn' => $value
];
return $result;
}

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

WSDL 客户端

1
2
3
4
5
6
7
8
9
10
<?php
try {
$client = new SoapClient('hello.wsdl');
$result = $client->__soapCall('greet', [
['name' => 'xpmozong']
]);
printf("Result = %s", $result->greetReturn);
} catch (Exception $e) {
printf("Message = %s",$e->__toString());
}

运行客户端

1
2
$ php test.php
Result = Hello xpmozong

non-WSDL 模式

non-WSDL 模式服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

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

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

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

non-WSDL 模式客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

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

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

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

运行客户端

1
2
$ php test.php
Result = Hello xpmozong

在 non-WSDL 模式中,因为没有使用 WSDL,传递了一个包含服务所在位置(location)和服务 URI 的参数数组作为参数。然后像 WSDL 模式中一样调用__soapCall() 方法,但是使用了 SoapParam 类用指定格式打包参数。返回的结果将获取 greet 方法的响应。

注:客户端实例化时所传入的服务 URI,实际上,我们可以把它看作该服务的一个命名空间(namespace)。客户端所传入的 URI 必与服务端所命名的 URI 一样。