公司有一项业务需要,需要计算N多公式,且这些公式频繁变化,但对性能要求不高,于是当时我想到了PHP,毕竟脚本化的语言,改动相当方便。后来又要求别的语言能调,得封成服务。

参照网上教程后发现问题颇多,对于经常写php的自不是难事,但对于我这种只能够依靠语法书敲点php代码的就不行了,于是自己将其中坑洞记下来。

首先php得5.0以上,目前想来应该很少有版本低于这个的了,问题应该不大。

第二步是修改php的配置文件,将php.ini中extension=php_soap.dll和extension=php_openssl.dll前面的;去掉,其中有两点注意

      1.到phpinfo下查看Loaded Configuration File的路径,以此路径的php配置文件为准,不一定是你php目录下的,我当时就是改来改去发现怎么都没效,然后一看phpinfo,居然是用的C盘windows下的配置文件。

   2.只将注释去掉就好,切勿改变顺序,谢谢php治好了我的强迫症,以前都爱将注释的归一块,没注释的归一块,黏贴来黏贴去居然还发现有加载顺序问题。

第三步,网上扒拉过来一个示例代码

 1  <?php  
 2     // 这里用PHP建立一个SOAP服务  
 3     class math{  
 4         public function add($a, $b){  
 5             return $a + $b;  
 6         }  
 7     }  
 8    $service = new SoapServer('math.wsdl', array('soap_version' => SOAP_1_2));
 9    $service->setClass("math"); //! 注册Service类的所有方法  
10    $service->handle(); //! 处理请求  
11     ?>  

