I am having the weirdest, head splitting issue ever. The real issue is I'm getting a SOAP error SOAP-ERROR: Parsing WSDL: Couldn't load from 'some website' : failed to load external entity
In the past it was caused by the host not responding, bad URL, etc. But today I have no problem connecting to the host.
I'm using Symfony to run the API. I stripped ALL of the soap code from the API, created a simple test.php file and ran it from the command line on the exact server the API is running on, and it worked perfectly!
So I went back to the Symfony, flushed the cache. Still not working.
Next I decided to test the simplest methods I could and slapped 'file_get_contents('the url to the WSDL')` at the very top of the service that's making this SOAP call. It returns an empty string. No errors in the error log.
Next I tried moving that to the Controller. Still an empty string.
I tried file_get_contents('https://google.com'). Still, empty string no matter where in the Controller or Service I stick it. But, if on that same server I run a PHP script from the command line, it works no problem.
I don't even know where to begin showing you my code. Because it doesn't matter if file_get_contents() is in the controller, an entity, or the services it's using. Every time it returns an empty string.
As a side note, this is a development server. Which is an exact mirror of production (they just made an image of the production server). The whole API works fine in production and also on my local dev environment and in other environments it's been deployed to. So I'm entirely lost on why it's just this server, and just this particular application.
Any help is appreciated.
==
Update 1
As suggested by a friend I checked allow_url_fopen in both the cli php -i and apache phpinfo() and in both cases it's set to On
==
Update 2
As Pedro suggested I ran a cURL test in the controller of the API. And that worked, it retrieved the contents of the WDSL, and of course Google.
However, it doesn't solve my root problem with SOAP not retrieving the contents of a URL. Nor the obvious file_get_contents() not working. Does the PHP SOAP client use file_get_contents() to retrieve WSDLs?
==
Update 3
For those curious this is where the code is failing. I have to omit a lot of the class because it contains information specific to my company.
<?php
class Carrier implements CarrierInterface
{
//...omitted code
private function getSoapClient($wsdl)
{
// This line is what fails.
return new \SoapClient( $wsdl , array('trace' => true));
}
//...omitted code
public function quote(QuoteInterface $quote)
{
//Get the Soap Client
$client = $this->getSoapClient($this->quoteWSDL);
// The rest of the SOAP CALL
return $quote;
}
}
But in short, $this->quoteWSDL is just a URL, and yes it has a the correct value I've checked. But it fails when trying to construct the SOAP client stating SOAP-ERROR: Parsing WSDL: Couldn't load from '<url>' : failed to load external entity
==
Update 4 (with Kinda Solution)
Restarting apache fixed everything. I'm not sure why I didn't just ask the SysAdmin to do that sooner. That's like IT 101 right there. Thanks for your help. But now I'm curious why this was an issue to begin with. Weird.
My guess is that allow_url_fopen is disabled.
To enable it, you'll have to set allow_url_fopen=1 on php.ini.
Restart the Apache server to reload the configuration.
Have you considered using curl? Here's an example:
$url = "http://google.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$contents = curl_exec($ch);
curl_close($ch);
PS: For future users: Make sure you read the comments below.
Related
I have been using this PHP class to upload images to S3. Here's an example code:
$s3 = new S3($awsAccessKey,$awsSecretKey);
$s3upload= $s3->putObject(
$s3->inputFIle($tmp_name, false),
$s3BucketName,
$filename,
S3::ACL_PUBLIC_READ
);
Out of nowhere I have been getting this error today:
Warning</b>: S3::putObject(): [7] Failed to connect to bucketName.s3.amazonaws.com port 80: No route to host in <b>/S3.php</b> on line <b>355
I have used the following script to check the curl settings, and I can get the whole google page, so there shouldn't be any problem with CURL
$ch = curl_init("http://google.com"); // initialize curl handle
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$data = curl_exec($ch);
print($data);
Anyone using that PHP class? Have you experienced this problem? How can I find out where the problem lays?
This can happen when some api calls get outdated. I would recommend using the official php libraries. They work almost the same way this library works, but they are being kept up-to-date by Amazon programmers.
I would recommend the official PHP library as well, it's well documented and works well.
No route to host might suggest network problems on your server.
Can you ping bucketName.s3.amazonaws.com from the server?
I am trying to get the content of WSDL from HTTPS Server
<?php
echo file_get_contents("https://zendsoap.lan/Zend_Soap_Server.php?wsdl");
?>
It Return:
Warning: file_get_contents() [function.file-get-contents]: SSL operation failed with code 1. OpenSSL Error messages: error:1408E0F4:SSL routines:func(142):reason(244) in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
Warning: file_get_contents() [function.file-get-contents]: Failed to enable crypto in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
Warning: file_get_contents(https://zendsoap.lan/Zend_Soap_Server.php?wsdl) [function.file-get-contents]: failed to open stream: operation failed in /Applications/AMPPS/www/zendSoap.lan/Zend_Soap_Client.php on line 4
AND when I can goto the WSDL Location (https://zendsoap.lan/Zend_Soap_Server.php?wsdl): Everything looks fine.
P.S: Can anybody tell me how can I share the WSDL file
I agree with RockyFord regarding it being an SSL issue (I'm pretty sure you will have a self signed certificate in place and due to using SSL there are a few steps you will need to take in order to minimise security concerns). Regarding the immediate issue you could try fixing it with code similar to this:
$url = 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl';
$contextOptions = array(
'ssl' => array(
'verify_peer' => true,
'CN_match' => 'zendsoap.lan' // assuming zendsoap.lan is the CN used in the certificate
)
);
$sslContext = stream_context_create($contextOptions);
$wsdlContent = file_get_contents($url, NULL, $sslContext);
(UPDATE: It might seem like an easy solution to change the code above to
'verify_peer' => false
while it may be ok for basic development it's not really a good idea and definitely shouldn't be used in a production environment as it introduces serious security concerns - see this excellent article on How to properly secure remote API calls over SSL from PHP code by Artur Ejsmont for more on this subject as well as the Transport Layer Security Cheat Sheet and Securing Web Services by OWASP)
To pick up on your point regarding sharing a WSDL from within a Zend Framework application you could do something like this to get started:
// go to application/configs/application.ini
// if your APPLICATION_ENV is development then add the following line in the development section:
phpSettings.soap.wsdl_cache_enabled = 0
The line above will prevent your wsdl being cached during development. Next you might want to create a SoapController and add this action like this:
public function serverAction()
{
$baseUrl = 'http://zendsoap.lan/soap/server';
if( isset( $_GET['wdsl'] ) ) {
$strategy = new Zend_Soap_Wsdl_Strategy_AnyType();
$server = new Zend_Soap_AutoDiscover($strategy);
$server->setUri($baseUrl);
$server->setClass('Application_Model_Web_Service');
$server->handle();
} else {
$server = new Zend_Soap_Server($baseUrl . '?wsdl');
$server->setClass('Application_Model_Web_Service');
$server->handle();
}
}
The nice thing about the approach above is the WSDL will be generated for you on the fly. You will have noticed the setClass() method is going to be called with 'Application_Model_Web_Service' passed as the only parameter. To test your configuration I recommend you create that class and insert the method below. Testing your configuration with a simple service containing a single method will help you with troubleshooting before you make the service more complex. Here is the example method:
// Note: you should definitely comment your methods correctly in the class so
// the WSDL will be generated correctly - by that I mean use #param and #return
// so the correct input and output types can be determined and added to the WSDL
// when the the ZF component generates it for you
/**
* #return string
*/
public function getMessage()
{
return 'ok';
}
(UPDATE: Also in response to the question you asked regarding using Zend_Soap_Client to access the web service, since it looks like you're intending to make it a secure service I'd suggest you raise a separate question regarding setting up secure soap services with php. If you explain more about what you're trying to do in that question you may get some good input from a range of experts on best practices :-)
)
I know you're new to SO so if you're happy with the answer you can accept it, also generally it's best to just reply to an answer rather than add another answer to reply. Easy when you know how of course and even easier when someone tells you ;-)
I tried your way of defining The Soap Server, only thing was I used my custom class instead of using Application_Model_Web_Service. I am using single files for Client & Server. When I run https://zendsoap.lan/Zend_Soap_Server.php without ?wsdl it result in this:
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl' : failed to load external entity "https://zendsoap.lan/Zend_Soap_Server.php?wsdl"
</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
And When I try file_get_contents() the way you told, I get this:
Warning: file_get_contents() [function.file-get-contents]: SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:func(144):reason(134) in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Warning: file_get_contents() [function.file-get-contents]: Failed to enable crypto in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Warning: file_get_contents(https://zendsoap.lan/Zend_Soap_Server.php?wsdl) [function.file-get-contents]: failed to open stream: operation failed in /Applications/AMPPS/www/zendSoap.lan/https_soap_test.php on line 16
Here is link to screenshot of My Certificate:
http://i.stack.imgur.com/bKoVD.png
Loads of thanks for your help.
Problem solved By changing 'verify_peer' => false
Can you (#dkcwd) please tell me what should be the code if I use Zend_Soap_Client without file_get_contents(). I mean is there any option which i can't find on internet to do something similar to 'verify_peer' => false.
Loads of Thanks to #dkcwd
UPDATE: Let me summarise what exactly I am doing, I am trying to create a basic SOAP Server over SSL. Before making Web Services available on my Production website, I have to test it on Development system with has got Self Signed Certificate (Whose authentication is a problem right now).
Following are the problems I am facing in that regard:
When I try to call https://zendsoap.lan/Zend_Soap_server.php?wsdl its works fine I can view the wsdl.
But when I try https://zendsoap.lan/Zend_Soap_server.php, I get this:
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://zendsoap.lan/Zend_Soap_Server.php?wsdl' : failed to load external entity "https://zendsoap.lan/Zend_Soap_Server.php?wsdl"
Is that something I should be
The reason I made verify_peer=>false as I am running it on dev server so no need to verify my own created certificate, but obviously on production I want the Certificate to be verified.
This thing work fine with NuSoap but most of the stuff in NuSoap is deprecated for our server which is running PHP 5.4.6, So the most reliable solution for me using PHP's SOAP extension. And the reason for me using Zend is we're in process of moving our system from some third party framework to Zend Framework and everyday I get requests from client to add this & that new components, I assumed if I develop every new request from Client using Zend libraries then it will be easy for me in later stages to move to Zend Framework.
I hope I made some sense there.
Many Thanks in advance...
I have a script which calls an external API using curl. This script worked perfectly when the website was on a dedicated server however I have had to move the server to a load balanced set up which sits behind a proxy and now for some reason I get
PHP Warning: SimpleXMLElement::__construct() [simplexmlelement.--construct]: Entity: line 1: parser error : Start tag expected, '<' not found in...file name.
In Firebug it comes back as a 500 error if there is a result (formatted XML) otherwise it processes as normal.
I am running Zend CE 5.1.0 with only the default modules installed. Do I need to set something on the proxy or do I need to install additional modules to get this working.
If you need further information let me know.
Cheers
Did you defined your proxy in php?
Something like:
define('HTTP_PROXY_HOST', '192.168.100.100');
define('HTTP_PROXY_PORT', '8080');
if (defined('HTTP_PROXY_HOST') && HTTP_PROXY_HOST != '') {
curl_setopt($ch, CURLOPT_PROXY, HTTP_PROXY_HOST);
}
if (defined('HTTP_PROXY_PORT') && HTTP_PROXY_PORT != '') {
curl_setopt($ch, CURLOPT_PROXYPORT, HTTP_PROXY_PORT);
}
I want to implement an OpenID login system with latest LightOpenID release. I'm testing the example provided with the source code line by line (I just replaced localhost with $_SERVER['HTTP_HOST'] in the constructor).
The issue is that everything works fine in my development box inside a private network (PHP/5.3.6 on Windows Vista) but validation always fails in my life server at the HSP public network (PHP/5.3.3 on CentOS).
I've added var_dump()'s all around and I can tell you that both copies of the code produce exactly the same request parameters and receive exactly the same response parameters (via GET). Only openid.assoc_handle, openid.sig, openid.response_nonce and openid.return_to have different values, which I guess is the expected behaviour.
However, my dev box receives this from the OpenID provider (no matter which one I use):
is_valid:true
ns:http://specs.openid.net/auth/2.0
... and my live fox receives this:
is_valid:false
ns:http://specs.openid.net/auth/2.0
There aren't any non-ASCII characters involved so it can't be an encoding issue. There must be something wrong in my hosting service but I just can't figure out what.
I need suggestions about possible causes and troubleshooting tips.
I've isolated the problem and found a workaround. The request() method makes some auto-detection to find out how to stablish HTTP connections:
protected function request($url, $method='GET', $params=array(), $update_claimed_id=false)
{
if (function_exists('curl_init')
&& (!in_array('https', stream_get_wrappers()) || !ini_get('safe_mode') && !ini_get('open_basedir'))
) {
return $this->request_curl($url, $method, $params, $update_claimed_id);
}
return $this->request_streams($url, $method, $params, $update_claimed_id);
}
In my dev box is uses CURL but in my live box it uses file_get_contents() because the check fails. The reason is that the open_basedir directive is not empty.
If I force LightOpenID to use CURL, everything runs smoothly.
Update #1: LightOpenID was right when deciding that curl was not usable. I found this in the log file:
CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled
or an open_basedir is set
As for the file_get_contents() version, I suspect I've found a typo in the library:
Index: lightopenid/openid.php
===================================================================
--- lightopenid/openid.php (0.60)
+++ lightopenid/openid.php (working copy)
## -349,7 +349,7 ##
$this->headers = $this->parse_header_array($http_response_header, $update_claimed_id);
}
- return file_get_contents($url, false, $context);
+ return $data;
}
protected function request($url, $method='GET', $params=array(), $update_claimed_id=false)
I've notified the author and he's confirmed it's a bug. I'll report back if it gets fixed.
Update #2: The bug was fixed in master branch on June 2012. It's still not part of the stable release but can be downloaded from the code repository.
Just a shot in the dark but when I worked with OpenID (not lightopenid) but a library for CodeIgniter, I got a similar issue when my permissions were not set correctly for the nonce cache folder. Maybe its a simple permission issue for storage?
if I use Firefox and access http://svcs.ebay.com/services/search/FindingService/v1 I get some sort of XML in respose, when I do that through PHP I get Internal Server Error 500
$ php -r 'print_r(simplexml_load_file("http://svcs.ebay.com/services/search/FindingService/v1"));'
PHP Warning: simplexml_load_file(http://svcs.ebay.com/services/search/FindingService/v1): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error
in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
PHP 2. simplexml_load_file() Command line code:1
PHP Warning: simplexml_load_file(): I/O warning : failed to load external entity "http://svcs.ebay.com/services/search/FindingService/v1" in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
PHP 2. simplexml_load_file() Command line code:1
$
When I visit http://svcs.ebay.com/services/search/FindingService/v1 in firefox, firebug reports that the HTTP reponse code is indeed 500. (even though it sends some XML in the request body)
You're calling the web service in the wrong way.
Yes, you got XML back, but the response code is 500, meaning your URL is wrong.
Calling ximlexml_load_file via url wrappers expects a success code.
That said, you could probably get at the data anyway. Maybe.
But you should figure out how the service wants you to to query.
If you want to be able to read 500 request data use curl
<?php
// create a new cURL resource
$ch = curl_init();
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "http://svcs.ebay.com/services/search/FindingService/v1");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// grab URL and pass it to the browser
$xml = curl_exec($ch);
$simpleXml = simplexml_load_string($xml);
// close cURL resource, and free up system resources
curl_close($ch);
?>
When I go to that site, I get:
<ms:errorMessage>
−
<error>
<errorId>2038</errorId>
<domain>SOA</domain>
<severity>Error</severity>
<category>System</category>
<message>Missing SOA operation name header</message>
</error>
</ms:errorMessage>
So it would seem that the URL is to a web service and probably requires some kind of authentication or at least input data in the request header. The HTTP response 500, according to Wikipedia, is a generic error meaning that the server can't specify the problem but knows there was one. Here's the best part of that article:
Response status codes beginning with
the digit "5" indicate cases in which
the server is aware that it has
encountered an error or is otherwise
incapable of performing the request.
Except when responding to a HEAD
request, the server should include an
entity containing an explanation of
the error situation, and indicate
whether it is a temporary or permanent
condition.
All that combined, I'd have to say your issue is that your are trying to grab a file from a remote server using a method that assumes you have some directory-level access to that file, and the server is responding with "Um, what?"
If you want to get the actual XML error as though you were in Firefox, use cURL:
$ebay_url = "http://svcs.ebay.com/services/search/FindingService/v1";
$ebay_page = curl_init();
curl_setopt($ebay_page, CURLOPT_RETURNTRANSFER, true); //output to string.
curl_setopt($ebay_page, CURLOPT_URL, $ebay_url); //set the url for the request.
$ebay_response = curl_exec($ebay_page);
print_r(simplexml_load_string($ebay_response));
If you want to actually get something back more meaningful, I would look at PHP's SoapClient methods and the actual ebay web service documentation.
The http headers need to be set specifying the operation to be executed. If you read how to make a call using the finding API, the article mentions the following http headers that need to be set:
X-EBAY-SOA-SERVICE-NAME: FindingService
X-EBAY-SOA-OPERATION-NAME: findItemsAdvanced <-- whatever call you are making
X-EBAY-SOA-SERVICE-VERSION: 1.0.0
X-EBAY-SOA-GLOBAL-ID: EBAY-US
X-EBAY-SOA-SECURITY-APPNAME: MyAppID
X-EBAY-SOA-REQUEST-DATA-FORMAT: XML
X-EBAY-SOA-MESSAGE-PROTOCOL: XML
Once those are set your call shoud work fine.
Maybe you want to try the following URL. When I do, I get back the XML and a 200 response.
http://svcs.ebay.com/services/search/FindingService/v1?wsdl
You need to reinstall your php (assuming you already have apache2 installed). Using these commands:
1) sudo apt update && apt upgrade
2) sudo apt install php-pear php-fpm php-dev php-zip php-curl php-xmlrpc php-gd php-mysql php-mbstring php-xml libapache2-mod-php
3) sudo service apache2 restart