PHP使用WSDL解决SOAP通信

一、前言

    最近在搞一个接口数据对接的项目,是采用Webservice进行数据对接。因之前一直采用视图、JSON或proto的方式对接,但是对webservice不太了解,所以通过这个项目把自己对webservice的理解总结记录下来。

二、基本概念

1. WebService

    webservice就是字面意思:web + service,也就是 服务(service)网络(web)化的意思。他力求的是跨语言,跨平台的,基于web传输的远程调用能力。他没有强调远程调用使用什么协议,所以你可以自由选择,比如soap 协议(可与基于http,smtp,等各种传输协议),或者常见的基于http的json化的数据传输协议,基于dubbo协议的dubbo服务调用都属于web service的一种实现。【XML Web services 概述】

2. SOAP

    soap是简单对象访问协议的缩写,是一种可以基于HTTP协议的访问方式。客户端发送请求,然后调用带参数的服务端函数得到服务端的数据;服务端编写处理函数并响应客户端。

3. WSDL

    wsdl是网络服务者动态语言的缩写,这里面定义了双方通信时包含的东西。客户端把wsdl文件给服务端,服务端分析wsdl并写出里面的函数,这样两者无论是什么平台、什么语言都可以通信。

    理解wsdl的网站:【Web Service描述语言 WSDL 详解】【描述 Web 服务:WSDL】

    运行实例网站:【在PHP中利用wsdl创建标准webservice】

    借鉴网站:【PHP使用WSDL格式Soap通信】

一个 WSDL 协议实例描述五项内容:
1. types,Web 服务接口的数据类型(其参数和返回类型)。
2. message,将数据类型变量分组以进行网络传输。
3. portType,将消息分组成逻辑操作。
4. binding,描述如何将 portType 映射成传输/消息传递协议。
5. service,列出某个特定绑定的连接信息。

以下为个人阅读WSDL文档的总结:
1. types的子元素complexType元素的name属性值为数组变量名, 子元素element的name属性值为数组变量名的键名;
2. message元素的name属性值为函数方法名,子元素part的type属性值为方法的形参变量名(变量名的定义在types中),name数据值为任意值,但在当前Message中是唯一的;
3. portType元素的子元素operation定义了方法名, operation元素的属性name值即为方法名称;
4. binging元素的name属性值与portType元素的属性name值一致。binging元素的子元素soap:binging用于创建绑定,用于绑定portType元素的所有子元素operation;
5. service元素的属性name值与WSDL根元素definitions的属性name值一致。service元素的子元素port的属性binging值与第四条bingding元素属性name值一致。

WSDL文档整体定义顺序按:函数内变量数据类型 → 函数方法及形参 → 类文件所有函数名 → 绑定类文件所有函数名 → 后台接口

三、本地测试

注:本地测试的四个文件EvaluateReport.wsdl、client.php、server.php、EvaluateReport.php 都放在WSDL目录下,配置域名www.adata.com【域名需做映射,访问127.0.0.1】跟路径指向WSDL的上级目录即可。

1. EvaluateReport.wsdl

