0

I'm storing files by reference, which means every file uploaded gets renamed to "temp_n", and stored in the database like ID, Name, Originalname, Mime. So when I roll a download for any file, I go to the url getfile.php?i=$id and grab the filed based off of the id. Here's my problem, it doesn't handle the files well, it will not show/force download the images, and it should force download any file there is. I'll do this to force download:

$url = "http".(!empty($_SERVER['HTTPS'])?"s":"")."://".$_SERVER['SERVER_NAME'].dirname($_SERVER['SCRIPT_NAME']);
$dir = '/uploads/messaging/'.$room.'/';
$path = $url.$dir;
header("Content-Type: " . $mime);
readfile($path.$tname);

For the specified examples, $room is 1 and is a valid folder, $path is a valid path. I have tried storing the extension as well, and doing readfile($path.$tname.$ext) where $ext was .png, but it failed. I've messed around with headers, but max I got it to force it to download getfile.php file instead of the file in question. The PHP code would contain this:

<br />
<b>Warning</b>:  readfile(http://url/uploads/messaging/1/upload_IvRWZc) [<a href='function.readfile'>function.readfile</a>]: failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden
 in <b>script/url</b> on line <b>32</b><br />

Where line 32 is the header in question, such as header("Content-Type: application/force-download"); or header('Content-Type: application/octet-stream');.

The current examples shows a broken image link, it knows it's an image (based off of the mime) but it doesn't show it. What it should do is simply download the file requested. There is no .htaccess in the folders and they are running 755 permission set.

PS. I'm not trying to trick users into downloading crap, I'm trying to make a secure file storage so nobody uploads funnyshell.php to my server and has a blast with it.

Predrag Beocanin
  • 1,402
  • 3
  • 18
  • 25

2 Answers2

1

Some ideas based on what I got from your description of the problem:

  • You probably shouldn't be passing readfile() a URL. Try passing it a valid file path instead, without the http:// prefix. You might want to check what the current working directory is first (getcwd()) as this may not be the same directory as the one your executing script is in, and therefore supplying a relative path could fail.
  • If you want to force a browser to download a response as a file, rather than interpreting the response and displaying it in the browser, you should set a Content-Disposition of attachment. Example: header('Content-Disposition: attachment; filename="name-of-file.ext"');
mwrichardson
  • 1,148
  • 1
  • 8
  • 12
  • Heya, thank you. I'm actually doing this right now and it works, it will download the file for me (realfilename.png) however, the file is 1kb and it contains this: `
    Warning: readfile(/uploads/messaging/1/chat-picture.png) [function.readfile]: failed to open stream: No such file or directory in /home/user/public_html/subdomain/realdomain/chatfiles.php on line 32
    `
    – Predrag Beocanin Feb 01 '14 at 18:21
  • Try losing the slash (/) before uploads, that would make it a more valid relative path. If still no luck, try outputting the value of getcwd() somewhere to check your relative path is valid. – mwrichardson Feb 01 '14 at 18:25
  • Did it thank you! I'll post the solution right now :) – Predrag Beocanin Feb 01 '14 at 18:30
0

Here's the solution, thanks to mwrichardson! I'll read the temp file name, output the real one, but use getcwd() instead of supplying it an url. Here's the code.

$cwd = getcwd();
$dir = $cwd.'/uploads/messaging/'.$room.'/';
header('Content-Disposition: attachment; filename="'.$rname.'"');
readfile($dir.$tname);

This will supply the path to the file, instead of the url and let it access it. Header will output real file name and extension, as stored in the database examplename.png.

Predrag Beocanin
  • 1,402
  • 3
  • 18
  • 25