I am working on a site in a shared host. I don't have access to the PHP ini file, or the PHP ini_set
function, and I can't use php_flag
or php_value
directives.
I'm using the set_error_handler
function to log most errors, and trying to use the register_shutdown_function
to log fatal ones. I've tried several of the solutions for catching fatal errors here: How do I catch a PHP Fatal Error
. I can successfully use the solutions there to either display the errors on screen or bring up a custom error page, and to log non-fatal errors, but I can't seem to log the fatal errors.
This is simplest version of my attempts:
function errorHandler($num, $str, $file, $line) {
$now = strftime("%B %d, %Y at %I:%M %p", time());
$text = "{$now} → error {$num} in {$file}, line {$line}: {$str}\n";
$errorlog = "my_path/my_log";
$new = file_exists($errorlog) ? false : true;
if($handle = fopen($errorlog, 'a')) {
fwrite($handle, $text);
fclose($handle);
if($new) { chmod($errorlog, 0755); }
} else {
print("Could not open log file for writing"); //I'm using this to test
}
}
function fatalHandler() {
$error = error_get_last();
if($error) {
errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}
}
set_error_handler("errorHandler");
register_shutdown_function("fatalHandler");
When I test this with a non-fatal error, like echo $undefined_variable
, it works and the error is logged properly. However if I test with a fatal error, like undefined_function()
, it does not log anything and prints "could not open log file". If I test with both errors present, it logs the non-fatal one, but not the fatal one.
Your question has been identified as a possible duplicate of another question. If the answers there do not address your problem, please edit to explain in detail the parts of your question that are unique.
@Vic Seedoubleyew -Well, the most obvious thing is the warning addressed in the question you mentioned failed to open stream: ...etc
has nothing to do with my situation. That warning never happened. The test message: "could not open log file for writing" is my own message that I wrote to myself, so I would have some evidence that the if
statement was being processed. I made that message up. It's noted very clearly in my question that the message is of my own making. Anyone experiencing the problem I was will never get the message failed to open stream...etc
, so they won't be helped by a question addressing a message they never got. I assume the point of all this is to actually help dummies like me.
The title: "Why does fopen
fail within a register shutdown function" was not my title. That is someone else's edit. My question was why I couldn't write to a log within the register_shutdown_function
. I didn't know whether fopen
was failing or there was some other problem. I was trying to log something out of the function and it wasn't working. Removing the stated goal (logging out of the function) from the question, and adding someone else's assessment "why does fopen
fail", actually makes it much less useful to anyone coming here for a solution to the situation I was experiencing. Had there already been a question present which addressed writing to a file within the shutdown function, I would have found it. "Why does fopen
fail" is too specific to be useful in a search by someone who doesn't know why they can't write to a file in the function.
I wasn't going to say anything about the edit, but since you have asked me to explain, I'm explaining. I realize everyone probably gets points for edits, but take a minute to consider the effect your edit has on the usefulness of the question to someone who comes here with the situation I had.
Are you using a relative path to your custom error log? If so, this note on the
register_shutdown_function
page might be relevant:In fact, the second comment says:
Other things I'll mention:
Your variable
$error
, and the logicif ($error) { ...
is misleading. See, when you register a function usingregister_shutdown_function
, you are telling PHP to invoke that function every single time your script finishes executing - regardless of whether or not there was an error. This means thatfatalHandler
is invoked even when your script finishes with a non-fatal error, or even no error at all!Since you have an alternative method for dealing with non-fatal errors (using
set_error_handler
), you should specifically check for fatal errors infatalHandler
:See the list of PHP error levels here.
You may not be aware of this, but PHP has a built-in error-logging function. By default, it writes to the file specified for
error_log
in yourphp.ini
.If you are interested in more advanced logging, and generally taking your PHP-fu to the next level, I suggest looking into the Monolog package. It is more or less considered the universal standard for logging in professional PHP communities.
For this situations I just include file
that has content like that:
And my Logger class:
p.s. usually no need to have special logs, if You've full access to system You can enable
error_log
in php settings.