<?xml version='1.0' encoding='utf-8'?>
<wsdl:definitions name="ServiceEvaluateWebServiceImplService" 
  targetNamespace="http://www.robdchina.com" 
  xmlns:ns1="http://schemas.xmlsoap.org/soap/http" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="http://www.robdchina.com" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  
  <!-- types中定义了函数使用的变量及数据类型 -->
  <wsdl:types>
  <xs:schema targetNamespace="http://www.robdchina.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <!-- 定义一个数组返回值变量returnData -->
    <xs:complexType name="returnData">
      <xs:sequence>
        <xs:element minOccurs="0" name="INFO" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="STATUS" type="xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>
    <!-- 定义一个数组变量variableNameOne -->
    <xs:complexType name="variableNameOne">
      <xs:sequence>
        <xs:element minOccurs="0" name="KEYONE" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="KEYTWO" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="KEYTHREE" type="xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>
    <!-- 定义一个数组变量variableNameTwo -->
    <xs:complexType name="variableNameTwo">
      <xs:sequence>
        <xs:element minOccurs="0" name="KEYONE" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="KEYTWO" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="KEYTHREE" type="xs:string"></xs:element>
        <xs:element minOccurs="0" name="KEYFOUR" type="xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>
    
    <xs:simpleType name="emailAddress">
      <xs:restriction base="xs:string">
        <xs:pattern value=".+@.+"/>
      </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="number">
      <xs:restriction base="xs:int">
        <xs:pattern value="\d+" />
      </xs:restriction>
    </xs:simpleType>
    <!-- 定义一个数组变量variableNameThree -->
    <xs:complexType name="variableNameThree">
      <xs:complexContent>
        <xs:extension base="tns:variableNameTwo">
          <xs:sequence>
            <xs:element name="KEYFIVE" type="tns:emailAddress"/>
            <xs:element name="KEYSIX" type="tns:number"/>
          </xs:sequence>
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>

    <!-- 定义一个异常变量Exception -->
    <xs:element name="Exception" type="tns:Exception"></xs:element>
    <xs:complexType name="Exception">
      <xs:sequence>
        <xs:element minOccurs="0" name="message" type="xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>

  </xs:schema>
  </wsdl:types>

  <!-- message定义类文件使用的方法名 -->
  <wsdl:message name="functionNameOne">
    <wsdl:part name="VariableNameOne" type="tns:variableNameOne">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="functionNameOneResponse">
    <wsdl:part name="return" type="tns:returnData">
    </wsdl:part>
  </wsdl:message>

  <wsdl:message name="functionNameTwo">
    <wsdl:part name="VariableNameTwo" type="tns:variableNameTwo">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="functionNameTwoResponse">
    <wsdl:part name="return" type="tns:returnData">
    </wsdl:part>
  </wsdl:message>

  <wsdl:message name="functionNameThree">
    <wsdl:part name="VariableNameThree" type="tns:variableNameThree">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="functionNameThreeResponse">
    <wsdl:part name="return" type="tns:returnData">
    </wsdl:part>
  </wsdl:message>

  <wsdl:message name="Exception">
    <wsdl:part element="tns:Exception" name="Exception">
    </wsdl:part>
  </wsdl:message>

  <!-- protType将message中的方法名做成逻辑操作 -->
  <wsdl:portType name="RobotWebService">
    <wsdl:operation name="functionNameOne">
      <wsdl:input message="tns:functionNameOne" name="functionNameOne"></wsdl:input>
      <wsdl:output message="tns:functionNameOneResponse" name="functionNameOneResponse"></wsdl:output>
      <wsdl:fault message="tns:Exception" name="Exception"></wsdl:fault>
    </wsdl:operation>

    <wsdl:operation name="functionNameTwo">
      <wsdl:input message="tns:functionNameTwo" name="functionNameTwo"></wsdl:input>
      <wsdl:output message="tns:functionNameTwoResponse" name="functionNameTwoResponse"></wsdl:output>
      <wsdl:fault message="tns:Exception" name="Exception"></wsdl:fault>
    </wsdl:operation>

    <wsdl:operation name="functionNameThree">
      <wsdl:input message="tns:functionNameThree" name="functionNameThree"></wsdl:input>
      <wsdl:output message="tns:functionNameThreeResponse" name="functionNameThreeResponse"></wsdl:output>
      <wsdl:fault message="tns:Exception" name="Exception"></wsdl:fault>
    </wsdl:operation>
  </wsdl:portType>

  <!-- bingding描述如何将portType 映射成传输/消息传递协议 -->
  <wsdl:binding name="EvaluateWebServiceSoapBinding" type="tns:RobotWebService">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"></soap:binding> 
    <wsdl:operation name="functionNameOne">
      <soap:operation soapAction="" style="rpc"></soap:operation>
      <wsdl:input name="functionNameOne">
        <soap:body namespace="http://www.robdchina.com" use="literal"></soap:body>
      </wsdl:input>
      <wsdl:output name="functionNameOneResponse">
        <soap:body namespace="http://www.robdchina.com" use="literal"></soap:body>
      </wsdl:output>
      <wsdl:fault name="Exception">
        <soap:fault name="Exception" use="literal"></soap:fault>
      </wsdl:fault>
    </wsdl:operation>

    <wsdl:operation name="functionNameTwo">
      <soap:operation soapAction="" style="rpc"></soap:operation>
      <wsdl:input name="functionNameTwo"><soap:body namespace="http://www.robdchina.com" use="literal"></soap:body></wsdl:input>
      <wsdl:output name="functionNameTwoResponse"><soap:body namespace="http://www.robdchina.com" use="literal"></soap:body></wsdl:output>
      <wsdl:fault name="Exception"><soap:fault name="Exception" use="literal"></soap:fault></wsdl:fault>
    </wsdl:operation>

    <wsdl:operation name="functionNameThree">
      <soap:operation soapAction="" style="rpc"></soap:operation>
      <wsdl:input name="functionNameThree"><soap:body namespace="http://www.robdchina.com" use="literal"></soap:body></wsdl:input>
      <wsdl:output name="functionNameThreeResponse"><soap:body namespace="http://www.robdchina.com" use="literal"></soap:body></wsdl:output>
      <wsdl:fault name="Exception"><soap:fault name="Exception" use="literal"></soap:fault></wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>

  <!-- service列出某个特定绑定的连接信息 -->
  <wsdl:service name="ServiceEvaluateWebServiceImplService">
    <wsdl:port binding="tns:EvaluateWebServiceSoapBinding" name="EvaluateWebServiceImplPort">
      <!-- location为后台要调用的接口 -->
      <soap:address location="http://www.adata.com:80/WSDL/server.php"></soap:address>
    </wsdl:port>
  </wsdl:service>

</wsdl:definitions>

2. 客户端client.php

