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的特点如下:
- SOAP的可扩展性;
- SOAP可以在几乎所有的传输协议上使用;
- SOAP独立于平台和语言,允许任何编程模型,并且不依赖于RPC.
补充:RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
WSDL文档是用XML语言来描述Web Service.WSDL文档主要由6部分元素构成:
- <definitions>根元素
- <types>元素
- <message>元素
- <portType>元素
- <binding>元素
- <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 ?>
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 ?>
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>
使用了上面的三个文件后输出: “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!通过了,一切顺利。
浙公网安备 33010602011771号