DB query error while Error Handling - php

I wrote the following snippet in order to handle errors.
(Page.php gets included in index page through : array( falseNamePage=> page.php, ....ect))
Perfoming some tests to see how it reacts, I delete a page.php from public_html.
RESULT :
-error logging ok
-alert email sending ok
-recording in DB : ERROR :
Notice: Undefined variable: $database in /home/.../public_html/index.php on line 40
Warning: mysql_query() expects parameter 2 to be resource, null given in /home/.../public_html/index.php on line 40 "impossible to connect with DB2"
I do not understands why it fails connecting to the DB in this case and sends back an error.
DB Connection works fine in every other cases ( delete, select,update, insert ...)
function errorHandler($errno, $errstr, $errfile, $errline)
{
require_once('connection.php');
$now = time();
$date = date("Y-m-d H:i:s",$now);
switch ($errno) {
case E_NOTICE:
case E_USER_NOTICE:
case E_DEPRECATED:
case E_USER_DEPRECATED:
case E_STRICT:
............ 5 first cases code...............
case E_WARNING:
case E_USER_WARNING:
$message_warning = "Warning : ".$errno." : ".$errstr." : ".$errfile." : ".$errline;
error_log ( $message_warning ,0);
$mail = 'my_mail#yahoo.com'; $sujet = $message_warning; $body_warning = $date." : ".$message_warning;
mail($mail,'=?UTF-8?B?'.base64_encode($sujet).'?=',stripslashes($body_warning));
$query_warning =" INSERT INTO errorlog (severity,errno,errstr,errfile,errline,time)
VALUES ('WARNING','".$errno."','".$errstr."','".$errfile."','".$errline."','".$date."')";
$result_warning = mysql_query($query_warning,$database) or die("impossible to connect with DB2");
break;
case E_ERROR:
case E_USER_ERROR:
............... 2 last cases code ..........
}
}
set_error_handler("errorHandler");
The final question is :
WHY IS AN INCLUDE ERROR ECHOED 4 TIMES ?
Does the system attempts 4 times to "open stream"?
I did :
function errorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno == E_NOTICE )
{ echo "<br/>".$errno."== E_NOTICE<br/>";}
if ($errno == E_USER_NOTICE)
{ echo "<br/>".$errno."== E_USER_NOTICE<br/>";}
if ($errno == E_DEPRECATED)
{ echo "<br/>".$errno."== E_DEPRECATED<br/>";}
if ($errno == E_USER_DEPRECATED)
{ echo "<br/>".$errno."== E_USER_DEPRECATED<br/>";}
if ($errno == E_STRICT)
{ echo "<br/>".$errno."== E_STRICT<br/>";}
if ($errno == E_WARNING)
{ echo "<br/>".$errno."== E_WARNING<br/>";}
if ($errno == E_USER_WARNING)
{ echo "<br/>".$errno."== E_USER_WARNING<br/>";}
if ($errno == E_ERROR)
{ echo "<br/>".$errno."== E_ERROR<br/>";}
if ($errno == E_USER_ERROR)
{ echo "<br/>".$errno."== E_USER_ERROR<br/>";}
}
set_error_handler("errorHandler");
RESULT :
2== E_WARNING
2== E_WARNING
2== E_WARNING
2== E_WARNING

Probably connection.php has already been included before, so when you use require_once in your code, it does not include connection.php again. Then, $database variable will not be defined, and you will got that error message.

Your problem is simple, and, in my opinion, it's YAPHPB: you're using require_once within a function definition, hoping that the file will be included just once - to shape up a function's body.
But it doesn't work like that: this code will be parsed each time (well, it's a bit simplified, but the reasons still the same) the function will get called. And because it's require_once, your file will be included just once indeed - only when the function is called first time. All the next calls will skip the file's inclusion, hence $database will not be defined.
The easiest way to fix it is to replace require_once with require. But I think the problem just will be covered - but not solved. The real solution would be to restructure your code in such way that your $database will actually become a record in registry - and will be lazily extracted from that registry if needed.
There are many ways to implement such behaviour: we often use Zend_Registry component for that. And in this topic there are some examples of how to use this component effectively.

