Php SoapClient is very slow on first connection - php

I use php SoapClient to call M3 (Movex) webservices, stored on our internal server. My Symfony 3.4 project which does the calls is on another internal linux server.
I noticed that the initialization of the soap client is very slow (2-3 minutes) when it's done after a long time without using it (several hours). For example, it occurs the morning, when I test my project for the first time of the day. But I have no problem for every initializations and calls done after several minutes (responds in 500ms).
Because of the 1st init takes several minutes, my nginx server returns a 504 gateway time-out error after 1 minute.
The webservices urls are in HTTPS and we use SSL certificates. We also had to authenticate with a login and a password. I use a session cookie, available for 8 hours, that I add in the HTTP request header. We don't use a proxy.
I think it's a cache problem. When I'm using SoapUI, I don't have the problem, the webservice responds very fastly.
Here is the configuration of the soap extension in my php.ini :
Here is my soap client init :
$client = new SoapClient("https://my-domain.com:55080/my-webservice?wsdl", array(
'login' => $login,
'password' => $pwd,
'trace' => true,
'exceptions' => true,
'stream_context' => stream_context_create(array(
'http' => ['header' => 'cookie: ' . $cookie]
))
));
I tried to add 'cache_wsdl' => WSDL_CACHE_MEMORY in the options but it's worse, every time I'm using it, it's very slow.
Here are the logs to see where the problem occurs (look at lines 3 and 4 -> 2 minutes) :
01/10/19 09:58:06 ------- Get Customer -------
01/10/19 09:58:06 - Cookie exists -> send it in the request
01/10/19 09:58:06 - BEGIN Init soap client
01/10/19 10:00:07 - END Init soap client
01/10/19 10:00:07 - BEGIN client->GetCustomerData
01/10/19 10:00:07 - END client->GetCustomerData
01/10/19 10:00:07 ------- END Get Customer -------
When I test it again after several minutes (no problem, done in the same second) :
01/10/19 10:03:52 ------- Get Customer -------
01/10/19 10:03:52 - Cookie exists -> send it in the request
01/10/19 10:03:52 - BEGIN Init soap client
01/10/19 10:03:52 - END Init soap client
01/10/19 10:03:52 - BEGIN client->GetCustomerData
01/10/19 10:03:52 - END client->GetCustomerData
01/10/19 10:03:52 ------- END Get Customer -------

As an answer to your question in your comments you can try to disguise your soap client as a browser. This might be a possible solution. There 's no garanty, that this is the one and only solution. ;)
// options
$wsdl = 'https://your.service.url.here?wsdl';
$options = [
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
'connection_timeout' => 30,
'user_agent' => 'Mozilla/1.0N (Windows)',
];
try {
$client = new SoapClient($wsdl, $options);
// more logic here
} catch (SoapFault $e) {
var_dump($e);
}

Download the wsdl file and put it on the same server than my project solved the problem.
I don't have a delay during the initialization of the soap client. And I disabled the cache too. It works perfectly now.
$client = new SoapClient("https://". $_SERVER['HTTP_HOST'] ."/path-to/file.xml", array(
'login' => $login,
'password' => $pwd,
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create(array(
'http' => ['header' => 'cookie: ' . $cookie]
))
));

Related

How to set trace-time option to CURL using GUZZLE

I'm using PHP + Laravel to send some requests.
I want to capture every thing from sending request to the end. So I did this:
$verbose_log_stream = fopen('./curl.log', 'a+');
$client = new GuzzleHttp\Client([
'curl' => [
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => $verbose_log_stream,
],
]);
I realized CURL also have some more options for better tracing called --trace-ascii and --trace-time
Anyone knows how can I set these two trace options to the Guzzle CURL options?

PHP SoapClient Doesn't Retrieve WSDL with Client Certificate

