The Suhua Blog: soap

学习 PHP SOAP 扩展的一些笔记

如何理解

因为 SOAP Web 服务是基于 HTTP 协议的,发出一个 SOAP 消息请求,实际上利用 HTTP 动词中的 POST,然后把 SOAP 消息放置在 HTTP body 里面发送。简单来说就是:每调用一次 SOAP 服务,就是发送一条 POST 请求。

下面是一次请求接口所发送的内容:

POST /webservices/qqOnlineWebService.asmx HTTP/1.1
Host: www.webxml.com.cn
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.4.29
Content-Type: application/soap+xml; charset=utf-8; action="http://WebXml.com.cn/qqCheckOnline"
Content-Length: 247

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope
    xmlns:env="http://www.w3.org/2003/05/soap-envelope"
    xmlns:ns1="http://WebXml.com.cn/">
    <env:Body>
        <ns1:qqCheckOnline>
            <ns1:qqCode>8698053</ns1:qqCode>
        </ns1:qqCheckOnline>
    </env:Body>
</env:Envelope>

我们可以看到,一次 SOAP 请求,实际上就是向服务器端发送了一个 POST 请求。而发送的内容正是 SOAP 消息(它表明你本次调用的接口方法以及参数等等)。

这个 POST 请求,有一些特点,比如:它发送的内容类型为:application/soap+xml,用户代理为 PHP-SOAP/5.4.29 ,其他特点自己观察,不多说。

SOAP 扩展的作用

实际上,既然我们知道请求一次接口只是发送一次 POST 请求,那么我们完全可以使用一些工具或 PHP 本身自带的一些库(比如 curl、fsockopen)模拟发送 POST 请求,而不需要使用 PHP 的 SOAP 扩展。对,没错!在 PHP 还没有提供 SOAP 扩展前,的确很多人也是这样做的。

那干嘛要用 SOAP 扩展呢? 因为它官网的呗,因为它用 C 语言写的,速度杠杠的,而且封装得很好用,也不需要自己编写繁琐的 XML 代码了,所以就用它。

换句话说,实际上 SOAP 扩展就是一个更好用,速度更快,专门用于处理 SOAP 服务的 HTTP 封装库,没有什么很深奥的东西。

继续阅读...

PHP SOAP 扩展的使用

原文地址:PHP SOAP 扩展,本文在原文基础上添加了一些内容和章节,也加入了一些注释,请读者注意。

简介

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 扩展关系图:

SOAP 扩展关系图1

上图并不是很准确,因为 SoapServer 也可以在响应时发送 SoapHeader。所有会有下面这个更加准确的关系图:

SOAP 扩展关系图2

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>
继续阅读...

SOAP Web 服务介绍

已经跨入 2015 年,当今最为常见的两种 Web 服务类型分别是: REST 和 SOAP 。不过,从趋势来看,越来越多人已经开始使用 REST 风格的 Web 服务。而 SOAP 大多也开始或已经转型 REST,应该说 REST 会慢慢成为主流。这篇文章不会对 REST 介绍太多,主要的重点还是介绍一下 SOAP 风格的 Web 服务。

Web Service 三要素

实际上,现在说 “Web Service 三要素”应该是不算很准确了,不过这个概念一直这样沿用,而且本文我们为了更能清楚阐释 SOAP Web 服务,那么就这样定义。

Web Service 的三个要素分别是:

  1. SOAP(Simple Object Access Protoco) 简单对象访问协议;
  2. WSDL(Web Services Description Language) 网络服务描述语言;
  3. UDDI(Universal Description Discovery and Integration)一个用来发布和搜索 WEB 服务的协议(非必须);

SOAP 用来描述传递信息的格式规范, WSDL 用来描述如何访问具体的接口(比如它会告诉你该服务有哪些接口可以使用,参数是什么等等), UDDI 用来管理、分发和查询 Web Service。下面我们将逐一详细介绍这三个要素,并通过结合实例来进行阐释。

为了把这三个要素说得更清楚,我们将会使用一个免费的 SOAP Web 服务作为例子进行阐述。该服务只提供一个接口即:根据 QQ 号,获取 QQ 在线状态。查看该服务

SOAP

它是一个协议,可以简单的理解为:它定义了一个基于 XML 的可扩展消息信封格式。因为客户端与服务器进行交互,由于大家的平台和应用程序都不一样,所以大家约定都采用 SOAP 这个协议来规范交互时的需要传递的消息。

请求接口时,发送的消息例子:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <qqCheckOnline xmlns="http://WebXml.com.cn/">
            <qqCode>8698053</qqCode>
        </qqCheckOnline>
    </soap:Body>
</soap:Envelope>

接口响应时,返回的消息例子:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <qqCheckOnlineResponse xmlns="http://WebXml.com.cn/">
            <qqCheckOnlineResult>Y</qqCheckOnlineResult>
        </qqCheckOnlineResponse>
    </soap:Body>
</soap:Envelope>

注:以上例子是使用 SOAP 1.1 发送的消息,SOAP 1.2 发送的消息格式其实大同小异,具体自己查看接口文档

下面对它结构进行详细说明。

XML 声明

<?xml version="1.0" encoding="utf-8"?>

