I recently came across How to force file download with PHP which describes setting Content-Transfer-Encoding. Is this header applicable when used with this application when used to download a file via HTTP (it appears to be email related)? If so, what should it be set as for MS Word and Excel files, ZIP files, PDFs, and Text?
header("Content-Transfer-Encoding: Binary");
It has been religiously included by carg-cult copy-paste programmers since it was mentioned in a comment to the readfile() manpage on PHP.net.
It indeed has little to do with HTTP and you can safely remove it.
I have a video file and I have commanded the server through htaccess to redirect when requesting the file url. However, I wonder if someone remote can use php functions such as file_get_contents to access the video file since I have only one server and I am not sure whether remote servers can access to it. In my own server I can access to it. Yet I don't want others to access the video file unless authenticated by php.
If you really do not want people to get that video why have it in public web folder? Just put it somewhere else and problem solved. What is the use case of this?
That said, if your redirect is working correctly, the file will not be served. file_get_contents() is still requesting the file from your webserver so it can't just magically ignore the redirect.
If you want to be able to download that file but prevent everyone else from doing it, put the file out of your www root and have a php script to retreive it. You can set up basic http authentication to prevent anyone accessing the php script.
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary")
header("Content-disposition: attachment; filename=\"myvideo.avi\"");
echo file_get_contents("/directory/out/of/www/that/is/readable/by/www-data");
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:
download zip
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:
download zip
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
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.
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.
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
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.
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");
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.
Here is the problem details:
1) I want to create dynamic (ip based) download link. So user can't download the file with different IP with the same download link.
2) Before start the actual download, i want to log this download request using php and perform some checks (verify the http referrer) to allow the user to download the actual file.
3) I also want the download file to be resumable and could be downloaded with download manager (with multiple download instances). Also want to limit the maximum number of allowed instances for each download.
4) The file size could be more than 200 MBs.
So, the solution which i am thinking is to create the download link with the md5 hash of user's ip. E.g.
http://yourdomain.com/download.php?ip_hash=hash-of-the-ip&file=file-to-download
This is just a example but we can also create a nice link of this using htaccess.
What should i do next? I tried to do it using
header("Content-Type: $ctype");
header("Content-Length: " . filesize($file));
header("Content-Disposition: attachment; filename=\"$fileName\"");
readfile($file);
But using this the download does not remain resumable for the end user.
Is this fine to send large files using this method?
After doing some research, I came to know that the .exe files become corrupted for the end user using this way.
After doing some more research, i have found the answer of my question. I just thought i should share it with you guys as well.
As rambo commented, we can use mod_xsendfile module of the apache server. We need to enable it if its disabled.
Here is the link to download the module files if your apache does not have this module. Its available for mostly all the versions of apache and available for both x32 and x64.
https://github.com/nmaier/mod_xsendfile
You can use the following code to send the file using this apache module after doing all your custom validations.
<?php
//We want to force a download box with the filename hello.txt
header('Content-Disposition: attachment;filename=hello.txt');
//File is located at data/hello.txt
header('X-Sendfile: data/hello.txt');
?>
I hope it will help you guys :)
I have users uploading DOCX files which I make available for download. The issues we have been experiencing is the unknown mime types of DOCX files which causes IE to open these docs as Zip files.
It is running on a Windows/IIS server.
Because this is a shared host, I cannot change any server settings.
I was thinking that I could just write some code that would handle DOCX files, perhaps custom output:
if (extension=docx) {
header("Content-Disposition: attachment; etc)
header('Content-Type: application/application/vnd.openxmlformats-officedocument.wordprocessingml.document');
//Output the file contents etc
}
Would this be a viable solution?? If so, can someone help fill in the gaps?
(PS I know the above syntax is not correct, just a quick example)
This should do it:
header('Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Disposition: attachment; filename="myfile.docx"');
readfile('myfile.docx');
Yes, that will work fine. The PHP docs have basically the exact code you want.