PHP SOAP实践

我现在公司里的系统都是SOA/面向服务架构的,用Java编写的Web Service,理论上Web Service支持异构语言的,我想测试一下用PHP来调用Java的Web Service是否方便。

首先用Java建立一个Web Service服务端(用CXF,JAX-WS实现),下面是公布出来的WSDL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="SampleWebService" targetNamespace="http://www.abc.net/WS/2008" xmlns:ns1="http://webservice.passport.abc.net/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.abc.net/WS/2008" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:import location="http://192.168.19.42:8080/sample/service/SampleWebService?wsdl=SampleWebService.wsdl" namespace="http://webservice.passport.abc.net/">
    </wsdl:import>
  <wsdl:message name="helloUser">
    <wsdl:part element="ns1:helloUser" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="helloUserResponse">
    <wsdl:part element="ns1:helloUserResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:binding name="SampleWebServiceSoapBinding" type="ns1:SampleWebService">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="helloUser">
      <soap:operation soapAction="" style="document" />
      <wsdl:input name="helloUser">
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output name="helloUserResponse">
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="SampleWebService">
    <wsdl:port binding="tns:SampleWebServiceSoapBinding" name="SampleWebServicePort">
      <soap:address location="http://192.168.19.42:8080/sample/service/SampleWebService" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

这个Web Service有个“helloUser”方法,传入一个参数,它返回一段文本“Hello 参数!”,

PHP5之后已经加入了SOAP的支持,我最开始用PHP5的SOAP函数来调用,下面是代码

1
2
$client = new SoapClient('http://192.168.19.42:8080/sample/service/SampleWebService?wsdl');
var_dump($client->__getFunctions());

但报错Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: <message> ‘helloUser’ already defined in …,我搜了PHP网站上的相关文档也没找到答案,没办法,我只能找其他SOAP的组件,找到了NuSOAP,它最近发布的版本是0.7.3,是在2007年发布的,现在已经2009了,用用试试吧,参考nusoap的例子,写好自己代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require_once('nusoap.php');
$client = new nusoap_client('http://192.168.19.42:8080/sample/service/SampleWebService?wsdl', 'wsdl');
$err = $client->getError();
if ($err) {
	echo '<h2>Constructor error</h2><p>' . $err . '</p>';
}
$param = array('arg0'=>'laoer');
$result = $client->call('helloUser', array('parameters' => $param),"http://webservice.passport.abc.net/",'', false, false,"document","literal");
 
if ($client->fault) {
	echo '<h2>Fault</h2><p>';
	print_r($result);
	echo '</p>';
} else {
	// Check for errors
	$err = $client->getError();
	if ($err) {
		// Display the error
		echo '<h2>Error</h2><p>' . $err . '</p>';
	} else {
		// Display the result
		echo '<h2>Result</h2><p>';
		//print_r($result);
		echo $result["return"];
		echo '</p>';
	}
}
 
echo '<h2>Request</h2><p>' . htmlspecialchars($client->request, ENT_QUOTES) . '</p>';
echo '<h2>Response</h2><p>' . htmlspecialchars($client->response, ENT_QUOTES) . '</p>';

执行结果

Result
Hello laoer!

Request
POST /sample/service/SampleWebService HTTP/1.0
Host: 192.168.19.42:8080
User-Agent: NuSOAP/0.7.3 (1.114)
Content-Type: text/xml; charset=UTF-8
SOAPAction: “”
Content-Length: 436

我们可以看到Request的SOAP文本

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://webservice.passport.abc.net/">
	<SOAP-ENV:Body>
		<helloUser xmlns="">
			<arg0 xmlns="">laoer</arg0>
		</helloUser>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Response
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
SOAPAction: “”
Content-Type: text/xml;charset=UTF-8
Content-Length: 237
Date: Fri, 27 Mar 2009 04:27:11 GMT
Connection: close

Response的SOAP文本

1
2
3
4
5
6
7
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
	<soap:Body>
		<ns2:helloUserResponse xmlns:ns2="http://webservice.passport.abc.net/">
			<return>Hello laoer!</return>
		</ns2:helloUserResponse>
	</soap:Body>
</soap:Envelope>

碰到一个小问题就是PHP给方法传参数,看是我不知道怎么填,后来我用soapUI,做了一个SOAP Request的例子,发现参数的Name是arg0,如果是多个参数,则arg0、arg1、arg2…以此类推,所以我们定义的参数是$param = array(‘arg0’=>’laoer’),还有就是nusoap里对返回信息的编码有点问题,如果你Web Service放回的编码是UTF-8,则nusoap多转换了一次,在nusoap.php文件nusoap_client类里把$decode_utf8置为false就可以了。