PHP SOAP扩展实现Web Service

一、什么是Web Service

随着Internet在各个领域应用的普及和深化,人们迫切需要能够方便实现Internet上跨平台、语言独立、松散耦合的异构应用的交互和集成。Web Service作为一种新的计算技术应运而生,提出了面向服务的分布式计算模型。Web Service采用标准化的通讯机制实现了不同开发环境和不同平台上的应用程序之间的互操作性,满足了人们对B2BBusiness to Business,商务对商务)集成、A2AApplication to Application,应用程序对应用程序)通讯和交互处理应用程序通讯的不断增长的需求。目前,Web Service已经成为学术界和技术厂商如IBMSUNMicrosoft的研究热点。

接下来我们从Web Service的基本概念、特点、体系架构、以及核心技术XMLSOAPUDDIWSDL进行详细的介绍

1.Web Service基本概念

20024月,W3CWorldwide Web Consortium,万维网协会)给出定义:“Web Service是一种通过URL标识的软件应用程序,其接口及其绑定形式可以通过XML标准来定义、描述和查找,并能通过XML消息及Internet协议与其他程序进行直接交互”。

简单的说,一个Web Service就是一个能够使用XML消息通过网络来访问的接口,这个接口描述了一组可以访问的操作。Web Service通过Web发布、查找和调用来实现其功能。一个Web Service配置好后,就可以被其他应用程序和Web Service发现和调用,这样就既可以响应客户的一个简单请求,也可以完成一个复杂的商务流程。

2.Web Service特点

(1)Web Service具有高度的可集成能力。由于Web Service采用标准Web协议作为组件界面描述和协同描述规范,完全屏蔽了不同软件平台的差异,任何软件都可以通过标准的协议进行互操作,实现了高度的可集成性。

(2)Web Service是松散耦合的。松耦合的基本概念是一端发生改变不会影响到另一端的操作。在松耦合的系统中允许更加自由地配置。

(3)Web Service具有完好的封装性。Web Service是一种部署在Web上的对象,具备对象的良好封装性,对使用者来说只能看到该对象提供的功能列表。

(4)Web Service是可重用的软件模型,是对软件开发中面向对象设计的发展和升华。基于组件的模型允许开发者重用其他人创建的代码模块,组合或扩展他们,形成新的软件。

(5)Web Service是在Internet上发布的,使用现在有的并广泛使用的传输协议,比如HTTPHTTPS。不需要调整现有的Internet架构,Web Service就可以通过防火墙进行通信。

3.Web Service体系架构

Web Service的体系架构由3个参与者和3个基本操作构成。3个参与者分别是服务提供者、服务请求者和服务注册代理,而3个基本操作分别是发布(publish)、查找(find)和绑定(bind)。Web Service的体系架构模型如图1所示。

wKiom1L4RjmQ__q5AAC5WM-BHo8855.jpg

1Web Service的体系架构模型

服务提供者在实现服务之后发布其服务给服务注册代理;当服务请求者需要调用某个服务时,它利用服务注册代理查找所需要的服务,并获得关于调用该服务的相关信息,然后服务注册代理对服务提供者和服务请求者进行绑定,服务调用的实现就直接在服务提供者和服务请求者之间进行,而无须再经过服务注册代理

4.Web Service核心技术

Web Service核心技术包括XMLSOAPWSDLUDDI

XMLWeb Service的基本标记语言,是Web Service的基石;SOAP作为互操作协议,提供了应用程序和Web Service之间的通信手段;通过UDDI可以注册服务的特性,其他应用程序可以通过UDDI查找到需要的Web ServiceWSDL作为服务描述语言,是描述Web Service的编程接口。

(1)XMLExtensible Markup Language,可扩展标记语言)

XML是目前开放环境下用于数据描述和交换的一种标准,为Internet上的数据内容描述和管理提供了一种与平台无关且可伸缩的元语言描述机制,他对信息采用树状结构和嵌套规则的描述,并支持Unicode实现语言的独立性。

