How to serve big files through PHP

HeavyThere are many reasons why you could be led to serve files though an application server: let's say for example you want to restrict the access of certain files to the registered users of your website (like the latest private pictures of Tabatha Big Bolts), every time somebody wants to display or download those files you must check that this somebody is logged in your site. The quick and simple way of doing that would be:

<?php
  // Here goes your code for checking that the user is logged in
  // ...
  // ...

  if ($logged_in) {
    $filename = 'path/to/your/file';
    $mimetype = 'mime/type';
    header('Content-Type: '.$mimetype );
    echo readfile($filename);
  }
  else {
    echo 'Tabatha says you haven\'t paid.';
  }
?>

This should work... until you have to deal with a big file, like a video or a really large picture. The readfile() function is loading the whole file into memory, which means that serving heavy files or several files at the same time could kill the performances of your server or simply generate errors by exceeding the memory_limit setting. You sure could edit these settings, given that you can perform such kind of change, but there is another way: split your file and serve it chunk by chunk. That is what the readfile_chunked() function found in the PHP documentation does:

<?php
  define('CHUNK_SIZE', 1024*1024); // Size (in bytes) of tiles chunk

  // Read a file and display its content chunk by chunk
  function readfile_chunked($filename, $retbytes = TRUE) {
    $buffer = '';
    $cnt =0;
    // $handle = fopen($filename, 'rb');
    $handle = fopen($filename, 'rb');
    if ($handle === false) {
      return false;
    }
    while (!feof($handle)) {
      $buffer = fread($handle, CHUNK_SIZE);
      echo $buffer;
      ob_flush();
      flush();
      if ($retbytes) {
        $cnt += strlen($buffer);
      }
    }
    $status = fclose($handle);
    if ($retbytes && $status) {
      return $cnt; // return num. bytes delivered like readfile() does.
    }
    return $status;
  }

  // Here goes your code for checking that the user is logged in
  // ...
  // ...
  
  if ($logged_in) {
    $filename = 'path/to/your/file';
    $mimetype = 'mime/type';
    header('Content-Type: '.$mimetype );
    readfile_chunked($filename);
  }
  else {
    echo 'Tabatha says you haven\'t paid.';
  }
?>

This method is pretty easy to implement and should work with most of the configurations, but there is a better solution if you use Lighttpd, an alternative webserver that I advise you to test if not adopt. Just so you know, Lighttpd is used by websites such as Youtube or ImageShack. It has a small memory footprint and great performances. I especially like the configuration files.

Still, after learning the chunk technique I was wondering if there was a way to use Apache to seamlessly redirect users to the requested file once checks have been performed, which I found more logical since PHP is not built to serve files in the first place. Well Lighttpd does that really well and with its usual easiness; you just need to set the X-Sendfile header to your file's path, Lighty will take care of everything. Now, our example would look like this:

<?php
  // Here goes your code for checking that the user is logged in
  // ...
  // ...

  if ($logged_in) {
    $filename = 'path/to/your/file';
    header('X-Sendfile: '.$filename);
  }
  else {
    echo 'Tabatha says you haven\'t paid.';
  }
?>

And that's it. I definitely need to find a good online host with Lighttpd. Any recommendation?

Cool idea with Lightppd; I'll have to explore that. You got me thinking though: .htaccess is great for protecting your files directory, but a pain for integrating with any home-grown PHP authentication (basically, both your app and .htaccess would have to utilize the same user database).

So here is a thought: is it possible to have PHP set a cookie, then send a standard redirect to the .htaccess protected file path...and have .htaccess utilize the cookie as proof that the user is allowed to download the file?

you cannot use .htaccess to read cookies. you can do it with simple php. just check the login-session and then start reading file for downloading.

this post my problems ending.Programı

thanks for sharing the code

kayyu good website thank you

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options