In my project to catch all the PHP errors I have set up my error handling mechanism as follows:
I have set error_reporting() in index.php file which overrides
anything in the php.ini file
An error handler is set in system/codeigniter/CodeIgniter.php using
set_error_handler - this error handler, _exception_handler, is
found in system/codeigniter/Common.php
The _exception_handler function ignores E_STRICT errors, calls the
show_php_error function From the Exceptions system library if the
severity is that specified by your error_reporting() function in
index.php and logs the error according to whatever you have set up in your config.php file
The handler returns FALSE so after this PHP goes on to handle the
error however it normally would according your error_reporting level
and display_errors setting.
The thing that is puzzling me is that E_ERROR errors i.e. fatal errors don’t seem to be being caught by _exception_handler at all. It’s not just that show_php_error isn’t being called, it looks like the function just isn’t being called for them. This is obviously a problem as it means that they aren’t get handled by show_php_error or logged. For example if I deliberately mistype $this->load->views('foo'); in a controller, the handler doesn’t get called.
Any suggestion about error handling would be much appreciated, thanks!
Now this is a rather big debate:
Whether you should catch the fatal errors or not.
Some say that they are FATAL so you dont know in which condition is the system but I will go with the "try to do the cleanup if the error occured".
In order to catch ALL fatal errors you will need to setup a pre_system hook.
go to application/config/hooks.php and enter
$hook['pre_system'][] = array(
'class' => 'PHPFatalError',
'function' => 'setHandler',
'filename' => 'PHPFatalError.php',
'filepath' => 'hooks'
);
after that go to hooks directory and add your handling of the error:
<?php
class PHPFatalError {
public function setHandler() {
register_shutdown_function('handleShutdown');
}
}
function handleShutdown() {
if (($error = error_get_last())) {
ob_start();
echo "<pre>";
var_dump($error);
echo "</pre>";
$message = ob_get_clean();
sendEmail($message);
ob_start();
echo '{"status":"error","message":"Internal application error!"}';
ob_flush();
exit();
}
}
as you can see we are using the register_shutdown_function to run a function that checks if an error had occured and if it had send it via email to the developer.
This setup is working flawlessly for over 2 years in several CI projects that I have been working with.
I've found this answer under an other question (https://stackoverflow.com/a/3675357), and i think it is also useful for anyone reading this question.
"For codeigniter specific error handling, you can override its 'Exception' library class by creating My_Exception class in your application/libraries folder. Copy original library function signatures into it and put in your code. It will surely work."
Simply you can handle all type of error in one file which is display
your client because of php error or any other error is not good to
display client.
Simply place file Common_Exceptions.php in core folder . Common is my because in config file I have declare $config['subclass_prefix'] = 'Common_';
Copy system\core\Exceptions.php file and paste in core\Common_Excepions file (class Common_Exceptions extends CI_Exceptions) and do your change in this file and call view for your want and display to client when error come.
NOTE: $config['log_threshold'] = 1; enable in config file for errorlog write and after you see what error come.
One more suggestion on view file which is display when error is come there place time so when you see in log then match this time and find which error is come that time
Related
My php setup currently records errors in the standard php_errorlog file. These errors tell me things like the type of error and the line it occurred on (standard stuff).
I'd like to add more information to this log, but only when an error occurs.
For example, I'd like to create a variable $error_details at the top of my script, into which I'd put things like the id of the user logged in at the time, and the php://input details.
I know I can write error_log($error_details), but this would record every time my script runs. I want it to record only when there is an error.
You can use the error_get_last function.
if (error_get_last()) {
//Error occurred
}
There are several ways to do that control error logs with libraries or self coding with tomuch works.
Monolog - Logging for PHP
Library and nice examples for basic types on Loggy
PHP Error Log Types
PHP provides a variety of error log types for identifying the severity of errors encountered when your application runs.
The error levels indicate if the engine couldn’t parse and compile your PHP statements, or couldn’t access or use a resource needed by your application, all the way down to letting you know if you have a possible typo in a variable name.
Although the error levels are integer values, there are predefined constants for each one.
Using the constants will make your code easier to read and understand and keep it forward-compatible when new error levels are introduced.
Common error levels encountered include:
Check for Predefined Constants
And here nice Tutorials : Ultimate Guide to Logging
Another Way is the base exception
PHP has a base Exception class that is available by default in the language.
The base Exception class is extensible if required.
Example: (assumes directive log_errors = 1).
try{
if(true){
throw new Exception("Something failed", 900);
}
} catch (Exception $e) {
$datetime = new DateTime();
$datetime->setTimezone(new DateTimeZone('UTC'));
$logEntry = $datetime->format('Y/m/d H:i:s') . ‘ ‘ . $e;
// log to default error_log destination
error_log($logEntry);
//Email or notice someone
//OR use fopen(); function and write in to error_log file
}
The example above would produce the following error log entry:
2020/01/05 15:02:24/Something failed/900//var/www/html/index.php/4
Shorter explanation:
I've realised I posted this as a really long-winded explanation - I've left the previous explanation below but added a shorter summary.
In my CodeIgniter application, the error reporting level is set to 0. If I try to reference an undefined index (for example) in a controller or view, no error is outputted which is as expected.
However, I have a library, which loads in a third party class (NuSoap).
If the NuSoap class experiences an error - it will still output the error in my application.
Errors will also be outputted if the error is encountered in the library file itself.
Why is this? If it's being loaded in through CodeIgniter, through a library surely it should inherit the error reporting level?
Previous (long-winded) explanation:
I'm having some trouble understanding how the error reporting is working throughout my CodeIgniter application.
In index.php my error reporting is set up as follows:
if (defined('ENVIRONMENT'))
{
switch (ENVIRONMENT)
{
case 'development':
error_reporting(E_ALL);
break;
case 'testing':
case 'production':
error_reporting(0);
break;
default:
exit('The application environment is not set correctly.');
}
}
I'm using the production environment, so my expected output when an error/warning/notice is due would be that nothing is displayed, but this isn't the case.
It's taken a while to get this far but I've made a couple of discoveries.
The reason I've picked up on this is during testing. My aim was to catch any errors connecting to an API we use which we connect to using a NuSoap client.
When I changed the username/password to make them deliberately incorrect, I found that PHP notices were being outputted from the NuSoap class - however my error reporting level is set to 0.
The error is a PHP Notice (Undefined index)
I have a library which included the main NuSoap class:
<?php
if(!defined('BASEPATH')) {
exit('No direct script access allowed');
}
class NuSoap {
var $nusoap_client;
public function __construct() {
/* Load the NuSoap class */
require_once('../httpdocs/application/libraries/nusoap/nusoap.php');
/* Initialise the NuSoap client */
$this->nusoap_client = new nusoap_client(NUSOAP_WSDL_FILE, 'wsdl', '', '', '', '', 120, 120);
/* Set the credentials */
$this->nusoap_client->set_credentials(USERNAME, PASSWORD);
$this->nusoap_client = $this->nusoap_client->getProxy();
}
}
?>
And the error is coming from the included file /application/libraries/nusoap/nusoap.php
In a seperate controller, which doesn't use the NuSoap library, I placed the following code in the index function:
$arr = array(); $arr['exists'] = true;
echo 'deliberate error - ' . $arr['not_exists'];
die(phpinfo());
Now going on the fact that the NuSoap class is outputting a notice for an undefined error, I would also expect the above to, but it doesn't.
Also - in the PHP Info output the following doesn't make sense to me:
Directive Local Value Master Value
display_errors On On
If display_errors is on - why are they not being outputted here?
To suppress the errors being generated in nusoap.php, I've found that putting error_reporting(0) at the top of the file will do this. What I can't understand is why the error reporting configuration in CodeIgniter isn't affecting this file even though it is loaded in by a CodeIgniter library?
It seems that it was only happening in a library when another library was loaded before the library in question.
The library causing the issue was PHPGrid, which was setting display_errors to 1.
I am looking for a way in which all the errors will be logged automatically with one line of code. If you know Asp.NET, you probably know what I mean like using Application_Error event handler.
I checked PHP Logging framework? question in SO but they all look same, you should log each and every log message manually which means I need to call the log function everywhere I want to log.
What I am looking for not something like this (which is used by KLogger)
require_once 'KLogger.php';
...
$log = new KLogger ( "log.txt" , KLogger::DEBUG );
// Do database work that throws an exception
$log->LogError("An exception was thrown in ThisFunction()");
// Print out some information
$log->LogInfo("Internal Query Time: $time_ms milliseconds");
// Print out the value of some variables
$log->LogDebug("User Count: $User_Count");
You can create your own custom error handler function in PHP and set it as the error handler
something like:
function handle_error($error_level,$error_message)
{
/*
here do what you want...typically log it into db/file/send out
emails based on error level etc..
*/
}
and to set this function as your default error handler for PHP add this line:
set_error_handler("handle_error");
All errors will now be handled by PHP based on what is written inside handle_error
mkdir() is working correctly this question is more about catching an error. Instead of printing this when the directory exists I would just like to have it write to a message to me in a custom log. How do I create this exception.
Warning: mkdir() [function.mkdir]: File exists
I would just like to have it write to a message to me in a custom log.
the solution is very easy. PHP already have everything for you:
ini_set('display_errors',0);
ini_set('log_errors',1);
ini_set('error_log','/path/to/custom.log');
or same settings in the php.ini or .htaccess
I think it would be better than write each possible error manually
If you don't want this error to be logged (as it may be not error but part of application logic), you can check folder existence first
if (!file_exists($folder)) mkdir($folder);
else {/*take some appropriate action*/}
You can stop the error message from displaying either by suppressing error messages globally (in config or runtime) with the display_errors setting, or case by case by prefixing the function call with an #-character. (E.g. #mkdir('...')).
You can then check with error_get_last when mkdir returns false.
For error logging global rules apply. You can log errors manually with error_log.
For further reading, see the manual section on Error handling.
Edit:
As suggested in the comments, a custom error handler is also a possible, arguably more robust (depending on your implementation) but certainly more elegant, solution.
function err_handler($errno, $errstr) {
// Ignore or log error here
}
set_error_handler('err_handler');
This way, the error message will not display, unless you explicitly echo it. Note, though, when using a custom error handler error_get_last will return NULL.
You can rewrite any system call function with a class like this:
file: system.php
namespace abc;
class System {
const CAN_NOT_MAKE_DIRECTORY = 1;
static public function makeDirectory($path) {
$cmd = "mkdir " . $path;
$output = \shell_exec($cmd . " 2>&1"); // system call
if ($output != "") {
throw new \Exception($output, System::CAN_NOT_MAKE_DIRECTORY);
}
return(\TRUE);
}
}
Then you can call the method and intercept the exception:
file: index.php
namespace abc;
require 'system.php';
try {
System::makeDirectory($directoryName);
} catch (\Exception $e) {
throw new \Exception($e->getMessage(), System::CAN_NOT_MAKE_DIRECTORY);
}
Now you can treat all the system errors with the try {...} catch(...) {...} finally {...} normally.
I run into this problem periodically, and I'm trying to figure out if it's a configuration issue or a peculiarity with PHP.
Basically, there will be a function foo() defined somewhere in my code, and then elsewhere I will accidentally define a function again with the same name foo(). I would expect an error of some kind to be thrown, e.g. "Fatal Error: Function already defined line 234, bar.php blah blah".
But I get nothing. I just get a blank screen. Debugging can take an eternity as I try to pinpoint exactly where the function is being accidentally redefined, without help from an error message.
My config settings for reporting errors are set to E_ALL, and I see all other kinds of errors without a hitch.
Any insights? Is there anything I can do to cause PHP to report these errors (so that I can either rename the offending function or wrap it in an if function_exists() clause)?
Edit: To be clear, I understand the many strategies to avoid namespace collisions in PHP. I'm talking about instances where for whatever reason I accidentally name a function a name that already exists during development (or for example I import a file where a function has already been defined). I would expect an error message when this occurs, which would help me debug, but I do not get one.
You can wrap function definitions in a conditional function_exists():
if (!function_exists("file_get_contents"))
{
function file_get_contents(....)
....
}
works for me.
You could wrap a function_exists check around each function and have it throw an error message if it already exists. The better way however would be finding out why fatal errors don't appear on screen. Can you check phpinfo() for the error_reporting and related settings?
This is what you should be getting when trying to redefine a function:
Fatal error: Cannot redeclare file_get_contents() in D:\xyz\htdocs\test.php on line 5
From my phpinfo():
display_errors On
error_reporting 22519 (equals... well, I don't know but it shows errors :)
In some hosting environments when error reporting was turned off completely, I have found defining a custom error handler very helpful: set_error_handler()
Are you hosting the script on your local server? I know a UK based hosting company that prevent any PHP errors from being returned at all, even if you've set E_ALL.
If this is the case consider testing the app locally with error reporting turned on.
As an alternative, you can actually check whether a function is already there by using function_exists.
if (function_exists('foo'))
{
echo 'foo function exists !!';
}
else
{
echo 'foo function does not exists !!';
}
Some suggestions to make your life easier:
I typically will create a generic functions file, where I store all my global functions that I'll be using throughout my app.
I'll also try and remain as object-oriented as possible. PHP will give errors if you're creating an object that already exists, and by encapsulating your functions into logical objects you'll have an easier time maintaining it.
It seems you're not organizing your code properly, try using a common library that you include in your files, and define functions there. Perhaps you just need to start uses classes, then you won't have collisions when you have two functions with the same name.