XML具有良好的可扩展性,使用标记来界定内容,允许用于定义任意复杂度的结构;同时XML具有自描述性,适合数据的交换和共享;另外,XML具有无关性,独立于具体的平台和厂商,确保了结构化数据的统一,因此使用XML有利于Web上的数据发布和集成,并能以可移植方式共享信息。XML作为Web Service中信息描述和交换的标准手段,真正实现分布式Web系统间跨平台、跨语言的无缝融合,从而解决了传统分布式体系结构无法解决的在Internet环境下的松耦分布式异构问题。XML是整个Web Service架构的基础。

(2)SOAPSimple Object Access Protocol,简单对象访问协议)

SOAP是一种基于XML,用于在分布式环境中进行消息交换的轻量级协议。它为在分布式应用程序环境中,两个或多个对等实体利用XML交换结构化的数据提供了简单的通信机制,实现了异构应用之间的互操作性。SOAP并不专门针对某一编程语言、产品或硬件平台,所以任何应用程序均可以使用它。SOAP主要由三部分组成:封装结构、编码规范和RPC(远程过程调用)机制。封装结构定义了一个整体框架,来描述消息内容。内容的属性以及谁负责处理等;编码规则定义了交换应用程序数据的一系列机制;RPC机制定义了远程调用和应答的协议。

SOAP可以有效的潜入HTTP协议中,通过结合单项交换和底层协议来创建请求/响应或请求/多重响应等交互模型进行发送和获取信息,其基本的消息传送机制如下所述:

SOAP将远程过程所需要的信息编组为SOAP信息,并封装成SOAP信封发送到SOAP接收站点;在SOAP接收端,SOAP信封通过处理器提取并取消编组,将消息转化为SOAP应用可理解的方法调用,从而完成整个消息的传送

(3)WSDLWeb Services Descirption LanguageWeb服务描述语言)

WSDLWeb Service的服务描述语言,用于表示有关如何调用Web服务的界面和语义的信息,描述服务提供者和请求者之间如何进行通信,说明服务提供者提供的Web服务的功能、位置、以及如何访问这些服务。简单的说,Web Service采用WSDL来描述其服务。

WSDL文档通过6个元素来具体定义一个服务及其属性,即definitions元素:定义Web Service的名称以及命名空间;types元素:一个使用特定类型规则定义的数据类型容器;message元素:对具有一定规则的交互数据的抽象描述;PortType元素:为端口提供不同抽象操作的结合;bingding元素:指定一个具体端口类型的协议和数据格式;service元素:一组端口地址与特定绑定的集合。

(4)UDDIUniversal Description Discovery and Integration,通用描述、发现和集成协议)

UDDI是一个基于SOAP协议,为Web Service提供信息注册中心的实现标注,同时也包含一组提供Web Service注册、发现和调用的访问协议,通过XML将用户提供的Web Service注册在UDDI的注册表中,注册表中的每一项均提供了Web Service的信息,以供其他用户查找和调用,一般可通过三个方面的信息来结构化描述一个Web Service

一般信息(白页):Web ServiceURL和提供者的名称、地址等基本信息。

分类信息(黄页):基于标准分类法(如相关产业、产品或提供服务类型以及地域等)的分类系统。

技术信息(绿页):是发现潜在Web Service的关键,提供发现的接口与发现的机制。

我们结合上述的概念、模型和标准描述了实现一个Web Service的基本步骤。如图2

wKioL1L4RiGSz1iBAAB1qmUEPvM762.jpg

2Web Service的实现过程

服务提供者开发和测试Web服务,使用WSDL定义服务描述,包括定义服务接口描述和定义服务实现描述。

服务提供者将这些服务描述注册并发送到UDDI注册中心,从而使潜在的服务请求者能够发现这些Web服务。

UDDI注册中心使用UDDI注册表将服务描述存储为绑定模块,提供了多种不同的SOAP操作,使得请求者可以访问器数据。

服务请求者通过查找UDDI注册表找到所需服务的绑定信息,找到Web服务应用程序的提供者。

服务请求者使用该绑定信息激活并获取该服务的WSDL描述,从而与服务提供者进行绑定,使用SOAP协议调用所需的Web服务。

