PHP基础(022)---Web Service与SOAP技术

Web Service与SOAP技术:

Web Service(web服务),简称WS.WS是可以跨平台提供各项服务的一种技术。下面介绍组成WS平台的3个技术:

  • SOAP : 简单对象访问协议
    • SOAP Envelope :
    • SOAP Header :
    • SOAP Body :
    • SOAP Fault : 此元素用于保存SOAP中的错误消息及状态信息。
  • WSDL : Web服务描述语言
  • UDDI : 通用发现,描述,集成

SOAP是一种轻理级协议,利用XML技术让应用程序跨HTTP进行信息交换。SOAP可以和许多Internet协议结合使用,包括HTTP,SMTP,MIME等。SOAP的特点如下:

  1. SOAP的可扩展性;
  2. SOAP可以在几乎所有的传输协议上使用;
  3. SOAP独立于平台和语言,允许任何编程模型,并且不依赖于RPC.

补充:RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

 

WSDL文档是用XML语言来描述Web Service.WSDL文档主要由6部分元素构成:

  1. <definitions>根元素
  2. <types>元素
  3. <message>元素
  4. <portType>元素
  5. <binding>元素
  6. <service>元素

 

UDDI规范 : 推出基于标准的服务描述和发行的规范。

 

PHP 内置SOAP类库,首先对SOAP进行一些配置,使PHP支持SOAP函数,然后建立一个WSDL文档,文档创建成功后使用SOAP类创建服务器和客户端程序。

  • 配置 SOAP : 需要对php.ini文件进行如下改动:
    • 打开"extension=php_soap.dll" ;
    • 设置"soap.wsdl_cache_enabled=1 " ;            ---设置为"1"表示打开WSDL缓存;
    • 设置"soap.wsdl_cache_dir="/tmp" ;              ---设置缓存目录
    • 设置 " soap.wsdl_cache_ttl=86400 " ;
    • 设置 " soap.wsdl_cache_limit=5" ;
    • 打开"always_populate_raw_post_data = On " ;   ---意思是允许未格式化的POST数据
  • 建立WSDL
  • 创建服务器端页面
  • 创建客户端页面
  • 示例代码如下:(三个测试文件分别是index.php , server.php , tmbccd.wsdl )
1 //index.php 
2 <?php
3     $client = new SoapClient("http://localhost/testsoap/1/tmbccd.wsdl"); 
4     $return = $client->getBccd('spcn');
5     echo $return;
6 ?>
View Code
 1 //server.php
 2 <?php
 3     function getBccd($user){
 4         return 'Hi! '.$user.", You can see me.^_^";
 5     }
 6     $server = new SoapServer('tmbccd.wsdl');
 7     $server->addFunction("getBccd");
 8     $server->handle();
 9 
10 ?>
View Code
 1 //tmbccd.wsdl
 2 <?xml version="1.0" encoding="gb2312"?>
 3 <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tm="http://localhost/wwwbccdnet" targetNamespace="http://localhost/wwwbccdnet">
 4     <types>
 5         <xs:schema/>
 6     </types>
 7     <message name="getBccdRequest">
 8         <part name="user" type="xs:string"/>
 9     </message>
10     <message name="getBccdResponse">
11         <part name="return" type="xs:string"/>
12     </message>
13     <portType name="getBccdPortType">
14         <operation name="getBccd">
15             <input message="tm:getBccdRequest"/>
16             <output message="tm:getBccdResponse"/>
17         </operation>
18     </portType>
19     <binding name="getBccdBinding" type="tm:getBccdPortType">
20         <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
21         <operation name="getBccd">
22             <soap:operation soapAction="http://localhost/wwwbccdnet/getBccd"/>
23             <input>
24                 <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
25             </input>
26             <output>
27                 <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
28             </output>
29         </operation>
30     </binding>
31     <service name="getBccdService">
32         <port name="getBccdPort" binding="tm:getBccdBinding">
33             <soap:address location="http://localhost/testsoap/server.php"/>
34         </port>
35     </service>
36 </definitions>
View Code

使用了上面的三个文件后输出: “Hi! spcn, You can see me.^_^

 

补充 : 推存第三方扩展包NuSOAP. NuSOAP类包的优势在于NuSOAP可以直接生成WSDL文件。NuSOAP是一个源代码开放的SOAP类库,可以从网上下载。将NuSOAP解压后会有两个文件夹,将其中的lib文件夹复制到服务器相应的目录下即可使用,另一个sample文件夹是一些实例程序。在使用NuSOAP之前,先要在php.ini中将"extension=php_soap.dll"注释掉(前面加上引号),因为NuSOAP类库的类名有冲突。重启服务器后,即可使用NuSOAP类库。

  • NuSOAP类包中主要包括3个类:soap_server , soapclient 和soap_fault.
    • 创建服务器端页面
    • 创建客户端页面

更多阅读: 

soap 之 nusoap 的使用 

先看一个基本的使用很简单的
这是 soap_server.php 文件   这个在网络上能找的到
[php]
include_once("lib/nusoap.php"); //插入文件
$server=new soap_server();     //生成对象
$server->configureWSDL("test_wsdl", "");
$server->wsdl->schemaTargetNamespace="urn:test_wsdl";
$server->register("hello", //方法名
array(
"name"=>"xsd:string",
"call"=>"xsd:string",
"tele"=>"xsd:string",
),//输入参数
array(
"return"=>"xsd:string",
),//输出参数
"urn:test_wsdl",//名字空间
"urn:test_wsdl#hello",//名字空间#要操作的函数名
"rpc",//style
"encoded",//use
"This is test."//说明
);
//test方法实现
function hello($name,$call,$tele) {
if($name==""){
return new soap_fault("Client","","Must supply a valid name.");
}
return "Hello, " . $name." ".$call." ".$tele;
}
//Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA=isset($HTTP_RAW_POST_DATA)?$HTTP_RAW_POST_DATA:"";
$server->service($HTTP_RAW_POST_DATA);
[/php]
在你写完了以后,在浏览器里输入url,应该会看到一个页面,根据那个页面分析下,会有很大的收获,
client端要根据上面的使用
这个是soap _client.php
[php]
include_once("lib/nusoap.php");   //插入文件
//设置参数数组
$para=array(
"name"=>"sera1ph.Liu",
"call"=>"123456",
"phone"=>"12345678",
);
//生成客户端对象,注意下面的url   ?wsdl是必须加的前面为服务端的文件
$client=new soapclient("http://localhost/nusoap/soap_server.php?WSDL");
//呼叫/使用 那个函数,注意名字空间的区分
$return=$client->call('hello',$para,"http://localhost/soap/test_wsdl","test_wsdl#hello");
print_r($return);
[/php]

上面是一个很基本的使用,我想不过多的说了

下面看一个比较复杂的使用
[php]
require_once('../../lib/nusoap.php');
//取得值返回 返回的是一个数组
function validate($userName,$randomNum)
{
$temp['userName'] = $userName;
$temp['randomNum'] =$randomNum;
return $temp;
}
//本想做个set一个get方法,但是这个时候发现了一个问题,以后再说
function refresh($refresh_userName,$refresh_randomNum)
{
$temp['userName'] = $userName;
$temp['randomNum'] =$randomNum;
return $temp;
}

function logout($logout_userName)//注销用户名(退出登录)
{
$flag=$logout_userName;

if($logout_userName=="" || $logout_userName!="叁石")
{
$flag = -1;
}

return $flag;
}

$soap = new soap_server();
//参数一,服务名字,也就是server文件
//参数二,名字空间
$soap->configureWSDL('AuthorityServicewsdl', 'urn:AuthorityServicewsdl');
//参数设置空间
$soap->wsdl->schemaTargetNamespace = 'urn:AuthorityServicewsdl';
//上面跟原来的基本一样,但是大家注意声明的时候发生了变化
//下面是设置一个返回的数组类型
//参数一,为你自己命名的数据类型
//参数二,混合类型,不用管
//参数三。为结构体,或者数组(array)
//参数四,按照什么排序,有三个选择all(全部)|sequence(次序)|choice(选择)
//参数五,基本约束
//注意:上面5个我们不用改变
//参数6,最重要的参数,也就是我们返回的类型想对应
//返回数组下标 =>array('name'=>"数组下标",'type'=>"xsd:对应的类型")
//类型基本包括 string,int, date,boolean 这几种形式
$soap->wsdl->addComplexType('userInfo','complexType','struct','all','',
array(
'userName' => array('name'=>'userName', 'type'=>'xsd:string'),
'randomNum' => array('name'=>'randomNum', 'type'=>'xsd:string')
)
);

//这里是注册函数
//参数一,函数名
//参数二,是这个函数接受的参数,注意指定类型
//参数三,为返回的值,不一定名字非叫return,叫其他的也可以,注意返回的类型,
//我这里是返回我自己定义的类型 tns:userInfo 如果为基本的类型为 xsd:string 这个样子
//其他的参数,只要统一就可以了,尤其是名字空间跟 soapaction
$soap->register('validate', // method name
array('userName' => 'xsd:string','randomNum' => 'xsd:string'), // input parameters
//array('return' => 'xsd:string'), // output parameters
array('return' => 'tns:userInfo'),
'urn:AuthorityServicewsdl', // namespace
'urn:AuthorityServicewsdl#validate', // soapaction
'rpc', // style
'encoded', // use
'验证用户名及随机数' // documentation
);

$soap->register('refresh', // method name
array('refresh_userName' => 'xsd:string','refresh_randomNum' => 'xsd:string'), // input parameters
//array('return' => 'xsd:string'),// output parameters
array('return' => 'tns:userInfo'),
'urn:AuthorityServicewsdl', // namespace
'urn:AuthorityServicewsdl#refresh', // soapaction
'rpc', // style
'encoded', // use
'按时地方' // documentation
);

$soap->register('logout', // method name
array('logout_userName' => 'xsd:string'), // input parameters
array('return' => 'xsd:int'), // output parameters
'urn:AuthorityServicewsdl', // namespace
'urn:AuthorityServicewsdl#logout', // soapaction
'rpc', // style
'encoded', // use
'退出登录' // documentation
);
//大家可能对 $HTTP_RAW_POST_DATA 这个变量比较疑惑,我们没有定义,怎么出来的呢
//我也有这样的想法,不过我看了下手册解释是 usually is the value of $HTTP_RAW_POST_DATA
//所以大家就别管它了,就这样使用吧
$soap->service($HTTP_RAW_POST_DATA);
[/php]

我们现在看下 客户端的使用
[php]
require_once('../../lib/nusoap.php');

$client=new soapclient('http://localhost/nusoap/samples/server/AuthorityService.php?wsdl',true);
$err = $client->getError();

$username = "叁石";
$randomnum = "d8A9";
$params1 = array('userName'=>$username,'randomNum'=>$randomnum);
$reversed = $client->call('validate',$params1);//此为返回值
//echo "注册值
";
print_r ($reversed);
echo "
";

$refresh_username = "叁石";
$refresh_randomnum = "d8A9";
$params1 = array('refresh_userName'=>$refresh_username,'refresh_randomNum'=>$refresh_randomnum);
$reversed = $client->call('refresh',$params1);
//echo "取得值
";
print_r ($reversed);
echo "
";

$logout_username = "叁石";
$params1 = array('logout_userName'=>$logout_username);
$reversed = $client->call('logout',$params1);
echo $reversed;
[/php]
-----------------------------------------------------------------------------------

首先定义一个类UserInfo:


class UserInfo {
    var $UserName;
    //...
    var $Sequence;
}

然后写一个测试用的远程方法:


function hello() {
    $a = new UserInfo();
    $a->UserName = "Jaypei";
    $a->Sequence = 1928388199;
    $b = new UserInfo();
    $b->UserName = "cnblogs";
    $b->Sequence = 83910021;
    return array($a, $b);
}

一个普通的nuSOAP程序如下:(整个过程是对它的改造)
$soap = new soap_server();
// 使用UTF-8
$soap->soap_defencoding = 'UTF-8';
$soap->decode_utf8 = false;
// 需设置WSDL命名空间,假设jaypei.cnblogs.com
$soap->configureWSDL('jaypei.cnblogs.com', 'urn:jaypei.cnblogs.com');

//... ...

$soap->register('hello');

$soap->service($HTTP_RAW_POST_DATA);

改造过程

首先,注册一个UserInfo的复合类型,方法如下:(这个之前已写过)
$soap->wsdl->addComplexType(
    'UserInfo',
    'complexType',
    'struct',
    'all',
    '',
    array(
        'UserName'=>array('name'=>'UserName', 'type'=>'xsd:string'),
        'Sequence'=>array('name'=>'Sequence', 'type'=>'xsd:int')
    ));

这样就可以通过以下方式返回一个单一的UserInfo对象:(hello中返回$a或者返回$b)

$soap->register('hello', array(),array('return'=>'tns:UserInfo'));


如果要返回一个列表,则需要改动return处的类型。起初找到了返回string或int等基础类型的列表方法,如下:


$soap->register('hello', array(), array('return'=>'SOAP-ENC:Array') );

当这个方法用到自定义复合类型上时类型处会变成:

xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="object[2]"

object并不是我们想要的。于是上网找相关资料发现了如下方法:

$soap->register('hello', array(), array('return'=>'tns:UserInfoArray') );
这里要自定义添加一个tns:UserInfoArray的数组类型,方法如下:

$soap->wsdl->addComplexType(
    'UserInfoArray',
    'complexType',
    'array',
    '',
    'SOAP-ENC:Array',
    array(),
    array(
        array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:UserInfo[]')
    ),
    'tns:UserInfo'
);

此时代码部分已完成,但是调用时nuSOAP缺报错了,是一个PHP错误:
Catchable fatal error: Object of class UserInfo could not be converted to string in ...\nusoap\nusoap.php on line 6002  

于是找到nusoap.php的6002行看一下为何UserInfo向string转换:$this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");

代码没有多看,不过很明显只是个debug的代码,没什么实际作用。于是直接注释掉继续调用,OK!通过了,一切顺利。

 

posted on 2014-05-03 17:17  lbsf  阅读(205)  评论(0)    收藏  举报

导航