App Engine PHP应用程序无法创建SoapClient

时间:2017-01-08 17:32:08

标签: php google-app-engine soap-client

我在Google App Engine上运行了一个PHP应用程序。我正在尝试从PHP客户端到远程主机进行SOAP 1.2 Web服务调用。使用以下代码创建SoapClient时出现以下错误:

$opts = array(
            'https'=>array('user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'),
            'ssl' => array('verify_peer'=>false, 'verify_peer_name' => false)
        );

$context = stream_context_create($opts);

$params = array (
    'encoding' => 'UTF-8', 
    'verifypeer' => false, 
    'verifyhost' => false,
    'soap_version' => SOAP_1_2,
    'trace' => 1, 
    'exceptions' => 1, 
    'connection_timeout' => 30,
    'stream_context' => $context,
    'cache_wsdl' => WSDL_CACHE_MEMORY
);

libxml_disable_entity_loader(false);
$client = new \SoapClient("https://<host_ip_address>/webservice.asmx?wsdl", $params); 

我得到的错误是:

ERROR: SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from '<host_ip_address>/webservice.asmx?wsdl' : failed to load external entity "<host_ip_address>/webservice.asmx?wsdl"

我已确认已加载以下模块:

php --info

Soap Client => enabled
...
XML Support => active
...
OpenSSL support => enabled
...

我在应用程序根文件夹中的php.ini文件包含:

google_app_engine.enable_functions = "libxml_disable_entity_loader"
extension = “curl.so”

我的GAE项目也启用了结算功能。关于如何成功创建SoapClient的任何建议都非常感谢。我能够通过CURL和SoapUI连接到Web服务,所以我认为Web服务没有任何问题。

1 个答案:

答案 0 :(得分:0)

试试这个:

<?php
declare(strict_types=1); // PHP 7.1 

class SoapAgent extends \SoapClient
{
    protected const WSDL_PATH = '/webservice.asmx?wsdl';
    protected const USER_AGENT = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';
    protected const SOAP_TIMEOUT = 300; // Increase this value if SOAP timeouts occur.

    // options for ssl for unverified SSL certs
    // allow_self_signed certs 
    protected const CTX_OPTS =
    [
        'http' => ['user_agent' => self::USER_AGENT],
        'ssl' =>
        [
            'verify_peer' => false, // Do not verify the cert
            'verify_peer_name' => false, // Or the name of the cert
            'allow_self_signed' => true // Allow self signed certs
        ]
    ];


    public function __construct(string $uri)
    {
        assert(func_num_args() === 1);

        /**
         * Workaround for a particularly nasty bug that 'sometimes'
         * creates a racing condition internally
         * for SOAP client constructors that use OpenSSL in Ubuntu.
         *
         * @link: https://bugs.launchpad.net/ubuntu/+source/php5/+bug/1160336
         *
         */
        libxml_disable_entity_loader(false);

        // Get the SOAP stream context
        $ctx = stream_context_create(self::CTX_OPTS);

        // SOAP 1.2 client options
        $options =
        [
            'Content-Type' => 'application/soap+xml;charset=UTF-8',
            'encoding' => 'UTF-8',
            'verifypeer' => false,
            'verifyhost' => false,
            'soap_version' => SOAP_1_2,
            'features' => SOAP_WAIT_ONE_WAY_CALLS |     SOAP_SINGLE_ELEMENT_ARRAYS,
            'compression' => SOAP_COMPRESSION_ACCEPT |     SOAP_COMPRESSION_GZIP | SOAP_COMPRESSION_DEFLATE,
            'trace' => true,
            'exceptions' => true,
            'cache_wsdl' => WSDL_CACHE_NONE,
            'cache_wsdl_ttl' => 0,
            'connection_timeout' => self::SOAP_TIMEOUT,
            'stream_context' => $ctx
        ];

        // Even though we pass these in as option settings (above) -- sometimes
        // they are being ignored so we force this into the INI settings as well.
        ini_set('soap.wsdl_cache_enabled', (string)$options['cache_wsdl']);
        ini_set('soap.wsdl_cache_ttl', (string)$options['cache_wsdl_ttl']);
        ini_set('default_socket_timeout', (string)$options['connection_timeout']);

        // Set the file path for where we are going to store the WSDL.
        $wsdlFile = sys_get_temp_dir() . '/' . $uri . '.wsdl';

        // Format the uri by affixing `https://` to the uri 
        $uri = "https://{$uri}/" . self::WSDL_PATH;

        // We perform our own WSDL caching in case there are errors we can actually look at the file itself.
        $wsdlXML = null;

        // Does the WSDL file already exist?
        if (!file_exists($wsdlFile)) {

            // Download the WSDL for the URI provided
            $wsdlXML = file_get_contents($uri, false, $options['stream_context']);

            // If we had trouble getting the WSDL then the URI from the user is probably bad.
            if (!isset($wsdlXML) || $wsdlXML === false || !is_string($wsdlXML)) {
                new \Exception('Unable to load WSDL from: '. $uri);
            }

                // Save the WSDL file.
                file_put_contents($wsdlFile, $wsdlXML);
            }


            // Call the PHP internal constructor for this using the downloaded file
            // to perform the actual WDSL configuration.
            parent::__construct($wsdlFile, $options);
    }
}

你应该可以这样做:

$soapClient = new SoapAgent('<host_ip_address>');

注意:代码是PHP 7.1,但应该很容易,可以打到不同的版本。