随着电子商务的迅速崛起和Web应用的迅速发展,Web Service将成为跨平台的电子商务系统中的共同技术趋势和有效的解决方案,因此近年来业界加强了对Web Service的研究和推广,并取得了极大进展,新的技术标准不断出现,但由于其推出的时间较短、体系机构、技术实现等尚待完善,Web Service各主要技术中还有一些需要解决的关键问题,如实现服务发展的高效性、自动化和智能化,动态按需组合Web Service以及Web Service安全性、性能优化等,这些都是将来有待进一步研究的内容。提到PHP调用Web Service,在PHP4时代,人们使用最多的是NuSOAP,它是一组功能强大的PHP类,使得PHP在调用Web Service时变得很方便。但是NuSOAP2007年已经停止更新了,而在PHP5中新增了SOAP扩展作为PHP5整体的一个组成部分,它是用C语言开发并编译成PHP内部函数库,所以在使用Web Service时变得更加方便,功能更强,效率也更高的。

二、PHP SOAP扩展

PHP5中的SOAP扩展可以用来提供和使用Web Service。换句话说,开发者既可以通过它搭建自己的Web Service,又可以通过它来使用已知的Web Service

下面介绍一下如何使用SOAP扩展:

Windows下如果已经搭建好了PHP环境,打开php.ini配置文件,

1.把extension=php_soap.dll前的(;)去掉

2.找到SOAP扩展的配置部分

[soap]

; Enables or disables WSDL caching feature.

soap.wsdl_cache_enabled=1

; Sets the directory name where SOAP extension will put cache files.

soap.wsdl_cache_dir="/tmp"

; (time to live) Sets the number of second while cached file will be used

; instead of original one.

soap.wsdl_cache_ttl=86400 http://www.pprar.com  

这段配置控制了 SOAP 扩展的 WSDL 缓存特性。默认情况下,WSDL 描述文件在 24 小时(86400 秒)内都缓存在 /tmp 目录下。我们迟些时候再讨论这些内容,现在要设置 soap.wsdl_cache_enabled=0,否则,在开发代码时,您会遇到一些莫名其妙的行为。完成开发之后,要记得打开 WSDL 缓存,使代码运行得更快。

保存后重新启动Apache服务器就可以了。

SOAP扩展把实现Web Service应用服务的操作都做了封装,SoapClient封装了客户端的所有操作,SoapServer类实现了Web Service服务端的所有操作,SoapFault用来做异常处理。下面详细介绍一下SOAP扩展中的类及比较重要的方法:

SOAP扩展实现了6个类。其中有三个高级的类,分别是 SoapClientSoapServerSoapFault。另外三个是除了构造器外没有实现任何方法的低级的类,分别是SoapHeaderSoapParamSoapVar

1.SoapClient

SoapClient类作为Web Service的客户端,用来调用Web Service。它有两种操作模式:WSDL模式和非WSDL模式。在WSDL模式中,构造器可以使用WSDL文件URI作为参数,并从WSDL文件中提取服务所使用的信息;非WSDL模式中使用参数来传递要使用的信息。

下面介绍几个常用的方法:

SoapClient()SoapClient类的构造函数。

object SoapClient(mixed wsdl [, array options])

wsdl参数确定该类是以WSDL模式还是非WSDL模式调用。如果是前者,则此参数指向一个WSDL文件的URI。否则,设置为nulloptions参数是一个数组,对于WSDL模式该参数是可选的,参数如下:

location

此参数指向Web Service文件的URI(在非WSDL模式下是必选参数)

uri

Web Service的命名空间,可以为空或任意字符串,需要保证和服务器端统一(在非WSDL模式下是必选参数)

encoding

字符编码,默认UTF-8

soap_version

SOAP版本

trace

是否检查SOAP请求和响应的信封

actor

URI格式指定SOAP节点为处理首部所担任角色的名称

compression

是否启用数据压缩。当前支持gzipx-gzip

exceptions

是否开启异常处理机制。默认是开启的

login

如果使用HTTP验证访问SOAP服务器,此参数将指定用户名

password

如果使用HTTP验证访问SOAP服务器,此参数将指定密码

proxy_host

指定通过代理服务器进行连接时的代理主机名

proxy_login

指定代理服务器用户名

proxy_password

指定代理服务器密码

proxy_port

指定通过代理服务器连接时的代理服务器端口

例:

//WSDL模式

$objClient = new SoapClient("http://domain/testserver.php?WSDL");

//WSDL模式

$objClient = new SoapClient(null, $args);

__soapCall():用来调用服务中的某个操作。

mixed __soapCall(string $function_name, array $arguments[, array $options[, mixed $input_headers [, array &$output_headers ]]])

function_name参数指定要调用Web服务的方法名。arguments参数指定调用function_name时需要的参数数组。optionsinput_headersoutput_headers参数可选。

例:

$result = $objClient->__soapCall("functionName",array($args));

__getFunctions():获取Web服务提供的所有方法。返回一个数组。

array __getFunctions()

例:

$funcs = $objClient->__getFunctions();

__getLastRequest():返回最后一个通过XML发送的SOAP请求信息的字符串。

__getLastResponse():返回最后一个通过XML发送的SOAP响应信息的字符串。

注:这两个方法必须是在WSDL模式下,并且tracetrue时才能获得结果。

2.SoapServer

SoapServer类作为Web Service的服务端,用来提供Web ServiceSoapServer类具有与SoapClient类相同的两种模式。在WSDL模式中,服务实现了WSDL提供的接口;在非WSDL模式中,参数被用来管理服务的行为。

下面介绍几个常用的方法:

SoapServer()SoapServer类的构造函数。

object SoapServer (mixed wsdl [, array options])

wsdl参数确定该类是以WSDL模式还是非WSDL模式调用。如果是前者,则此参数指向一个WSDL文件的URI。否则,设置为nulloptions参数是一个数组,对于WSDL模式该参数是可选的,参数如下:

uri

Web Service的命名空间,可以为空或任意字符串,需要保证和服务器端统一(在非WSDL模式下是必选参数)

encoding

字符编码,默认UTF-8

soap_version

SOAP版本

例:

//WSDL模式

