1

I have gone through all articles on Stack Overflow and can't fix my issue. I am using following code:

$file = $_GET['url'];
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"'); 
header('Content-Length: ' . filesize($file));
readfile($file);
exit;

The above mention code is downloading the file from the directly above the root and Yes it is downloading a PDF file but the file is only of 1KB size and not the original size. The $_GET['url'] is receiving ../dir/dir/filename.pdf in it. the filename is space in it as well. For security reason I cannot share the file name.

Please let me know where am I going wrong.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • further to expand on this I have also replaced application/octet-stream with application/pdf. – Syed M Hammad Kazmi Jul 07 '16 at 08:55
  • The question is "PHP (how to) Force download corrupt PDF file", yet in your question you say: "The above mention code is downloading the file" - so what is the problem? – ajmedway Jul 07 '16 at 09:00
  • The code above is downloading a file which is corrupt. When I check the size of the PDF file it is 1KB. Sorry about the confusing title. – Syed M Hammad Kazmi Jul 07 '16 at 09:05
  • after the first line, add this code and try again `echo '
    IS FILE: ' . (is_file($file) ? 'YES!' : 'NO :(') . '
    ';` - what do you see?
    – ajmedway Jul 07 '16 at 09:14
  • I see IS FILE: NO :( the file is there. Could it be because the file name has spaces in it? – Syed M Hammad Kazmi Jul 07 '16 at 09:18
  • 1
    That's your problem - you must supply a valid filename. – ajmedway Jul 07 '16 at 09:21
  • http://stackoverflow.com/questions/5595485/php-file-download – ajmedway Jul 07 '16 at 09:24
  • `$file = $_GET['url']` ... this implies that the user is inputting a full URL into the form. But the code then uses `$file` as if it's a file in the local file system. Which is it? For the rest of the code to work, `$file` needs to have a valid and complete path to the file on the local filesystem, but the user shouldn't know about paths on the local file system, so you will need some code in there to deal with that. – Simba Jul 07 '16 at 09:45

1 Answers1

1

Please make sure you are using the web server path to access the file - for instance your path could be: /home/yourusername/public/sitename/downloads/<filename>, you should check first - to help you can run this at the top of your PHP script to find out the full path for the current script:

echo '<pre>FILE PATH: '.print_r(__FILE__, true).'</pre>';
die();

Only send the filename with the url using urlencode() and on the receiving PHP script use urldecode() to handle any character encoding issues.

See here: http://php.net/manual/en/function.urlencode.php and here: http://php.net/manual/en/function.urldecode.php

So where you create your url:

<a href="/my-download-url/<?= urlencode('file name.pdf') ?>">Download File</a>

And in your php script:

$file_base_path = '/home/yourusername/public/sitename/downloads/';
$file = urldecode($_GET['url']);
$file = $file_base_path . $file;
$file = $_GET['url'];
if (file_exists($file))
{
    if (FALSE!== ($handler = fopen($file, 'r')))
    {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: chunked'); //changed to chunked
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        //header('Content-Length: ' . filesize($file)); //Remove

        //Send the content in chunks
        while(false !== ($chunk = fread($handler,4096)))
        {
            echo $chunk;
        }
    }
    exit;
}
echo "<h1>Content error</h1><p>The file does not exist!</p>";

I hope this helps you!

ajmedway
  • 1,492
  • 14
  • 28
  • Its just failing on file exists... doesn't even enter the if. What should be my path/url? should it be the whole thing from http? or will using "../dir/dir/filename.pdf" suffice? – Syed M Hammad Kazmi Jul 07 '16 at 09:39
  • You will need to find out where the file is located, otherwise you will get nowhere. Yes you can use relative paths, but it must be correct in reference to the location of the script being executed. Best to find out the full path and populate in `$file_base_path` using my code above. – ajmedway Jul 07 '16 at 09:42
  • woohoo... ok so its now downloading the file correct but the only issue is that its not a downloading with .pdf extension. I can open the downloaded file with openwith... The file_base_path trick worked. How can I make it so that it download the file with .pdf extension? do I change the Content-Type to application/pdf? Also in you code above in line 4 I don't think we need that line. – Syed M Hammad Kazmi Jul 07 '16 at 09:56
  • @SyedMHammadKazmi - excellent! Try using: `Content-Disposition = 'attachment; filename='.basename($file).'.pdf'` – ajmedway Jul 07 '16 at 10:00
  • @SyedMHammadKazmi - if this has fixed your issue, please mark my answer as accepted answer and upvote also. Thanks! – ajmedway Jul 07 '16 at 10:01
  • Still no luck but I can take over from here. Thanks for the help. – Syed M Hammad Kazmi Jul 07 '16 at 10:09