简介 php 的 soap 扩展可以用来提供和使用 web services。换句话说,php 开发者可以利用这个 php 扩展来写他们自己的 web services,也可以写一些客户端来使用给定的 web services。
php5 中的这个 soap 扩展目的是为了实现 php 对 web services 的支持。与其它实现 php 对 web services 的支持的方法不同,soap 扩展是用 c 写的,因此它比其它方法具有速度优势。注:soap 扩展是在 php5 才开始提供,所以在此之前人们要使用 soap 去调用 web services 时,一般是使用第三方提供的 soap 封装库来实现,比如:nusoap。
soap 扩展支持以下规范:
soap 1.1
soap 1.2
wsdl 1.1
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-enabledsoap.wsdl_cache_enabled=1; sets the directory name where soap extension will put cache files.; http://php.net/soap.wsdl-cache-dirsoap.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-ttlsoap.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 模式服务端 下面是 wsdl 模式的服务使用 soap 扩展来实现提供服务的代码:
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 请求:
suhua
下面是服务端响应上诉请求而发送的 soap 响应:
hello suhua
上面的 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 来写。
最后 这篇文章的原文 php soap extension,中文译文 php soap 扩展。在转载这篇文章的时候,对文章添加了一些注释以及本人的一些见解,而且例子也是重新编写的,所以与原文比会有所不同。本文的所有代码将会被放到 notes 仓库中,方便以后翻阅和复习。(本文已存档 github)
参考文献 php soap 扩展
php soap extension
php soap 扩展详解
