App Engine PHP application failed to create SoapClient - php

I have a PHP application running on Google App Engine. I'm trying to make a SOAP 1.2 Web Service call from the PHP client to a remote host. I get the following error when creating the SoapClient using the code below:
$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);
The error that I get is:
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"
I have confirmed that the following modules have been loaded:
php --info
Soap Client => enabled
...
XML Support => active
...
OpenSSL support => enabled
...
And my php.ini file in the root folder of the app contains:
google_app_engine.enable_functions = "libxml_disable_entity_loader"
extension = “curl.so”
My GAE project also has billing enabled. Any advise on what I can do to successfully create a SoapClient is much appreciated. I am able to connect to the web service via CURL and SoapUI so I assume that there is nothing wrong with the web service.

Try this:
<?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);
}
}
You should be able to do this:
$soapClient = new SoapAgent('<host_ip_address>');
Note: The code is PHP 7.1 but should be easy enough to thunk down to a different version.

Related

problem accessing soap web service's production environment

I hope this question won't be marked as duplicate as I read many related questions and answers on the site: although I tried most of the suggestions out there I still couldn't resolve my problem.
My codebase : (I left comments on purpose to give an idea of what I have been trying so far, based on my browsing)
try {
$opts = array(
//~mrossw 'http' => array(
//~mrossw 'user_agent' => 'PHPSoapClient'
//~mrossw ),
//~mrossw 'socket' => array('bindto' => '158.69.189.149')
'socket' => array('bindto' => '127.0.0.1')
//~mrossw ,
//~mrossw 'ssl' => [
//~mrossw 'verify_peer' => true,
//~mrossw 'verify_peer_name' => true,
//~mrossw 'allow_self_signed' => true
//~mrossw ]
);
$context = stream_context_create($opts);
$client = new SoapClient("https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl",
//~mrossw $client = new SoapClient($doc_root.'OpCotizadorVehiculoExtReqABCS.xml',
array(
'location' => "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl",
'uri' => "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones",
// Stuff for development.
'trace' => 1,
'exceptions' => true,
'keep_alive' => true,
'connection_timeout' => 120,
'stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE,
'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | SOAP_COMPRESSION_DEFLATE,
//~mrossw 'local_cert' => $certRequest_param['sslcertfile'],
//~mrossw 'login'=>'username',
//~mrossw 'password' => 'password'
)
);
} catch (Exception $e) {
echo \"<h2>Exception Error!</h2>\";
echo $e->getMessage();
// print_r($e);
}
The WS provider has an dev environment on port xxxx and a prod env on port yyyy. Hostname and path request are the same.
SoapClient instanciation and operation call work perfect in dev env.
When i change the port to fetch against prod env I get the following error:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl' : failed to load external entity "https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl"
Provider says my public web server's IP is correctly set as allowed in their firewall. It looks right because when I tried to run the code from a different server with different IP and it fails with the same error in both dev and prod env.
When I run that code from a server inside a private network, it works in both
environment ! I don't know much about security, but this sounds to me like a security breach. I mention it here though, in case it can give a clue. I guess this is because this server has a private ip and the provider's firewall don't filter it.
When I go to https://ws_provider_hostname:xxxx/foo/bar/blah/Operaciones/OpFooBarBlahReqABCS?wsdl in my PC browser i get the correct wsdl's xml.
Do you have an idea of what can prevent the code to work form my public web server ?
Or maybe what else can I check ?
For example I couldn't find a way to check the ws server's http response code from outside my browser.
I could neither get a curl request form bash to return the wsdl xml, but that should be another question maybe.
Also let me know if i can provide any other relevant test or data.

Running PHP SoapServer behind a proxy

