我在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服务没有任何问题。
答案 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,但应该很容易,可以打到不同的版本。