$ objServer = new SoapServer(‘testwsdl.wsdl');

//WSDL模式

$objServer = new SoapServer(null , array($args));

addFunction()设定用来实现Web Service的方法

void addFunction (string $functions)

functions参数设置提供Web服务的一个方法名字符串或多个方法名字符串数组。

例:

$objServer->addFunction("ServiceFunc");

setClass()设定用来实现Web Service的类

void setClass (string $class_name [, array $args])

class_name参数设置提供Web服务的类。args参数可选,设置Web服务类在创建时构造函数需要的参数数组。

例:

$objServer->setClass("ServiceClass");

handle()方法指示Web Service脚本处理SOAP请求

void handle ([string $soap_request])

soap_request参数可选,设置Web服务获得的SOAP请求信息

例:

$objServer->handle();

3.SoapFault

SoapFault类继承Exception类,用来处理异常。

常用的方法:

getMessage()返回异常信息

string getMessage ()

例:

try { 

}catch (SoapFault $e){

//输出错误信息

print_r($e->getMessage());

}

4.SoapHeaderSoapParamSoapVar

SoapHeader类用来描述SOAP 头信息。它只是一个只包含构造器方法的数据容器。

SoapParam类用来描述传给Web Service操作的参数。在非WSDL模式中,可以用来传递期望格式的参数。它也是一个只包含构造器方法的低级类。

SoapVar类用来给一个Web Service操作传递参编码数。它也是一个只包含构造器方法的低级类。

三、项目实例

MemberBean.php

<?php

/**

会员实体类

*

*/

class MemberBean{

/**

会员名

*

* @var string

*/

private $member_name;

/**

密码

*

* @var string

*/

private $member_pwd;

/**

设置私有属性的值(PHP预定义函数)

*

* @param string $paramkey

* @param string $paramvalue

*/

public function __set($paramkey, $paramvalue){

$this->$paramkey = $paramvalue;

}

/**

获取私有属性的值(PHP预定义函数)

*

* @param string $paramkey

* @return string 

*/

public function __get($paramkey){

return $this->$paramkey;

}

}

?>

MemberClass.php

<?php

/**

会员操作类

*

*/

class MemberClass{

/**

会员登录接口

*

* @param MemberBean $objMember

* @return Response

*/

public function memberLogin($objMember){

//加载响应实体类

include_once("./bean/Response.php");

//实例化实体类

$objResp = new Response();

//判断用户输入的参数

if ($objMember->member_name == 'admin' && $objMember->member_pwd == '123456') {

$objResp->returnCode = '000000';

$objResp->description = '成功';

}elseif ($objMember->member_name == 'admin') {

$objResp->returnCode = '301001';

$objResp->description = '密码错误';

}else {

$objResp->returnCode = '301003';

$objResp->description = '用户不存在';

}

return $objResp;

}

/**

会员登出接口

*

* @param MemberBean $objMember

* @return Response

*/

public function memberLogout($objMember){

//加载响应实体类

include_once("./bean/Response.php");

//实例化实体类

$objResp = new Response();

//判断用户输入的参数

if ($objMember->member_name == 'admin') {

$objResp->returnCode = '000000';

$objResp->description = '成功';

}else {

$objResp->returnCode = '301003';

$objResp->description = '登出失败';

}

return $objResp;

}

}

?>

soapserver.php

<?php

//设置soap缓存失效

ini_set("soap.wsdl_cache_enabled", 0); 

//加载会员操作类

include_once("./interface/MemberClass.php");

//创建 Web Service 服务器端对象

//$objServer = new SoapServer(null ,

//array("uri" => "http://demo/")); //WSDL模式下,必须与客户端一直

$objServer = new SoapServer('./wsdl/membermanage.wsdl');//WSDL模式

//设定实现 Web Service 的类

$objServer->setClass("MemberClass");

//处理请求

$objServer->handle();

//if (isset($HTTP_RAW_POST_DATA)) { //全局变量 $HTTP_RAW_POST_DATA 来接收post过来的数据,比如 text/xml 或者 soap 等等

//$request = $HTTP_RAW_POST_DATA;

//} else {

//$request = file_get_contents('php://input');// php://input 是一个数据流,可以获得POST的原始数据

//}

//$objServer->handle($request);

?>

Response.php

<?php

/**

响应实体类

*

*/

class Response {

/**

返回结果码

*

* @var string

*/

private $returnCode;

/**

返回结果描述

*

* @var string

*/

private $description;

public function __construct(){}

/**

设置私有属性

*

* @param string $key

* @param string $value

*/

public function __set($key,$value){

$this->$key = trim($value);

}

/**

获取私有属性的值

*

* @param string $key

* @return string

*/

public function __get($key){

return $this->$key;

}

}

?>

soapclient.php

<?php

header("Content-type:text/html;charset=utf-8");

//设置soap缓存失效

ini_set("soap.wsdl_cache_enabled", 0);

//参数

$args = array("location" => "http://localhost/soapDemo/server/soapserver.php?WSDL", //Web Service 地址

"uri" => "http://demo/",//在非WSDL模式下工作时,SOAP服务的命名空间(必须和服务器端统一)

"encoding" => "utf-8", //默认UTF-8

"soap_version" => SOAP_1_2, //SOAP版本

"trace" => 1); //是否希望检查SOAP请求和响应的信封

//创建 Web Service 客户端对象

//$objClient = new SoapClient(null, $args); //WSDL模式

$objClient = new SoapClient("http://localhost/soapDemo/server/soapserver.php?WSDL",array('trace'=>1));//WSDL模式

//加载会员实体类

include_once("./bean/MemberBean.php");

//实例化会员实体类

$objMemberBean = new MemberBean();

//设置属性的值

$objMemberBean->member_name = 'admin';

$objMemberBean->member_pwd = '123456';

try {

//调用 Web Service 操作

//$result = $objClient->memberLogin($objMemberBean);

$result = $objClient->__soapCall("memberLogin",array($objMemberBean));

//输入响应的结果

echo "返回码:".$result->returnCode."<br>";

echo "描述:".$result->description;

//调用服务器端的方法

//$funcs = $objClient->__getFunctions();//获取服务器端提供调用的所有方法,返回的是数组

//print_r($funcs);

}catch (SoapFault $e){

//输出错误信息

print_r($e->getMessage());

}

?>