这是一个需要wsdl文件的服务端,我们保存下来,命名为math.php,我们此时可以通过工具来生成wsdl文件,不过我不耐去下载,于是找了一个soapdiscovery.class.php的php文件,能帮助生成wsdl文件,源代码见下

  1     <pre name="code" class="php"><?php  
  2         
  3     /**  
  4      * Copyright (c) 2005, Braulio José Solano Rojas  
  5      * All rights reserved.  
  6      *   
  7      * Redistribution and use in source and binary forms, with or without modification, are  
  8      * permitted provided that the following conditions are met:  
  9      *   
 10      *  Redistributions of source code must retain the above copyright notice, this list of  
 11      *  conditions and the following disclaimer.   
 12      *  Redistributions in binary form must reproduce the above copyright notice, this list of  
 13      *  conditions and the following disclaimer in the documentation and/or other materials  
 14      *  provided with the distribution.   
 15      *  Neither the name of the Solsoft de Costa Rica S.A. nor the names of its contributors may  
 16      *  be used to endorse or promote products derived from this software without specific  
 17      *  prior written permission.  
 18      *   
 19      * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  
 20      * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
 21      * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  
 22      * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
 23      * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
 24      * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
 25      * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  
 26      * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  
 27      * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
 28      * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
 29      * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
 30      * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
 31      * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 32      *   
 33      *  
 34      * @version $Id$  
 35      * @copyright 2005   
 36      */  
 37       
 38     /**  
 39      * SoapDiscovery Class that provides Web Service Definition Language (WSDL).  
 40      *   
 41      * @package SoapDiscovery  
 42      * @author Braulio José Solano Rojas  
 43      * @copyright Copyright (c) 2005 Braulio José Solano Rojas  
 44      * @version $Id$  
 45      * @access public  
 46      **/  
 47     class SoapDiscovery {  
 48         private $class_name = '';  
 49         private $service_name = '';  
 50           
 51         /**  
 52          * SoapDiscovery::__construct() SoapDiscovery class Constructor.  
 53          *   
 54          * @param string $class_name  
 55          * @param string $service_name  
 56          **/  
 57         public function __construct($class_name = '', $service_name = '') {  
 58             $this->class_name = $class_name;  
 59             $this->service_name = $service_name;  
 60         }  
 61           
 62         /**  
 63          * SoapDiscovery::getWSDL() Returns the WSDL of a class if the class is instantiable.  
 64          *   
 65          * @return string  
 66          **/  
 67         public function getWSDL() {  
 68             if (empty($this->service_name)) {  
 69                 throw new Exception('No service name.');  
 70             }  
 71             $headerWSDL = "<?xml version=\"1.0\" ?>\n";  
 72             $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";  
 73             $headerWSDL.= "<types xmlns=\"http://schemas.xmlsoap.org/wsdl/\" />\n";  
 74       
 75             if (empty($this->class_name)) {  
 76                 throw new Exception('No class name.');  
 77             }  
 78               
 79             $class = new ReflectionClass($this->class_name);  
 80               
 81             if (!$class->isInstantiable()) {  
 82                 throw new Exception('Class is not instantiable.');  
 83             }  
 84               
 85             $methods = $class->getMethods();  
 86               
 87             $portTypeWSDL = '<portType name="'.$this->service_name.'Port">';  
 88             $bindingWSDL = '<binding name="'.$this->service_name.'Binding" type="tns:'.$this->service_name."Port\">\n<soap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\" />\n";  
 89             $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";  
 90             $messageWSDL = '';  
 91             foreach ($methods as $method) {  
 92                 if ($method->isPublic() && !$method->isConstructor()) {  
 93                     $portTypeWSDL.= '<operation name="'.$method->getName()."\">\n".'<input message="tns:'.$method->getName()."Request\" />\n<output message=\"tns:".$method->getName()."Response\" />\n</operation>\n";  
 94                     $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://schemas.xmlsoap.org/soap/encoding/\" />\n</input>\n<output>\n<soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</output>\n</operation>\n";  
 95                     $messageWSDL.= '<message name="'.$method->getName()."Request\">\n";  
 96                     $parameters = $method->getParameters();  
 97                     foreach ($parameters as $parameter) {  
 98                         $messageWSDL.= '<part name="'.$parameter->getName()."\" type=\"xsd:string\" />\n";  
 99                     }  
100                     $messageWSDL.= "</message>\n";  
101                     $messageWSDL.= '<message name="'.$method->getName()."Response\">\n";  
102                     $messageWSDL.= '<part name="'.$method->getName()."\" type=\"xsd:string\" />\n";  
103                     $messageWSDL.= "</message>\n";  
104                 }  
105             }  
106             $portTypeWSDL.= "</portType>\n";  
107             $bindingWSDL.= "</binding>\n";  
108             //return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>');  
109             $fso = fopen($this->class_name . ".wsdl" , "w");   
110             fwrite($fso, sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'));   
111         }  
112           
113         /**  
114          * SoapDiscovery::getDiscovery() Returns discovery of WSDL.  
115          *   
116          * @return string  
117          **/  
118         public function getDiscovery() {  
119             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>";  
120         }  
121     }  
122       
123     ?>  

此时,我们需要在同级目录下写个调用php以生成wsdl文件,该文件我们命名为create_wsdl.php

1 <?php
2 include_once('math.php');
3 include_once('SoapDiscovery.class.php');
4 $wsdl=new SoapDiscovery('math','soap');
5 $wsdl->getWSDL();
6 ?>

在运行create_wsdl.php之前请下注释掉math.php中new server和调用的代码

 //$service = new SoapServer('math.wsdl', array('soap_version' => SOAP_1_2));
 //$service->setClass("math"); //! 注册Service类的所有方法   
//$service->handle(); //! 处理请求

访问这个页面,于是就生成wsdl文件,随后将math.php中三行代码放开注释。

最后打开wsdl文件,修改soap地址,即完成服务

soap:address location="http://127.0.0.1:80/math.php"

写到这,php调用已经可以了,不过如果其他语言调用你会发现所有的输入参数都是字符串。

自然,类似C#等语言你任意数据类型可以.ToSting()来转换,但却说不出的恶心,手工一个个去改WSDL里类型又太烦。

  1     <pre name="code" class="php"><?php  
  2         
  3     /**  
  4      * Copyright (c) 2005, Braulio José Solano Rojas  
  5      * All rights reserved.  
  6      *   
  7      * Redistribution and use in source and binary forms, with or without modification, are  
  8      * permitted provided that the following conditions are met:  
  9      *   
 10      *  Redistributions of source code must retain the above copyright notice, this list of  
 11      *  conditions and the following disclaimer.   
 12      *  Redistributions in binary form must reproduce the above copyright notice, this list of  
 13      *  conditions and the following disclaimer in the documentation and/or other materials  
 14      *  provided with the distribution.   
 15      *  Neither the name of the Solsoft de Costa Rica S.A. nor the names of its contributors may  
 16      *  be used to endorse or promote products derived from this software without specific  
 17      *  prior written permission.  
 18      *   
 19      * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  
 20      * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  
 21      * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  
 22      * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
 23      * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
 24      * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  
 25      * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  
 26      * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  
 27      * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
 28      * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
 29      * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
 30      * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
 31      * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 32      *   
 33      *  
 34      * @version $Id$  
 35      * @copyright 2005   
 36      */  
 37       
 38     /**  
 39      * SoapDiscovery Class that provides Web Service Definition Language (WSDL).  
 40      *   
 41      * @package SoapDiscovery  
 42      * @author Braulio José Solano Rojas  
 43      * @copyright Copyright (c) 2005 Braulio José Solano Rojas  
 44      * @version $Id$  
 45      * @access public  
 46      **/  
 47     class SoapDiscovery {  
 48         private $class_name = '';  
 49         private $service_name = '';  
 50           
 51         /**  
 52          * SoapDiscovery::__construct() SoapDiscovery class Constructor.  
 53          *   
 54          * @param string $class_name  
 55          * @param string $service_name  
 56          **/  
 57         public function __construct($class_name = '', $service_name = '') {  
 58             $this->class_name = $class_name;  
 59             $this->service_name = $service_name;  
 60         }  
 61           
 62         /**  
 63          * SoapDiscovery::getWSDL() Returns the WSDL of a class if the class is instantiable.  
 64          *   
 65          * @return string  
 66          **/  
 67         public function getWSDL($desdir,$desphp) {  
 68             if (empty($this->service_name)) {  
 69                 throw new Exception('No service name.');  
 70             }  
 71             $headerWSDL = "<?xml version=\"1.0\" ?>\n";  
 72             $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";  
 73             $headerWSDL.= "<types xmlns=\"http://schemas.xmlsoap.org/wsdl/\" />\n";  
 74       
 75             if (empty($this->class_name)) {  
 76                 throw new Exception('No class name.');  
 77             }  
 78               
 79             $class = new ReflectionClass($this->class_name);  
 80               
 81             if (!$class->isInstantiable()) {  
 82                 throw new Exception('Class is not instantiable.');  
 83             }  
 84               
 85             $methods = $class->getMethods();  
 86               
 87             $portTypeWSDL = '<portType name="'.$this->service_name.'Port">';  
 88             $bindingWSDL = '<binding name="'.$this->service_name.'Binding" type="tns:'.$this->service_name."Port\">\n<soap:binding style=\"rpc\" transport=\"http://schemas.xmlsoap.org/soap/http\" />\n";  
 89             $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']."/".$desdir."/".$desphp.".php\" />\n</port>\n</service>\n";  
 90             $messageWSDL = '';  
 91             foreach ($methods as $method) {  
 92                 if ($method->isPublic() && !$method->isConstructor()) {  
 93                     $portTypeWSDL.= '<operation name="'.$method->getName()."\">\n".'<input message="tns:'.$method->getName()."Request\" />\n<output message=\"tns:".$method->getName()."Response\" />\n</operation>\n";  
 94                     $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://schemas.xmlsoap.org/soap/encoding/\" />\n</input>\n<output>\n<soap:body use=\"encoded\" namespace=\"urn:$this->service_name\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" />\n</output>\n</operation>\n";  
 95                     $messageWSDL.= '<message name="'.$method->getName()."Request\">\n";  
 96                     $parameters = $method->getParameters();  
 97                     foreach ($parameters as $parameter) {
 98             if(strlen(strpos($parameter->getName(),"dbVal")) > 0)
 99                           $messageWSDL.= '<part name="'.$parameter->getName()."\" type=\"xsd:double\" />\n";  
100                         else if(strlen(strpos($parameter->getName(),"intVal")) > 0)
101                           $messageWSDL.= '<part name="'.$parameter->getName()."\" type=\"xsd:integer\" />\n"; 
102                         else
103                           $messageWSDL.= '<part name="'.$parameter->getName()."\" type=\"xsd:string\" />\n";                          
104                     }  
105                     $messageWSDL.= "</message>\n";  
106                     $messageWSDL.= '<message name="'.$method->getName()."Response\">\n";  
107                     if(strlen(strpos($method->getName(),"_Int")) > 0)
108                       $messageWSDL.= '<part name="'.$method->getName()."\" type=\"xsd:integer\" />\n"; 
109                     else if(strlen(strpos($method->getName(),"_Double")) > 0)
110                       $messageWSDL.= '<part name="'.$method->getName()."\" type=\"xsd:double\" />\n";
111             else
112                       $messageWSDL.= '<part name="'.$method->getName()."\" type=\"xsd:string\" />\n";  
113                     $messageWSDL.= "</message>\n";  
114                 }  
115             }  
116             $portTypeWSDL.= "</portType>\n";  
117             $bindingWSDL.= "</binding>\n";  
118             //return sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>');  
119             $fso = fopen($desphp . ".wsdl" , "w");   
120             fwrite($fso, sprintf('%s%s%s%s%s%s', $headerWSDL, $portTypeWSDL, $bindingWSDL, $serviceWSDL, $messageWSDL, '</definitions>'));   
121         }  
122           
123         /**  
124          * SoapDiscovery::getDiscovery() Returns discovery of WSDL.  
125          *   
126          * @return string  
127          **/  
128         public function getDiscovery() {  
129             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>";  
130         }  
131     }  
132       
133     ?>  

 

于是我把SoapDiscovery.class.php自己稍微改吧了下,大致是只要按一定命名规范来,

1 public function CalcTest_Double($intValA,$intValB){
2           try{
3                //$total = "TestOK";
4              return $intValA + $intValB;
5           }
6           catch (SoapFault $fault){
7           ErrorReporter("CalcTest",$fault->faultcode,$fault->faultstring);
8           }
9     }

这样就能识别出该服务是返回double,输入两个int的服务,另前面类名必须与php文件名一致,不然得改生成的wsdl名,我也改吧了下,输入两个参数,第一个参数是多级目录路径,

如只在www下(我装的appserv),就传空字符串即可

$wsdl->getWSDL("","math");

 

,如此,简单用用是凑合了,不过毕竟不是写php的,希望有大牛以后能完善下这个自动化类。

 

posted on 2018-01-16 11:30  xuddk727  阅读(663)  评论(0编辑  收藏  举报