php有两个扩展可以实现web service,一个是NuSoap,一个是php 官方的soap扩展,由于soap是官方的,所以我们这里以soap来实现web service.由于默认是没有打开soap扩展的,所以自己先看一下soap扩展有没有打开。
在soap编写web service的过程中主要用到了SoapClient,SoapServer,SoapFault三个类。
SoapClient类
这个类用来使用Web services。SoapClient类可以作为给定Web services的客户端。
它有两种操作形式:
* WSDL 模式
* Non-WSDL 模式
在WSDL模式中,构造器可以使用WSDL文件名作为参数,并从WSDL中提取服务所使用的信息。
non-WSDL模式中使用参数来传递要使用的信息。
SoapServer类
这个类可以用来提供Web services。与SoapClient类似,SoapServer也有两种操作模式:WSDL模式和non-WSDL模式。这两种模式的意义跟 SoapClient的两种模式一样。在WSDL模式中,服务实现了WSDL提供的接口;在non-WSDL模式中,参数被用来管理服务的行为。
在SoapServer类的众多方法中,有三个方法比较重要。它们是SoapServer::setClass(),SoapServer::addFunction()和SoapServer::handle()。
下面给出实例:
定义一个提供服务的php类,这个类所提供的函数就是web service对外提供的服务
1
<?
php
2
Class
PersonInfo
3
{
4
/*
*
5
* 返回姓名
6
* @return string
7
*
8
*/
9
public
function
getName(){
10
return
"
My Name is Chance
"
;
11
}
12
}
13 ?>
下面给出服务器端的代码:
1 <?php
2 //包含提供服务的类进来
3 require_once('PersonInfo.php');
4
5 //wsdl方式提供web service,如果生成了wsdl文件则可直接传递到//SoapServer的构造函数中
6 //$s = new SoapServer('PersonInfo.wsdl');
7
8 //doesn't work 只有location不能提供web service
9 //output:looks like we got no XML document
10 //$s = new SoapServer(null,array("location"=>"http://localhost/Test/MyService/Server.php"));
11
12 //下面两种方式均可以工作,只要指定了相应的uri
13 //$s = new SoapServer(null,array("uri"=>"Server.php"));
14 $s = new SoapServer(null,array("location"=>"http://localhost/Test/MyService/Server.php","uri"=>"Server.php"));
15
16 $s -> setClass("PersonInfo");
17
18 $s -> handle();
19 ?>
下面是客户端代码:
1 <?php
2 try{
3 //wsdl方式调用web service
4 //wsdl方式中由于wsdl文件写定了,如果发生添加删除函数等操作改动,不会反应到wsdl,相对non-wsdl方式
5 //来说不够灵活
6 //$soap = new SoapClient("http://localhost/Test/MyService/PersonInfo.wsdl");
7
8 //non-wsdl方式调用web service
9 //在non-wsdl方式中option location系必须提供的,而服务端的location是选择性的,可以不提供
10 $soap = new SoapClient(null,array('location'=>"http://localhost/Test/MyService/Server.php",'uri'=>'Server.php'));
11
12 //两种调用方式,直接调用方法,和用__soapCall简接调用
13 $result1 = $soap->getName();
14 $result2 = $soap->__soapCall("getName",array());
15 echo $result1."<br/>";
16 echo $result2;
17
18 }catch(SoapFault $e){
19 echo $e->getMessage();
20 }catch(Exception $e){
21 echo $e->getMessage();
22 }
23
24 ?>
WSDL
WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。这种文档可描述某个 Web service。它可规定服务的位置,以及此服务提供的操作(或方法)。
一个 WSDL 文档的主要结构是类似这样的:
03 | definition of types........ |
06 | definition of a message.... |
09 | definition of a port....... |
12 | definition of a binding.... |
WSDL 文档可包含其它的元素,比如 extension 元素,以及一个 service 元素,此元素可把若干个 web services 的定义组合在一个单一的 WSDL 文档中。
PHP生成WSDL
类代码(SoapDiscovery.class.php):
03 | private $class_name = '' ; |
04 | private $service_name = '' ; |
12 | public function __construct( $class_name = '' , $service_name = '' ) { |
13 | $this ->class_name = $class_name ; |
14 | $this ->service_name = $service_name ; |
22 | public function getWSDL() { |
23 | if ( empty ( $this ->service_name)) { |
24 | throw new Exception( 'No service name.' ); |
26 | $headerWSDL = "<?xml version=" 1.0 " ?>n" ; |
27 | $headerWSDL .= "<definitions name=" $this ->service_name " targetNamespace=" urn: $this ->service_name " xmlns:wsdl=" http: |
28 | $headerWSDL .= "<types xmlns=" http: |
30 | if ( empty ( $this ->class_name)) { |
31 | throw new Exception( 'No class name.' ); |
34 | $class = new ReflectionClass( $this ->class_name); |
36 | if (! $class ->isInstantiable()) { |
37 | throw new Exception( 'Class is not instantiable.' ); |
40 | $methods = $class ->getMethods(); |
42 | $portTypeWSDL = '<portType name="' . $this ->service_name. 'Port">' ; |
43 | $bindingWSDL = '<binding name="' . $this ->service_name. 'Binding" type="tns:' . $this ->service_name."Port ">n<soap:binding style=" rpc " transport=" http: |
44 | $serviceWSDL = '<service name="' . $this ->service_name." ">n<documentation />n<port name=" ".$this->service_name.'Port" binding= "tns:'.$this->service_name." Binding "><soap:address location=" http: |
46 | foreach ( $methods as $method ) { |
47 | if ( $method ->isPublic() && ! $method ->isConstructor()) { |
48 | $portTypeWSDL .= '<operation name="' . $method ->getName()." ">n" . '<input message="tns:' . $method ->getName()."Request " />n<output message=" tns: ".$method->getName()." Response " />n</operation>n" ; |
49 | $bindingWSDL .= '<operation name="' . $method ->getName()." ">n" . '<soap:operation soapAction="urn:' . $this ->service_name. '#' . $this ->class_name. '#' . $method ->getName()." " />n<input><soap:body use=" encoded " namespace=" urn: $this ->service_name " encodingStyle=" http: |
50 | $messageWSDL .= '<message name="' . $method ->getName()."Request ">n" ; |
51 | $parameters = $method ->getParameters(); |
52 | foreach ( $parameters as $parameter ) { |
53 | $messageWSDL .= '<part name="' . $parameter ->getName()." " type=" xsd:string " />n" ; |
55 | $messageWSDL .= "</message>n" ; |
56 | $messageWSDL .= '<message name="' . $method ->getName()."Response ">n" ; |
57 | $messageWSDL .= '<part name="' . $method ->getName()." " type=" xsd:string " />n" ; |
58 | $messageWSDL .= "</message>n" ; |
61 | $portTypeWSDL .= "</portType>n" ; |
62 | $bindingWSDL .= "</binding>n" ; |
63 | return sprintf( '%s%s%s%s%s%s' , $headerWSDL , $portTypeWSDL , $bindingWSDL , $serviceWSDL , $messageWSDL , '</definitions>' ); |
71 | public function getDiscovery() { |
72 | return "<?xml version=" 1.0 " ?>n<disco:discovery xmlns:disco=" http: |
使用方法(服务端server.php):
02 | define( 'WSDL_URL' , 'hello.wsdl' ); |
03 | ini_set ( 'soap.wsdl_cache_enabled' , '0' ); |
06 | if (! file_exists (WSDL_URL)) |
08 | require_once 'SoapDiscovery.class.php' ; |
09 | $disco = new SoapDiscovery( 'HelloWorld' , 'IELIWB_HelloWorld' ); |
10 | $str = $disco ->getWSDL(); |
11 | file_put_contents (WSDL_URL, $str ); |
15 | $server = new SoapServer(WSDL_URL); |
16 | $server ->setClass( 'HelloWorld' ); |
23 | public function __construct( $name = 'World' ) { $this ->name = $name ;} |
24 | public function greet( $name = '' ) { $name = $name ? $name : $this ->name; return 'Hello ' . $name . '.' ;} |
25 | public function serverTimestamp() { return time();} |
客户端client.php:
05 | $result = $client ->greet( 'ieliwb' ); |
07 | echo "The answer isresult" ; |
10 | echo "Error Message: {$f->getMessage()}" ; |
创建 Webservice
1. 创建wsdl
- 非标准的webservice,可能只能PHP才能访问
- 标准的webservice,就必须要使用wsdl(webservice description language,就是用XML语法标准来描述你的服务内容,我是这么理解的)
在这里我只介绍标准的webservice。那么如何创建wsdl呢?对于PHP来说这确实是件很不容易的事情,有人说用zend studio创建很方便,这是一种方法。但对于那些不喜欢用zend studio的人来说,会觉得创建一个webservice还要安装zend studio,太强人所难了,我就是,嘿嘿。
在这里我介绍一个简单的方法,到网上下载SoapDiscovery.class.php类,里面有个公用方法:getWSDL,这个方法末尾是用的return,那么,你修改一下这个方法,我是这么做的:
3 | $fso = fopen ( $this ->class_name . ".wsdl" , "w" ); |
4 | fwrite( $fso , sprintf( '%s%s%s%s%s%s' , $headerWSDL , $portTypeWSDL , $bindingWSDL , $serviceWSDL , $messageWSDL , '</definitions>' )); |
现在生成wsdl的类有了,SoapDiscovery.class.php。
我只要再准备一个提供服务的类或者函数就可以创建wsdl了。比如我有个类:person,文件名为:person.class.php★,里面有两个方法,一个是say,一个是run。很简单。
06 | return ( "i'm speaking." ); |
10 | return ( "i'm running,don't disturb me please." ); |
到这里有两个类了:SoapDiscovery.class.php和person.class.php。
开始正式生成wsdl:创建文件server.php。将以下内容拷贝进去,运行即可生成一个person.wsdl文件
2 | include ( "person.class.php" ); |
3 | include ( "SoapDiscovery.class.php" ); |
6 | $disco = new SoapDiscovery( 'person' , 'Person' ); |
2. 创建webservice服务端程序
将server.php文件的内容清空,复制以下代码进去:
2 | include ( "person.class.php" ); |
3 | $objSoapServer = new SoapServer( "person.wsdl" ); |
5 | $objSoapServer ->setClass( "person" ); |
6 | $objSoapServer ->handle(); |
3. 创建webservice客户端程序,测试webservice是否有效,文件名是:client.php
2 | $client = new SoapClient( "person.wsdl" ); |
OK,结束。.NET如果要使用的话,你只要提供一个url给他就行了。
获得url的方法:你可以先到person.wsdl文件里面查找<soap:address location="http://xxxxxxxxxxxxxxxxxxxx/server.php" />,这里的url(具体url是根据你的目录确定的)就是你要提供给.NET开发人员使用的。不过别高兴太早,后面要加:“?wsdl”,http://xxxxxxxxxxxxxxxxxxxx/server.php?wsdl这样才是对的,不信你可以将url拷贝到浏览器的地址栏里看下就知道了。
.NET开发人员获得你给他的url之后,就可以在自己的项目里面添加一个服务引用或者web引用了,然后就可以根据提示完成相关操作,对于使用.NET的开发人员来说很简单的。