-1

Possible Duplicate:
forcing a file download with php
force download of different files

I am trying to allow users to download images from my site in php. I have seen a bunch of articles on it, and I was trying to use readfile from the php docs. But I can't seem to get it to work.

This is the code for the button that I am trying to set up to start the download:

        <!-- download image button  -->
    <form class="grid_12" style="text-align: center;" action="../includes/download.php" method="post">
        <input type="hidden" name="id" value="<?php echo $photo->id; ?>" />
        <input type="hidden" name="img" value="<?php echo $photo->filename; ?>" />
        <?php if(isset($_GET['cat'])){?>
            <input type="hidden" name="cat" value="<?php echo $_GET['cat']; ?>" />
        <?php } ?>  
        <div id="download"><input type="submit" name="submit" value="Download Photo" /></div>
    </form>

And this is the code I have set up in my download.php file (redirect_to is just a function that calls header(Location: var) where the var is what you pass in.

<?php
require_once('initialize.php');
?>
 <?php
header("Content-type: application/force-download; filename=".$_POST['img']);

// Force download of image file specified in URL query string and which
// is in the same directory as this script:
if(!empty($_POST['img']))
{
   $file = $_POST['img'];
   if (file_exists($file)) {
        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');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
        ob_clean();
        flush();
        readfile($file);
        exit;
    }

   $addy = "../public/photo.php?id=".$_POST['id'];
   if(isset($_POST['cat'])){
        $addy .= "&cat=".$_POST['cat'];
   }
   redirect_to($addy);
}
header("HTTP/1.0 404 Not Found");
?> 

The hidden variables I am sending in the post are mostly for the redirection to take the user back to the page they downloaded from after the download starts. On my local host I get redirected to the page I clicked the download button on. On my server I just get sent to a blank page registering as download.php. I think this has some thing to do with output buffering potentially, because I am getting a blank page. Which generally means there was some kind of output before I call the header() function.

If anyone could give me some insight as to what I am doing wrong here I would greatly appreciate it, Thanks for reading.

-Alan

Community
  • 1
  • 1
Alan DeLonga
  • 454
  • 1
  • 10
  • 27
  • 1
    do ob_start(); at the top of your download file – Aman Virk Oct 17 '12 at 18:17
  • Your script is probably vulnerable to [path traversal](https://www.owasp.org/index.php/Path_Traversal) which allows to read any file on your server. – Gumbo Oct 17 '12 at 18:17
  • 1
    You are setting the `Content-Type: ` header two times, I'm not so sure what the RFC tells about that ... you probably want to check that first. – hakre Oct 17 '12 at 18:18
  • 1
    you should give absolute path to your file into readfile(). right only you given filename ? – GBD Oct 17 '12 at 18:20
  • Thanks for all the quick responses I will look into what all of you has said. Aman, I thought about that but I was curious where the output was. hakre, I do have 2 headers, I guess I looked up where someone said to set it up like that. Gumbo, I dont think it is vulnerable to path traversal because I am using post not get, and all the values for the post are generated by the photo for the page. The only thing they could possibly do is change the photo, but I dont think they can just download anything off my server (as far as I know). GBD, I will try the absolute path and see how that works. – Alan DeLonga Oct 17 '12 at 18:33
  • Just a side note as well. The only header you really need here is header('Content-Disposition: attachment; filename='.basename($file)); – mando222 May 23 '16 at 20:47

1 Answers1

0

Thank you for the insight, I believe it was a combination of what hakre and GBD pointed out. I was calling the header twice, because I had one set up how I saw an example set it up. Then I used the example from the php doc for readfile as well...

Then I had to fix the absolute path for the image file because I was only sending in the file name. Thanks again for the quick help I really appreciate it.

**UPDATE

This fixed everything for me on my local host but on the server it now takes me to a page full of gibberish symbols instead of starting the download... I will look into this issue and repost when I find the solution.

**Fix

First I had to go into my php.ini file on the server and change allow_url_fopen = On so that the server can use file methods like readfile, fopen, etc. Then I also had to add output buffering on the file because there were so many header calls. Without output buffering the first one was called before the entire call was set up.

Thanks again for all the help, it works on my local host and server now.

Alan DeLonga
  • 454
  • 1
  • 10
  • 27