WSDL(網絡服務描述語言,Web Services Description Language)是一門基於 XML 的語言,用於描述 Web Services 以及如何對它們進行訪問。這種文檔可描述某個 Web service。它可規定服務的位置,以及此服務提供的操作(或方法)。
一個 WSDL 文檔的主要結構是類似這樣的:
<definitions> <types> definition of types........ </types> <message> definition of a message.... </message> <portType> definition of a port....... </portType> <binding> definition of a binding.... </binding> </definitions>
WSDL 文檔可包含其它的元素,比如 extension 元素,以及一個 service 元素,此元素可把若干個 web services 的定義組合在一個單一的 WSDL 文檔中。
類代碼(SoapDiscovery.class.php):
<?php class SoapDiscovery { private $class_name = ''; private $service_name = ''; /** * SoapDiscovery::__construct() SoapDiscovery class Constructor. * * @param string $class_name * @param string $service_name **/ public function __construct($class_name = '', $service_name = '') { $this->class_name = $class_name; $this->service_name = $service_name; } /** * SoapDiscovery::getWSDL() Returns the WSDL of a class if the class is instantiable. * * @return string **/ public function getWSDL() { if (empty($this->service_name)) { throw new Exception('No service name.'); } $headerWSDL = "<?xml version="1.0" ?>n"; $headerWSDL.= "<definitions name="$this->service_name" targetNamespace="urn:$this->service_name" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="urn:$this->service_name" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/">n"; $headerWSDL.= "<types xmlns="http://schemas.xmlsoap.org/wsdl/" />n"; if (empty($this->class_name)) { throw new Exception('No class name.'); } $class = new ReflectionClass($this->class_name); if (!$class->isInstantiable()) { throw new Exception('Class is not instantiable.'); } $methods = $class->getMethods(); $portTypeWSDL = '<portType name="'.$this->service_name.'Port">'; $bindingWSDL = '<binding name="'.$this->service_name.'Binding" type="tns:'.$this->service_name."Port">n<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />n"; $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://".$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['PHP_SELF']."" />n</port>n</service>n"; $messageWSDL = ''; foreach ($methods as $method) { if ($method->isPublic() && !$method->isConstructor()) { $portTypeWSDL.= '<operation name="'.$method->getName()."">n".'<input message="tns:'.$method->getName()."Request" />n<output message="tns:".$method->getName()."Response" />n</operation>n"; $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" encoding />n</input>n<output>n<soap:body use="encoded" namespace="urn:$this->service_name" encoding />n</output>n</operation>n"; $messageWSDL.= '<message name="'.$method->getName()."Request">n"; $parameters = $method->getParameters(); foreach ($parameters as $parameter) { $messageWSDL.= '<part name="'.$parameter->getName()."" type="xsd:string" />n"; } $messageWSDL.= "</message>n"; $messageWSDL.= '<message name="'.$method->getName()."Response">n"; $messageWSDL.= '<part name="'.$method->getName()."" type="xsd:string" />n"; $messageWSDL.= "</message>n"; } } $portTypeWSDL.= "</portType>n"; $bindingWSDL.= "</binding>n"; return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'); } /** * SoapDiscovery::getDiscovery() Returns discovery of WSDL. * * @return string **/ public function getDiscovery() { return "<?xml version="1.0" ?>n<disco:discovery xmlns:disco="http://schemas.xmlsoap.org/disco/" xmlns:scl="http://schemas.xmlsoap.org/disco/scl/">n<scl:contractRef ref="http://".$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['PHP_SELF']."?wsdl" />n</disco:discovery>"; } } ?>
使用方法(服務端server.php):
<?php define('WSDL_URL','hello.wsdl'); //定義WSDL文件路徑 ini_set('soap.wsdl_cache_enabled','0'); //關閉WSDL緩存 //WSDL文件不存在時自動創建 if(!file_exists(WSDL_URL)) { require_once 'SoapDiscovery.class.php'; $disco = new SoapDiscovery('HelloWorld','IELIWB_HelloWorld'); $str = $disco->getWSDL(); file_put_contents(WSDL_URL,$str); } //SOAP開啟並接收Client傳入的參數響應 $server = new SoapServer(WSDL_URL); $server->setClass('HelloWorld'); $server->handle(); //測試定義公開的類 class HelloWorld { private $nombre = ''; public function __construct($name = 'World') {$this->name = $name;} public function greet($name = '') {$name = $name?$name:$this->name;return 'Hello '.$name.'.';} public function serverTimestamp() {return time();} } ?>
客戶端client.php:
<?php $client = new SoapClient("http://127.0.0.1/createsoap/hello.wsdl"); try { $result = $client->greet('ieliwb'); var_dump($result); echo "The answer isresult"; } catch (SoapFault $f){ echo "Error Message: {$f->getMessage()}"; } ?>
1. 創建wsdl
在這裡我只介紹標准的webservice。那麼如何創建wsdl呢?對於PHP來說這確實是件很不容易的事情,有人說用zend studio創建很方便,這是一種方法。但對於那些不喜歡用zend studio的人來說,會覺得創建一個webservice還要安裝zend studio,太強人所難了,我就是,嘿嘿。
在這裡我介紹一個簡單的方法,到網上下載SoapDiscovery.class.php類,裡面有個公用方法:getWSDL,這個方法末尾是用的return,那麼,你修改一下這個方法,我是這麼做的:
//return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'); //生成wsdl文件,將上面的return注釋 $fso = fopen($this->class_name . ".wsdl" , "w"); 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。很簡單。
<?php class person { public function say() { return("i'm speaking."); } public function run() { return("i'm running,don't disturb me please."); } } ?>
到這裡有兩個類了:SoapDiscovery.class.php和person.class.php。
開始正式生成wsdl:創建文件server.php。將以下內容拷貝進去,運行即可生成一個person.wsdl文件
<?php include("person.class.php"); include("SoapDiscovery.class.php"); //第一個參數是類名(生成的wsdl文件就是以它來命名的),即person類,第二個參數是服務的名字(這個可以隨便寫)。 $disco = new SoapDiscovery('person','Person'); $disco->getWSDL(); ?>
2. 創建webservice服務端程序
將server.php文件的內容清空,復制以下代碼進去:
<?php include("person.class.php"); $objSoapServer = new SoapServer("person.wsdl");//person.wsdl是剛創建的wsdl文件 //$objSoapServer = new SoapServer("server.php?wsdl");//這樣也行 $objSoapServer->setClass("person");//注冊person類的所有方法 $objSoapServer->handle();//處理請求 ?>
3. 創建webservice客戶端程序,測試webservice是否有效,文件名是:client.php
<?php $client = new SoapClient("person.wsdl"); //$client = new SoapClient("server.php?wsdl");//這樣也行 echo($client->say()); echo "<br />"; echo($client->run()); echo "<br />"; ?>
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的開發人員來說很簡單的。