PHP tip: How to make a file downloadable through your script

October 10, 2008 – 11:46 am Tags: ,

This seems to be a relatively common question on #zftalk nowadays, so here’s a quick wrapup!

The traditional plain-PHP way

$file = file_get_contents('some.zip');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="some.zip"');
header('Content-Length: ' . strlen($file));
echo $file;

The Zend Framework controller way

//this is inside an action in one of your controllers:
$file = file_get_contents('some.zip');
 
$this->getResponse()
     ->setBody($file)
     ->setHeader('Content-Type', 'application/zip')
     ->setHeader('Content-Disposition', 'attachment; filename="some.zip"')
     ->setHeader('Content-Length', strlen($file));
 
//If using Zend_Layout, we need to disable it:
$this->_helper->layout->disableLayout();
 
//Disable ViewRenderer:
$this->_helper->viewRenderer->setNoRender(true);

In closing

As mentioned in the comments, this approach may not be suitable especially if you deal with very large files. I recommend checking out this post about using mod_xsendfile with PHP, as it solves the issues associated with sending files “manually” through PHP.

Share this:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • description
  • E-mail this story to a friend!
  • LinkedIn
  • Pownce
  • Reddit
  • StumbleUpon
  • Technorati

RSS feed Subscribe to my RSS feed

  1. 9 Responses to “PHP tip: How to make a file downloadable through your script”

  2. Here’s a short explanation of what the ZF code does:

    the getResponse method returns the response object, which contains the headers and the data that will get sent to the user.

    So, we simply use the setBody method, which will set the body (the data) of the response, and the setHeader method, to modify the response to suit our needs.

    You could use the plain-PHP snippet with ZF and append exit; in the end to prevent any other output, but if you ever needed to unit test or something, it would cause problems. Using the response object, we can easily test its contents and headers.

    By Jani Hartikainen on Oct 10, 2008

  3. Informative.

    I was about to make such a post on my blog. I think you published it after yesterday’s conversation on #zftalk.

    By Sudheer on Oct 10, 2008

  4. This is ugly - it breaks HTTP resuming, breaks caching.

    Instead of very problematic (esp. in IE) Content-Disposition you could use mod_rewrite or /file.php/file.zip trick.

    By kL on Oct 10, 2008

  5. I don’t see how this differs from using file.php/file.zip, if that’s simply a PHP script which sends you the file. Also, Content-Disposition works perfectly well at least from what I’ve tested it.

    Perhaps you should explain your comment better next time.

    By Jani Hartikainen on Oct 11, 2008

  6. In my opinion file_get_contents is the total wrong way for handling any kind of downloading files, it will consume a lot of memory, and if the file is bigger than memory_limit, it will break the script.

    If someone wants to handle file-downloads through php, it should a least support resuming and I think using Zend_View is even in an Zend Framework Enviroment the wrong way, because it forces sending all content in one step, no chance for reading and sending data from a source in a loop.

    By robo47 on Oct 11, 2008

  7. That’s a good point. Using filesize() and fpassthru() are probably better options if your files are bigger - though you can’t use the response object “correctly” with fpassthru, unless you use output buffering, which would make it equal file_get_contents and nullifying the advantages it has

    By Jani Hartikainen on Oct 11, 2008

  8. I found mod_xsendfile a good solution to the readfile/file_get_contents dilemma. Just send the standard headers along with X-Sendfile and it handles with file transfer. Definitly worth a look…

    By Tom Graham on Oct 11, 2008

  9. file_get_contents? Seriously?

    Web applications are practically front-ends. They run some instructions in the back. You run some Apache threads, each thread is manageable, you get a reasonably performant system. Start loading entire files into memory, you then have to unload them, and your thread is busy for that process. Caching is a real pain too.

    A file should not be downloadable through a script. Create a symlink on the fly, or maybe do some socket business (in Python?) and create a mini-app to handle it. But PHP scripts are not here to serve files over HTTP; that’s what web servers are for.

    By Josh on Oct 27, 2008

  1. 1 Trackback(s)

  2. Mar 6, 2009: Sending files better: Apache mod_xsendfile and PHP | CodeUtopia

Post a Comment