How to log calling line of code which produces an error - php

I get a notice from my php-script:
Undefined offset: 32 in C:\xampp\htdocs\WWW\myfilexyz.php on line 74
I want to detect where the error occurs as the procedure which produces the error is called many times.
I added the following line of code:
error_log("you made a mistake", 3, "errorfile.log");
Looking into errorfile.log, the message appears 3 times, but the procedure is called more than 100 times. How can I find the 3 lines where the error is produced?
I would like to see sometime like:
"you made a mistake, called from line 234 from start.php"

The easiest is to use a proper error handler which provides a stacktrace for each error. You can install xdebug, which outputs a lot more details about an error when activated. While you're at it, look into using xdebug to hook up a debugger (read xdebug's documentation).
Alternatively write your own error handler which uses debug_backtrace to give you a decent stacktrace.

$err = error_get_last();
error_log($err['message'] . ' in ' . $err['file'] . ' on line' . $err['line'], 3, "errorfile.log");

Related

Add PHP generated errors in error log

I have this code here to create error log:
error_log(date("[Y-m-d H:i:s]:")." You messed up!", 3, "../my-errors.log");
Here, we can see the custom error 'You messed up!' that I have set to print in the error log. I don't want to use the custom error here. Instead of this I want to set the Errors/Warnings/Notices that are generated by PHP itself.
Is this possible and how can we do that?
Thankyou
if I understood it well, you're looking for error_get_last():
array error_get_last ( void )
error_get_last — Get the last occurred error. / Gets information about the last error that occurred.
Take a look:
$last_error = error_get_last();
$formated_last_error = sprintf('%s in %s on line %d'.PHP_EOL,
$last_error['message'], $last_error['file'], $last_error['line']);
error_log(date(DATE_ATOM) . $formated_last_error().PHP_EOL, 3, '/tmp/logs.log');
However, you should take a look at set_error_handler() function which is a general approach.

PHP buffering error <unknown> in line 0

Would anybody be kind to help me with any possible information on this error? causes? login? where to look/start?
Cannot use output buffering in output buffering display handlers in <**Unknown**> on line **0**
Example code:
function test($b) { return _strrev($b); }
ob_start("test");
echo "123";
ob_end_flush();
Information:
This is CentOS 6.7
This is PHP PHP 5.5.32 (cli)
This is NOT Wordpress
This is a simple PHP file with pseudo code (above)
No caching, no Varnish, no Nginx, no custom headers
Thanks
In an effort to make this question of some use to others I will summarise the comments section in the form of an answer.
It turns out that if you make a coding error in the callback function used by ob_start it generates this somewhat unhelpful error message
In testing I quite accidentally made a silly error while amending the callback funtion shown by the questioner, I coded
<?php
function test($b) {
return str-replace('2', 'XXX', $b);
}
ob_start("test");
echo "123";
ob_end_flush();
Note the misspelling of the str_replace() function.
This generated the error
Fatal error: Unknown: Cannot use output buffering in output buffering display handlers in Unknown on line 0
So it appears that PHP cannot report runtime errors in an ob_start callback funtion. Instead it must default to a generic error along the lines of Ouch that hurt
Maybe one of us should report this as a PHP Bug
After some more testing, this error senario produces a meaningful error in PHP 7.0.5
Notice: Use of undefined constant str - assumed 'str' in tst.php on line 3
Fatal error: Uncaught Error: Call to undefined function replace() in tst.php:3
so this may be fixed now, but all previous PHP versions i.e. 5.4 / 5.5 / 5.6 produce the unhelpful error message

Alternating class not found error when using session handler

First of all, if it's relevant, this is in a session handler. This function is the one that writes to the database and is passed to session_set_save_handler along with my other functions like this
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
I have this chunk of code...
$qid = "select count(*) as total
from zen_sessions
where sesskey = '" . $key . "'";
if(!class_exists('DB'))
require_once dirname(dirname(__FILE__)).'/class/DB.class.php';
var_dump(new DB()); //this is line 109
$total = DB::select_one($qid);
the conditional and var_dump are for testing. Oddly enough sometimes it works fine while others it gives me an error:
Fatal error: Class 'DB' not found in /path/to/file/session_functions.php on line 109
I cannot figure how this wouldn't crash at the require instead of the var_dump and why only sometimes?
Thanks in advance for any insight.
edit-- response to comment/question:
The result of the following code
var_dump(class_exists('DB', false));
var_dump(is_file(dirname(__DIR__).'/class/DB.class.php'));
is:
bool(false) bool(true)
before trying to require it and the same result after the require(or true true when it doesn't give me an error)
Looks something like:
bool(true) bool(true) object(DB)#3 (0) { }
The previous code chunk is the result about once out of every 5 page loads while the error is the result the other 4.
Edit2 -- new findings.
Even more curious is according to the manual I should never see these debugging statements or errors
Note:
The "write" handler is not executed until after the output stream is
closed. Thus, output from debugging statements in the "write" handler
will never be seen in the browser. If debugging output is necessary,
it is suggested that the debug output be written to a file instead.
Edit 3 - A Note for clarity:
The DB class Should have been autoloaded(and is everywhere else in the application) the class_exists and require are simply there for testing purposes.
Edit 4 - Stack trace
I decided to try and throw an exception when the class isn't found to see the stack trace, this is what I get
Fatal error: Uncaught exception 'Exception' with message 'DB Class Not Found.'
in /path/to/file/session_functions.php:108
Stack trace: #0 [internal function]: sess_write('074dabb967260e9...', 'securityToken|s...')
#1 {main} thrown in /path/to/file/session_functions.php on line 108
The only thing that I can think of that may be causing this, is from a notice in the PHP docs for session_set_save_handler:
Warning
Current working directory is changed with some SAPIs if session is closed in the script termination. It is possible to close the session earlier with session_write_close().
From what you are experiencing, I am guessing the current working directory is changed, so require_once doesn't find the file.
I would try adding session_write_close(); to somewhere in your function and see if that fixes it.
Admittedly, not sure why is_file would return true in this case, but maybe worth a shot.
Even though I can not be sure, but I bet that the error is somewhere else and it's just projecting itself as you've described it.
In order to test and debug your code, you need to use a debugger like PDT. But then the problem is that you need to debug a part of your code that is out of debugger's reach, the session writer! To overcome this problem you can use session_write_close. You can put it somewhere at the end of your bootstrap or if you don't have one, you can do it like this:
<?php
function shutdown_function()
{
session_write_close();
}
register_shutdown_function('shutdown_function');
Then by setting a break point, you can start debugging your session code from here. Let me know if I win the bet.
try:
$save_handler = new DB();
session_set_save_handler($save_handler, true);
then map read, write, etc functions inside your class. i faced a similar issue(bizarre random errors about a class not being found) implementing another user's custom save handler workaround for HHVM with redis, and this is how i fixed it. if you are using HipHopVirtualMachine (or possibly some other type of JIT compiler or app cache), sometimes your project can cache some functions without updating, producing odd errors like this. usually a restart of the fastcgi daemon and adding white space to one of your files is enough to force it to re interpret your project.

Is there a way to easily open/edit the files shown in the PHP errors in your browser?

Is there a way (through a browser addon or other means) to easily open the files shown to be causing errors?
For example, it would be nifty to be able to click on the Notice below and open the file in my IDE, rather than having to go back to my IDE and look for the file when the notice appears.
Notice: Undefined index: xyz in C:\xampp\htdocs\index.php on line 141
You could possibly do something using set_error_handler and register_shutdown_function (to handle fatal errors) to intercept the errors and display them differently. The example below isn't a fully functional of what you're asking but should point you in the right direction. I'll leave it up to you to figure out how to launch the program of your choice.
<?php
function error_handler($errno, $errstr, $errfile, $errline)
{
echo $errstr . ' in '.$errfile.' on line ' . $errline . PHP_EOL;
}
function shutdown_handler()
{
$err = error_get_last();
// Fatal errors don't trigger the error handler so trigger the error handler manually.
if ( ! empty($err['type']) && $err['type'] === E_ERROR )
error_handler($err['type'], $err['message'], $err['file'], $err['line']);
}
set_error_handler('error_handler');
register_shutdown_function('shutdown_handler');
// The following 2 line throw errors.
preg_replace('invalid regex', '', 'Sample');
stack('overflow');
After some further research I have found that installing Xdebug and making use of the file_link_format configuration variable was exactly what I needed.
This forum thread helped me to get it set up with Netbeans which is the IDE I am using but you will be able to get it to work with any IDE/text editor with a change to the batch file they suggest.

Specify page/line when throwing die()?

I am using PHP 4, the only way I know of to cause an error and stop everything is calling die(). But in case I run into the error later and don't remember where its coming from I would like to specify the page and line number that the die() occurred on (like other php errors do). Is there a way to do this?
Thanks!
You should look into the magic constants.
echo __LINE__; // Line number
You can also run error_log() to send errors quietly to the log.
I think you should use trigger_error() to generate an E_USER_ERROR or E_USER_WARNING. This allows you to control the behaviour in detail. For example you can specify whether the messages should be shown at all using error_reporting(), or handle the E_USER_WARNING:s explicitly using set_error_handler().
The simplest way is to use:
echo __FILE__ . ": line " . __LINE__;
die();
If you were to use PHP5, you could also use Exceptions:
throw new Exception("My error message!");
The stack trace will reveal the whole call stack and the line this was thrown on.
(EDIT: Thanks to [#John Isaacs] and [#Emil H] for informing me that Exceptions weren't added to PHP until PHP5)
In addition to #Jukka Dahlbom and #Ólafur Waage's suggestions you might also consider using debug_backtrace().
Better use error_log() to report an error and debug_backtrace() for debugging. You could also write your own error handling function (see set_error_handler()) to combine both.

Categories