I'm attempting to run both a PHP SoapClient and a SoapServer (for Magento) behind a proxy, where the only network traffic allowed out is via the proxy server.
I have got this working with the client as so:
$client = new SoapClient('https://www.domain.co.uk/api/v2_soap/?wsdl=1', [
'soap_version' => SOAP_1_1,
'connection_timeout' => 15000,
'proxy_host' => '192.168.x.x',
'proxy_port' => 'xxxx',
'stream_context' => stream_context_create(
[
'ssl' => [
'proxy' => 'tcp://192.168.x.x:xxxx',
'request_fulluri' => true,
],
'http' => [
'proxy' => 'tcp://192.168.x.x:xxxx',
'request_fulluri' => true,
],
]
),
]);
This works as expected - all the traffic is going via the proxy server.
However, with the SoapServer class, I can't work out how to force it to send all outbound traffic via the SoapServer. It appears to be trying to load http://schemas.xmlsoap.org/soap/encoding/ directly form the network, not via the proxy, which is causing the "can't import schema from 'http://schemas.xmlsoap.org/soap/encoding/'" error to be thrown.
I've tried adding a hosts file entry for schemas.xmlsoap.org to 127.0.0.1 and hosting this file locally, but I'm still getting the same issue.
Is there something I'm missing?
Try stream_context_set_default like in file_get_contents:
file_get_contents behind a proxy?
<?php
// Edit the four values below
$PROXY_HOST = "proxy.example.com"; // Proxy server address
$PROXY_PORT = "1234"; // Proxy server port
$PROXY_USER = "LOGIN"; // Username
$PROXY_PASS = "PASSWORD"; // Password
// Username and Password are required only if your proxy server needs basic authentication
$auth = base64_encode("$PROXY_USER:$PROXY_PASS");
stream_context_set_default(
array(
'http' => array(
'proxy' => "tcp://$PROXY_HOST:$PROXY_PORT",
'request_fulluri' => true,
'header' => "Proxy-Authorization: Basic $auth"
// Remove the 'header' option if proxy authentication is not required
)
)
);
//Your SoapServer here
Or try to run server in non-WSDL mode
<?php
$server = new SoapServer(null, array('uri' => "http://localhost/namespace"));
$server->setClass('myClass');
$data = file_get_contents('php://input');
$server->handle($data);

PHP - SOAP WSDL

Currently i'm trying to build a little PHP - Soap Connector, which worked pretty good so far. But when i'm deploying my little script to my server, it won't work anymore and i have no clue, why.
I'm connecting in 2 different ways (by curling the SOAP WSDL Scheme, and saving it temporary in the script location, and creating from that a new SOAP Client, and creating a SOAP Client directly by using the SOAP WSDL Scheme URL):
$opts = array(
'http'=>array(
'user_agent' => 'PHP Soap Client'
)
);
$context = stream_context_create($opts);
// SOAP 1.2 client
$params = array (
'encoding' => 'UTF-8',
'verifypeer' => false,
'verifyhost' => false,
'soap_version' => SOAP_1_2,
'trace' => 1,
'exceptions' => 1,
'connection_timeout' => 30,
);
$curlStuff = curl_init($soapURL);
curl_setopt($curlStuff,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curlStuff,CURLOPT_FOLLOWLOCATION,true);
curl_setopt($curlStuff,CURLOPT_TIMEOUT,30);
$response = curl_exec($curlStuff);
$info = curl_getinfo($curlStuff);
if($response) {
file_put_contents("./tempSoapScheme.wsdl", $response);
}
$soapClient = new SoapClient(
'./tempSoapScheme.wsdl',
array(
'trace' => 1,
'stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE
)
);
$soapClientTwo = new SoapClient(
$soapURL,
array(
'trace' => 1,
'stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE
)
);
$result = $soapClient->myLoginMethod(
array(
'username' => 'my#email.example',
'password' => 'password'
)
);
As i said earlier - on my local machine it works like a charm, and everything is fine. The param "soapURL", which is not inside the script, is just the https path to my SOAP WSDL Scheme.
I've tried different options inside "$params" array, other curl setopt settings, but i can't make it work.
The response from both SoapClients:
SOAP-ERROR: Parsing WSDL: Couldn't load from '<MyURL>' : failed to load external entity "<MyURL>", which is pretty uncommon, because the CURL could save everything.
Do you have any suggestions for me?
EDIT - forgot the most important thing:
- The server, which should execute the script, has very strong firewall restrictions, and the SOAP URL Scheme is on another server (not the same). And i guess, that is the point, why it won't work, but i receive an answer from the Scheme by executing CURL.. So it's just SOAP?

php soapclient wsdl SOAP-ERROR: Parsing WSDL: Couldn't load from

