I've tried several download scripts (particularly tested the ones in the notes of www.php.net/readfile) but no matter what i do the size of the file being sent is not being reported to the browser which means users don't know how much of the file is left to download or if they got the whole file.

i tried this:

function DownloadFile($file) { // $file = include path
        if(file_exists($file)) {
            ob_clean();
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename='.basename($file));
            header('Content-Transfer-Encoding: binary');
            header('Expires: 0');
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header('Pragma: public');
            header('Content-Length: ' . filesize($file));
            flush();
            readfile($file);
            exit;
        }

} 

and also a more advanced script that supports file-resuming (assuming of course the size was sent in the first place:
http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/

any ideas whats going on here? is it some kind of php or apache setting?

    I tried running your code on my server and it returned the size of the file...not sure why it wouldn't work on yours though. Is it giving a content-length of 0 or no content-length at all? Are all the other headers outputting correctly? Try running JUST this code with nothing else and see if it works:

    <?php
    function DownloadFile($file) 
    {
    	if(file_exists($file)) 
    	{
    		ob_clean();
    		header('Content-Description: File Transfer');
    		header('Content-Type: application/octet-stream');
    		header('Content-Disposition: attachment; filename='.basename($file));
    		header('Content-Transfer-Encoding: binary');
    		header('Expires: 0');
    		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    		header('Pragma: public');
    		header('Content-Length: ' . filesize($file));
    		flush();
    		readfile($file);
    		exit;
    	}
    } 
    
    DownloadFile('testFile.txt');
    ?>
    

    Also, make sure nothing, not even a space or newline, is being output before you call DownloadFile('testFile.txt');

      Also try surrounding the name of the file in the Content-Disposition header in quotes.

      If that doesn't work, try changing the header() to echo() so you can visually examine the headers. Also, is there a reason you're using output buffering/flush here?

        I tried the script mikell posted and gave me the same problem. You can see it running at http://www.cluboholic.com/test3.php

        doing that will send you an mp3 file but it will not report the file size to the browser.

        I also attempted removing flush and ob_clean but it didnt change anything.

        replacing header with echo gave me the following (note that i added new line breaks in the echo for readability):

        Content-Description: File Transfer
        Content-Type: application/octet-stream
        Content-Disposition: attachment; filename="test.mp3"
        Content-Transfer-Encoding: binaryExpires: 0
        Cache-Control: must-revalidate, post-check=0, pre-check=0
        Pragma: public
        Content-Length: 55844217

        is there a way of checking the http headers received by the browser? I run firefox and ie on windows.

          The link you gave me attempts to send a "test.mp3" though it's 0 bytes, so I'm not sure what's going on there. Is there a link to a working version that sends the mp3 file, even if it doesn't appear to report the size?

          Also, for FireFox, I use an add-on called HttpFox, "[a]n HTTP analyzer addon for Firefox."

            I get the same thing as bradgrafelman...a file of 0 bytes.
            If you try to access it directly it says file not found: http://www.cluboholic.com/test.mp3
            That would explain why there is no file size in the header.

            I use the "Live HTTP Headers" add on for Firefox. That and the "Tamper Data" add on is pretty useful.

              kyriakos wrote:

              Content-Length: 55844217

              But it doesn't do this when you try to set it in a header? (Or is that the wrong figure? I have entire albums ripped that are smaller than that. Or is it just seriously hardcore bitrate?🙂)

                ok my apologies for the zero-byte file. It was my mistake, i had commented out readfile while i was testing and left it like that thats why you were receiving a 0 byte file. I uncommented it now you might want to check again.

                Weedpacket the file size is
                -rw-r--r-- 1 root root 55844217 Jul 24 09:46
                thats 55mb, which is normal.

                I will try the firefox plugins to see what i get.

                  ----------------------------------------------------------
                  http://www.cluboholic.com/test3.php
                  
                  GET /test3.php HTTP/1.1
                  Host: www.cluboholic.com
                  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
                  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                  Accept-Language: en-gb,en;q=0.5
                  Accept-Encoding: gzip,deflate
                  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
                  Keep-Alive: 300
                  Connection: keep-alive
                  Cookie: 
                  
                  HTTP/1.x 200 OK
                  Date: Mon, 28 Jul 2008 06:22:15 GMT
                  Server: Apache
                  Content-Description: File Transfer
                  content-disposition: attachment; filename="test.mp3"
                  Content-Transfer-Encoding: binary
                  Expires: 0
                  Cache-Control: must-revalidate, post-check=0, pre-check=0
                  Pragma: public
                  Vary: Accept-Encoding
                  Content-Encoding: gzip
                  Connection: close
                  Transfer-Encoding: chunked
                  Content-Type: application/octet-stream
                  ----------------------------------------------------------
                  

                  this is what i get with livehttpheaders, which doesnt appear to have content-length. actually the headers dont even come in the order the script sends them.

                    No idea why its not giving you the content-length...I downloaded that file to my server and ran the script that I gave you and it gave me the content-length when I downloaded it with my browser. Here is the output from LiveHTTP Headers:

                    http:/<someurl>/test.php

                    GET /test.php HTTP/1.1
                    Host: <someurl>
                    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16
                    Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,/;q=0.5
                    Accept-Language: en-us,en;q=0.5
                    Accept-Encoding: gzip,deflate
                    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
                    Keep-Alive: 300
                    Connection: keep-alive
                    Cookie: PHPSESSID=73ca6961780a4fe5ca138710fd909d6f

                    HTTP/1.x 200 OK
                    Date: Mon, 28 Jul 2008 06:58:30 GMT
                    Server: Apache/2.2.4 (FreeBSD) mod_ssl/2.2.4 OpenSSL/0.9.8e DAV/2 PHP/5.2.3 with Suhosin-Patch
                    X-Powered-By: PHP/5.2.3
                    Content-Description: File Transfer
                    content-disposition: attachment; filename=test.mp3
                    Content-Transfer-Encoding: binary
                    Expires: 0
                    Cache-Control: must-revalidate, post-check=0, pre-check=0
                    Pragma: public
                    Content-Length: 55844217
                    Keep-Alive: timeout=5, max=100
                    Connection: Keep-Alive

                    Content-Type: application/octet-stream

                    Looks like you might be using some kind of compression on your server...you have the following headers and I don't:

                    Vary: Accept-Encoding
                    Content-Encoding: gzip
                    Connection: close
                    Transfer-Encoding: chunked

                    That might have something to do with it, I dunno...thats all I got. Good luck!

                      Indeed it might have. Is there a way of disabling gzip output handler for a specific php file?

                        FIXED!

                        got it to work. the problem was caused by mod_deflate. apparently since the output is compressed it doesn't know beforehand how long the content-length will be therefore mod_deflate appears to remove the content-length header. i disabled mod_deflate on the particular php file and now it seems to be working ok.

                        for anyone who might need it there's instructions here on how to do that:
                        http://hype-free.blogspot.com/2008/06/disabling-moddeflate-for-certain-files.html

                        thanks to everyone who tried to help 🙂

                          Write a Reply...