warning instead of php exception? - php

I have this piece of code:
try
{
foreach($obj_c->getGalleries($db_conn1) as $gallery)
{
$gallery->Save($db_conn1);
}
$k = 0;
$testing_the_exception = 15/$k;
//settin status to 1...
$obj_c->set_exec_status(3, 1, $db_conn1);
}
catch (Exception $e)
{
//settin status to 3...
$obj_c->set_exec_status(3, 3, $db_conn1);
echo 'Caught exception: ', $e->getMessage(), "\n";
}
unset($obj_c);
The fact is that it should be entering into the catch part, because of the division by zero exception, but instead it is just popping a warning and continuing to set status to 1. Is this the expected behaviour? Thanks a lot in advance.

This is more a a wholesale solution. Set up error reporting to throw exceptions:
<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
set_error_handler("exception_error_handler");
/* Trigger exception */
strpos();
?>
This is an example from the set_error_handler documentation on php.net

Thats because division by 0 is a warning in php and not an exception. The best way to catch this is to test for it and throw your own exception.
if($k == 0)
throw new Exception("Division by zero");
$testing_the_exception = 15/$k;

Related

Catching fwrite() / socket errors

I am creating a library which is making a socket connection:
public function __construct(Options $options)
{
$this->responseBuffer = new Response();
$this->connection = stream_socket_client($options->fullSocketAddress());
if (!$this->isAlive($this->connection)) {
throw new DeadSocket();
}
stream_set_timeout($this->connection, $this->timeout);
$this->options = $options;
}
Sending the data to the server goes through send() method which looks like this:
public function send(string $xml)
{
try {
fwrite($this->connection, $xml);
} catch (Exception $e) {
$this->options->getLogger()->error(__METHOD__ . '::' . __LINE__ . " fwrite() failed " . $e->getMessage());
return;
}
}
The problem being here that catch doesn't capture PHP notice errors which seem to be the indicator in my case that connection itself is broken.
In case the server error happened, I am getting a <stream:error> (XMPP standard), however if socket broke or some timeout happened like this one, I can't catch it:
[22-May-2019 12:35:07 UTC] PHP Notice: fwrite(): send of 94 bytes failed with errno=110 Connection timed out in .../Socket.php on line 52
At this time I would like to know if error happened so that I can trigger reconnection, however doing any of these didn't seem helpful:
if (!is_resource($this->connection)) $this->reconnect();
if (!$this->connection) $this->reconnect();
As well as checking any of the socket_get_status() properties since socket_get_status($this->connection)['timed_out'] can be true even with alive connection.
Is there a way to catch this notice?
Also is there a way to simulate the behavior so I can reproduce it even when the connection doesn't time out?
You can set just the level by calling error_reporting, like:
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
Or, you can set your own error handler, using set_error_handler. You can find an example on the page as well:
<?php
// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting, so let it fall
// through to the standard PHP error handler
return false;
}
switch ($errno) {
case E_USER_ERROR:
echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
echo " Fatal error on line $errline in file $errfile";
echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
echo "Aborting...<br />\n";
exit(1);
break;
case E_USER_WARNING:
echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
break;
case E_USER_NOTICE:
echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
break;
default:
echo "Unknown error type: [$errno] $errstr<br />\n";
break;
}
/* Don't execute PHP internal error handler */
return true;
}
// function to test the error handling
function scale_by_log($vect, $scale)
{
if (!is_numeric($scale) || $scale <= 0) {
trigger_error("log(x) for x <= 0 is undefined, you used: scale = $scale", E_USER_ERROR);
}
if (!is_array($vect)) {
trigger_error("Incorrect input vector, array of values expected", E_USER_WARNING);
return null;
}
$temp = array();
foreach($vect as $pos => $value) {
if (!is_numeric($value)) {
trigger_error("Value at position $pos is not a number, using 0 (zero)", E_USER_NOTICE);
$value = 0;
}
$temp[$pos] = log($scale) * $value;
}
return $temp;
}
// set to the user defined error handler
$old_error_handler = set_error_handler("myErrorHandler");
// trigger some errors, first define a mixed array with a non-numeric item
echo "vector a\n";
$a = array(2, 3, "foo", 5.5, 43.3, 21.11);
print_r($a);
// now generate second array
echo "----\nvector b - a notice (b = log(PI) * a)\n";
/* Value at position $pos is not a number, using 0 (zero) */
$b = scale_by_log($a, M_PI);
print_r($b);
// this is trouble, we pass a string instead of an array
echo "----\nvector c - a warning\n";
/* Incorrect input vector, array of values expected */
$c = scale_by_log("not array", 2.3);
var_dump($c); // NULL
// this is a critical error, log of zero or negative number is undefined
echo "----\nvector d - fatal error\n";
/* log(x) for x <= 0 is undefined, you used: scale = $scale" */
$d = scale_by_log($a, -2.5);
var_dump($d); // Never reached
?>

