kael
kael

Reputation: 6735

PHP-FPM serving blank pages after fatal php error

I've got a custom setup of nginx and php-fpm on arch linux. I'll post my configs below. I think I've read the documentation for these two programs front to back about 6 times by now, but I've reached a point where I simply can't squeeze any more information out of the system and thus have nothing left to google. Here's the skinny:

I compiled both nginx and php from scratch (I'm very familiar with this, so presumably no problems there). I've got nginx set up to serve things correctly, which it does consistently: php files get passed through the unix socket (which is both present and read-/write-accessible to the http user, which is the user that both nginx and php-fpm run as), while regular files that exist get served. Calls for folders and calls for files that don't exist are both sent to the /index.php file. All permissions are in order.

The Problem

My pages get served just fine until there's a php error. The error gets dumped to nginx's error log, and all further requests for pages from that specific child process of php-fpm return blank. They do appear to be processed, as evidenced by the fact that subsequent calls to the file with errors continue to dump error messages into the log file, but both flawed and clean files alike are returned completely blank with a 200 status code.

What's almost wilder is that I found if I then just sit on it for a few minutes, the offending php-fpm child process doesn't die, but a new one is spawned on the next request anyway, and the new process serves pages properly. From that point on, every second request is blank, while the other request comes back normal, presumably because the child processes take turns serving requests.

My test is the following:

// web directory listing:
mysite/
--index.php
--bad_file.php
--imgs/
----test.png
----test2.png

index.php:

<?php
  die('all cool');
?>

bad_file.php*:

<?php
  non_existent_function($called);
?>

* Note: I had previously posted bad_file.php to contain the line $forgetting_the_semicolon = true, but found that this doesn't actually produce the error I'm talking about (this was a simplified example that I've now implemented on my own system). The above code, however, does reproduce the error, as it produces a fatal error instead of a parse error.

test calls from terminal:

curl -i dev.mysite.com/              # "all cool"
curl -i dev.mysite.com/index.php     # Redirected to / by nginx
curl -i dev.mysite.com/imgs          # "all cool"
curl -i dev.mysite.com/imgs/test.png # returns test.png, printing gibberish
curl -i dev.mysite.com/nofile.php    # "all cool"
curl -i dev.mysite.com/bad_file.php  # blank, but error messages added to log
curl -i dev.mysite.com/              # blank! noooooooo!!
curl -i dev.mysite.com/              # still blank! noooooooo!!
#wait 5 or 6 minutes (not sure how many - probably corresponds to my php-fpm config)
curl -i dev.mysite.com/              # "all cool"
curl -i dev.mysite.com/              # blank!
curl -i dev.mysite.com/              # "all cool"
curl -i dev.mysite.com/              # blank!
#etc....

nginx.conf:

user  http;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  text/plain;

    sendfile        on;
    keepalive_timeout  65;

    index /index.php;

    server {
        listen       127.0.0.1:80;
        server_name  dev.mysite.net;
        root /path/to/web/root;

        try_files /maintenance.html $uri @php;
        location = /index.php {
          return 301 /;
        }
        location ~ .php$ {
          include fastcgi_params;
          fastcgi_pass unix:/usr/local/php/var/run/php-fpm.sock;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }
        location @php {
            include        fastcgi_params;
            fastcgi_pass   unix:/usr/local/php/var/run/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        }
    }
}

php-fpm.conf:

[global]
pid = run/php-fpm.pid
error_log = log/php-fpm.log
log_level = warning

[www]
user = http
group = http
listen = var/run/php-fpm.sock
listen.owner = http
listen.group = http
listen.mode = 0660

pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3

php.ini upon request

In Summary

All pages are served as expected until there's a php error, at which point all subsequent requests to that particular php-fpm child process are apparently processed, but returned as completely blank pages. Errors that occur are reported and continue to be reported in the nginx error log file.

If anyone's got any ideas, throw them at me. I'm dead in the water til I figure this out. Incidentally, if anyone knows of a source of legitimate documentation for php-fpm, that would also be helpful. php-fpm.org appears to be nearly useless, as does php.net's documentation for fpm.

Thanks!

Upvotes: 4

Views: 2767

Answers (1)

kael
kael

Reputation: 6735

I've been messing with this since yesterday and it looks like it's actually a bug with output buffering. After trying everything, reading everything, going crazy on it, I finally turned off output buffering and it worked fine. I've submitted a bug report here.

For those who don't know, output buffering is a setting in php.ini that prevents php from sending output across the line as soon as it receives it. Not a totally crucial feature. I switched it from 4096 to Off:

;php.ini:
...
;output_buffering = 4096
output_buffering = Off
...

Hope this helps someone else!

Upvotes: 3

Related Questions