简体   繁体   中英

How to download msg file with PHP

I'm currently creating a feature that would allow to download files from remote server. My script works fine for all file types required but it doesn't work for the msg files for some reason (It downloads empty file (0K)). Same behavior in Chrome and IE by the way. I thought the problem is with file size so I've tested to download large zip file and it also work fine, seems that only msg files I've got issue with.

My script:

// Get parameter form html page
if(isset($_GET['file_name'])) $file_name = $_GET['file_name'];

$file_name = str_replace('"', '\\"', $file_name);
$file_url = 'http://mypath/uploads/' . $file_name;

header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$file_name."\"");
header("Content-Transfer-Encoding: Binary");

readfile($file_url);
exit;

What I'm doing wrong?

PS I think possible solution is to archive (zip) .msg file during uploading process and then download it as .zip instead but I'm looking for a better solution.

You are trying to use readfile with a URL file location, which is possible only if fopen wrappers have been enabled.

From PHP readfile :

Tip A URL can be used as a filename with this function if the fopen wrappers have been enabled. See fopen() for more details on how to specify the filename. See the Supported Protocols and Wrappers for links to information about what abilities the various wrappers have, notes on their usage, and information on any predefined variables they may provide.

It's not safe and you should use a local system path insted of a URL like this:

// Get parameter form html page
if(isset($_GET['file_name'])) $file_name = $_GET['file_name'];

$file_name = str_replace('"', '\\"', $file_name);
//$file_url = 'http://mypath/uploads/' . $file_name;
// The script is located to one level up directory of the uploads directory
// You can change this to fit your script and uploads directory locations
$uploads_local_path = __DIR__.'/uploads/';
$file_path = $uploads_local_path.$file_name;

header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$file_name."\"");
header("Content-Transfer-Encoding: Binary");

readfile($file_path);
exit;

and now it works and downloads the file. Just pay attention and have the correct path locations for the uploads directory.

You can even try my local example based on your code here and download a file: http://zikro.gr/dbg/php/dl-file/

A direct link to the download script you can try: http://zikro.gr/dbg/php/dl-file/dodl.php?file_name=1011191_orig.png

Expanding my comment into an answer:

I tested your script with a local file, eg. $file_url = 'test.msg'; , and this is working here. So I suspect that there is a problem getting the file from the remote server. Can you download the remote .msg file from the server where your PHP script is running by other means than PHP, eg. with wget http://mypath/uploads/test.msg ? You could also check the return value of readfile - if it is false, there is an error reading the file . If you cannot download the file or if readfile returns false, then the problem is not in your code, but a server configuration or connectivity issue, which you have to fix first.

Regarding your code: you should sanitize your $_GET['file_name'] , to avoid someone passing stuff like ../passwd .

尝试使用其他内容类型:

header("Content-Type: application/download");

Probably a stupid question but, have you tried a simple

$fileurl="http://example.com/file.msg";
$fileContent = file_get_contents($fileurl);
file_put_contents($saveDir.$fileName, $fileContent);

http://php.net/manual/en/function.file-get-contents.php

http://php.net/manual/en/function.file-put-contents.php

Try to add a user-agent and accept all MIME types on your request .. by using cURL:

// Get parameter form html page
if(isset($_GET['file_name'])) $file_name = $_GET['file_name'];

$file_name = str_replace('"', '\\"', $file_name);
$file_url = 'http://mypath/uploads/' . $file_name;

header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$file_name."\"");
header("Content-Transfer-Encoding: Binary");

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $file_url);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0');
$headerData[] = 'Accept: */*';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec ($ch);
$error = curl_error($ch); 
curl_close($ch);
echo $data;
exit;

Try it

// Get parameter form html page
if(isset($_GET['file_name'])) $file_name = $_GET['file_name'];

$file_name = str_replace('"', '\\"', $file_name);
$file_url = 'http://mypath/uploads/' . $file_name;

header("Content-Type: application/download");
header("Content-disposition: attachment; filename=\"".$file_name."\"");
header("Content-Transfer-Encoding: Binary");

readfile($file_url);
exit;

I think you must specify the Content-lenght header, and i think disable caching may help too.

for example:

header("Content-length: " . strlen($output); // tells file size
header("Pragma: no-cache");
header("Expires: 0");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM