How to use exceptions for queries? - php

I want to handle errors in MySQL queries as exceptions.
For example, if I am inserting a record but a column is not in the table then it will show me an error.
Is there any way to handle it so that the user won't be able to see the error?

CI has no good support for exceptions.You need to do is setup proper exception handling.
Now all your database errors will automatically throw exceptions. And as a bonus you have good exception handling in your entire CI application.
Register a custom errorhandler that transforms PHP errors into exceptions, for instance put this in top of your config/config.php
function my_error_handler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno))
{
// This error code is not included in error_reporting
return;
}
log_message('error', "$errstr #$errfile::$errline($errno)" );
throw new ErrorException( $errstr, $errno, 0, $errfile, $errline );
}
set_error_handler("my_error_handler");
Register an uncaught exception handler, put something like this in your config/config.php
function my_exception_handler($exception)
{
echo '<pre>';
print_r($exception);
echo '</pre>';
header( "HTTP/1.0 500 Internal Server Error" );
}
set_exception_handler("my_exception_handler");
Set a termination handler:
function my_fatal_handler()
{
$errfile = "unknown file";
$errstr = "Fatal error";
$errno = E_CORE_ERROR;
$errline = 0;
$error = error_get_last();
if ( $error !== NULL )
{
echo '<pre>';
print_r($error);
echo '</pre>';
header( "HTTP/1.0 500 Internal Server Error" );
}
}
register_shutdown_function("my_fatal_handler");
Set a custom assert handler that converts asserts into exceptions, put something like this in your config/config.php:
function my_assert_handler($file, $line, $code)
{
log_message('debug', "assertion failed #$file::$line($code)" );
throw new Exception( "assertion failed #$file::$line($code)" );
}
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_BAIL, 0);
assert_options(ASSERT_QUIET_EVAL, 0);
assert_options(ASSERT_CALLBACK, 'my_assert_handler');
Use wrappers like this in your controllers
public function controller_method( )
{
try
{
// normal flow
}
catch( Exception $e )
{
log_message( 'error', $e->getMessage( ) . ' in ' . $e->getFile() . ':' . $e->getLine() );
// on error
}
}
You can tune and customize the whole thing to your likings!
Hope this helps.
You will also need to intercept the CI show_error method. Place this in application/core/MY_exceptions.php:
class MY_Exceptions extends CI_Exceptions
{
function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
log_message( 'debug', print_r( $message, TRUE ) );
throw new Exception(is_array($message) ? $message[1] : $message, $status_code );
}
}
And leave in application/config/database.php this setting on FALSE to have database errors converted into exceptions.
$db['default']['db_debug'] = TRUE;

Related

PHP Function - Trapping for Error or Success Result

I'm working on my first function with PHP - it's a login function that calls cURL to login to an API. This is all working well so far, but I would like to add some error checking so that if the login fails or succeeds I can branch for that.
There's 2 possible types of errors that I can see:
cURL errors
API login errors
If there are no cURL errors the API will return a response in JSON like this for a successful login:
{
"token": "6a2b4af445bb7e02a77891a380f7a47a57d3f99ff408ec57a62a",
"layout": "Tasks",
"errorCode": "0",
"result": "OK"
}
and this for a failed login:
{
"errorMessage": "Invalid user account and/or password; please try again",
"errorCode": "212"
}
so that should be easy enough to trap for by the error code or result value. If there is a cURL error there could be many types of errors.
Here's the outline of my function at the moment:
function Login ($username, $password, $layout) {
$curl = curl_init();
// set curl options
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
return json_decode($response, true);
}
}
and I call it via:
$login = Login($username, $password, $layout);
Looking for advice on how I can return an error if there was a curl error and check the response on the calling page that calls the function.
As suggested by #larwence-cherone in the comments, you should throw and catch exceptions.
// note: made the method name lowercase, because uppercase usually indicates a class
function login ($username, $password, $layout) {
$curl = curl_init();
// set curl options
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
throw new Exception($err);
} else {
// returns an associative array
$result = json_decode($response, true);
// the status was not OK or if we received an error code.
// Check the API doc for a recommended way to do this
if ($result['result'] !== 'OK' || $result['errorCode'] > 0) {
$errorMessage = $result['errorMessage'];
// no error message: return a genuine error
if (!$errorMessage) {
$errorMessage = 'An undefined error occurred';
}
throw new Exception($errorMessage);
}
// if no error occurred, return the API result as an
return $result;
}
}
call the method in a try/catch block:
try {
$login = login($username, $password, $layout);
print_r($login);
} catch (Exception $error) {
echo $error;
}
If you want to refine it, you could create your own exception(s) by extending the SPL Exception class.

PHP Try Catch with custom error handler always returns empty exception

I'm trying to follow Can I try/catch a warning? and treat all warnings as exceptions. I can get the error details in the custom error handler but the ErrorException I get in my catch block is always empty.
private function SetCustomExceptionHandler() {
set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
log_message('error', '$errno ' . $errno);
log_message('error', '$errstr ' . $errstr);
log_message('error', '$errfile ' . $errfile);
log_message('error', '$errline ' . $errline);
log_message('error', '$errcontext ' . json_encode($errcontext));
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
}
$this->SetCustomExceptionHandler();
try {
//LDAP query that returns: ldap_search(): Partial search results returned: Sizelimit exceeded
}
catch (ErrorException $e) {
log_message('error', json_encode($e));
}
This was answered here: Exception message not being shown if json_encode is applied to the output
In my code, all I had to do was the following:
catch (Exception $e) {
$data['exception'] = $e->getMessage();
}
echo json_encode($data);
This was enough to get my exception data to come through my JSON array.

register_shutdown_function with error 500

I am trying to download some big videos from dropbox and then upload them again to another server. This works pretty well with small files. However when the files are getting bigger, I keep getting 500er errors. I was trying to catch them via register_shutdown_function (see How do I catch a PHP Fatal Error for more details) but apparently the handler gets never called (I dont get any emails whatsoever). Is there something I am doing wrong here?
// error handler
function fatal_handler() {
$error = error_get_last();
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
error_mail(format_error( $errno, $errstr, $errfile, $errline));
}
}
function format_error( $errno, $errstr, $errfile, $errline ) {
$trace = print_r( debug_backtrace( false ), true );
// some beautiful error output with content being the container
return $content;
}
function error_mail($msg) {
mail("email#example.org", "Error", $msg);
}
register_shutdown_function('fatal_handler');
error_reporting(E_ALL);

How to override the Exception Class and not to display the Fatal error