<?php 
$client = new SoapClient("EvaluateReport.wsdl", array(
	'trace' => 1,
	'cache_wsdl' => WSDL_CACHE_NONE
));

try {
    //打印暴露的方法
    echo "<pre>";
    print_r($client->__getFunctions());
    echo "</pre>";
    //打印对应方法的参数和参数类型
    echo "<pre>";
    print_r($client->__getTypes());
    echo "</pre>";

    echo "<hr>";
    ///调用第一个类方法functionNameOne//
    $arrParams = [
    	'KEYONE'   => '第一个键值',
    	'KEYTWO'   => '第二个键值',
    	'KEYTHREE' => '第三个键值',
    ];
    //第一种调用方法
    $arrResultOne = $client->__soapCall('functionNameOne', [$arrParams]);
    //第二种调用方法
    //$arrResultOne = $client->receiveTaskResult($arrParams);
    echo "<pre>";
    print_r($arrResultOne);
    echo "</pre>";

    echo "<hr>";
    ///调用第二个类方法functionNameTwo//
    $arrParams = [
    	'KEYONE'   => '第一个键值',
    	'KEYTWO'   => '第二个键值',
    	'KEYTHREE' => '第三个键值',
    	'KEYFOUR'  => '第四个键值',
    ];
    $arrResultTwo = $client->__soapCall('functionNameTwo', [$arrParams]);
    echo "<pre>";
    print_r($arrResultTwo);
    echo "</pre>";

    ///调用第三个类方法functionNameThree//
    $arrParams = [
        /*'KEYONE'   => '第一个键值',
        'KEYTWO'   => '第二个键值',
        'KEYTHREE' => '第三个键值',
        'KEYFOUR'  => '第四个键值',*/
        'KEYFIVE'  => '第五个键值',
        'KEYSIX'   => '第六个键值',
    ];
    $arrResultThree = $client->__soapCall('functionNameThree', [$arrParams]);
    echo "<pre>";
    print_r($arrResultThree);
    echo "</pre>";

}catch (SoapFault $f){
    echo "Error Message: {$f->getMessage()}";
    //問題1:Error Message: Procedure 'functionNameThree' not present
    //解決方法:將server的tmp目錄下的wsdl文件刪除
}

3. 服务端server.php

<?php 
require_once 'EvaluateReport.php';

$servidorSoap = new SoapServer("EvaluateReport.wsdl");
$servidorSoap->setClass('EvaluateReport');
$servidorSoap->handle();

4. 类文件EvaluateReport.php

<?php 

class EvaluateReport
{
	private $returnData = [
		'INFO' => 'info',
		'STATUS' => 'status',
	];

	private $exception = 'exception msg';

	public function __construct()
	{

	}

	/**
	 *  第一个类方法
	 *  @access public
	 *  @author GPS
	 *  @param
	 *  @return
	 *  @time   2018-05-09
	 */
	public function functionNameOne($variableNameOne)
	{
		foreach ($variableNameOne as $key => $item) {
			file_put_contents(__DIR__ . "/WSDL.txt", $key . '--'.$item.PHP_EOL, FILE_APPEND);
		}
		$jsonData = json_encode($variableNameOne, JSON_UNESCAPED_UNICODE);
		file_put_contents(__DIR__ . "/WSDL.txt", time().PHP_EOL, FILE_APPEND);

		return $returnData = [
			'INFO' => $jsonData,
			'STATUS' => 'status',
		];
	}

	/**
	 *  第二个类方法
	 *  @access public
	 *  @author GPS
	 *  @param
	 *  @return
	 *  @time   2018-05-09
	 */
	public function functionNameTwo($variableNameTwo)
	{
		foreach ($variableNameTwo as $key => $item) {
			file_put_contents(__DIR__ . "/WSDL.txt", $key . '--'.$item.PHP_EOL, FILE_APPEND);
		}
		$jsonData = json_encode($variableNameTwo, JSON_UNESCAPED_UNICODE);
		file_put_contents(__DIR__ . "/WSDL.txt", time().PHP_EOL, FILE_APPEND);

		return $returnData = [
			'INFO' => $jsonData,
			'STATUS' => 'status',
		];
	}

	/**
	 *  第三个类方法
	 *  @access public
	 *  @author GPS
	 *  @param
	 *  @return
	 *  @time   2018-05-09
	 */
	public function functionNameThree($variableNameThree)
	{
		foreach ($variableNameThree as $key => $item) {
			file_put_contents(__DIR__ . "/WSDL.txt", $key . '--'.$item.PHP_EOL, FILE_APPEND);
		}
		$jsonData = json_encode($variableNameThree, JSON_UNESCAPED_UNICODE);
		file_put_contents(__DIR__ . "/WSDL.txt", time().PHP_EOL, FILE_APPEND);

		return $returnData = [
			'INFO' => $jsonData,
			'STATUS' => 'status',
		];
	}

	public function Exception($exception)
	{
		return $this->exception;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值