Why isn't my PHP Error Handler Echoing All Errors?

I have code that causes 2 errors, 1 from the php function pg_query_params because I've input an invalid query, and the Exception that I throw when the result of that function is false:
if (!$res = pg_query_params($this->sql, $this->args)) {
// note pg_last_error seems to often not return anything
$msg = pg_last_error() . " " . $this->sql . PHP_EOL . " Args: " . var_export($this->args, true);
throw new \Exception("Query Execution Failure: $msg");
}
Then I have error handler code which logs the errors and is supposed to echo them. Both errors are logged, but only the last (the thrown exception) is echoed. I'd like both echoed, as the first contains helpful debugging info. I don't understand why both aren't, as I've done some debugging and echo is called for both errors. Is it something related to output buffering or a concurrency issue?
Here is a shortened version of my error handler code. The throwableHandler method is registered with set_exception_handler() and the phpErrorHandler method with set_error_handler(). I haven't included generateMessageBodyCommon() but it simply adds error info to the message body:
private function handleError(string $messageBody, int $errno)
{
// echo
if ($this->echoErrors) {
$messageBody .= 'inside echo'; // this goes into the log file for both errors
echo nl2br($messageBody, false);
}
// log
#error_log($messageBody, 3, $this->logPath);
}
public function throwableHandler(\Throwable $e)
{
$message = $this->generateMessageBodyCommon($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
$message .= PHP_EOL . "Stack Trace:" . PHP_EOL . $e->getTraceAsString();
$this->handleError($message, $e->getCode(), $exitPage);
}
public function phpErrorHandler(int $errno, string $errstr, string $errfile = null, string $errline = null)
{
$message = $this->generateMessageBodyCommon($errno, $errstr, $errfile, $errline) . PHP_EOL . "Stack Trace:". PHP_EOL . $this->getDebugBacktraceString();
$this->handleError($message, $errno, false);
}
Be careful with '#' -> #error_log($messageBody, 3, $this->logPath);
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
http://php.net/manual/en/language.operators.errorcontrol.php
Error level :
error_reporting(E_ALL);
http://www.php.net/manual/en/function.error-reporting.php
error_reporting — Sets which PHP errors are reported

How do I stop the page to display a particular warning (see detail), using exception handling or error handling?

I'm receiving this particular warning:
Warning: Division by zero in C:\xampp\htdocs\OnlineQuiz\Resultpage.php
on line 98
I've used a division expression. Something like this:
Ratio = Correct answers/Attempted questions
if both things are 0, I'll get the warning. But I don't want this. I just want a message instead of this error. How do handle this?
by adding # sign before operation to ignore errors:
Ratio = #Correct answers/Attempted questions
http://php.net/manual/en/language.operators.errorcontrol.php
Add # sign before operation to ignore errors report/messages
Ratio = #Correct_answers / $Attempted_questions
You need to check $Attempted_questions to not be zero before division:
if ($Attempted_questions != 0) {
$Ratio = $Correct_answers / $Attempted_questions
}
You can simply use try..catch along with throw as
function makeratio($Correct_answers, $Attempted_questions) {
if (!$Attempted_questions) {
throw new Exception('Division by zero');
}
return $result = ($Correct_answers / $Attempted_questions);
}
try {
echo makeratio($Correct_answers, $Attempted_questions);
} catch (Exception $e) {
echo 'Caught Exception : ' . $e->getMessage();
}

PHP error is visible in production in shared hosting

I am getting the below error in one of the file in Production, where the function is defined twice. I tried to recreate the issue, getting in a different file.
Fatal error: Cannot redeclare foo() (previously declared in
/home/content/45/8989001/html/test/test.php:5) in
/home/content/45/8989001/html/test/test.php on line 10
To suppress this error, its advised to make an entry to php.ini file, but I don't have access to it as its shared hosting.
Alternatively, its suggested to make an entry to existing php file inside the <?php ?> tags. I did the below change.
error_reporting(0); // This is not working, still error is displayed
error_reporting(E_NONE); // This is not working, still error is displayed
ini_set('display_errors', 0); // This is not working, still error is displayed
My complete code,
<?php
function foo() {
return "foo";
}
function foo() {
return "foo";
}
// error_reporting(0); // This is not working, still error is displayed
// error_reporting(E_NONE); // This is not working, still error is displayed
ini_set ( 'display_errors', 0 ); // This is not working, still error is displayed
echo "hello";
?>
Problem: How to suppress this error in Production, instead log to some file. or at-least suppress the error?
Note: The error is fixed in prod, but how to suppress it to avoid user seeing error in some other file next time
Update1:
After the below change too, the error is the same.
<?php
ini_set ( 'display_errors', 0 );
function foo() {
return "foo";
}
function foo() {
return "foo";
}
// error_reporting(0); // This is not working, still error is displayed
// error_reporting(E_NONE); // This is not working, still error is displayed
// ini_set ( 'display_errors', 0 ); // This is not working, still error is displayed
echo "hello";
?>
Update2:
<?php
register_shutdown_function( "fatal_handler" );
function fatal_handler() {
echo "inside fatal_handler";
$errfile = "test";
$errstr = "shutdown this test";
$errno = E_CORE_ERROR;
$errline = 0;
$error = error_get_last();
echo $error;
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
$newline = "\r\n";
define ( 'senderName', 'Error' );
define ( 'senderEmail', 'admin#abc.com' );
$headers = "From: " . senderName . " <" . senderEmail . "\r\n";
$subject_admin = 'Error-Fix it';
$body_admin = "Dear Admin, $newline$newline An error occured $newline" . "error number : " . $errno . $newline . " error file : $errfile" . $newline . "error line :" . $errline . $newline . "error string : $errstr" . $newline;
$body_footer = " **** This is an an auto-generated mail. kindly do not reply to this mail. Thank You. ****" . $newline . $newline;
$body_admin = $body_admin . $newline . $newline . $newline . $body_footer;
$to_admin1 = 'mymail#gmail.com';
mail ( $to_admin1, $subject_admin, $body_admin, $headers );
//error_mail(format_error( $errno, $errstr, $errfile, $errline));
}
}
function foo() {
return "foo";
}
function foo() {
return "foo";
}
// error_reporting(0); // This is not working, still error is displayed
// error_reporting(E_NONE); // This is not working, still error is displayed
// ini_set ( 'display_errors', 0 ); // This is not working, still error is displayed
echo "hello";
?>
update 3
Still getting same error
<?php
register_shutdown_function ( "fatal_handler" );
function fatal_handler() {
echo 'YAY IT WORKED';
}
function foo() {
return "foo";
}
function foo() {
return "foo";
}
// error_reporting(0); // This is not working, still error is displayed
// error_reporting(E_NONE); // This is not working, still error is displayed
// ini_set ( 'display_errors', 0 ); // This is not working, still error is displayed
echo "hello";
?>
Update4
<?php
//error_reporting(0);
function fatalErrorHandler() {
echo 'YAY IT WORKED';
}
# Registering shutdown function
register_shutdown_function('fatalErrorHandler');
// let force a Fatal error -- function does not exist
functiontest();
echo "hello";
?>
<!--
output:
Fatal error: Call to undefined function functiontest() in ...test2.php on line 12
YAY IT WORKED -->
<?php
error_reporting(0);
function fatalErrorHandler() {
echo 'YAY IT WORKED';
}
# Registering shutdown function
register_shutdown_function('fatalErrorHandler');
// let force a Fatal error -- function does not exist
functiontest();
echo "hello";
?>
<!-- output:
YAY IT WORKED -->
Final update:
This resolved my intermediate question
register_shutdown_function is not getting called
If I were you I would call my host and ask them to make the changes to my phpini. They may have special things setup.
Now you should never just hide errors. You send yourself an email and fix right away. The error you are trying to surpress is fatal and the script will no longer run, so hiding it only results in a blank page, the user stkill cannot continue.
It is a fatal error and you cannot recover from it. The way to hide fatal error properly in my opinion is to create your own error handler function.
And you would use something like this to catch the fatal errors.
http://php.net/manual/en/function.register-shutdown-function.php
The function needs to be on every page in order to catth the error. I have a error.php that I require in my db class, which is on every page.
//This function gets called every time your script shutsdown
register_shutdown_function( "fatal_handler" );
function fatal_handler() {
$errfile = "unknown file";
$errstr = "shutdown";
$errno = E_CORE_ERROR;
$errline = 0;
$error = error_get_last();
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
//send error email
error_mail(format_error( $errno, $errstr, $errfile, $errline));
}
}
UPDATE
**OP said the function is not being called. **
The above should work.
Here is basically what I use in production, it should tottally work.
ON_SCREEN_ERRORS and SEND_ERROR_EMAIL are my own config constants for development.
//Set error handler function (See function below)
set_error_handler("StandardErrorHandler");
/**
* Will take an error string and if ON_SCREEN_SQL_ERRORS is set to on, it will display the error on the screen with the SQL in a readable format and
* if SEND_SQL_ERROR_EMAILS is set to on, it will dendthe error email with the SQL in a readable format.
*
* PHP will pass these parameters automatically on error.
*
* #param string $errno The error type code.
* #param string $errstr The error string.
* #param string $errfile The file that the error occured in.
* #param string $errline The line number that the error occured.
*/
function StandardErrorHandler($errno, $errstr, $errfile, $errline) {
$Err = $errstr.'<br />'.GetErrorType($errno).'on line '.$errline.' in '.$errfile.'<br />';
if (ON_SCREEN_ERRORS===TRUE)
{
err($Err);
}
if ($errno =='256' and SEND_ERROR_EMAILS === TRUE)
{
$Path = "http://". $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// Custom error function
gfErrEmail($Err, $Path, 'SQL Error');
}
}
//Set the Fatal Error Handler function (See function below)
register_shutdown_function("FatalErrorHandler");
/**
* This function gets called on script shutdown, it will check if the last error is a fatal error. You cannot catch fatal errors,
* but using this function we will be notified about it and be able to fix it.
* If error is fatal, and if ON_SCREEN_FATAL_ERRORS is set to ON, this function will display the fatal error on the screen.
* If error is fatal, and if SEND_FATAL_ERROR_EMAILS is set to ON, this function will send error email.
*
*/
function FatalErrorHandler() {
$error = error_get_last();
if($error !== NULL) {
//check if error is of fatal, compliler or other non recoverable error types
if ($error["type"] =='1' || $error["type"] =='4' || $error["type"] =='16' || $error["type"] =='64' || $error["type"] =='4096')
{
$errno = GetErrorType($error["type"]);
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
$Err = '<strong>'.$errno.'<br/></strong>'.$errstr.'<br />'.$errno.' on line '.$errline.' in '.$errfile.'<br />';
if (ON_SCREEN_ERRORS===TRUE)
{
err($Err);
}
if (SEND_ERROR_EMAILS === TRUE)
{
$Path = 'http://'. $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
//Custom function
gfErrEmail($Err, $Path, $errno);
}
}
}
}
/**
* This function receives the error code and returns the specified string.
* The return strings are what the error message will display.
*
* #return string The error title
*/
function GetErrorType($Type)
{
switch($Type)
{
case 1:
// 'E_ERROR';
return 'Fatal Error ';
case 2:
// 'E_WARNING';
return 'Warning ';
case 4:
// 'E_PARSE';
return 'Compile Time Parse Error ';
case 8:
// 'E_NOTICE';
return 'Notice ';
case 16:
// 'E_CORE_ERROR';
return 'Fatal Start up Error ';
case 32:
// 'E_CORE_WARNING';
return 'Start Up Warning ';
case 64:
//'E_COMPILE_ERROR';
return 'Fatal Compile Time Error ';
case 128:
// 'E_COMPILE_WARNING';
return 'Compile Time Warning ';
case 256 :
// 'E_USER_ERROR' - USED FOR SQL ERRORS - DO NOT USE THIS ERROR CODE to TRIGGER_ERROR()
return 'SQL Error ';
case 512:
// 'E_USER_WARNING';
return 'Warning - Thrown using trigger_error() ';
case 1024:
// 'E_USER_NOTICE';
return 'Notice - Thrown using trigger_error() ';
case 2048:
// 'E_STRICT';
return 'Strict Error (PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.) ';
case 4096:
// 'E_RECOVERABLE_ERROR';
return 'Catchable Fatal Error (This error can be caught, use a Try Catch) ';
case 8192:
// 'E_DEPRECATED';
return 'Warns you of depreciated code that will not work in future versions of PHP. ';
case 16384:
// 'E_USER_DEPRECATED';
return 'Programmer Triggered Error - Thrown using trigger_error() ';
}
return "Error Type Undefined ";
}

