Opening downloaded zip file creates cpgz file? - php

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.

Related

PHP Force Download - Limit possible file download

I'm using the following to force download of MP3 files:
http://www.aaronfagan.ca/blog/2014/how-to-use-php-to-force-a-file-download/
Basically using PHP lines to force a download
<?php
if ($_GET['id']) {
$file = $_GET['id'];
header("Content-Description: File Transfer");
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header("Content-Length: ".filesize($file));
readfile($file);
}
else {
header('Location: http://www.mywebsite.com/error/');
}
?>
Am I correct to understand that anyone that knows how it works could basically download any files on any website with this?
For example, if I place that file in the root of mywebsite.com, anyone with knowledge could use a link like the following to download any file anywhere?:
http://www.mywebsite.com/download.php?id=http://www.anywebsite/files/file.pdf
Or would it only work on my website?
The files I want users to be able to download are MP3 files, would there be a way to "restrict" the type of files the "download.php" would process? so this way the "Content-Type" be set to something for only MP3 files, this way the "hack" would be restricted?
For example if I place that file in the root of mywebsite.com, anyone
with knowledge could use a link like the following to download any
file anywhere?:
http://www.mywebsite.com/download.php?id=http://www.anywebsite/files/file.pdf
If permissions open for http://www.anywebsite/files/file.pdf (it means you can open/download file.pdf with browser) you can download it remotly with your script (but as I now basename uses for local paths),
but usually permissions denied for direct download (you can close permissions too).
Also if you want you can add captcha to your download method to disable grab
Thanks.
Your code works only on your website.
For serving resources from other servers you can use this script Resource-Proxy.
Good Luck

PHP header attachment download corrupts ZIP file

I have a file like "983Y4938920820894838947" on my server, and I'd like the user to save it as "subject.zip".
Using header location makes downloading work and the file is not damaged.
Whenever i use the headers with attachment, content type and the new filename, the download zip file is corrupt (I think?).
Whenever I open the ZIP file (e.g. test.zip), it makes a new file called test.zip.cpgz. I assume this is mac's way of saying the file is corrupt.
I'm using the following code
// Download the ZIP File
header("Content-Type: application/zip");
header('Content-Disposition: attachment; filename="' . stripslashes($new_filename) . '"');
readfile($filename);
This makes the file corrupt, while the below code works perfectly (but doesn't change the name):
header("Location: $filename");
I tried other headers without any success. Does anybody have any idea? Thanks!
You are missing a header there, if you dont specify the content length, the browser will not know what the size of the file is:
header("Content-Length: {{replace.with.your.file.size}}");
Maybe this will solve your problems.
The problem was that I had an echo. The echo made the zip corrupt. So it makes sense that it only worked the header location and not the regular headers for changing the filename. Removing the echo fixed it for me.

PHP: readfile() returns zip file with 0 bytes

I have created php script to allow user to download zip files.
Script looks like:
$filePath = '/path/to/zipfile.zip'; // file is below /public_html/ directory
if(file_exists($filePath)) {
$fileName = basename($filePath);
$fileSize = filesize($filePath); //returns: 26494938
header("Content-Type: application/zip");
header("Content-Length: ".$fileSize);
header("Content-Disposition: attachment; filename=".$fileName);
readfile($filePath);
die;
};
I would expect this script to pass zipfile.zip for downloading. And it does, the save dialog pops up, I am choosing where to save, pressing save and zip file saves. Except one important thing - the file is with 0 bytes, it is completely empty zip file. Original zip file is full with files (around 25Mb). Maybe the size is the problem?
Can someone please help with some advice? Path to file is correct. I suspect that the problem is most likely related to readfile() function and/or zip file size, if so is there some alternative to readfile() that would work? Thank you!
Update: I have tried to use function readfile_chunked as mentioned in this post: "Readfile reads 0 bytes from large file?" - the result is that zip after downloading now have some size (no longer 0 bytes) and all correct content inside it, looks like everything is ok, but the zip is invalid, and cannot be unzipped and opened normally. In Win8 when trying to open downloaded zip file I am receiving this error: The Compresed (zipped) Folder zipfile.zip is invalid.. Of course the original zip file works fine. WinRAR shows this error: zipfile.zip: Unexpected end of archive. It looks the same problem as described in this post, without any working solution.
Try to add ob_end_flush(); before readfile($filePath); . It
The simplest solution is to do away with the php completely, just provide an HTML link to the zip and let your server do the work
also if you really must stick with php to serve this, you have no code there that actually sends the file to the user, readfile doesn't do that it just loads it into the program

accessing file of another drive

previously I could download wav file in php and IIS. But now file is not downloadable.I don't know what is going wrong . After installing and changeing php 5.3 to php 5.4 with php manager in IIS, the file is not able to downloaded. I have link to file to download it which looks like this:
Download
download.php scripts
<?php
$filename = $_GET['voice'];
$dir = 'd:/temp_file/voice/';
if(is_file($dir.$filename))
{
header('Content-type: audio/wav');
header('Content-Disposition: attachment; filename='".$filename.'"');
echo file_get_contents($dir.$filename);
}
?>
while I was trying to find the mistake why file is not downloadable, I remove if statement and run program, it does prompt window download file with audio player of empty wav file. So, I conclude that there is mistake in path which is not allowing to access file of another drive. I have php code in c:\inetpub\wwwroot\ but wav file to be download is in the d:\temp_file\voice path. What Should I have to do?
Maybe PHP open_basedir restriction.
Try to add d:/temp_file/voice/, to its content in php.ini.
Update
I never used IIS, but another thing that you have to check is if the IIS User have permission to read that directory. Try to add, just for test, Everyone with all permission to d:\temp_file\voice.
I don't know what is going wrong
Then enable error reporting, for what it looks like to me it's a syntax error at header('Content-Disposition: attachment; filename='".$filename.'"'), you're missing a quote (') after filename='". But since you say it has worked (and works without the if), I'd say that's a copy paste error.
Then do a var_dump($filename), which might contain quotes, since you put those around the URL in the link (<a href="download.php?voice='$filename'">). The file D:/temp_file/voice/'foo.wav' might not exist.

PHP - Opening uploaded DOCX files with the correct MIME TYPE

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.

Categories