PHP Dynamically Generated Zip File by ZipArchive Can't be downloaded - php

I am trying to create a zip file and download that zip file on a button click in WordPress but when I try to download the file it always throws error -
Cannot modify header information - headers already sent by
Here is my code -
function downloadZipFile($file_array){
# create new zip object
$zip = new ZipArchive();
# create a temp file & open it
$tmp_file = tempnam('.', '');
$zip->open($tmp_file, ZipArchive::CREATE);
# loop through each file
foreach ($file_array as $file) {
//echo $file;
# download file
$download_file = file_get_contents($file);
#add it to the zip
$zip->addFromString(basename($file), $download_file);
}
# close zip
$zip->close();
# send the file to the browser as a download
echo ABSPATH.'downloadZip.php';
header('Content-disposition: attachment; filename="my file.zip"');
header('Content-type: application/zip');
readfile($tmp_file);
unlink($tmp_file);
}
In the above function I am passing a file array which is coming from box api. I can see all files are coming fine from box api endpoint.

Related

"Permission Denied" in the content of the zip folder created using PHP

I have created a jpeg-pdf conversion tool in php. After the conversion I have multiple pdf files. So I created a $zip in php to store the pdf files so that user can download all the single pdf files at once.
In my linux system when I'm downloading the zip file that is getting generated I cant open the individual pdf files from the zip showing "error opening file: some/path/: Permission Denied". So I even tried assigning 777 permission to the zip as you can see below which also didn't workout.
But the pdf files inside the zip is opening fine if I open it after extracting the zip.
Here is my snippet where I am creating the zip.
Please note I'm using headers to download the zip. Is that the cause of this problem ?
for ($x = $arrayEndIndex; $x >= 0; $x--) {
$pdf = new Imagick($imageFilesArray[$x]);
$pdf->setImageFormat('pdf');
$pdf->writeImages("../upload/converted-{$x}.pdf", true);
//chmod("../upload/converted-{$x}.pdf", 0777);
array_push($pdfFilesArray,"../upload/converted-{$x}.pdf");
}
$zip = new ZipArchive();
$tmp_file = tempnam('.', '');
chmod($tmp_file, 0777);
$zip->open($tmp_file, ZipArchive::CREATE);
foreach ($pdfFilesArray as $pdf) {
$download_file = file_get_contents($pdf);
$zip->addFromString(basename($pdf), $download_file);
}
$zip->close();
header('Content-disposition: attachment; filename="Splitted-PDFs.zip"');
header('Content-type: application/zip');
readfile($tmp_file);
unlink($tmp_file);

ZipArchive invalid in Windows only

I am using ZipArchive with the following code to create zip files. It works well in all browsers on a Mac. But it says the file is invalid on any browser on a Windows computer. I don't understand why. I emailed the supposedly corrupt file from the Windows computer to myself and opened it on my Mac computer, and it worked fine. I also read through all the suggestions on this thread and tried all of them, with no luck.
Do you see anything wrong with my code?
if(extension_loaded('zip')){
if(isset($post['afiles']) and count($post['afiles']) > 0){
$zip = new ZipArchive();
$url = get_stylesheet_directory();
$filepath = $url;
$zip_name = "DSV".time().".zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "Error";
}
foreach($post['afiles'] as $file){
// get the file directory url from the file ID
$path = get_attached_file( $file );
// add each file to the zip file
$zip->addFile($path, basename($path));
}
$zip->close();
ob_clean();
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_name);
unlink($zip_name);
}else
$error .= "* Please select file to zip <br/><br />";
}else
$error .= "* You do not have the ZIP extension<br/><br />";
I echoed basename($path) to confirm that there are no slashes. It is simply the filename like "this-is-my-file.docx". Thanks for any insight!
Edit: The exact error in Windows says:
Compressed (zipped) Folders Error
Windows cannot open the folder.
The Compressed (zipped) Folder 'C:\Users\krist\Downloads\DWV1620652983.zip' is invalid.
After inspecting the ZIP files, there's HTML coming after the ZIP content. The fix is to make sure to call exit as soon as possible after calling readfile so that nothing else is written to the stream.

How to Stream files into a Zip from Amazon S3

I'm using the PHP Flysystem package to stream content from my Amazon S3 bucket. In particular, I'm using $filesystem->readStream.
My Question
When I stream a file, it ends up in myzip.zip and the size is correct, but when unzip it, it become myzip.zip.cpgz. Here is my prototype:
header('Pragma: no-cache');
header('Content-Description: File Download');
header('Content-disposition: attachment; filename="myZip.zip"');
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
$s3 = Storage::disk('s3'); // Laravel Syntax
echo $s3->readStream('directory/file.jpg');
What am I doing wrong?
Side Question
When I stream a file like this, does it:
get fully downloaded into my server's RAM, then get transferred to the client, or
does it get saved - in chunks - in the buffer, and then get transferred to the client?
Basically, is my server being burdened if I have have dozens of GB's of data being streamed?
You are currently dumping the raw contents of the directory/file.jpg as the zip (which a jpg is not a zip) . You need to create a zip file with those contents.
Instead of
echo $s3->readStream('directory/file.jpg');
Try the following in its place using the Zip extension:
// use a temporary file to store the Zip file
$zipFile = tmpfile();
$zipPath = stream_get_meta_data($zipFile)['uri'];
$jpgFile = tmpfile();
$jpgPath = stream_get_meta_data($jpgFile)['uri'];
// Download the file to disk
stream_copy_to_stream($s3->readStream('directory/file.jpg'), $jpgFile);
// Create the zip file with the file and its contents
$zip = new ZipArchive();
$zip->open($zipPath);
$zip->addFile($jpgPath, 'file.jpg');
$zip->close();
// export the contents of the zip
readfile($zipPath);
Using tmpfile and stream_copy_to_stream, it will download it in chunks to a temporary file on disk and not into RAM

