欢迎各位兄弟 发布技术文章
这里的技术是共享的
<?php libxml_disable_entity_loader(false); try{ // wsdl方式调用web service // 创建 SoapClient 对象 $client = new SoapClient('https://aaaa.bbbb.com.cn:444/dws/dhcpoperations.asmx?wsdl', array( "soap_version" => SOAP_1_1, 'login'=>"bbbbb\\admin", 'password'=>'mypassword', 'trace' => 1, 'stream_context' => stream_context_create(array( 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ) ) )) ); // var_dump($client); // var_dump($client->__getFunctions()); // var_dump($client->__getTypes()); // var_dump($client->isAdmin()); // var_dump($client->__soapCall('isAdmin',array())); // var_dump("isadmin"); // var_dump($client->__soapCall('isAdmin',array(),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/isAdmin"))); // var_dump($client->__soapCall('GetGlobalPermissions',array(),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/GetGlobalPermissions"))); // var_dump($client->__call('GetPermissions',array('Ip'=>'192.169.40.10'),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/EnumAzIpRanges"))); // var_dump($client->__call('GetPermissions',array('Ip'=>'192.169.40.10'),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/EnumAzIpRanges"))); var_dump("ServerFindAllClients"); // var_dump($client->EnumLeases(array('server'=>array('Ip'=>array('Ip'=>'192.169.40.26'))))); $one_dim_param = array( 'server'=>array('Ip'=>'192.170.2.4'), 'terms'=>array('IpRegEx'=>'192.170.'),////最好为1,感觉为空不行,为空取不到值 ); var_dump($client->__soapCall('ServerFindAllClients',array($one_dim_param),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/ServerFindAllClients"))); var_dump("aaaaaaaaa"); // 调用函数, var_dump($client->__getLastRequestHeaders()); var_dump($client->__getLastRequest()); } catch(SoapFault $e){ var_dump("bbbbbb"); echo $e->getMessage(); var_dump("CCCCCCCCCCCCCCCCCC"); var_dump($client->__getLastRequestHeaders()); var_dump("CCCCCCCCCCCCCCCCCC"); var_dump($client->__getLastRequest()); }catch(Exception $e){ var_dump("cccccccc"); echo $e->getMessage(); throw new \Exception("Soup request failed! Response: ".$client->__getLastResponse()); } ?> string(20) "ServerFindAllClients" string(6) "bbbbbb" looks like we got no XML document string(18) "CCCCCCCCCCCCCCCCCC" string(318) "POST /dws/dhcpoperations.asmx HTTP/1.1 Host: aaaa.bbbb.com.cn:444 Connection: Keep-Alive User-Agent: PHP-SOAP/5.6.30 Content-Type: text/xml; charset=utf-8 SOAPAction: "http://www.unf.edu/~jrupard/dws/ServerFindAllClients" Content-Length: 376 Authorization: Basic bHV4c2hhcmVcanNlczpHPkRvUjR4YmxBcUp9ekVn " string(18) "CCCCCCCCCCCCCCCCCC" string(376) "<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.unf.edu/~jrupard/dws/"><SOAP-ENV:Body><ns1:ServerFindAllClients><ns1:server><ns1:Ip>192.170.2.4</ns1:Ip></ns1:server><ns1:terms><ns1:IpRegEx>192.170.</ns1:IpRegEx></ns1:terms></ns1:ServerFindAllClients></SOAP-ENV:Body></SOAP-ENV:Envelope> "
调用 AWS 的 soap 后 报错 内容是 looks like we got no XML document
问题概要
你正在使用 PHP 的 SoapClient 类来调用一个 Web Service,地址是 https://aaaa.bbbb.com.cn:444/dws/dhcpoperations.asmx?WSDL。 你遇到了一个问题,服务器返回错误信息 "looks like we got no XML document",这表明你的 SOAP 请求格式不正确,服务器无法解析。
排查思路和解决方案
WSDL 文件是关键:
详细阅读 WSDL: 这是最重要的步骤。你需要仔细查看 WSDL 文件,了解 Web Service 提供的各个方法、期望的输入参数以及返回的数据格式。 可以使用在线的 WSDL 查看器,或者直接用文本编辑器打开。
注意 Target Namespace: WSDL 中定义的 Target Namespace 非常重要。 你的 SOAP 请求中使用的命名空间 (例如 xmlns:ns1) 必须与 WSDL 中定义的 Target Namespace 完全一致。
核对数据类型: 确认每个参数的数据类型,比如字符串、整数、布尔值或者复杂类型。 你的 PHP 代码需要按照 WSDL 定义的数据类型传递参数。
核对参数名称: 你的 PHP 代码中参数的名称必须与 WSDL 中定义的参数名称完全一致,包括大小写!
复杂类型结构: 如果某个方法接收复杂类型(比如包含多个属性的对象),WSDL 会定义这个类型的结构。 你的 PHP 数组需要正确地反映这个结构。
SOAPAction Header:
SOAPAction HTTP Header 用于告诉服务器你要调用哪个方法。 确保 SOAPAction 的值和你使用 __soapCall 设置的值与 WSDL 中该方法定义的 soapAction 属性完全一致。
请求结构:
错误信息 "looks like we got no XML document" 表明服务器没有接收到正确格式的参数。 你的 \$one_dim_param 数组的结构可能不符合服务器的期望。
可能的错误: 需要查看 WSDL 确定正确的参数结构,并修改 PHP 代码。
身份验证:
你使用了 login 和 password 参数来提供身份验证信息。 确认这些凭据是正确的,并且 Web Service 配置为接受 Basic Authentication。
SSL/TLS:
你禁用了 SSL 证书验证。 这在开发环境中可能可以接受,但绝对不要在生产环境中使用。 正确的做法是在服务器上安装自签名证书,或者使用来自证书颁发机构 (CA) 的有效签名证书。
错误日志:
改进你的错误日志记录。 除了打印 $e->getMessage(),还要将整个异常对象 ($e) 记录到文件中。 这会提供更多上下文信息。
使用 __getLastRequest() 和 __getLastResponse() 调试:
你已经使用了 __getLastRequest() 和 __getLastRequestHeaders()。 很好! 还要使用 __getLastResponse() 来查看服务器返回的原始 XML 响应 (如果有)。 这能提供有价值的线索。 检查 XML 是否包含错误消息或意外的数据。
使用 SoapUI 或 Postman:
使用专门的工具(如 SoapUI 或 Postman)可以更方便地调试 SOAP 调用。 这些工具可以让你手动构造 SOAP 请求并详细检查响应。 你可以将 WSDL 导入这些工具,它们会帮助你构建有效的请求。 这可以帮助你判断问题是出在 PHP 代码还是 Web Service 本身。
9. DHCP 的 web 服务器接口可以查看一下:
修改后的代码示例(仅供参考,需要分析 WSDL)
关键要点
WSDL 是你的最佳助手。 深入理解它。
密切关注命名空间、数据类型和参数名称。
使用 __getLastRequest()、__getLastRequestHeaders() 和 __getLastResponse() 进行调试。
考虑使用 SoapUI 或 Postman 进行测试。
解决禁用实体加载和 SSL 验证带来的安全风险。
按照这些步骤,并仔细分析 WSDL 和错误消息,你应该能够解决问题并成功调用 Web Service。 请记住将修改后的代码示例中的占位符注释替换为 WSDL 中的正确值。
echo "Response:\n" . $client->__getLastResponse() . "\n"; // 调试的关键! 加上这一行很重要,,,,
能够得到 响应的 xml 结果($client->__getLastResponse()
返回的是原始的 SOAP 响应 XML 字符串,)
这个字符串 looks like we got no XML document (不像xml文档)
<?php
libxml_use_internal_errors(true); //libxml_use_internal_errors(true)
是 PHP 中一个重要的 XML 处理相关函数调用,它的核心作用是启用 libxml 的错误收集功能,防止 XML 解析错误直接触发 PHP 警告或错误.
$responseXml = $client->__getLastResponse();
$xml = simplexml_load_string($responseXml);
if ($xml === false) {
echo "解析失败: " . implode("\n", libxml_get_errors());
} else {
// 处理 XML
}
?>
XML 解析失败:
xmlParseCharRef: invalid xmlChar value 24
xmlParseCharRef: invalid xmlChar value 24
xmlParseCharRef: invalid xmlChar value 24
<?php
libxml_use_internal_errors(true); //libxml_use_internal_errors(true)
是 PHP 中一个重要的 XML 处理相关函数调用,它的核心作用是启用 libxml 的错误收集功能,防止 XML 解析错误直接触发 PHP 警告或错误.
$responseXml = $client->__getLastResponse();
// 对 $responseXml 进行处理
$result = sanitizeXml($responseXml ); //这个函数下面有 目的是为了清理 invalid xmlChar value
$result = strictSanitizeXml($responseXml ); //这个函数下面有 目的也是为了清理 invalid xmlChar value
$result = domSanitizeXml($responseXml ); //这个函数下面有 目的同样是为了清理 invalid xmlChar value
$xml = simplexml_load_string($responseXml);
if ($xml === false) {
echo "解析失败: " . implode("\n", libxml_get_errors());
} else {
// 处理 XML
}
// 注册命名空间以便访问 SOAP Body
$xml->registerXPathNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('ns', 'http://www.unf.edu/~jrupard/dws/');
// 获取所有 DhcpClient 节点
$clients = $xml->xpath('//ns:DhcpClient');
//下面的 php 代码是把 $clients 由 xml转换为$object对象
$data = [];
foreach ($clients as $client) {
$data[] = [
'ip' => (string)$client->IpAddress->Ip,
'mac' => (string)$client->MacAddress->Mac,
'name' => (string)$client->Name,
'comment' => (string)$client->Comment,
'leaseExpires' => (string)$client->LeaseExpires
];
}
?>
<?php
$dhcpClientArray = [];
foreach ($clients as $client) {
$dhcpClientArray[] = xmlElementToArray($client); // xmlElementToArray() 函数下面有
}
// 3. 把数组转换为 stdClass 对象(并保留嵌套结构)
$responseObject = new stdClass();
$responseObject->ServerFindAllClientsResult = new stdClass();
$responseObject->ServerFindAllClientsResult->DhcpClient = json_decode(json_encode($dhcpClientArray));
// 打印结果
var_dump($responseObject); //这个就是最后打印的标准 object对象,,, 我们所需要的对象 ,与 var_dump($client->__soapCall('ServerFindAllClients',array($one_dim_param),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/ServerFindAllClients"))); 的格式是一样的
exit;
?>
下面是我自己最终实现的代码 to-webservice-wsdl-13-4-ServerFindAllClients-ok2 OK 有大用