When there is no function definition and no constant definition in connection.php use require instead of require_once.
The variable $database will not be available when the function is called the second time, because of require_once. It is a little bit bad designed here.
A solution would be to have $database as a constant, so it acts like a global variable no matter if connection.php was the included first or second time.

Related

Determining the difference between error_reporting(0) and pre-pending # in PHP

Having written a custom error handler for a PHP system I'm trying to figure out how to determine if the error reporting level (which can be obtained via error_reporting()) has been globally set to Off (0) or has been disabled for that line only using the # prefix
The issue at current is that for both circumstances the error_reporting() function returns 0
Update #1
This example unfortunately does not work for PHP 5.3.3 on CentOS 6.8 as the ini_get() function returns the same value as error_reporting()
function errhandle($errno, $errstr, $errfile, $errline) {
if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
echo 'error_reporting(0) was used';
} else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
echo '# was used';
}
}
set_error_handler('errhandle');
echo error_reporting()."\n";
echo #$arr['name'];
// Prints
22527
error_reporting(0) was used
In addition to error_reporting(), you can also check the error reporting level with ini_get('error_reporting'). Theoretically this is similar, but it has a subtle difference that makes it valuable for what you're trying to do.
If the error reporting has been disabled globally with error_reporting(0) then ini_get('error_reporting') will return the string 0. But if error reporting was left alone and the line was prefixed with #, it will return a non-zero value (the value of the existing INI directive).
So you can compare the 2 values and determine exactly what happened:
if (error_reporting() === 0 && error_reporting() === (int)ini_get('error_reporting')) {
echo 'error_reporting(0) was used';
} else if (error_reporting() === 0 && error_reporting() !== (int)ini_get('error_reporting')) {
echo '# was used';
}
This is just an example of the kind of condition you can do in your custom error handler. If it's not quite what you want, let me know and I'll try tweaking it.
Tested locally on my PHP 7.1.2 (CLI on Windows).
Update #1
After a bit more thought I came up with this idea. Just a warning, this seems very hacky and inefficient, but I'm starting to think it might be the only way to do it.
If you're following the example from the PHP docs for set_error_handler, then the function signature for your custom error handler probably looks like this:
function myErrorHandler($errno, $errstr, $errfile, $errline)
In other words, you have the file and line number where the error occurred. You can use this info to open the file itself, look at that line number, parse the tokens and look for the # character. The code would look like this:
function myErrorHandler($errno, $errstr, $errfile, $errline) {
$errfileContents = file($errfile);
$errlineContents = $errfileContents[$errline - 1];
$tokens = token_get_all('<?php ' . $errlineContents . ' ?>');
if (error_reporting() === 0) {
if (in_array('#', $tokens)){
echo '# was used';
} else {
echo 'error_reporting(0) was used';
}
}
}
Obviously you could expand that condition by checking to see if both or neither of the techniques were used.
Anyway, it's ugly, but it's working for me on my PHP 5.6.6 (CLI on Windows).

Why not output I hope result in PHP7 using try and catch? [duplicate]

