可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
If I make the url for a zip file the href
of a link and click the link, my zip file gets downloaded and opening it gets the contents as I expect.
Here's that HTML:
<a href="http://mysite.com/uploads/my-archive.zip">download zip</a>
The problem is I'd like the link to point to my application such that I could determine whether the user is authorized to access this zip file.
so I'd like my HTML to be this:
<a href="/canDownload">download zip</a>
and my PHP for the /canDownload
page:
//business logic to determine if user can download
if($yesCanDownload){
$archive='https://mysite.com/uploads/my-archive.zip';
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=".basename($archive));
header("Content-Length: ".filesize($archive));
ob_clean();
flush();
echo readfile("$archive");
}
So, I think the problem has to do with the header()
code but i've tried a bunch of things related to that based on various google and other SO suggestions and none work.
If you answer my question, it is likely you can answer this question too: Zipped file with PHP results in cpgz file after extraction
回答1:
The answer in my case was that there was an empty line being output before readfile().
So i added:
ob_end_clean();
readfile($filename);
But you should probably search for the place where this line is being output in your code.
回答2:
The PHP documentation for readfile says that it will output the contents of a file and return an int.
So your code, echo readfile("$archive");
, will echo $archive
(btw, the double quotes are meaningless here; you should remove them), and THEN output the int
that is being returned. That is, your line should be: readfile($archive);
Also, you should be using a local path (not an http:// link) to the archive.
Altogether:
if($yesCanDownload){
$archive='/path/to/my-archive.zip';
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=".basename($archive));
header("Content-Length: ".filesize($archive));
ob_clean();
flush();
readfile($archive);
}
Lastly, if that does not work, make sure filesize($archive)
is returning the accurate length of the file.
回答3:
Ok, I answered my own question.
The main problem, which I originally didn't make clear, was that the file was not located on my application server. It was in a Amazon AWS s3 bucket. That is why I had used a full url in my question, http://mysite...
and not just a file path on the server. As it turns out fopen()
can open urls (all s3 bucket "objects", a.k.a. files, have urls) so that is what I did.
Here's my final code:
$zip= "http://mysite.com/uploads/my-archive.zip"; // my Amazon AWS s3 url
header("Content-Type: archive/zip"); // works with "application/zip" too
header("Content-Disposition: attachment; filename='my-archive.zip"); // what you want to call the downloaded zip file, can be different from what is in the s3 bucket
$zip = fopen($zip,"r"); // open the zip file
echo fpassthru($zip); // deliver the zip file
exit(); //non-essential
回答4:
Another possible answer, I found After much searching, I found that the two possible reasons for a *.zip
"unzipping" to a *.zip.cpgz
are:
- the
*.zip
file is corrupted
- the "unzip" tool being used can't
handle >2GB files
Being a Mac user, the second reason was the cause for my problem unzipping the file: the standard Mac OS tool is Archive Utility, and it apparently can't handle >2GB files. (The file in question for me was a zipped 4GB raspbian disk image.)
What I ended up doing was to use a Debian virtual machine, already existing in Virtual Box on my Mac. unzip
6.0 on Debian 8.2 had no problem unzipping the archive.
回答5:
You're passing the URL to readfile()
like:
$archive = 'https://mysite.com/uploads/my-archive.zip';
While you should pass the path on the server, for example:
$archive = '/uploads/my-archive.zip';
Assuming the file is located in the upload folder.
Additionally try the following headers:
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=file.zip");
回答6:
In my case, I was trying to create the file in a directory above public_html and the rules of the hosting didn't allow it.