php file_get_contents(): content truncated from 2147483648 to 2147483647 bytes

How can I find out the issue when I'm going to create zip file of 2GB file.
Error
file_get_contents(): content truncated from 2147483648 to 2147483647
bytes
Fatal error: Out of memory (allocated 2151677952) (tried to allocate
18446744071562067968 bytes) in
I am using dedicated server and already set memory_limit,max_execution_time,max_upload_filesize,max_post_size. But it is not working for me.Please check my code and let me know what i am doing wrong -
create new zip object
$zip = new ZipArchive();
# create a temp file & open it
$tmp_file = tempnam('.','');
$zip->open($tmp_file, ZipArchive::CREATE);
# loop through each file
foreach($files as $file){
# download file
$download_file = file_get_contents($file_path.'/'.$file);
#add it to the zip
$zip->addFromString(basename($file_path.'/'.$file),$download_file);
}
# close zip
$zip->close();
$zip_name = $last_seg.'.zip';
# send the file to the browser as a download
header("Content-disposition: attachment; filename=$zip_name");
header('Content-type: application/zip');
readfile($tmp_file);
I change $zip->addFromString() to $zip->addFile() because you don't need read the content file to add the file, I test your code with 3 films and don't works (I had the same error) but when I use $zip->addFile() all go ok and I could download the zip file with 3gb.
I need to use set_time_limit(0);
If you want test this code only change the values of:
$files //Array of files name
$file_path //Path where your files ($files) are placed
$last_seg //The name of your zip file
<?php
set_time_limit(0);
$files = array('Exodus.mp4', 'the-expert.webm', 'what-virgin-means.webm');
$file_path = 'zip';
$last_seg = 'test';
$zip = new ZipArchive();
# create a temp file & open it
$tmp_file = tempnam('.','');
$zip->open($tmp_file, ZipArchive::CREATE);
# loop through each file
foreach($files as $file){
$zip->addFile($file_path.'/'.$file, $file);
}
# close zip
$zip->close();
$zip_name = $last_seg.'.zip';
# send the file to the browser as a download
header("Content-disposition: attachment; filename=$zip_name");
header('Content-type: application/zip');
readfile($tmp_file);
?>
You can read more at:
http://php.net/manual/en/ziparchive.addfile.php
You'll never been able to allocate more memory than PHP_INT_MAX. So maybe the linux x64 versions of PHP can handle this if the file_gets_content isn't internally limited to a signed int 32bits, but on windows or on a 32bits system you have no chance to achieve this without streaming.
Something like this might work: (not tested yet)
$fr = fopen("http://...", "r");
$fw = fopen("zip://c:\\test.zip#test", "w");
while(false !== ($buffer = fread($fr, 8192)))
{
fwrite($fw, $buffer, strlen($buffer));
}
fclose($fr);
fclose($fw);
Ok my bad apparently PHP do not provide the mode "+w" for a zip stream... Your last options will be then, writing the whole file in a temp file (by streaming it like i did, no file_get_contents) before giving it to an external program (with a system() or popen call...) or using another compression format (apparently php support write stream operation for zlib ant bzip2) or use an external library for php.
try to put this line in the beginning of your code:
ini_set("memory_limit", -1);
Refer to this question
Fatal error: Out of memory (allocated 1134559232) (tried to allocate 32768 bytes) in X:\wamp\www\xxx

How to download a zipped file in php? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to zip a whole folder using PHP
Hi,
I am creating a zip folder using zipArchive in php.The zipped file contains a folder(with a file in it) and a file. I am using the following code to download the zipped file:
$file_path = "zip/test.zip";
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=download.zip');
header('Content-Length: ' . filesize( $file_path));
readfile($file_path);
The folder gets downloaded. But I am unable to unzip it.
The error specified is "Decompression failed".
I can download a single file with the same code but not a file within a folder.
Please help..
Here is the code to zip the files:
$zip = new ZipArchive;
if ($zip->open($file_path,ZIPARCHIVE::CREATE) === TRUE) {
if($zip->addEmptyDir('dir1')) {
$zip->addFile($filepath,$destinationPath);
if($zip->addEmptyDir('Files')) {
$zip->addFile($filepath2,$destinationPath2);
}
}
}
I got the code working...
Need to add a $zip->close() code.

Categories