0

The code below displays this:

/home/my_site/www/wp-content/uploads/2017/03/2017-03-17-my_file.mp3

As far as I can tell, this path is correct. Yet when I comment away the echo and download the file, it's an empty file. Why?

Code:

if (isset($_GET['file'])) { 
    clearstatcache();
    $file_path = str_replace('http://www.example.com/', '', $_GET['file']);
    $file_path = $_SERVER['DOCUMENT_ROOT'] . '/' . $file_path . '.mp3';
    echo $file_path;

    if(file_exists($file_path)) {
        $file_name = basename($file_path);
        $file_size = filesize($file_path);
        header("Cache-Control: private");
        header("Content-Type: application/stream");
        header("Content-Length: ".$file_size);
        header("Content-Disposition: attachment; filename=".$file_name);
        exit();
    }
    else {
        die('The provided file path is not valid.');
    }
}

EDIT: this is what I have after KIKO Software's suggestion. Still downloads empty file.

<?php
if (isset($_GET['file'])) { 
  $file_path = $_SERVER['DOCUMENT_ROOT'] . '/' . $_GET['file'] . '.mp3';
  //echo $file_path;
  //$file_path = $_SERVER['SCRIPT_FILENAME'];  
  if (file_exists($file_path)) {
    $file_name = basename($file_path);
    $file_size = filesize($file_path);
  header('Content-type: application/octet-stream');
  header('Content-Transfer-Encoding: binary');
  header('Content-Length: '.$file_size);
  header('Content-Disposition: attachment; filename='.$file_name);
  //readfile($file_path);
  exit();
  }
  else {
      die('The provided file path is not valid.');
  }
}
?>
drake035
  • 3,955
  • 41
  • 119
  • 229

1 Answers1

4

Simple example to download a file:

$content = 'This is the content.';
$size    = strlen($content);
$name    = 'test.txt';
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.$size);
header('Content-Disposition: attachment; filename='.$name);
echo $content;

Make sure this works first. If it doesn't there could be a problem with the headers. Switch on error reporting and see: How to fix "Headers already sent" error in PHP

Then build up on that. Start by downloading the script itself:

$file_path = $_SERVER['SCRIPT_FILENAME'];  
if (file_exists($file_path)) {
  $file_name = basename($file_path);
  $file_size = filesize($file_path);
  header('Content-type: application/octet-stream');
  header('Content-Transfer-Encoding: binary');
  header('Content-Length: '.$file_size);
  header('Content-Disposition: attachment; filename='.$file_name);
  readfile($file_path);
  exit();
}
else {
  die('The provided file path is not valid.');
}     

And only after that try to download something else.

By approaching the problem step by step it is easier to see where it goes wrong.

Community
  • 1
  • 1
KIKO Software
  • 15,283
  • 3
  • 18
  • 33
  • If I do that Firefox crashes and there's no file download at all... In Chrome I see the (gibberish) content of the file, no file download either. – drake035 Apr 03 '17 at 08:18
  • I have to admit, I didn't test your code. The `readfile()` is correct, so that's not causing the problem you have. I changed your headers slightly, perhaps that will help? They were not the standard ones. Also read the manual on `readfile()` when you are using an url. **A URL can be used as a filename with this function if the fopen wrappers have been enabled.** – KIKO Software Apr 03 '17 at 12:22
  • Also see: https://stackoverflow.com/help/mcve if you want people to give you working code. – KIKO Software Apr 03 '17 at 12:29
  • Thanks! However your code triggers download of an empty file too. – drake035 Apr 03 '17 at 17:07
  • Try simple content. So instead of reading and outputting a file, simply `echo '1234567890';` and see if you can download that. After that, make sure your PHP has permission to read the file. – KIKO Software Apr 03 '17 at 19:23
  • It sounds all good but I'm sorry I have no idea how to do that... For the test you're prescribing, what should I set in lines like header("Content-Length: ".$file_size); ? – drake035 Apr 04 '17 at 08:08
  • No. I changed by answer to explain it. – KIKO Software Apr 04 '17 at 08:22
  • Both the first and second snippet work! From there I'll try to go nearer to my case later on today and report back. – drake035 Apr 04 '17 at 09:47
  • Just tried your second script (which works) and simply replaced $file_path = $_SERVER['SCRIPT_FILENAME']; with my file's path. Downloads empty file again... If I don't comment away readfile($file_path); Firefox crashes. Argh. – drake035 Apr 04 '17 at 20:16
  • So the problem is in your file's path? It is probably something else, as well. Firefox crashing is a strong indication of a `header()` problem. Basically the headers are not sent to the browser because something else has already been sent. This means that Firefox is trying to render the MP3 as a web page, can't do that, and crashes. See my answer for a link. When you say; "and simply replaced .. with my file's path", are you sure that is really the absolute only thing you do?? Remember: Step by step. – KIKO Software Apr 04 '17 at 21:17
  • Not sure what I was doing, but it works now. Thanks :) Any idea why the bounty is gone? I'd like to award the +50 to you but there's no mention of bounty any more – drake035 Apr 05 '17 at 14:42
  • I never saw a bounty, nor have I got any idea how that works. Never mind, I don't do it for the points anyway. – KIKO Software Apr 05 '17 at 15:29
  • Ah I thought I had started one on that thread. Thanks anyway! – drake035 Apr 05 '17 at 21:23