Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP readfile() never ends and makes Apache server hang

I have a big problem with an apache server, php app.

The server is serving a quite high traffic website which is running with php.

Every 24h or 48h, apache hangs, and i have to reboot it to be able to access the website again. I have to reboot it, because apache reaches the maximum number of allowed processes/servers (16000 for me), and it cannot free other processes because other processes are all active.

The website hosted on this server is a php app, that serve a file at the end: let say it is a download server.

Files are requested by the browser via a form that submit a POST request.

The problem is that this post request seems to never end (i can see that nearly all the 16000 processes on my server status are POST requests).

Files that are served are big files (10M to 2G), and i serve them with php readfile function (i don't want to serve them with a href link, so i use a form POST request so that the user never see where the file is on my filesystem).

The function that use php readfile seems to never end even if i use exit() at the end of it (see code snipet below).

I am asking here for a way to avoid this never ending POST requests that are caused by my php code. I want to keep POST way of serving files.

First my conf:

  • Ubuntu server 14.04
  • apache 2.4 with mpm prefork
  • php 5.5.9 (mod php)
  • hardware: 128G RAM

my mpm_prefork.conf file:

<IfModule mpm_prefork_module>
        StartServers              512
        MinSpareServers           512
        MaxSpareServers          1024
        ServerLimit             16000 # no problem with my server ram
        MaxRequestWorkers       16000
        MaxConnectionsPerChild  10000
</IfModule>

my apache2.conf file:

...
Timeout 300
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5
...

My php.ini file:

max_execution_time = 7200

my apache log files: nothing interesting for my problem

A munin graph that shows when the issue happens: enter image description here

My apache server status at looks like that: enter image description here

enter image description here

And my server class (the code that is causing the issue):

class Server
{
    /* the file is served from a remote url source */
    public function serveFileFromUrl()
    {
        if (empty($_POST)) {
            return;
        }

        $url  = $_POST['file_url'];
        $mime = $_POST['mime'];
        $name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime;
        $size = $_POST['size'];

        if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {

            // for Internet Explorer
            if ($mime == 'mp3') {
                header('Content-Type: "audio/' . $mime . '"');
            } else {
                header('Content-Type: "video/' . $mime . '"');
            }
            header('Content-disposition: attachment; filename="' . $name . '"');
            header('Expires: 0');
            if ($size !== '') {
                header('Content-Length: ' . $size);
            }
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header("Content-Transfer-Encoding: binary");
            header('Pragma: public');

        } else {

            // not for internet Explorer
            if ($mime == 'mp3') {
                header('Content-Type: "audio/' . $mime . '"');
            } else {
                header('Content-Type: "video/' . $mime . '"');
            }
            header('Content-disposition: attachment; filename="' . $name . '"');
            header('Expires: 0');
            if ($size !== '') {
                header('Content-Length: ' . $size);
            }
            header("Content-Transfer-Encoding: Binary");
            header('Pragma: no-cache');

        }

        ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
        flush();        // fix memory problems with readfile
        readfile($url); 
        @ob_end_flush();
        exit();
    }

    /* file is served from my filesystem */
    public function serveFileFromPath()
    {
        if (empty($_POST)) {
            return;
        }

        $url  = APP_PATH . '/download/' . $_POST['file_name'];
        $mime = $_POST['mime'];
        $name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime;
        $size = $_POST['size'];

        if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {

            // for Internet Explorer
            if ($mime == 'mp3') {
                header('Content-Type: "audio/' . $mime . '"');
            } else {
                header('Content-Type: "video/' . $mime . '"');
            }
            header('Content-disposition: attachment; filename="' . $name . '"');
            header('Expires: 0');
            if ($size !== '') {
                header('Content-Length: ' . $size);
            }
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header("Content-Transfer-Encoding: binary");
            header('Pragma: public');

        } else {

            // not for internet Explorer
            if ($mime == 'mp3') {
                header('Content-Type: "audio/' . $mime . '"');
            } else {
                header('Content-Type: "video/' . $mime . '"');
            }
            header('Content-disposition: attachment; filename="' . $name . '"');
            header('Expires: 0');
            if ($size !== '') {
                header('Content-Length: ' . $size);
            }
            header("Content-Transfer-Encoding: Binary");
            header('Pragma: no-cache');

        }

        ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
        flush();        // fix memory problems with readfile
        readfile($url);
        @ob_end_flush();
        exit();
    }
}

Does someone has a solution to avoid the never ending POST requests? I am ok to serve files via other thing than php if it can solve the issue.

Please no duplicate, i have added enough code, conf snippet and pictures to make this question specific :)

like image 720
hedi Avatar asked Nov 23 '15 08:11

hedi


1 Answers

mod_xsendfile is a good alternative to PHP delivering files.

https://tn123.org/mod_xsendfile/

Else you could simply add a timelimit to your PHP script, so it cannot run forever.

http://php.net/manual/de/function.set-time-limit.php

like image 118
user5542121 Avatar answered Nov 02 '22 08:11

user5542121