I need to catch some warnings being thrown from some php native functions and then handle them.
Specifically:
array dns_get_record ( string $hostname [, int $type= DNS_ANY [, array &$authns [, array &$addtl ]]] )
It throws a warning when the DNS query fails.
try/catch doesn't work because a warning is not an exception.
I now have 2 options:
set_error_handler seems like overkill because I have to use it to filter every warning in the page (is this true?);
Adjust error reporting/display so these warnings don't get echoed to screen, then check the return value; if it's false, no records is found for hostname.
What's the best practice here?
Set and restore error handler
One possibility is to set your own error handler before the call and restore the previous error handler later with restore_error_handler().
set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();
You could build on this idea and write a re-usable error handler that logs the errors for you.
set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();
Turning errors into exceptions
You can use set_error_handler() and the ErrorException class to turn all php errors into exceptions.
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// error was suppressed with the #-operator
if (0 === error_reporting()) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
dns_get_record();
} catch (ErrorException $e) {
// ...
}
The important thing to note when using your own error handler is that it will bypass the error_reporting setting and pass all errors (notices, warnings, etc.) to your error handler. You can set a second argument on set_error_handler() to define which error types you want to receive, or access the current setting using ... = error_reporting() inside the error handler.
Suppressing the warning
Another possibility is to suppress the call with the # operator and check the return value of dns_get_record() afterwards. But I'd advise against this as errors/warnings are triggered to be handled, not to be suppressed.
The solution that really works turned out to be setting simple error handler with E_WARNING parameter, like so:
set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();
function warning_handler($errno, $errstr) {
// do something
}
Be careful with the # operator - while it suppresses warnings it also suppresses fatal errors. I spent a lot of time debugging a problem in a system where someone had written #mysql_query( '...' ) and the problem was that mysql support was not loaded into PHP and it threw a silent fatal error. It will be safe for those things that are part of the PHP core but please use it with care.
bob#mypc:~$ php -a
Interactive shell
php > echo #something(); // this will just silently die...
No further output - good luck debugging this!
bob#mypc:~$ php -a
Interactive shell
php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error: Call to undefined function something() in php shell code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
bob#mypc:~$
This time we can see why it failed.
I wanted to try/catch a warning, but at the same time keep the usual warning/error logging (e.g. in /var/log/apache2/error.log); for which the handler has to return false. However, since the "throw new..." statement basically interrupts the execution, one then has to do the "wrap in function" trick, also discussed in:
Is there a static way to throw exception in php
Or, in brief:
function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
# error_log("AAA"); # will never run after throw
/* Do execute PHP internal error handler */
# return false; # will never run after throw
}
...
set_error_handler('warning_handler', E_WARNING);
...
try {
mkdir($path, 0777, true);
} catch (Exception $e) {
echo $e->getMessage();
// ...
}
EDIT: after closer inspection, it turns out it doesn't work: the "return false && throwErrorException ..." will, basically, not throw the exception, and just log in the error log; removing the "false &&" part, as in "return throwErrorException ...", will make the exception throwing work, but will then not log in the error_log... I'd still keep this posted, though, as I haven't seen this behavior documented elsewhere.
Combining these lines of code around a file_get_contents() call to an external url helped me handle warnings like "failed to open stream: Connection timed out" much better:
set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
$iResult = file_get_contents($sUrl);
} catch (Exception $e) {
$this->sErrorMsg = $e->getMessage();
}
restore_error_handler();
This solution works within object context, too. You could use it in a function:
public function myContentGetter($sUrl)
{
... code above ...
return $iResult;
}
Normaly you should never use # unless this is the only solution. In that specific case the function dns_check_record should be use first to know if the record exists.
If dns_get_record() fails, it should return FALSE, so you can suppress the warning with # and then check the return value.
You should probably try to get rid of the warning completely, but if that's not possible, you can prepend the call with # (i.e. #dns_get_record(...)) and then use any information you can get to figure out if the warning happened or not.
try checking whether it returns some boolean value then you can simply put it as a condition. I encountered this with the oci_execute(...) which was returning some violation with my unique keys.
ex.
oci_parse($res, "[oracle pl/sql]");
if(oci_execute){
...do something
}
As of PHP8, you can do the following instead of setting error handlers to catch Errors and Warnings. I Believe in PHP 7.something you could catch some Errors.
try {
call_user_func('sprintf', array_merge([$string], $args));
} catch (Throwable $e) {
$logger->info('mesage...');
}
You should generally be somewhere that you can pass or access a logger if you bulkhead in this way, as it can obfuscate coder errors, such as passing incorrectly typed parameters to a method, and mask a variety of other problems.
https://php.watch/versions/8.0/internal-function-exceptions
Not sure if notices are caught (likely not), but you can likely solve around examples like this one, by thinking a little more about what you are looking to do.
Both builder pattern, and options patterns provide solutions for this where prior to the site of call, which can be a private function or just after validity checks, you can throw a real custom exception that is attributable only to your code. That will make even built-in functions very safe to use.
One other nice practice is to use either debug_backtrace, with DEBUG_BACKTRACE_IGNORE_ARGS or use the getTrace or getTraceAsString methods on the Throwable so that some of the context is preseved.
FolderStructure
index.php //Script File
logs //Folder for log Every warning and Errors
CustomException.php //Custom exception File
CustomException.php
/**
* Custom error handler
*/
function handleError($code, $description, $file = null, $line = null, $context = null) {
$displayErrors = ini_get("display_errors");;
$displayErrors = strtolower($displayErrors);
if (error_reporting() === 0 || $displayErrors === "on") {
return false;
}
list($error, $log) = mapErrorCode($code);
$data = array(
'timestamp' => date("Y-m-d H:i:s:u", time()),
'level' => $log,
'code' => $code,
'type' => $error,
'description' => $description,
'file' => $file,
'line' => $line,
'context' => $context,
'path' => $file,
'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
);
$data = array_map('htmlentities',$data);
return fileLog(json_encode($data));
}
/**
* This method is used to write data in file
* #param mixed $logData
* #param string $fileName
* #return boolean
*/
function fileLog($logData, $fileName = ERROR_LOG_FILE) {
$fh = fopen($fileName, 'a+');
if (is_array($logData)) {
$logData = print_r($logData, 1);
}
$status = fwrite($fh, $logData . "\n");
fclose($fh);
// $file = file_get_contents($filename);
// $content = '[' . $file .']';
// file_put_contents($content);
return ($status) ? true : false;
}
/**
* Map an error code into an Error word, and log location.
*
* #param int $code Error code to map
* #return array Array of error word, and log location.
*/
function mapErrorCode($code) {
$error = $log = null;
switch ($code) {
case E_PARSE:
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$error = 'Fatal Error';
$log = LOG_ERR;
break;
case E_WARNING:
case E_USER_WARNING:
case E_COMPILE_WARNING:
case E_RECOVERABLE_ERROR:
$error = 'Warning';
$log = LOG_WARNING;
break;
case E_NOTICE:
case E_USER_NOTICE:
$error = 'Notice';
$log = LOG_NOTICE;
break;
case E_STRICT:
$error = 'Strict';
$log = LOG_NOTICE;
break;
case E_DEPRECATED:
case E_USER_DEPRECATED:
$error = 'Deprecated';
$log = LOG_NOTICE;
break;
default :
break;
}
return array($error, $log);
}
//calling custom error handler
set_error_handler("handleError");
just include above file into your script file like this
index.php
error_reporting(E_ALL);
ini_set('display_errors', 'off');
define('ERROR_LOG_FILE', 'logs/app_errors.log');
include_once 'CustomException.php';
echo $a; // here undefined variable warning will be logged into logs/app_errors.log
Since PHP7 you can catch most errors and warnings like so:
try {
whatever();
} catch (Throwable $e) {
}
More: https://www.php.net/manual/en/language.errors.php7.php
I would only recommend using # to suppress warnings when it's a straight forward operation (e.g. $prop = #($high/($width - $depth)); to skip division by zero warnings). However in most cases it's better to handle.