php - How to catch an unexpected error?

I'm writing a script, where a lot of things could go wrong. I'm making if/else statements for the obvious things, that could heppen, but is there a way to catch something, that could possible heppen, but I don't know what it is yet?
For example something causes an error of some kind, in the middle of the script. I want to inform the user, that something has gone wrong, but without dozens of php warning scripts.
I would need something like
-- start listening && stop error reporting --
the script
-- end listening --
if(something went wrong)
$alert = 'Oops, something went wrong.';
else
$confirm = 'Everything is fine.'
Thanks.
Why not try...catch?
$has_errors = false;
try {
// code here
} catch (exception $e) {
// handle exception, or save it for later
$has_errors = true;
}
if ($has_errors!==false)
print 'This did not work';
Edit:
Here is a sample for set_error_handler, which will take care of any error that happens outside the context of a try...catch block. This will also handle notices, if PHP is configured to show notices.
based on code from: http://php.net/manual/en/function.set-error-handler.php
set_error_handler('genericErrorHandler');
function genericErrorHandler($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
switch ($errno) {
case E_USER_ERROR:
echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
echo " Fatal error on line $errline in file $errfile";
echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
echo "Aborting...<br />\n";
exit(1);
break;
case E_USER_WARNING:
echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
break;
case E_USER_NOTICE:
echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
break;
default:
echo "Unknown error type: [$errno] $errstr<br />\n";
break;
}
/* Don't execute PHP internal error handler */
return true;
}
$v = 10 / 0 ;
die('here');
Read up on Exceptions:
try {
// a bunch of stuff
// more stuff
// some more stuff
} catch (Exception $e) {
// something went wrong
}
throw new Exception('Division by zero.');
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
http://php.net/manual/en/language.exceptions.php
You should definitely use the try-catch syntax to catch any exception thrown by your script.
Additionally you can extend exceptions and implement new ones that fulfill your needs.This way, you can throw your own exceptions when you find any other kind of unexpected error (error for your script's logic).
A very short example explaining the use of extending exceptions :
//your own exception class
class limitExceededException extends Exception { ... }
try{
// your script here
if($limit > 10)
throw new limitExceededException();
}catch(limitExceededException $e){//catching only your limit exceeded exception
echo "limit exceeded! cause : ".$e->getMessage();
}catch(Exception $e){//catching all other exceptions
echo "unidentified exception : ".$e->getMessage();
}
Besides using try/catch, I think it's important to consider if you should catch an unexpected error. If it's unexpected then your code has no idea how to handle it and allowing the application to continue may produce bad data or other incorrect results. It may be better to just let it crash to an error page. I just recently had a problem where someone had added generic exception handlers to everything, and it hid the original location of the exception making the bug difficult to find.

Categories