I have googled and looked here in stackoverflow but I have not found a solution to my specific problem. I keep getting the error
SOAP-ERROR: Parsing WSDL: Couldnt load from "https://sampleurl.com/MerchantQueryService.asmx?WSDL" : failed to load external entity "https://sampleurl.com/MerchantQueryService.asmx?WSDL"
I am trying to use a SOAP API with a URL like
https://sampleurl.com/MerchantQueryService.asmx?WSDL
I am running MAMP on my localhost and using godaddy shared hosting, I have tried on both with the wsdl file can be found here
http://clemdemo.com/test.wsdl
In PHP I use the code below
error_reporting(-1);
ini_set('display_errors', 'On');
ini_set('soap.wsdl_cache_enabled', 0);
echo "<pre>";
try {
$url = "https://sampleurl.com/MerchantQueryService.asmx?WSDL ";
$headers = [
'Host: sampleurl.com',
'Connection: Keep-Alive',
'User-Agent: PHP-SOAP/5.3.29',
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "RequestTransaction"',
'Content-Length: 409'];
$rq = [
"userName" => "username_here",
"passWord" => "password_here",
"referenceId" => "3455566694",
"msisdn" => "346774313"];
try {
$cient = new SoapClient($url,
[
'soap_version' => SOAP_1_2,
'exceptions' => 1,
'cache_wsdl' => WSDL_CACHE_NONE,
'trace' => 1,
'stream_context' => stream_context_create(array('http' => array('header' => $headers)))
]);
print_r($cient);
} catch (SoapFault $e) {
echo "\nFault Code: ".$e->faultcode;
echo "\nFault String: ".$e->faultstring;
}
On my MAMP localhost i have SOAP,openssl and curl.
ALSO, I tried using (sending request) to the API with an online WSDL http://wsdlbrowser.com it WORKS but on code using PHP it fails
It often happens that providers neglect their SSL certificates and hence the sites and services end up having an invalid certificates - I suspect this is the case here.
Disabling the certificate validation as described by Kaii here or even better get your provider to fix their certificate.
Your code could/should then be something like:
$url = "https://sampleurl.com/MerchantQueryService.asmx?WSDL ";
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
$rq = ["userName" => "username_here",
"passWord" => "password_here",
"referenceId" => "3455566694",
"msisdn" => "346774313"];
$service = new SoapClient($url, array('stream_context' => $context));
$service->RequestTransaction($rq);
The error message appears to say that your app is not able to read our WSDL. Try opening a browser from the same machine on which your app is running and see if you can access the WSDL address at https://sampleurl.com/MerchantQueryService.asmx?WSDL.
If not - you have a network/firewall/Anti Virus problem. (in case)
If you can access this address from a browser - is your app still experiencing this problem? then check any app that could be hindering your firewall.(Anti virus are most probable cause)
If you use docker there is a chance you get error because of OpenSSL default security level. Even if you disable verify and allow self-signed in SoapClient options.
Try out to lower seclevel in /etc/ssl/openssl.cnf from DEFAULT#SECLEVEL=2 to
DEFAULT#SECLEVEL=1
Or just add into Dockerfile
RUN sed -i "s|DEFAULT#SECLEVEL=2|DEFAULT#SECLEVEL=1|g" /etc/ssl/openssl.cnf
By: https://github.com/dotnet/runtime/issues/30667#issuecomment-566482876
You can verify it by run on container
curl -A 'cURL User Agent' -4 https://ewus.nfz.gov.pl/ws-broker-server-ewus/services/Auth?wsdl
Better diagnostics can be performed with: libxml_get_last_error();
Could have cached a bad response, set 'cache_wsdl' => WSDL_CACHE_NONE when initating the object
if you skip cache, and get this in your libxml error:
LibXMLError Object
(
[level] => 1
[code] => 1549
[column] => 0
[message] => failed to load external entity "URL"
[file] =>
[line] => 0
)
With no description on Ubuntu, then its not pulling the file period. You just got hit with the Ubuntu update. Wave them the bronx salute and reboot.

PHP Soap call through https

i have a problem with running methods with SOAP. I'm using Apache and PHP.
this is the PHP code:
$opts = array(
'ssl' => array('ciphers'=>'RC4-SHA')
);
ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);
$client = new SoapClient('https://host?wsdl', array (
'stream_context' => stream_context_create($opts),
"trace" => 1,
"exceptions" => 0,
"connection_timeout"=>2000));
var_dump($client->__getFunctions());
$params = array ("key" => "value");
$result = $client->availabeFunction($params);
var_dump($result);
The __getFunctions() It returns me all of the available functions.
Then when i'm trying to call the the available function with parameters.
It returns me a strage error message:
public 'faultstring' => string 'Could not connect to host' (length=25)
public 'faultcode' => string 'HTTP' (length=4)
So i presume it is for some reasons are connecting to through the HTTP, but not through HTTPS.
I've looked up the web, and in some cases they are using a local_cert value with a .pem file.
It it neccecity to have it? Or i'm missing something else?
It's an openssl library bug.
At first try to disable SSL check by adding this params
"stream_context" => stream_context_create(
array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
)
)
)
And next try to not use ?wsdl in location link, try use something like
.wsdl
The solution was much easier as i thoguht it will be:
ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);
$location = 'https://host';
$client = new SoapClient($location . '?wsdl', array (
"trace" => 1,
"exceptions" => 0,
"connection_timeout"=>2000,
"location"=>$location // <- this was the reqiured parameter
));
Everything else is same as before.
This beeing cause by WSDL file configuration, that instead of https URL, it has http.

Categories