PHP: Modern error handling in functions script

In my functions.php I have a set of functions used in my website's page templates. I am wondering what is the best way of handling errors. At the moment, my functions.php looks like this:
// include database
require_once 'system/db.php';
// Functions
// =========
function getUrlsPhotos($db, $resultId) {
$query = "SELECT * FROM pictures WHERE result_id=$resultID ORDER BY id ASC";
$results = $db -> query($query);
// Was there an error?
if ($db -> error) {
$output = 'error_getting_photos';
} else {
// loop for getting photos... ... ...
$output = $array_photos;
}
return $output;
}
function getActivityName($db, $activitiesId) {
$query = "SELECT * FROM activities WHERE id=$activitiesId LIMIT 1";
$results = $db -> query($query);
if ($db -> error) {
$output = 'db_error_getting_activityname';
} else {
$result = $results -> fetch_assoc();
$output = $result;
}
return $output;
}
My goal is to somehow see if an error has occured WITHOUT of course the user seeing it. What is an effective way of handling errors for all my functions? What do I need to initialize?
--- EDIT: ---
Reading more about error handling, I came up with the following script for storing errors in my database:
<?php
function errorHandler($errno, $errstr, $errfile, $errline) {
static $db;
if (empty($db)) {
$db = new PDO(DSN, DBUSER, DBPASS);
}
$query = "INSERT INTO errorlog (severity, message, filename, lineno, time) VALUES (?, ?, ?, ?, NOW())";
$stmt = $db->prepare($query);
switch ($errno) {
case E_NOTICE:
case E_USER_NOTICE:
case E_DEPRECATED:
case E_USER_DEPRECATED:
case E_STRICT:
$stmt->execute(array("NOTICE", $errstr, $errfile, $errline));
break;
case E_WARNING:
case E_USER_WARNING:
$stmt->execute(array("WARNING", $errstr, $errfile, $errline));
break;
case E_ERROR:
case E_USER_ERROR:
$stmt->execute(array("FATAL", $errstr, $errfile, $errline));
exit("FATAL error $errstr at $errfile:$errline");
default:
exit("Unknown error at $errfile:$errline");
}
}
set_error_handler("errorHandler");
My questions:
What is the best place to put this error handling function in order to be valid for all my php functions? Is it sufficient to put it at the beginning of my functions.php?
A disadvantage of this solution surely is that there is no way to get notified if the database is down. How can I achieve that in this case I for example get a notification e-mail?
Use set_error_handler and create a (ideally, but not a necessity) class to handle errors.
set_error_handler(array("ErrorHandling", "doHandleErrors"), E_USER_ERROR | E_NOTICE | E_USER_NOTICE | E_ERROR);
Note: This won't catch FATALs. To handle FATALs, I would use register_shutdown_function().
Your class would be something like this;
<?php
class ErrorHandling {
//Methods need to be static
public static function doHandleErrors($strErrorCode, $strErrorMsg, $strErrorFile, $intErrorLine) {
//Handle errors.
//Depending on the $strErrorCode, you would either display the message, or display a http status code 500 & direct to a 500 error page.
//Depending on the severity of the error, e-mail your programmers.
//Try not to display any errors to the consumer/user
//Make the error something like "Ooops, something went wrong." and not "An error occured on file.php, line 23."
//But that may be more a question for UX.se
}
}
What is the best place to put this error handling function in order to be valid for all my php functions? Is it sufficient to put it at the beginning of my functions.php?
I would go for putting set_error_handler(array("ErrorHandling", "doHandleErrors"), E_USER_ERROR | E_NOTICE | E_USER_NOTICE | E_ERROR); in your main "brain file" - before your database connection is established, so we can use your custom error handler to handle database connection issues.
A disadvantage of this solution surely is that there is no way to get notified if the database is down. How can I achieve that in this case I for example get a notification e-mail?
With a custom error handler, you can catch the error/exception and e-mail your programmers, then kill the process gracefully, displaying 500 Internal Server Error or 503 Service Unavailable page to the end user.
You can use set_error_handler in php for custom error handling
check for more
http://php.net/manual/en/function.set-error-handler.php
http://www.sitepoint.com/error-handling-in-php/
PHP : Custom error handler - handling parse & fatal errors

