I'm trying to log errors from my codeigniter web app and I think the messages that get written to file are getting truncated. I say this because whenever the error is displayed on screen I get the file name where the error occurred whereas when I check the error logs it only says,
Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 24
Is there a way to have the error log return the file location of the error?
No, currently there isn't a built-in way to do this in CodeIgniter.
What you can do is to extend the core CI_Log class, override its write_log() method and use debug_backtrace() to get the appropriate file name and prepend it to the message.
// application/core/MY_Log.php
class MY_Log extends CI_Log {
public function write_log($level, $msg)
{
foreach (debug_backtrace() as $call)
{
// Somehow find the appropriate call here ...
if ( ! (/* condition to ignore error-handling calls */))
{
break;
}
$msg = '['.$call['file'].'] '.$msg;
break;
}
return parent::write_log($level, $msg);
}
}
Related
I have a PHP class called FilterInput. When my Symfony (3.0.3) based application calls a static member function of FilterInput, an implicit call to Symfony's DebugClassLoader is made. The method is called loadClass and it starts like this:
public function loadClass($class)
{
ErrorHandler::stackErrors();
try {
if ($this->isFinder) {
if ($file = $this->classLoader[0]->findFile($class)) {
require_once $file;
}
} else {
call_user_func($this->classLoader, $class);
$file = false;
}
} finally {
ErrorHandler::unstackErrors();
}
...
The issue I'm observing is that when execution reaches the include_once directive, the app fails silently. That is, the http request returns empty and there is no output in dev.log or my apache logs. I have verified that the $file variable contains the full and correct /path/to/FilterInput.php. I've also verified that this file is readable. So my questions are:
Why does execution stop at this point?
Why does it fail silently with no log error message or return data in the response.
EDIT: further information: if I fill in a junk path, e.g. "/foo/bar" then I do get an error message Compile Error: AppBundle\Components\Factory::getDBO(): Failed opening required '/foo/bar' (include_path='.:'); so presumably the silent failure is somehow related to the fact that there is a file at the given path.
require_once will fail silently of couse if a directive such as:
defined('PATH_BASE') or die();
appears at the head of the source file; and the required definition does not exist
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
I've got a custom database class which extends the MySQLi class.
It connects to the database using parent in the __construct method.
Below is the portion of the query if the query is not successful, how do I return the error from the server?
$query = parent::query($querystr, $resultmode);
if (!$query) {
$error = str_replace(
'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use',
'Syntax Error',
mysqli_error(self::getInstance()));
\core\debug::sqlerrorlog($error);
} else {
\core\debug::sqlSuccess();
}
According to docs, you just need to do $this->error.
As I understand, your problem now is that you don't pass a correct intsance of mysqli to mysql_error - maybe self::getInstance() is not doing what it supposed to, but I can't tell from what I see.
I am trying to do something like this:
$this->request->redirect("/?message=".HTML::entities($message));
However, this is resulting in my index controller dying on me (ie 500 internal server error, no stacktrace). Is this a no no?
No stacktrace while 500 error in Kohana indicates some low level error (PHP or Web Server error). It could be object properties or method Visibility issue or something.
Otherwise Kohana would generate for you exception explanation (when errors => true is set in bootstrap.php in Kohana::init() section).
Inspect your server error log file for last errors. You'll find solution there.
public function action_index()
{
$to = arr::get($_GET,'to' , 'world');
$this->response->body('hello, '.urldecode($to).'!');
}
public function action_jump() {
$to = urlencode('Tony Stark');
$this->request->redirect('/?to=' . $to);
}
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.