I'm trying to connect to a soap service using a WSDL file in php 5.6
The snippet below works fine if I'm on the network, but if I'm disconnected I get a fatal error.
try {
$soap_client = new SoapClient($wsdl_file, ['exceptions' => true]);
}
catch (SoapFault $fault) {
echo 'poop';
}
catch (Exception $exception) {
echo 'pee';
}
edit: it does seem to do something with the SoapFault, because I can see my 'poop' debug message, but it still results in a fatal error
These are the errors I get
Warning (2): SoapClient(): php_network_get_addresses: getaddrinfo failed: No such host is known.
Warning (2): SoapClient(http://soap.service.com/serivce.svc) [soapclient.soapclient]: failed to open stream: php_network_getaddresses: getaddrinfo failed: No such host is known.
Error: SOAP-ERROR: Parsing Schema: can't import schema from 'http://soap.service.com/serivce.svc'
How can I gracefully handle the error so that php continues to run, so I can set a variable and render an HTML page indicating that there was a problem connecting
This was a cakephp issue
https://github.com/cakephp/cakephp/issues/8501
$restore = error_reporting(0);
try {
$soap_client = new SoapClient($wsdl_file, ['exceptions' => true]);
}
catch (SoapFault $e) {
trigger_error($e->getMessage()); // Overwrites E_ERROR with E_USER_NOTICE
}
finally {
error_reporting($restore);
}
Related
I have Sentry keeping track of uncaught exceptions in my PHP application, and I noticed a peculiar uncaught exception from PDO. The code looks like this:
/**
* #return boolean TRUE if the connection to the database worked; FALSE otherwise.
*/
public function verifyDatabase() {
try{
$this->pdo->query('SELECT 1');
return true;
}
catch (\PDOException $e) {
echo 'Lost connection to database: ' . $e->getMessage() . PHP_EOL;
return false;
}
}
This should catch errors like "MySQL server has gone away", and it indeed works on my development machine. However, Sentry recently recorded this error:
ErrorException
PDO::query(): MySQL server has gone away
According to sentry, this was thrown by the $this->pdo->query('SELECT 1'); statement above. Errors like this should have been caught by the try/catch. Why is PDO throwing an ErrorException rather than a PDOException?
I can't reproduce an ErrorException.
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', ..., ...);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
sleep(20); // during this sleep, I stop my MySQL Server instance.
$result = $pdo->query("SELECT 1");
Output:
Warning: PDO::query(): MySQL server has gone away
Warning: PDO::query(): Error reading result set's header
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Stack trace:
#0 /Users/bkarwin/Documents/SO/pdo.php(8): PDO->query('SELECT 1')
This shows it throws a PDOException when the server has gone away, not an ErrorException.
Tested with MySQL 5.6.37 and PHP 7.1.23.
I wonder if the code you show in your question is actually the code that is deployed and throwing the exception to Sentry. Perhaps you have some code like:
catch (\PDOException $e) {
throw ErrorException($e->getMessage());
}
Either in your verifyDatabase() function, or else in the code that calls verifyDatabase(). In other words, what does your app do when verifyDatabase() returns false?
Okay, I think I've figured it out. It appears that this is related to a bug in which the PDO MySQL driver emits warnings even when they are supposed to be disabled (See also: this answer). I believe Sentry is then catching these as errors.
I was finally able to replicate, and solve this, by modifying Bill Karwin's test script:
// Initialize the Sentry reporting client
$ravenClient = new \Raven_Client(SENTRY_KEY);
$ravenClient->install();
echo 'Connecting...' . PHP_EOL;
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'Connected. Waiting...' . PHP_EOL;
sleep(20); // during this sleep, I stop my MySQL Server instance.
echo 'Querying...' . PHP_EOL;
try {
$result = $pdo->query("SELECT 1");
}
catch(\PDOException $e) {
echo 'Caught PDOException ' . $e->getMessage() . PHP_EOL;
}
This will print the following:
Connecting...
Connected. Waiting...
Querying...
PHP Warning: PDO::query(): MySQL server has gone away in /home/xxx/src/test.php on line 37
PHP Stack trace:
PHP 1. {main}() /home/xxx/src/test.php:0
PHP 2. PDO->query() /home/xxx/src/test.php:37
Caught PDOException SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Done.
And Sentry will record an ErrorException on the query() line.
I was able to solve this issue by implementing the "solution" posted by jferrer on the PHP bug report.
// Convert NOTICE, WARNING, ... in Exceptions
$convertErrorToException = function ($level, $message, $file, $line){
throw new ErrorException($message, 0, $level, $file, $line);
};
// The $previousErrorHandler will contain Sentry's handler
$previousErrorHandler = set_error_handler($convertErrorToException);
try {
$result = $pdo->query("SELECT 1");
}
catch(\PDOException $e) {
echo 'Caught PDOException ' . $e->getMessage() . PHP_EOL;
}
catch(\ErrorException $e) {
echo 'Caught ErrorException ' . $e->getMessage() . PHP_EOL;
}
// Restore Sentry as the default handler
set_error_handler($previousErrorHandler);
This results in just the ErrorException being thrown and caught:
Connecting...
Connected. Waiting...
Querying...
Caught ErrorException PDO::query(): MySQL server has gone away
Done.
I'm trying to catch an exception when sending an email, but Laravel won't do it. I read that Laravel turns every warning and error into an ErrorException but that doesn't seem to be working in my case.
$transportExchange = new SmtpTransport($myHost, 25, 'tls');
$transportExchange->setUsername('...');
$transportExchange->setPassword('...');
$configExchange = new Swift_Mailer($transportExchange);
try {
Mail::setSwiftMailer($configExchange);
Mail::to($email['to'])->send(new GeneralEmail($email));
} catch (ErrorException $ex) {
do_something();
}
When the password is not correct, I'm getting a Laravel error screen showing stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
But instead of that I want to reach the do_something() statement.
After three days I found the answer in here: Why does `catch (Exception $e)` not handle this `ErrorException`?
This is what I needed to do:
try {
static::$function_name($url);
} catch (\Exception $e) {}
I am reading some extra information from Redis and the desired behaviour is to skip connection error silently, if any:
try {
$r = new Redis();
$r->connect("127.0.0.1", "6379");
} catch (Error $e) {
;
} catch (Throwable $e) {
;
}
If Redis fails, monitoring system will show alert to right people to fix it.
Unfortunatelly the code above still causes Yii to fail and produce HTTP 500:
2018/04/09 12:28:04 [error] [php] Redis::connect(): connect() failed: Connection refused
What am I doing wrong?
You need to catch the Exception thrown...
try {
$r = new Redis();
$r->connect("127.0.0.1", "6379");
} catch (\Exception $e) {
;
}
I think you can catch the very specific exception of Predis\Connection\ConnectionException if you need to.
I'm getting this error when I run in local host, if internet is disconnected (if internet is connect its ok) I want to handle this error, "error can show " but want to handle not fatal error break on PHP page.
Warning: SimpleXMLElement::__construct() [simplexmlelement.--construct]:
php_network_getaddresses: getaddrinfo failed: No such host is known.
in F:\xampp\htdocs\shoptpoint\sections\docType_head_index.php on line 30
but I'm trying to handle using try-catch. Below is my code
$apiurl="http://publisher.usb.api.shopping.com/publisher/3.0/rest/GeneralSearch?apiKey=78b0db8a-0ee1-4939-a2f9-d3cd95ec0fcc&trackingId=7000610&categoryId='5855855'";
try{
new SimpleXMLElement($apiurl,null, true);
}catch(Exception $e){
echo $e->getMessage();
}
How do I handle the error and my page can execute end of the project?
Using set_error_handler, you can do the following to convert any notices/warnings raised by SimpleXMLElement into a catchable Exception.
Take the following:-
<?php
function getData() {
return new SimpleXMLElement('http://10.0.1.1', null, true);
}
$xml = getData();
/*
PHP Warning: SimpleXMLElement::__construct(http://10.0.1.1): failed to open stream: Operation timed out
PHP Warning: SimpleXMLElement::__construct(): I/O warning : failed to load external entity "http://10.0.1.1"
PHP Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML'
*/
See how we get 2 Warnings before the the Exception from SimpleXMLElement is thrown? Well, we can convert those to an Exception like this:-
<?php
function getData() {
set_error_handler(function($errno, $errstr, $errfile, $errline) {
throw new Exception($errstr, $errno);
});
try {
$xml = new SimpleXMLElement('http://10.0.1.1', null, true);
}catch(Exception $e) {
restore_error_handler();
throw $e;
}
return $xml;
}
$xml = getData();
/*
PHP Fatal error: Uncaught exception 'Exception' with message 'SimpleXMLElement::__construct(http://10.0.1.1): failed to open stream: Operation timed out'
*/
Good luck,
Anthony.
If for any reason you don't want to set up the error handler you can also use some libxml functions to suppress E_WARNING from raising:
// remembers the old setting and enables usage of libxml internal error handler
$previousSetting = libxml_use_internal_errors(true);
// still need to try/catch because invalid XML raises an Exception
try {
// XML is missing root node
new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>',null, true);
} catch(Exception $e) {
echo $e->getMessage(); // this won't help much: String could not be parsed as XML
$xmlError = libxml_get_last_error(); // returns object of class LibXMLError or FALSE
if ($xmlError) {
echo $xmlError->message; // this is more helpful: Start tag expected, '<' not found
}
}
// sets libxml usage of internal error handler to previous setting
libxml_use_internal_errors($previousSetting);
Alternatively you can use libxml_get_errors() instead of libxml_get_last_error() to get all errors. With it you can get all errors regarding parsing the XML as an array of LibXMLError objects.
Some helpful links:
https://www.php.net/manual/en/function.libxml-use-internal-errors.php
https://www.php.net/manual/en/function.libxml-get-last-error.php
I am writing a script to install the database of an application in php. It working fine but when im trying to install a database that doesnt exist i want only my own error message but i keep getting the default Warning : Warning: mysqli::mysqli() [mysqli.mysqli]: (HY000/2005): Unknown MySQL server host 'kasdasd'.
So I know that the host is wrong and I want it to be so, with only my own errormessage. How do I get rid of this message?
My connectclass with parameter DBConfig $config:
$this->mysqli = new mysqli($config->m_host,
$config->m_user,
$config->m_passw,
$config->m_db);
if ($this->mysqli->connect_error) {
return false;
}
$this->mysqli->set_charset("utf8");
return true;
an easy solution would be to see if you can open the hostname using fsockopen and suppressing the errors:
$port = 80;
if($fp = #fsockopen($config->m_host,$port)){
$db = new mysqli($config->m_host,$config->m_user,$config->m_passw,$config->m_db);
}else{
echo 'hostname not recognized';
}
#fclose($fp);
Edited:
You can use
if ($mysqli->connect_error) {
/** handle your error here **/
// Throw a custom exception if you like! (see below)
// or just echo "There was an error";
}
You can further use mysqli_connect_errno() to find out wht happened and handle it accordingly.
Edit: mysqli doesn't throw erros so below is incorrect.
Wrap your code in a try-catch, then you can throw whatever kind of error you like:
try {
/** your code here **/
} catch (Exception $e) {
/** your handling here **/
// i.e.
throw new BadHostNameException($config->m_host);
// or
echo "Could not connect!":
}
Note: you should replace Exception $e with the specific kind of exception a bad host throws so catch(MysqlBadHostnameException $e) (the type of error will be in your error log from your previous attempts or you can do get_class($e) in my example above.
// Isusing a custom exception: Add this outside of your class..
class BadHostNameException extends Exception {}