Make undefined variable an error in php

I have the following code snippet:
<?php
ini_set('display_errors', '1');
error_reporting(E_ALL | E_NOTICE);
print $bla;
print 7;
?>
which prints out a warning that bla is undefined, but continues afterwards. I want php to throw an error and stop code execution when an undefined variable is encountered. How to do that?
The above is just an example. I want to handle EACH undefined variable within a multi thousand block clode piece.
You could write your own error handler. And make it halt execution when you encounter this type of notice. Take a look at
http://php.net/manual/en/function.set-error-handler.php
A small and simple example:
function new_error_handler($errno, $errstr, $errfile, $errline) {
switch ($errno) {
case E_NOTICE:
if (strstr($errstr, 'Undefined variable')) {
die('Undefined variable found');
}
break;
}
}
set_error_handler('new_error_handler');
echo $foo;
Implement an error handler with set_error_handler and put a die inside.
if(!isset($bla)){
throw new Exception('bla variable is not defined');
}

Can I try/catch a warning?

I need to catch some warnings being thrown from some php native functions and then handle them.
Specifically:
array dns_get_record ( string $hostname [, int $type= DNS_ANY [, array &$authns [, array &$addtl ]]] )
It throws a warning when the DNS query fails.
try/catch doesn't work because a warning is not an exception.
I now have 2 options:
set_error_handler seems like overkill because I have to use it to filter every warning in the page (is this true?);
Adjust error reporting/display so these warnings don't get echoed to screen, then check the return value; if it's false, no records is found for hostname.
What's the best practice here?
Set and restore error handler
One possibility is to set your own error handler before the call and restore the previous error handler later with restore_error_handler().
set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();
You could build on this idea and write a re-usable error handler that logs the errors for you.
set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();
Turning errors into exceptions
You can use set_error_handler() and the ErrorException class to turn all php errors into exceptions.
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// error was suppressed with the #-operator
if (0 === error_reporting()) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
dns_get_record();
} catch (ErrorException $e) {
// ...
}
The important thing to note when using your own error handler is that it will bypass the error_reporting setting and pass all errors (notices, warnings, etc.) to your error handler. You can set a second argument on set_error_handler() to define which error types you want to receive, or access the current setting using ... = error_reporting() inside the error handler.
Suppressing the warning
Another possibility is to suppress the call with the # operator and check the return value of dns_get_record() afterwards. But I'd advise against this as errors/warnings are triggered to be handled, not to be suppressed.
The solution that really works turned out to be setting simple error handler with E_WARNING parameter, like so:
set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();
function warning_handler($errno, $errstr) {
// do something
}
Be careful with the # operator - while it suppresses warnings it also suppresses fatal errors. I spent a lot of time debugging a problem in a system where someone had written #mysql_query( '...' ) and the problem was that mysql support was not loaded into PHP and it threw a silent fatal error. It will be safe for those things that are part of the PHP core but please use it with care.
bob#mypc:~$ php -a
Interactive shell
php > echo #something(); // this will just silently die...
No further output - good luck debugging this!
bob#mypc:~$ php -a
Interactive shell
php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error: Call to undefined function something() in php shell code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
bob#mypc:~$
This time we can see why it failed.
I wanted to try/catch a warning, but at the same time keep the usual warning/error logging (e.g. in /var/log/apache2/error.log); for which the handler has to return false. However, since the "throw new..." statement basically interrupts the execution, one then has to do the "wrap in function" trick, also discussed in:
Is there a static way to throw exception in php
Or, in brief:
function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
# error_log("AAA"); # will never run after throw
/* Do execute PHP internal error handler */
# return false; # will never run after throw
}
...
set_error_handler('warning_handler', E_WARNING);
...
try {
mkdir($path, 0777, true);
} catch (Exception $e) {
echo $e->getMessage();
// ...
}
EDIT: after closer inspection, it turns out it doesn't work: the "return false && throwErrorException ..." will, basically, not throw the exception, and just log in the error log; removing the "false &&" part, as in "return throwErrorException ...", will make the exception throwing work, but will then not log in the error_log... I'd still keep this posted, though, as I haven't seen this behavior documented elsewhere.
Combining these lines of code around a file_get_contents() call to an external url helped me handle warnings like "failed to open stream: Connection timed out" much better:
set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
$iResult = file_get_contents($sUrl);
} catch (Exception $e) {
$this->sErrorMsg = $e->getMessage();
}
restore_error_handler();
This solution works within object context, too. You could use it in a function:
public function myContentGetter($sUrl)
{
... code above ...
return $iResult;
}
Normaly you should never use # unless this is the only solution. In that specific case the function dns_check_record should be use first to know if the record exists.
If dns_get_record() fails, it should return FALSE, so you can suppress the warning with # and then check the return value.
You should probably try to get rid of the warning completely, but if that's not possible, you can prepend the call with # (i.e. #dns_get_record(...)) and then use any information you can get to figure out if the warning happened or not.
try checking whether it returns some boolean value then you can simply put it as a condition. I encountered this with the oci_execute(...) which was returning some violation with my unique keys.
ex.
oci_parse($res, "[oracle pl/sql]");
if(oci_execute){
...do something
}
As of PHP8, you can do the following instead of setting error handlers to catch Errors and Warnings. I Believe in PHP 7.something you could catch some Errors.
try {
call_user_func('sprintf', array_merge([$string], $args));
} catch (Throwable $e) {
$logger->info('mesage...');
}
You should generally be somewhere that you can pass or access a logger if you bulkhead in this way, as it can obfuscate coder errors, such as passing incorrectly typed parameters to a method, and mask a variety of other problems.
https://php.watch/versions/8.0/internal-function-exceptions
Not sure if notices are caught (likely not), but you can likely solve around examples like this one, by thinking a little more about what you are looking to do.
Both builder pattern, and options patterns provide solutions for this where prior to the site of call, which can be a private function or just after validity checks, you can throw a real custom exception that is attributable only to your code. That will make even built-in functions very safe to use.
One other nice practice is to use either debug_backtrace, with DEBUG_BACKTRACE_IGNORE_ARGS or use the getTrace or getTraceAsString methods on the Throwable so that some of the context is preseved.
FolderStructure
index.php //Script File
logs //Folder for log Every warning and Errors
CustomException.php //Custom exception File
CustomException.php
/**
* Custom error handler
*/
function handleError($code, $description, $file = null, $line = null, $context = null) {
$displayErrors = ini_get("display_errors");;
$displayErrors = strtolower($displayErrors);
if (error_reporting() === 0 || $displayErrors === "on") {
return false;
}
list($error, $log) = mapErrorCode($code);
$data = array(
'timestamp' => date("Y-m-d H:i:s:u", time()),
'level' => $log,
'code' => $code,
'type' => $error,
'description' => $description,
'file' => $file,
'line' => $line,
'context' => $context,
'path' => $file,
'message' => $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'
);
$data = array_map('htmlentities',$data);
return fileLog(json_encode($data));
}
/**
* This method is used to write data in file
* #param mixed $logData
* #param string $fileName
* #return boolean
*/
function fileLog($logData, $fileName = ERROR_LOG_FILE) {
$fh = fopen($fileName, 'a+');
if (is_array($logData)) {
$logData = print_r($logData, 1);
}
$status = fwrite($fh, $logData . "\n");
fclose($fh);
// $file = file_get_contents($filename);
// $content = '[' . $file .']';
// file_put_contents($content);
return ($status) ? true : false;
}
/**
* Map an error code into an Error word, and log location.
*
* #param int $code Error code to map
* #return array Array of error word, and log location.
*/
function mapErrorCode($code) {
$error = $log = null;
switch ($code) {
case E_PARSE:
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$error = 'Fatal Error';
$log = LOG_ERR;
break;
case E_WARNING:
case E_USER_WARNING:
case E_COMPILE_WARNING:
case E_RECOVERABLE_ERROR:
$error = 'Warning';
$log = LOG_WARNING;
break;
case E_NOTICE:
case E_USER_NOTICE:
$error = 'Notice';
$log = LOG_NOTICE;
break;
case E_STRICT:
$error = 'Strict';
$log = LOG_NOTICE;
break;
case E_DEPRECATED:
case E_USER_DEPRECATED:
$error = 'Deprecated';
$log = LOG_NOTICE;
break;
default :
break;
}
return array($error, $log);
}
//calling custom error handler
set_error_handler("handleError");
just include above file into your script file like this
index.php
error_reporting(E_ALL);
ini_set('display_errors', 'off');
define('ERROR_LOG_FILE', 'logs/app_errors.log');
include_once 'CustomException.php';
echo $a; // here undefined variable warning will be logged into logs/app_errors.log
Since PHP7 you can catch most errors and warnings like so:
try {
whatever();
} catch (Throwable $e) {
}
More: https://www.php.net/manual/en/language.errors.php7.php
I would only recommend using # to suppress warnings when it's a straight forward operation (e.g. $prop = #($high/($width - $depth)); to skip division by zero warnings). However in most cases it's better to handle.

Categories