该行是 XML 声明。它定义 XML 的版本 (1.0) 和所使用的编码(utf-8)。

Envelope 元素

<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	....
</soap:Envelope>

Envelope 元素是 SOAP 消息的固定根元素,SOAP 协议规定的,不能变,其中 xmlns 是 XML Namespace 的缩写,表示 XML 命名空间。xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"Envelope的一个属性,它表示定义个以 soap 为前缀的命名空间 http://schemas.xmlsoap.org/soap/envelope/,即命名空间的名字是:http://schemas.xmlsoap.org/soap/envelope/,而它的前缀是 soap,这样子就把 soap 前缀与该命名空间进行了绑定。即任何用 soap 为前缀的元素都属于该命名空间的,包括根元素 Envelope 。举个例子:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <qqCheckOnline xmlns="http://WebXml.com.cn/">
            <qqCode>8698053</qqCode>
        </qqCheckOnline>
    </soap:Body>
</soap:Envelope>

其中,EnvelopeBody 元素就是以 soap 为前缀的,那么 EnvelopeBody 元素都是属于 http://schemas.xmlsoap.org/soap/envelope/ 这个命名空间的。

同时,SOAP 协议中规定,SOAP 消息必须使用 SOAP Envelope 命名空间,所以 http://schemas.xmlsoap.org/soap/envelope/ 这个命名空间是固定的不能变(注意:这里只针对 SOAP 1.1 版本,SOAP 1.2 会有所不同)。所有 SOAP 消息元素,比如:EnvelopeHeaderBodyFault 也都必须属于该命名空间。

继续阅读...

SOAP 介绍

简介

SOAP(Simple Object Access Protoco)简单对象访问协议是在分散或分布式的环境中交换信息的简单的协议,是一个基于 XML 的协议。此协议规范由 IBM、Microsoft、UserLand 和 DevelopMentor 在1998年共同提出,并得到 IBM,莲花(Lotus),康柏(Compaq)等公司的支持,于2000年提交给万维网联盟(World Wide Web Consortium;W3C)。现在,SOAP 协议规范由万维网联盟的 XML工作组维护。SOAP 1.2 版在2003年6月24日成为 W3C 的推荐版本。

SOAP 协议包括以下四个部分的内容:

  1. SOAP 封装(envelop),封装定义了一个描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们的框架;
  2. SOAP 编码规则(encoding rules),它定义了不同应用程序间交换信息时,需要使用到的数据类型;
  3. SOAP RPC 表示(RPC representation),它定义了一个表示远程过程调用和应答的协定;
  4. SOAP 绑定(binding),它定义 SOAP 使用哪种底层协议交换信息的协定。使用 HTTP/TCP/UDP 协议都可以;

四个部分之间的关系

SOAP 消息基本上是从发送端到接收端的单向传输,但它们常常结合起来执行类似于请求 / 应答的模式。所有的 SOAP 消息都使用 XML 编码。一条 SOAP 消息就是一个包含有一个必需的 SOAP 的封装包,一个可选的 SOAP 标头(Header)和一个必需的 SOAP 体块(Body)的 XML 文档。

把 SOAP 绑定到 HTTP 提供了同时利用 SOAP 的样式和分散的灵活性的特点以及 HTTP 的丰富的特征库的优点。在HTTP上传送 SOAP 并不是说 SOAP 会覆盖现有的 HTTP 语义,而是 HTTP 上的 SOAP 语义会自然的映射到 HTTP 语义。在使用 HTTP 作为协议绑定的场合中, RPC 请求映射到 HTTP 请求上,而 RPC 应答映射到 HTTP 应答。然而,在 RPC 上使用 SOAP 并不仅限于 HTTP 协议绑定。SOAP也可以绑定到TCP和UDP协议上。

虽然这四个部分都作为 SOAP 的一部分,作为一个整体定义的,但他们在功能上是相交的、彼此独立的。特别的,信封(envelop)和编码规则(encoding rules)是被定义在不同的 XML 命名空间中,这样使得定义更加简单。

语法规则

  1. SOAP 消息必须用 XML 来编码;
  2. SOAP 消息必须使用 SOAP Envelope 命名空间;
  3. SOAP 消息必须使用 SOAP Encoding 命名空间;
  4. SOAP 消息不能包含 DTD 引用;
  5. SOAP 消息不能包含 XML 处理指令;

SOAP 消息格式

SOAP 消息的格式比较简单,如下图:

SOAP 消息格式

下面是一条 SOAP 消息的基本格式:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
    soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
    <soap:Header>
        <!-- 消息头,可选 -->
    </soap:Header>
    <soap:Body>
        <!-- 消息内容,必需 -->

        <soap:Fault>
            <!-- 错误信息,可选 -->
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

一条 SOAP 消息就是一个普通的 XML 文档,包含如下元素:

  1. 必需的 Envelope 元素,据此可把该 XML 文档标识为一条 SOAP 消息;
  2. 可选的 Header 元素,包含头部信息,一般用于身份验证;
  3. 必需的 Body 元素,包含所有的调用和响应信息;
  4. 可选的 Fault 元素,提供有关在处理此消息时,所发生的错误的描述信息;
继续阅读...