2

I have a problem I am trying to solve. The issue is downloading a file using CURL and offering a Save As prompt to the user in browser when this happens. I can successfully open the file but it opens directly in the browser as character data.

So far I have tried using the standard Content-Type and Content-Disposition headers with no luck actually producing the save dialogue prompt:

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "ftp://server.com/recordings/4_23_2019/CD36FAFA9DFD4DE190B487C503D5A3D2 @ 2_04_28 PM.wav");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FILE, $file); #output
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
$file = curl_exec($ch);
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="CD36FAFA9DFD4DE190B487C503D5A3D2 @ 2_04_28 PM.wav"');
    header('Content-Transfer-Encoding: binary');
    header('Content-length: ' . filesize($file));
    readfile($file);
    exit;
}
?>

I believe using these headers should offer a save prompt to the user, but instead I get a page with a bunch of random characters.

Errors Produced:

Warning: file_exists() expects parameter 1 to be resource, string given in /path/name

Warning: Cannot modify header information - headers already sent

DarkBee
  • 16,592
  • 6
  • 46
  • 58
P A
  • 41
  • 7
  • Possible duplicate of [PHP file\_exists and wildcard](https://stackoverflow.com/questions/2746364/php-file-exists-and-wildcard) – coder42 Apr 23 '19 at 22:27
  • Thanks, removing the wildcard portion of the question. – P A Apr 23 '19 at 22:40
  • You may need to be careful with your PHP tags. For example, if you have "" on a line by itself, up towards the top of your PHP file, the server might send down a newline before sending the headers, which generally ruins the headers. If you can, try it from inside the very first PHP tag, before the newline has a chance to be rendered. – UncaAlby Apr 23 '19 at 22:52
  • Would that browser be in the IE family? – Déjà vu Apr 23 '19 at 22:52
  • Thanks, @UncaAlby no issues with the headers from what I can see, no php output errors, I've updated the code to show where the php tags are. – P A Apr 23 '19 at 23:06
  • @RingØ, I've tested in Chrome and Firefox, same issue in each – P A Apr 23 '19 at 23:07
  • I would try after changing the filename in the header `Content-Disposition`, remove the `@` (and maybe spaces). – Déjà vu Apr 23 '19 at 23:12
  • @RingØ I tried changing to just 'recording.wav', still no go, same result – P A Apr 23 '19 at 23:40
  • Then, since the headers seem to be correct, have a look at the curl funcs, do they output anything, maybe? – Déjà vu Apr 23 '19 at 23:43
  • I suspect the content disposition header is ok...but one of the other headers might be in conflict...have you tried changing the `Content-Type` to something like `application/x-download` or removing `Content-Transfer-Encoding`? – Polak Apr 23 '19 at 23:44
  • @RingØ Okay, so I figured out the issue at least. The problem is the error checking in the script. If I remove the file_exists error check I'm able to download the file correctly. Any alternative ideas to use for error checking here? I also tried using 'if(!curl_errno($file))' which did not work. I've added the error output to the original post – P A Apr 24 '19 at 01:43
  • Why don't you just check the [response code](https://stackoverflow.com/a/28427868/446594) for a successful state like `200`? – DarkBee Apr 24 '19 at 06:18

1 Answers1

-1

This is a working code from one project (not in product).

if (file_exists($path)) {
    if (is_readable($path)) {
        @set_time_limit(900);
        $NomFichier = basename($path);
        header("Content-Type: application/force-download; name=\"$NomFichier\"");
        header("Content-Transfer-Encoding: binary");
        header("Content-Disposition: attachment; filename=\"$NomFichier\"");
        header("Expires: 0");
        header("Cache-Control: no-cache, must-revalidate");
        header("Pragma: no-cache");
        readfile($path);

      exit;
    } else {
        $this->say_error("Access denied for this file.");
    }
} else {
    $this->say_error("File moved or deleted.");
}
Dell
  • 930
  • 6
  • 13
  • If the file would live on OP's server there would be no need to test if the file exists through curl right? So using `$mypath` seems a far stretch to solve this – DarkBee Apr 24 '19 at 05:55
  • curl for load file from remote server and fill local(template) file. In this situation $mypath is template file for save content and read for user download. If mr. PA write full spec. about his task we can find optimal solution. I corrected his code not more. – Dell Apr 24 '19 at 06:31
  • See OP's last [comment](https://stackoverflow.com/questions/55820067/trouble-downloading-a-file-in-browser-using-curl/55821232?noredirect=1#comment98308539_55820067) – DarkBee Apr 24 '19 at 06:37
  • Oh, yes, I missed a lot part of question, I will replace the answer with a working piece of code from one project, maybe it will help the author. Thank you for correcting me. – Dell Apr 24 '19 at 13:59
  • Please add some explanation to your code. Why do you think that it solves the OPs problem? – Nico Haase Apr 24 '19 at 14:10
  • Thanks, yes I'm not trying to download the file to our server, I'm serving it locally to users in browser. I will try your updated code and see if it resolves the error – P A Apr 24 '19 at 18:39