PHP SOAP Second request doesn't throw an exception - php

i am trying to connect to a webservice. My webserviceHelper is:
class webserviceHelper {
public function __construct($params) {
$this->service_url = $params['service_url'];
try {
$this->soap = new SoapClient($this->service_url,
array('exceptions' => true));
}
catch (SoapFault $exc) {
echo 'SoapFault<br />';
die;
}
catch (Exception $exc) {
echo 'Exception<br />';
die;
}
}
...
}
When the service is down, i make a request to the page where the webserviceHelper object created. Before the response i make second request to the same page. At first one, i got "soapFault" as output but at the second, i got a fatal error.
Fatal error: SOAP-ERROR: Parsing WSDL: Couldn't load from 'WebService?wsdl' : failed to load external entity "WebService?wsdl" in webserviceHelper.php on line 40
How can i prevent this error?

use error_get_last() after $this->soap = new SoapClient(..... to get potential errors

I handled it by using a hook in codeigniter. Thanks to the blogger. How To Catch PHP Fatal Error In CodeIgniter

Related

XML Exception in PHP not being caught

My code snippet is below - as you can see, I have a try-catch block, but inspite of this, I still get an uncaught exception that terminates the entire application. What am I missing?
try {
$cakeXml = simplexml_load_string($xml);
$parseSuccess = $cakeXml->xpath('//ParseSuccess');
} catch (Exception $ex) {
$response['parseSuccess'] = false;
$response['errors']['ParseError'] = 'An unknown error occurred while trying to parse the file. Please try again';
return $response;
}
2014-12-16 22:45:12 Error: Fatal Error (1): Call to a member function xpath() on a non-object
2014-12-16 22:45:12 Error: [FatalErrorException] Call to a member function xpath() on a non-object
If you read the error message more-carefully, you will see that it is not dieing on an Exception, but on a Fatal Error. A try/catch statement cannot catch a fatal error in PHP, as there is no way to recover from a fatal error.
As for solving this issue, your error is telling you $cakeXml is a non-object. One solution would be to do something like this.
try {
$cakeXml = simplexml_load_string($xml);
if (!is_object($cakeXml)) {
throw new Exception('simplexml_load_string returned non-object');
}
$parseSuccess = $cakeXml->xpath('//ParseSuccess');
} catch (Exception $ex) {
$response['parseSuccess'] = false;
$response['errors']['ParseError'] = 'An unknown error occurred while trying to parse the file. Please try again';
return $response;
}
DOMXPath methods i.e. xpath or evaluate does not throw exceptions. Hence, you will need to explicitly validate and throw the exception.
See below code snippet:
$xml_1= "";
try {
$cakeXml = simplexml_load_string($xml_1);
if ( !is_object($cakeXml) ) {
throw new Exception(sprintf('Not an object (Object: %s)', var_export($cakeXml, true)));
} else {
$parseSuccess = $cakeXml->xpath('//pages');
print('<pre>');print_r($parseSuccess);
}
} catch (Exception $ex) {
echo 'Caught exception: ', $ex->getMessage(), "\n";
}

How can I check if file exists with exception handeling

I am trying to use exception handling in case a file does not exists. For example when I run the model method and pass a string usr (which I know there is no file with that name) . It gives me the following error message
Fatal error: Uncaught exception 'Exception' with message 'Usr.php was not found' in /app/core/controller.php on line 14
I can't figure out whats wrong here. Can someone please help me figure this out?
Below is my code. Thanks alot!
class Controllers{
public function model($model){
if(!file_exists("../app/models/".$model.".php")) {
throw new exception("{$model}.php was not found");
}
try {
require ("../app/models/".$model.".php");
} catch(Exception $e) {
echo $e->getMessage();
}
return new $model();
}
}
You can't throw an exception without catching it; this automatically causes the PHP script to crash. So, you need to surround your entire function in the try-catch block, or the "model not found" exception will be uncaught. Your code should be something like this:
<?php
class Controllers {
public function model($model){
try {
if (!file_exists("../app/models/".$model.".php")) {
throw new Exception("{$model}.php was not found");
}
require ("../app/models/".$model.".php");
} catch(Exception $e) {
echo $e->getMessage();
}
return new $model();
}
}
Never mind guys! I found out I needed to use the try/catch blocks in the file where my method is being invoked
Example..
class Home extends Controllers{
public function index($name = ""){
try{
$user = $this->model('Usr');
}catch (Exception $e){
echo $e->getMessage();
}
//var_dump($user);
}

How can I catch Mandrill Exceptions

I'm using the Mandrill API and trying to get some stats by a tag name
$mandrill = new \Mandrill(MANDRILL_API_KEY);
return $mandrill->tags->info('campaign-117');
If the tag exists, it works fine. But if it doesn't exist yet (because I just sent the mails with the tag) the call throws an exception:
PHP Fatal error: Uncaught exception 'Mandrill_Invalid_Tag_Name' with message 'no such tag "campaign-117"'
How can I catch this exception?
The following doesn't seem to work:
try {
$mandrill = new \Mandrill(MANDRILL_API_KEY);
return $mandrill->tags->info('campaign-117');
} catch(Mandrill_Invalid_Tag_Name $e) {
....
} catch(Mandrill_Error $e) {
....
} catch(Exception $e) {
....
}

ZF1 Get errors before redirect

As the title says, I want to get all errors before the redirect. So this is my case:
I have a select for changing databases(identical structure but different data);
So let's say I am here: localhost/user/edit/id/100 (database 1)
on db change, I am redirecting the user to the same page, but we load data from database 2.
If it is not found, I get an error:
"Fatal error: Call to a member function on a non-object ..."
How do I catch the errors before the redirect occurs in order to change the url?
Thanks!
Use try {} catch() {} for catching errors before redirect.
try {
if (/* if error occured */) {
throw new \Exception('Error occured');
}
} catch(\Exception $e) {
// redirect with error occured
}
// redirect without error
In Zend maybe need to use return $redirectObj, I don't know Zend well.
In your case, try to do this:
try {
if ( ! $this->getResponse()) {
throw new Exception('Error occured! Can not get response object');
}
return $this->getResponse()->setRedirect($url);
} catch (Exception $e) {
echo $e->getMessage();
die();
}

PHP SOAP error catching

I'm getting desperate, all I want is simple error handling when the PHP SOAP Web Service is down to echo an error message login service down. Please help me!
At the moment it's still displaying the error (along with warnings...):
Fatal error: SOAP-ERROR: Parsing WSDL
Here is the script:
<?php
session_start();
$login="0000000000000nhfidsj"; //It is like this for testing, It will be changed to a GET
$username = substr($login,0,13); //as password is always 13 char long
//(the validation is done int he javascript)
$password = substr($login,13);
try
{
ini_set('default_socket_timeout', 5); //So time out is 5 seconds
$client = new SoapClient("http://192.168.0.142:8080/services/Logon?wsdl"); //locally hosted
$array = $client->login(array('username'=>$username,
'password'=>$password));
$result = $array->return;
}catch(SoapFault $client){
$result = "0";
}
if($result == "true")//as this would be what the ws returns if login success
{
$_SESSION['user'] = $login;
echo "00";
}
else
{
echo "01 error: login failed";
}
?>
UPDATE July 2018
If you don't care about getting the SoapFault details and just want to catch any errors coming from the SoapClient you can catch "Throwable" in PHP 7+. The original problem was that SoapClient can "Fatal Error" before it throws a SoapFault so by catching both errors and exceptions with Throwable you will have very simple error handling e.g.
try{
soap connection...
}catch(Throwable $e){
echo 'sorry... our service is down';
}
If you need to catch the SoapFault specifically, try the original answer which should allow you to suppress the fatal error that prevents the SoapFault being thrown
Original answer relevant for older PHP versions
SOAP can fatal error calling the native php functions internally which prevents the SoapFaults being thrown so we need to log and suppress those native errors.
First you need to turn on exceptions handling:
try {
$client = new SoapClient("http://192.168.0.142:8080/services/Logon?wsdl",array(
'exceptions' => true,
));
} catch ( SoapFault $e ) { // Do NOT try and catch "Exception" here
echo 'sorry... our service is down';
}
AND THEN you also need to silently suppress any "PHP errors" that originate from SOAP using a custom error handler:
set_error_handler('handlePhpErrors');
function handlePhpErrors($errno, $errmsg, $filename, $linenum, $vars) {
if (stristr($errmsg, "SoapClient::SoapClient")) {
error_log($errmsg); // silently log error
return; // skip error handling
}
}
You will then find it now instead trips a SoapFault exception with the correct message "Soap error: SOAP-ERROR: Parsing WSDL: Couldn't load from '...'" and so you end up back in your catch statement able to handle the error more effectively.
Fatal error: SOAP-ERROR: Parsing WSDL Means the WSDL is wrong and maybe missing? so it's not related to soap. And you cannot handle FATAL ERROR with a try catch. See this link : http://ru2.php.net/set_error_handler#35622
What do you get when you try to access http://192.168.0.142:8080/services/Logon?wsdl in your browser?
You can check if the WSDL is present like this
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
$response = curl_exec($handle);
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
/* You don't have a WSDL Service is down. exit the function */
}
curl_close($handle);
/* Do your stuff with SOAP here. */
Unfortunately SOAP throws a fatal error when the service is down / unreachable rather than returning a SoapFault object.
That being said, you can set it to throw an exception. You probably omitted the part where you're setting the exceptions soap_client option to false
$client = new SoapClient("http://192.168.0.142:8080/services/Logon?wsdl",array(
'exceptions' => false, // change to true so it will throw an exception
));
Catch the exception when service is down:
try {
$client = new SoapClient("http://192.168.0.142:8080/services/Logon?wsdl",array(
'exceptions' => true,
));
}
catch ( Exception $e )
{
echo 'sorry... our service is down';
}
Perhaps a better alternative:
set_error_handler('my_error_handler');
set_exception_handler('my_exception_handler');
function my_exception_handler($e) {
exit('Error, something went terribly wrong: '.$e);
}
function my_error_handler($no,$str,$file,$line) {
$e = new ErrorException($str,$no,0,$file,$line);
my_exception_handler($e);
}
Where you can adjust error messages in the mentioned functions.
I use it to return a message in the same situation you do, as it can occur at any time.
Say you send a soap message after the initial login, and that response never arrives or arrives only partially, this way you can return a message without any script paths, names and linenumbers.
In such cases I do not return $e at all, instead I just output something like: 'Something went wrong, please try it again (later).'
I ended up handling it this way:
libxml_use_internal_errors(true);
$sxe = simplexml_load_string(file_get_contents($url));
if (!$sxe) {
return [
'error' => true,
'info' => 'WSDL does not return valid xml',
];
}
libxml_use_internal_errors(false);
Do your soap call after this check.
Everything turned out to be much more trivial - when using namespaces, be sure to specify the root ns!
Those catch (SoapFailt $fault) - is wrong, right way catch (\SoapFault $fault)
SoapFault doesn't extends Exception, catch the especific type works:
try {
$client = new SoapClient("http://192.168.0.142:8080/services/Logon?wsdl",array(
'exceptions' => true,
));
}
catch ( SoapFault $e )
{
echo 'sorry... our service is down';
}

Categories