PHP: Modern error handling in functions script - php

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

Related

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.

Simply stop script execution upon notice/warning

How may arrange that script execution stops upon notice/warning, without changing other behaviour, inc, the notice/warning messages, i.e. e.g. not throwing an exception.
Stop script execution upon notice/warning is a different question.
You can create a custom error handling function, like so:
<?php
// error handler function
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
switch ($errno) {
case E_USER_ERROR: exit('Im a user error.');
case E_USER_WARNING: exit('Im a user warning');
case E_USER_NOTICE:
printNotice($errno, $errstr, $errfile, $errline);
break;
default: exit('Unknown Error');
}
// don't execute PHP internal error handler
return true;
}
function printNotice($errno, $errstr, $errfile, $errline)
{
// use the following vars to output the original error
var_dump($errno, $errstr, $errfile, $errline);
exit;
}
Important are the constants: E_USER_NOTICE and E_USER_WARNING.
The function printNotice() shows how you can print the original error,
so that it appears unmodified and then stops script execution with exit.
All the original error data (message, line number, etc.) is in the variables
$errno, $errstr, $errfile, $errline. PHP makes the error data automatically available at the registered errorhandler (here myErrorHandler).
In this example i'm forwarding all the parameters a second time, to printNotice() function, which could format the error differently or do what you like upon it.
And then register it with set_error_handler(), like so:
<?php
// register your error handler
set_error_handler('myErrorHandler');
In order to test the error handling you might use the function trigger_error():
trigger_error("This is a User Error", E_USER_ERROR);
trigger_error("This is a User Warning", E_USER_WARNING);
trigger_error("This is a User Warning", E_USER_NOTICE);
Straight forward answer to your question is NO you can't.
You have to create a custom error handler that stops execution.
As there is no way to do this outside.

insert all errors in website into mysql database (Maintain log errors in database)

i am searching for the code or script that is helpfull to insert all errors into mysql database.i do not know about it ,even not a little bit.
give me any idea about it.
how can i do this means insert all erros in database and the display them in my php page.
PHP lets you specify you own error handler - set_error_handler().
function error_handler($errno, $errstr, $errfile, $errline) {
global $db; //naughty use of global. You could re-create your database connection here instead.
switch ($errno) {
case E_NOTICE:
case E_USER_NOTICE:
$error = 'Notice';
break;
case E_WARNING:
case E_USER_WARNING:
$error = 'Warning';
break;
case E_ERROR:
case E_USER_ERROR:
$error = 'Fatal Error';
break;
default:
$error = 'Unknown';
break;
}
$db->query('INSERT INTO ...'); // create error log here
return true;
}
// Error Handler
set_error_handler('error_handler');
The parameters used in my custom function above have the same names as the manual:
$errno The first parameter, errno, contains the level of the error
raised, as an integer.
$errstr The second parameter, errstr, contains
the error message, as a string.
$errfile The third parameter is
optional, errfile, which contains the filename that the error was
raised in, as a string.
$errline The fourth parameter is optional,
errline, which contains the line number the error was raised at, as an
integer.
Using these parameters you should be able to determine what the error was, what file it was in, and what line it occured on.
i would use something like this to log custom error, but you can modify it around to store all encountered errors.
class Logger extends PDO{
private $_message;
public function __construct(){
parent::__construct("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password);//make sure these matches your database configs
return null;
}
public function setMessage($message){
$this->_message = $message;
return $this;
}
public function saveMessage(){
if (!isset($this->_message)){
die('Error Message has not been set');
}
$sql = 'INSERT INTO erros_table error_message,date_created';
$sql.= 'VALUES (:error_message,:date_created)';
$query = $this->prepare($sql);
$query->execute([':error_message' => $this->_message,':date_created' => date('y-m-d')]);
return null;
}
}
//now you will do something like this
//you can use this custom class anywhere
try{
//execute any code here
//and make sure to throw an error upon any code fail
//its up to you to throw exceptions on your custom code, but i advice you so
}catch(Exception $e){
$logger = new Logger();
$logger->setMessage($e->getMessage())->saveMessage();
}
You're question it's too generic. The main problem here is how to track errors and it's not clear if you want to track client side errors (javascript), server side errors (PHP) or transactions errors (MySQL).
In case you want to track all of these, you can develop you're own error handlers.
For example, for javascript I use this snippet of code:
window.jsErrors = [];
window.onerror = function(errorMessage, url, lineNumber) {
err = { "host" : window.location.host, "url" : url,
"error": errorMessage, "line" : lineNumber,
"user": "John" };
window.jsErrors[window.jsErrors.length] = err;
notify(err);
}
The notify funcion makes an ajax request.
For PHP, take a look at this.
For Java, take a look at Log4J DB appender
You should have to do like this for error hanling in mysql.
function throw_ex($er){
throw new Exception($er);
}
try {
$q = mysql_query("Insert into test (col1,col2,col3) VALUES ('blah','blah','blah')") or throw_ex(mysql_error());
}
catch(exception $e) {
echo "ex: ".$e;
}

Catching errors thrown by token_get_all (Tokenizer)

PHPs token_get_all function (which allows converting a PHP source code into tokens) can throw two errors: One if an unterminated multiline comment is encountered, the other if an unexpected char is found.
I would like to catch those errors and throw them as Exceptions.
Problem is: As those errors are parse errors they cannot be handled with an error handling function you would normally specify using set_error_handler.
What I have currently implemented is the following:
// Reset the error message in error_get_last()
#$errorGetLastResetUndefinedVariable;
$this->tokens = #token_get_all($code);
$error = error_get_last();
if (preg_match(
'~^(Unterminated comment) starting line ([0-9]+)$~',
$error['message'],
$matches
)
) {
throw new ParseErrorException($matches[1], $matches[2]);
}
if (preg_match(
'~^(Unexpected character in input:\s+\'(.)\' \(ASCII=[0-9]+\))~s',
$error['message'],
$matches
)
) {
throw new ParseErrorException($matches[1]);
}
It should be obvious that I'm not really excited to use that solution. Especially the fact that I reset the error message in error_get_last by accessing an undefined variable seems pretty unsatisfactory.
So: Is there a better solution to this problem?
Set a custom errorhandler using set_error_handler.
Call token_get_all.
Then unset the error handler by calling restore_error_handler.
This will allow you to catch warnings. Make sure you remove the # suppressor.
You can for instance register an error handler that is in a class that will just record any warnings for inspection later on.
Untested example code:
class CatchWarnings {
private $warnings = array();
public function handler($errno, $errstr, $errfile, $errline) {
switch ($errno) {
case E_USER_WARNING:
$this->warnings[] = $errstr;
return true; // cancel error handling bubble
}
return false; // error handling as usual
}
public function has_warnings() {
return count($this->warnings) > 0;
}
}
$cw = new CatchWarnings();
set_error_handler(array($cw, "handler"));
token_get_all();
restore_error_handler();
Usually validation and execution are two separate things, but it seems like there is no way to validate/lint a piece of PHP code (not since 5.x anyway).

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