Other similar questions have not helped me resolve this.
I have to retrieve a WSDL file using a client certificate + private key combination from my webserver calling another external SOAP API.
$wsdl = 'https://www.example.com?wsdl';
$endpoint = 'https://www.example.com';
$sslContext = stream_context_create($contextOptions);
$options = [
'local_cert' => '/var/www/combo.pem',
'passphrase' => 'Pass1',
'cache_wsdl' => WSDL_CACHE_MEMORY,
'trace' => 1,
'stream_context' => stream_context_create([
'ssl' => [
'ciphers' => 'RC4-SHA',
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
])
];
try{
$soapClient = new SoapClient($wsdl, $options);
}
catch(Exception $e)
{
var_dump($e);
}
The error I'm getting is:
SOAP-ERROR: Parsing WSDL: Couldn't load from '..domain..' : failed to load external entity "..domain..?wsdl"
I tried numerous settings and none of them made any difference to this response. I tried no settings, empty array.
What has worked:
Establishing a raw connection via CURL, so the certificate file is fine
Retrieving WSDL information from SoapUI, so the WSDL destination is correct and the certificate file was okay
phpinfo() returns SoapClient is enabled, OpenSSL is enabled. What else could I try or check?
SOAP error could come from invalid character encoding or maybe some HTTP header missing like 'User-Agent' when you query the remote server.
Try to adding User-Agent to options like the sample below.
$options = array(
'http' => array(
'user_agent' => 'PHP_Embedded_Soap_Client'
)
);
PS: I would not recommend to strict ciphers to: RC4-SHA
I wanted to comment this but based on others' suggestions of using file_get_contents and your reply mentioning that it returned false, I'm now kind of sure it's more of a connection problem. Please check followings:
It's obvious that your actual $wsdl value is different than what is posted but please make sure that .com?wsdl is not happening in your code. it should be .com/?wsdl.
Check your DNS settings. A lookup through dnslookup can help identify problem.
Make sure date & time setting of server is correct. It can lead to SSL errors.
If none of above helped. You might consider downloading WSDL content with other tools (such as cURL) and on different machines to identify the cause of problem.

PHP SoapClient fails with - Failed to load external entity

I've been trying to use the European Union's website to validate TIN numbers (Europa TIN validation website - there is a WSDL available at the bottom of the page)
The problem I'm having is that when I try to make a new SoapClient the function fails immediately when building the client. At first I was having a "Failed to load external entity" and I assumed it was because the WSDL has a secure connection. After searching around I found some answers that said that the problem could have to do with the certificate being outdated and the most recent versions of PHP throw errors in that case, so I disabled certificate validation with:
// Stream context due to certificate problems
$streamContext = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
But now I'm getting another error: "failed to open stream: HTTP Request failed! HTTP/1.1 502 Bad Gateway". Any thoughts about how to solve this issue? If I remove "https://" from the link I get the same result as before with the "failed to load external entity" message.
Now here's the real brain picker. If I try to use chrome's extension "Boomerang" to test SOAP calls on the WSDL it works absolutely perfectly, so I have no idea what's wrong here... Anyone can easily try this by attempting to make a soap call in a PHP file.
Here's the full code:
public static function validateTIN($tin) {
// Stream context due to certificate problems
$streamContext = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
));
// Create our soap client
$client = new SoapClient('https://ec.europa.eu/taxation_customs/tin/checkTinService.wsdl', array(
'exceptions' => 0,
'trace' => 1,
'connection_timeout' => 1800,
'stream_context' => $streamContext
));
dd($client->__getFunctions());
return true;
}
After spending hours researching and trying to figure out the problem I found a 2 years old post that somehow served my purpose.
Unfortunately I can't mark this as duplicate so I'll just link it here: SOAP error parsing wsl couldn't load from but works on wamp
I couldn't find this question because Google didn't tag it as using the Europa services.
Either way, my problem was that I needed to specify my user agent explicitly because Europa web services are too outdated and can't resolve IPv6 requests, only IPv4. Like so:
$opts = array(
'http'=>array(
'user_agent' => 'PHPSoapClient'
)
);
$context = stream_context_create($opts);
$client = new SoapClient('http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl',
array('stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE));
$result = $client->checkVat(array(
'countryCode' => 'DK',
'vatNumber' => '47458714'
));
The example uses the CheckVAT SOAP function but it works just as well for the CheckTIN function.

Unable to obtain token using Abraham's TwitterOAuth for PHP; HTTP 500 returned

I am attempting to use #abraham's TwitterOAuth 0.5.3 library for PHP, but when I make a request to request a token for the 3-legged authorization, I receive an HTTP 500 as a response.
Here is how I have the code set up in PHP:
<?php
/* Start session and load library. */
session_start();
require_once('config.php');
require_once('twitteroauth/autoload.php');
use Abraham\TwitterOAuth\TwitterOAuth;
/* Build TwitterOAuth object with client credentials. */
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
/* Get temporary credentials. */
// Error occurs on the following line, unable to dump $request_token
$request_token = $connection->oauth('oauth/request_token', array('oauth_callback' => OAUTH_CALLBACK));
//print_r($request_token); // <-- Never reached!!
I know that this problem is not within the Twitter API, as I have verified that I can access my Twitter account via the Dev console.
In addition, I have verified to some degree that the TwiterOAuth library is working, by following the Authorization flow example provided with the library. The example can also access my Twitter account.
I just can't figure out what is going on as I am unable to properly authorize my PHP application to have access to my Twitter account.
What am I doing wrong?
It turns out that a response was never obtained. As a result, attempting to process a response, when there was none resulted in errors on the server side.
One of the PHP functions that Twitter OAuth relies upon is curl. I had tested to see if curl_init existed:
print function_exists('curl_init') ? 'curl_init is enabled' : 'curl_init is disabled';
and I erroneously assumed that curl_exec was also enabled. (Why would you leave curl_init enabled, but only disable curl_exec?)
That assumption was incorrect as my web hosting provider has disabled curl_exec "due to security concerns" and I was unaware of this. In addition, my call to use the Twitter API has worked in the past, so this was new behavior.
It took me a while to come back to testing curl_exec. I verified that I was receiving a valid TwitterOauth object and eventually wound my way into the TwitterOauth class and into the request function.
I was receiving no curl error, but was the response from curl_exec was null (not TRUE or FALSE as expected). I thought that this was unusual and at first thought that curl was missing a configuration option.
However, it was not.
So, if you run into problems with this library (which has worked great for me in the past), it may be that your hosting provider disabled curl_exec.
You can test this scenario via the following PHP code:
print function_exists('curl_exec') ? 'curl_exec is enabled' : 'curl_exec is disabled';
My problem was fixed in another way. After checking (as per jhenderson2099 answer) that my hosting had curl_exec enabled (which it did). I found out that my problem was caused by two lines in src/TwitterOauth.php (TwitterOauth class):
$bundlePath = CaBundle::getSystemCaRootBundlePath(); <-- Comment this line
$options = [
// CURLOPT_VERBOSE => true,
CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_USERAGENT => $this->userAgent,
$this->curlCaOpt($bundlePath) => $bundlePath,<-- Comment this line
];
so that your code will look like this:
//$bundlePath = CaBundle::getSystemCaRootBundlePath();
$options = [
// CURLOPT_VERBOSE => true,
CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_USERAGENT => $this->userAgent,
//$this->curlCaOpt($bundlePath) => $bundlePath,
];

SOAP Request over https fails everytime

my first time doing a SOAP Request fails and fails again.
I have to send some Data via SOAP but i dont get a stable connection.
I use the SOAP Extension of PHP. My Code looks like the following.
$certificate = file_get_contents(DATA_PATH.'/modules/va/misc/CKTC.cer');
$options = array(
'uri' => 'https://data2.kroschke.net/service/MeinAutoUeberfuehrungen',
'allow_self_signed' => true,
'verify_peer' => true,
'local_cert' => $certificate,
'trace' => 1,
'exceptions' => true,
);
$wsdl = 'https://data2.kroschke.net/service/MeinAutoUeberfuehrungen?WSDL';
$SOAPClient = new SoapClient($wsdl, $options);
fb($SOAPClient->__getFunctions());
Now my Problem is, that the SOAP Request always runs into a timeout.
I checked my php settings and SOAP and OpenSSL are activated.
I also tried it with a .pem instead of a .cer File. Same Problem.
This is what i get all the time:
Warning: SoapClient::SoapClient(https://data2.kroschke.net/service/MeinAutoUeberfuehrungen?WSDL): failed to open stream: Connection timed out in
Anyone who can help?
PS: Dont mind the fb() Function. Just a function to print everything into FireBug.
just try to open https://data2.kroschke.net or https://data2.kroschke.net/service/MeinAutoUeberfuehrungen?WSDL in you browser: you'll get a timeout, too.
the best solution would be to get in contact with the provider of that soap-server (kroschke.com/kroschke.de ?) and ask them why their server is down or seems to hang.
EDIT:
this doesn't seem to be the problem, so your only option is to set the timeout to a higher value. for this, just add connection_timeout (value in seconds) to your options:
$options = array(
'uri' => 'https://data2.kroschke.net/service/MeinAutoUeberfuehrungen',
'allow_self_signed' => true,
'verify_peer' => true,
'local_cert' => $certificate,
'trace' => 1,
'exceptions' => true,
'connection_timeout'=> 30
);
if it still times out, set the value even higher - if it still times out then, try to test the soap-communication with a program like soapUI before implementing it with PHP - if you get problems with soapUI, too, contact the provider of that soap-server and ask why their methods take such a long time.
for more information, take a look at the soapclient and it's options.

Categories