欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

looks like we got no XML document maxai chatgpt 自己亲自做的 有大用 有大大用 有大大大用

<?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 请求格式不正确,服务器无法解析。

排查思路和解决方案


  1. 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)

    php    
    <?php
    libxml_disable_entity_loader(false); // 安全风险 - 仅在绝对必要时禁用
    
    try {
        $client = new SoapClient('https://aaaa.bbbb.com.cn:444/dws/dhcpoperations.asmx?WSDL',
            array(
                "soap_version" => SOAP_1_1,
                'login' => "luxshare\\jses",
                'password' => 'G>DoR4xblAqJ}zEg',
                'trace' => 1,
                'stream_context' => stream_context_create(array(
                    'ssl' => array(
                        'verify_peer' => false,
                        'verify_peer_name' => false,
                        'allow_self_signed' => true
                    )
                ))
            ));
    
        // **重要:使用从 WSDL 中获取的正确结构替换此行**
        $params = array(
            'server' => array('Ip' => '192.168.2.5'),
            'network' => array('Ip' => '192.168.220.0'),
            'terms' => array('IpRegEx' => '1'),
        );
    
        // **重要:验证 WSDL 中的 SOAPAction URL**
        $soapAction = "http://www.unf.edu/~jrupard/dws/SubnetFindAllClients";
    
        try {
            $result = $client->__soapCall('SubnetFindAllClients', array($params), array("soapaction" => $soapAction));
            var_dump($result);
        } catch (SoapFault $fault) {
            echo "SOAP Fault: " . $fault->getMessage() . "\n";
            echo "Request Headers:\n" . $client->__getLastRequestHeaders() . "\n";
            echo "Request:\n" . $client->__getLastRequest() . "\n";
            echo "Response:\n" . $client->__getLastResponse() . "\n";  // 调试的关键!
        }
    
    } catch (SoapFault $e) {
        echo "General SOAP Error: " . $e->getMessage() . "\n";
    } catch (Exception $e) {
        echo "General Error: " . $e->getMessage() . "\n";
    }
    
    ?>
    
       



    关键要点

    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 有大用

    <?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.16940.26')))));

        $one_dim_param = array(
            'server'=>array('Ip'=>'192.170.2.4'),
            'terms'=>array('IpRegEx'=>'192.170.1'),////最好为1,感觉为空不行,为空取不到值
            );
        var_dump("XXXXXX");
         $result = $client->__soapCall('ServerFindAllClients',array($one_dim_param),array("soapaction"=>"http://www.unf.edu/~jrupard/dws/ServerFindAllClients"));
        var_dump("YYYYYY");
        print_r($result);


    //    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());
        var_dump("DDDDDDDD");
        $result =$client->__getLastResponse();
        var_dump($result);

        if (is_string($result)) {
            libxml_use_internal_errors(true); //libxml_use_internal_errors(true) 是 PHP 中一个重要的 XML 处理相关函数调用,它的核心作用是启用 libxml 的错误收集功能,防止 XML 解析错误直接触发 PHP 警告或错误
            $result = sanitizeXml($result);
            $result = strictSanitizeXml($result);
            $result = domSanitizeXml($result);
            // 检查字符串中是否真的存在 ASCII 24 (0x18)
    //        if (strpos($xmlString, chr(24)) !== false) {
    //            echo "字符串中仍然存在 ASCII 24 字符!";
    //        } else {
    //            echo "ASCII 24 字符已被移除";
    //        }
            var_dump("MMMMMMM");
            var_dump($result);


          var_dump('这里$result 是 xml 字符串,是对上面 $client->__getLastResponse() 处理后的结果!');


            $xml = simplexml_load_string($result);
            if ($xml === false) {
                echo "XML 解析失败:\n";
                foreach (libxml_get_errors() as $error) {
                    echo $error->message . "\n";
                }

            }
            // 注册命名空间
            $xml->registerXPathNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
            $xml->registerXPathNamespace('ns', 'http://www.unf.edu/~jrupard/dws/');

    // 用 XPath 找 DhcpClient
            $clients = $xml->xpath('//ns:DhcpClient');

    //        foreach ($clients as $c) {
    //            echo "IP: " . (string)$c->IpAddress->Ip . PHP_EOL;
    //            echo "MAC: " . (string)$c->MacAddress->Mac . PHP_EOL;
    //            echo "Name: " . (string)$c->Name . PHP_EOL;
    //            echo "Comment: " . ((string)$c->Comment ?: '') . PHP_EOL;
    //            echo "LeaseExpires: " . (string)$c->LeaseExpires . PHP_EOL;
    //            echo "------------------------" . PHP_EOL;
    //        }
            $dhcpClientArray = [];
            $dhcpClientArray = [];
            foreach ($clients as $client) {
                $dhcpClientArray[] = xmlElementToArray($client);
            }
            // 3. 把数组转换为 stdClass 对象(并保留嵌套结构)
            $responseObject = new stdClass();
            $responseObject->ServerFindAllClientsResult = new stdClass();
            $responseObject->ServerFindAllClientsResult->DhcpClient = json_decode(json_encode($dhcpClientArray));
            // 打印结果
            var_dump($responseObject);
            exit;

        } else {
            var_dump("FFFFF");
            // 已经是对象
            $resultObject = $result;
        }

        print_r($resultObject);

    }catch(Exception $e){
        var_dump("cccccccc");

        echo $e->getMessage();
        throw new \Exception("Soup request failed! Response: ".$client->__getLastResponse());
    }
    //去除中英文空格
    function _removeCnEnSpace($str)
    {
        $str = trim($str);
        return mb_ereg_replace('(^( | )+|( | )+$)', '', $str);
    }
    function sanitizeXml($xmlString) {
        // 移除 ASCII 控制字符(0-31),除了制表符、换行和回车
        $xmlString = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $xmlString);
        // 专门移除 ASCII 24
        $xmlString = str_replace(chr(24), '', $xmlString);
        return $xmlString;
    }
    function strictSanitizeXml($xmlString) {
        // 1. 首先去除所有非法 XML 1.0 字符
        $xmlString = preg_replace(
            '/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}]/u',
            '',
            $xmlString
        );

        // 2. 特别针对可能在UTF-8多字节字符中的残留问题
        $xmlString = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $xmlString);

        // 3. 处理非法字符引用(如 &#24; 这种形式)
        $xmlString = preg_replace('/&#(0?[1-9]|1[0-9]|2[0-4]);/', '', $xmlString);

        return $xmlString;
    }
    function domSanitizeXml($xmlString) {
        $dom = new DOMDocument();
        $dom->recover = true;
        $dom->strictErrorChecking = false;

        // 先尝试直接加载
        if (@$dom->loadXML($xmlString, LIBXML_NOENT | LIBXML_NOCDATA)) {
            return $dom->saveXML();
        }

        // 如果失败,使用更彻底的清理
        $xmlString = iconv('UTF-8', 'UTF-8//IGNORE', $xmlString);
        $xmlString = preg_replace('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}]/u', '', $xmlString);

        // 再次尝试加载
        if (@$dom->loadXML($xmlString)) {
            return $dom->saveXML();
        }

        // 最后尝试极端情况处理
        $xmlString = strip_tags($xmlString);
        $xmlString = htmlspecialchars_decode($xmlString);
        $xmlString = preg_replace('/&(?!amp;|lt;|gt;|quot;|#39;)/', '&amp;', $xmlString);

        return $xmlString;
    }
    function parseSoapXmlToObject($xmlString) {
        // 1. 清理 BOM 和非法字符
        $xmlString = preg_replace('/^\xEF\xBB\xBF/', '', $xmlString);
        $xmlString = preg_replace('/[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]/u', '', $xmlString);

        // 2. 转换为 SimpleXML
        $simpleXml = simplexml_load_string($xmlString);
        if ($simpleXml === false) {
            throw new Exception("XML 解析失败");
        }

        // 3. SimpleXML -> JSON -> 数组
        $arrayData = json_decode(json_encode($simpleXml), true);

        // 4. 获取 Body -> ServerFindAllClientsResponse
        if (!isset($arrayData['soap:Body']['ServerFindAllClientsResponse'])) {
            throw new Exception("SOAP Body 中未找到 ServerFindAllClientsResponse");
        }

        $responseArray = $arrayData['soap:Body']['ServerFindAllClientsResponse'];

        // 5. 转为 stdClass
        $responseObj = json_decode(json_encode($responseArray));

        // 6. 保证 DhcpClient 是数组
        if (isset($responseObj->ServerFindAllClientsResult->DhcpClient)) {
            if (!is_array($responseObj->ServerFindAllClientsResult->DhcpClient)) {
                $responseObj->ServerFindAllClientsResult->DhcpClient = [
                    $responseObj->ServerFindAllClientsResult->DhcpClient
                ];
            }
        } else {
            $responseObj->ServerFindAllClientsResult->DhcpClient = [];
        }

        return $responseObj;
    }
    // $clients 已经通过 XPath 获取
    // 1. 把 SimpleXMLElement 转换为数组(递归)
    function xmlElementToArray($element) {
        $result = [];
        foreach ($element->children() as $child) {
            $name = $child->getName();
            if (count($child->children()) > 0) {
                $result[$name] = xmlElementToArray($child);
            } else {
                $result[$name] = (string)$child;
            }
        }
        return $result;
    }
    ?>


    普通分类: