Dummy Dummy - 1 month ago 11x
PHP Question

Why does fopen fail within a register shutdown function?

I am working on a site in a shared host. I don't have access to the PHP ini file, or the PHP

function, and I can't use

I'm using the
function to log most errors, and trying to use the
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);
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"]);


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
, 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
loop 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
. I didn't know whether fopen was failing or there was some other problem. I was trying to log something out of the funtion and it wasn't working. Removing the stated goal (logging out of the funtion) 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 in the situation I did.


Are you using a relative path to your custom error log? If so, this note on the register_shutdown_function page might be relevant:

Working directory of the script can change inside the shutdown function under some web servers, e.g. Apache.

In fact, the second comment says:

If you want to do something with files in function, that registered in register_shutdown_function(), use ABSOLUTE paths to files instead of relative. Because when script processing is complete current working directory chages to ServerRoot (see httpd.conf)

Other things I'll mention:

Your variable $error, and the logic if ($error) { ... is misleading. See, when you register a function using register_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 that fatalHandler 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 in fatalHandler:

function fatalHandler() {
    if( $error !== NULL && $error['type'] == E_ERROR) {
        errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
        header("HTTP/1.1 500 Internal Server Error");

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 your php.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.