I am trying to write a class that communicate with an API. I would like to override the standard Exception class in PHP to return the message, error code that I want.
I have added this extension
<?php namespace API;
/**
* API Exception
*
* #package ICWS
*/
class ApiException extends \Exception
{
public function __construct($message, $code = 0)
{
// Custom ICWS API Exception Message
$apiMessage = 'ICWS API Error: ' . $message;
//More code to come to custom the error message/code.....
// Run parent construct using custom message
parent::__construct($apiMessage, $code);
}
}
?>
Then when needed I create new ApiException like so
throw new ApiException($errorMessage, $errorNo);
Finally I wrap the function that throws an exception by try{} catch() block to capture the exception.
However, I still get the a fatal error instead of just the message that I provided.
Here is my code
public function createSession($userID, $password){
$data = array('userID' => $userID,
'password' => $password);
try {
$data = $this->_makeCall('POST', 'connection', $data);
$this->_csrfToken = $data['csrfToken'];
$this->_sessionId = $data['sessionId'];
$this->_alternateHostList = $data['alternateHostList'];
} catch (Exception $e){
$this->_displayError($e);
}
}
private function _makeCall($uri, $data = false, $header = array())
{
$ch = curl_init();
$url = $this->_baseURL . $uri;
//disable the use of cached connection
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_URL, $url);
//return the respond from the API
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if(!empty($header)){
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($ch, CURLOPT_POST, true);
if ($data){
$JSON = json_encode( $data );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $JSON );
}
$result = curl_exec($ch);
//throw cURL exception
if($result === false){
$errorNo = curl_errno($ch);
$errorMessage = curl_error($ch);
throw new ApiException($errorMessage, $errorNo);
}
$result = json_decode($result, true);
//throw API exception
if( $this->_hasAPIError($result) )
){
throw new ApiException($result['message'], 0);
}
return $result;
}
private function _displayError(Exception $e){
echo 'Error Number: ' . $e->getCode() . "\n";
echo 'Error Description: ' . $e->getMessage() . "\n\n";
}
private function _hasAPIError($result){
if( isset($result['errorId']) && !empty($result['errorId'])
&& isset($result['errorCode']) && !empty($result['errorCode'])
&& isset($result['message']) && !empty($result['message'])
){
return true;
}
return false;
}
I would like to see something like this at then end "if there is an error"
Error Number: 0
Error Description: ICWS API Error: The authentication process failed
This is what I currently get
Fatal error: Uncaught exception 'API\ApiException' with message 'ICWS API Error: The authentication process failed.' in C:\phpsites\icws\API\ICWS.php:130 Stack trace: #0 C:\phpsites\icws\API\ICWS.php(57): API\ICWS->_makeCall('connection', Array) #1 C:\phpsites\icws\index.php(17): API\ICWS->createSession('user', 'pass') #2 {main} thrown in C:\phpsites\icws\API\ICWS.php on line 130
You did not import the Exception class into your namespace, so when doing catch (Exception $e), Exception is an unknown class (because PHP is assuming API\Exception) and PHP will not notice that APIException is a subclass of Exception. Curiously, PHP does not complain about catching a non-existing class (I've just confirmed this locally with PHP 5.6.8).
The following should work:
catch (\Exception $e) {
// ...
}
Alternatively:
use Exception;
// ...
catch (\Exception $e) {
// ...
}
The error is that you are catching Exception, not ApiException. Try this:
try {
$data = $this->_makeCall('POST', 'connection', $data);
$this->_csrfToken = $data['csrfToken'];
$this->_sessionId = $data['sessionId'];
$this->_alternateHostList = $data['alternateHostList'];
} catch (ApiException $e){ // Here is the change: Exception to ApiException
$this->_displayError($e);
}

PHP SoapClient timeout error handler

I am calling some web services, using SoapClient. I am looking for a mechanism which will help me to display some errors to user, whenever web services goes offline or down.
As I have to wait for some time(15 sec) before displaying any errors to user. I am adding connection_timeout in SoapClient like this, for timeout.
$this->client = new SoapClient($clienturl,array('trace' => 1,
'exceptions'=> 1,
'connection_timeout'=> 15)); //$clienturl is webservice url
Also in top section of page, I have added this line,
ini_set("default_socket_timeout", 15); // 15 seconds
After specific timeout interval I am getting different SOAP-ERROR like this,
SOAP-ERROR: Parsing WSDL: Couldn't load from $clienturl
So I am looking for an error handler which will handle these SOAP-ERROR so as to display those in human-readable format to user like "Server is down, Try again after some time." Or Is there any way to handle timeout errors?
You can put it in a try/catch
try {
$time_start = microtime(true);
$this->client = new SoapClient($clienturl,array('trace' => 1,
'exceptions'=> 1,
'connection_timeout'=> 15
));
} catch (Exception $e) {
$time_request = (microtime(true)-$time_start);
if(ini_get('default_socket_timeout') < $time_request) {
//Timeout error!
} else {
//other error
//$error = $e->getMessage();
}
}
This is what I am using for soapClien connection in php
set_error_handler('error_handler');
function connectSoapClient($soap_client){
while(true){
if($soap_client['soap_url'] == ''){
trigger_error("Soap url not found",E_USER_ERROR);
sleep(60);
continue;
}
try{
$client = #new SoapClient($soap_client['soap_url'],array("trace" => 1,"exceptions" => true));
}
catch(Exception $e){
trigger_error("Error occured while connection soap client<br />".$e->getMessage(),E_USER_ERROR);
sleep(60);
continue;
}
if($client){
break;
}
}
return $client;
}
function error_handler($errno, $errstr, $errfile, $errline){
if($errno == E_USER_ERROR){
$error_time = date("d-m-Y H:i:s");
$errstr .= "\n
############################### Error #########################################\n
Error No: $errno
Error File: $errfile
Line No: $errline
Error Time : $error_time \n
##############################################################################
";
mail($notify_to,$subject,$errstr);
}
}

Categories