I wrote a PHP script that creates a zipfile and prompts the browser for download. Not only does it download to the client, for some reason it also creates a duplicate zipfile in my server in the same directory as this script.
I only want this script to download to the client, and not a duplicate on my server.
$layoutName = $_POST['layoutName'];
$htmlContent = $_POST['htmlContent'];
$layoutDir = 'http://myapp.com/public/views/layouts/' . $layoutName;
$zipFileName = 'Myapp-' . $layoutName . '.zip';
$decompressedFolderName = 'Myapp-' . $layoutName;
$zip = new ZipArchive();
$zip->open($zipFileName, ZipArchive::CREATE);
if($zip)
{
// Add index.html
$zip->addFromString('index.html', $htmlContent);
// Add CSS Folder
$cssContent = file_get_contents($layoutDir . '/css/default.css', false);
$zip->addFromString('css/default.css', $cssContent);
} else {
echo 'Could not create zip';
}
$zip->close();
header('Content-Type: application/octet-type');
header('Content-Disposition: attachment; filename=Myapp-' . $layoutName . '.zip');
header('Content-Length: ' . filesize($zipFileName));
ob_clean();
flush();
echo file_get_contents($zipFileName);
exit;
UPDATE
PROBLEM SOLVED. This code now works!
That was my exact problem. I changed readfile() to file_get_contents(), and now it doesn't create the file on my server.
Related
I want to create a zip file which contains some PDFs which are saved at my server.
Here is the code I tried,
$filenamez = 'datasheets1.zip';
$zip = new ZipArchive;
if ($zip->open('datasheets1.zip', ZipArchive::CREATE) === true) {
// Add files to the zip file
for ($m = 0; $m <= $total - 1; $m++) {
$zip->addFile('datasheet' . $m, $model1[$m] . ".pdf");
}
$zip->close();
echo 'Archive created!';
header('Content-type: application/zip');
header('Content-disposition: attachment; filename="' . $filenamez . '"');
header("Content-length: " . filesize($filenamez));
readfile($filenamez);
}
When I execute this code the zip file is created and downloaded but when I open it shows following error: " this archive is either in unknown format or damaged ".
In addition to Andrei's comment, you're echoing the string 'Archived Created!', and then also setting an application/zip header, and then streaming the contents of the ZIP file to the browser. So the content of the ZIP will be polluted by having that string inserted at the top, making it corrupt.
Part of what's being displayed:
PKd�wL��� ���/images/image_0.jpg��ex\K��1昙�3�133���;ffff����Ԇ�����w�̼߳�cw��딎�$��Z�������&QRTB�|>��E��M5���|�~b��)�o�3�� �>s���o�'���^B�O��V ����#���Q?S#(�� 6���v4���8����vvV�sy}#�_ �O��s�o���L�7Fv.F&�ol��WV.V��?�����g�W!�/w!�������K�oLL�1`���G�p�X���T�>C�#��L��)q���s��3�g�8�p�O�?
I'm trying to download images into zip file, this is what i've got so far:
if (count($headers->images) > 0) {
$counter = 0;
$zip = new ZipArchive();
$tmpFile = "tmpFolder/tmp" . strtotime("now") . ".zip";
$zip->open($tmpFile, ZipArchive::CREATE);
foreach($headers->images as $key => $images) $zip->addFromString("/images/image_" . $counter++ . ".jpg", file_get_contents($images));
$zip->close();
if (file_exists($tmpFile)) {
$fname = basename($_POST["titleZipFile"] . ".zip");
$size = filesize($tmpFile);
header("Content-Type: archive/zip");
header("Content-Disposition: attachment; filename=$fname");
header("Content-Length: " . $size);
ob_end_clean();
readfile($tmpFile);
//unlink($tmpFile);
echo "<div id='reportMessage'><p>You have successfully save images. Please go to your folder " . $_POST["titleZipFile"] . ".zip<p></div>";
}
}
if I remove the unlink($tmpFile); line then the tmp zip is actually generated and has the images inside the zip. However it's not actually showing the zip downloading in browser.
Does any one have any ideas why this could be happening?
Try to change the header for the content type to the following. I think the header is causing the browser problems with interpreting what it is supposed to do. Try the following type.
header('Content-type: application/zip');
I searched and tried a few previous questions/example codes, but couldn't get this to work.
I'm trying to deliver the results to end-users via PHP code. Here is my code.
$varZipFile = $varBaseNameParts[0] . '.' . $varDate . '.zip';
$varZipDir = $varBaseNameParts[0] . '_' . $varDate;
$zip = new ZipArchive();
$zip->open($varZipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->addFile('008.csv');
$zip->addFile('002.csv');
$zip->close(); // mark line xxx
header("Content-Type: application/zip");
header("Content-disposition: attachment;filename=$varZipFile");
header('Content-Length: ' . filesize($varZipFile)); // with or without this line, got the same error
header("Content-Type: application/force-download"); // with or without this line, got the same error
readfile($varZipFile);
I got the .zip file in my browser. However WinZip cannot open it, neither can 7-Zip. WinZip complains that "Error: Central directory not found".
Interestingly, when I manually transfer the file via WinSCP from my server to my Windows machine, I can open the file with either WinZip or 7-Zip. This indicates it works all fine to 'mark line xxx', and problems occurs in the header lines.
TIA!
Your ouput buffer may not be cleared before you try to serve the download. Try to clean the output buffer before serving the download with the ob_clean() function like this:
$zip->close(); // mark line xxx
ob_clean();
Your code is working well on my side, debug this $varBaseNameParts[0] to see if the value is correct or try the below code.
// $name = name of the archive
// $archive_directory = directory to save the archive
// $file_array = list of files
function create_archive($name, $archive_directory, $file_array) {
$target_file = $archive_directory . '/' . $name . date('m-d-y').date('h-i-sa') . '.zip';
$zip = new ZipArchive();
if (count($file_array)) {
if ($zip->open($target_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) {
foreach ($file_array as $file) {
$zip->addFile($file);
}
$zip->close();
chmod($target_file, 0777);
return $target_file;
}
}
return null;
}
function create_download($archive) {
$file_name = basename($archive);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$file_name");
header("Content-Length: " . filesize($archive));
readfile($archive);
}
// create the archive file
$archive = create_archive('test', 'archive', ['008.csv', '002.csv']);
if ($archive) {
create_download($archive);
}
Im having issues with my code being able to open a zip file that i have uploaded and moved into a folder, the zip file uploads fine and you can open it in any Zip program however, when i attempt to open it with ZipArchive to extract the data it errors.
$path = "../"; // Upload directory
$count = 0;
foreach ($_FILES['files']['name'] as $f => $name) {
if(move_uploaded_file($_FILES["files"]["tmp_name"][$f], $path . $name))
$count++; // Number of successfully uploaded file
}
$kioskFile = $_FILES['files']['name'][0];
$kioskFile = explode(".", $kioskFile);
$kioskFile = $kioskFile[0];
$zipFile = "../" . $kioskFile . ".zip";
$zip = new ZipArchive;
$res = $zip->open($zipFile);
if ($res === true) {
$zip->extractTo("./");
$zip->close();
} else {
echo "Error Cannot Open Zip File - Error Code: ";
}
When i run the code it shows me a Error Code 19
ZIPARCHIVE::ER_NOZIP - 19
This is the error im getting, however the file exists and if i use zip_open, it returns that it can open the zip file.
Any help would be very greatful
EDIT1
If i upload a zip file that i manually create (using a zip program) then the upload works fine. However if i use a ZipArchive created zip file, then it instantly errors with a error 19.
EDIT2
I have now added a check to make sure the file exists in the right directory and also put a print of the location also, both match, however still the same issue. Error 19
$path = "../"; // Upload directory
$count = 0;
foreach ($_FILES['files']['name'] as $f => $name) {
if(move_uploaded_file($_FILES["files"]["tmp_name"][$f], $path . $name))
$count++; // Number of successfully uploaded file
}
$kioskFile = $_FILES['files']['name'][0];
$kioskFile = explode(".", $kioskFile);
$kioskFile = $kioskFile[0];
$realpath = realpath("../");
$zipFile = $realpath . "\\" . $kioskFile . ".zip";
if (file_exists($zipFile)) {
$extract = zip_extract($zipFile, "../");
if ($extract === TRUE) {
} else {
echo "The file " . $zipFile . " cannot be opened";
}
} else {
echo "The file " . $zipFile . " does not exist";
die();
}
UPDATE1
So i think ive narrowed it down to either this bit of code, or the download script that i use to download the .zip file from the system, if i leave the zip on the system and use the exact same bit of code it works fine.
Here is my download code, maybe ive missed something on this that is causing the issue.
$fileID = $_GET['id'];
$backupLoc = "backups/";
$sql = "SELECT * FROM backups WHERE id = '" . addslashes($fileID) . "' LIMIT 1";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$backupFile = $row['backupFile'];
$zipFile = $backupLoc . "/" . $backupFile . ".zip";
$zipSize = filesize($zipFile);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="' . basename($zipFile). '"');
ob_end_flush();
readfile($zipFile);
exit;
die();
Open the archive with a text or hex editor and make sure you have the 'PK' signature at the start of the file.
If you have any HTML before that signature, it would suggest that your buffers are not being cleaned or are being flushed when they should not be, meaning that PHP ZipArchive will assume an invalid archive.
It was the download.php file that was causing the issue, here is the solution. which was to do a OB CLEAN rather than a Flush
///echo "<div style='padding: 50px;'>Please Wait .....</div>";
$fileID = $_GET['id'];
$backupLoc = "backups/";
$sql = "SELECT * FROM backups WHERE id = '" . addslashes($fileID) . "' LIMIT 1";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$backupFile = $row['backupFile'];
$zipFile = $backupLoc . "/" . $backupFile . ".zip";
$zipSize = filesize($zipFile);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="' . basename($zipFile). '"');
//ob_end_flush();
ob_end_clean();
readfile($zipFile);
exit;
die();
I've implemented the code to Create Zip Folder of Files (from db path) and download zipped folder in PHP. I am using Ubuntu OS.
public function actionDownload($id) {
$model = $this->loadModel($id, 'Document');
$results = array();
$results = $this->createZip($model);
$zip = $results[0];
$size = filesize($zip->filename);
if ($zip->filename) {
header("Content-Description: File Transfer");
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"" . $model->name . "\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $size);
ob_end_flush();
flush();
readfile($zip->filename);
// To Store User Transaction Data
//$this->saveTransaction();
//ignore_user_abort(true);
unlink($zip->filename);
$zip->close();
// Delete newly created files
foreach ($results[1] as $fl) {
unlink($fl);
}
}
}
public function createZip($model) {
$data = Document::model()->findAll('parent_folder=:id', array(':id' => (int) $model->document_id));
$fileArr = array();
foreach ($data as $type) {
$fileArr[] = $type->path;
}
$filestozip = $fileArr; // FILES ARRAY TO ZIP
$path = Yii::app()->basePath . DS . 'uploads' . DS . Yii::app()->user->id;
//$model->path = trim(DS . $path . DS); // DIR NAME TO MOVE THE ZIPPED FILES
$zip = new ZipArchive();
$files = $filestozip;
$zipName = "USR_" . Yii::app()->user->id . "_" . $model->name . "_" . date("Y-m-d") . ".zip";
$fizip = $path . DS . $zipName;
if ($zip->open($fizip, ZipArchive::CREATE) === TRUE) {
foreach ($files as $fl) {
if (file_exists($fl)) {
$zip->addFile($fl, basename($fl)) or die("<p class='warning'>ERROR: Could not add file: " . $fl . "</p>");
}
}
}
$resultArr = array();
$resultArr[] = $zip;
$resultArr[] = $files;
return $resultArr;
}
The Zip creation code working fine and its creating zip file there but the issue is owner of the file is www-data and file permission is Read-Only.
When I am trying to set chmod($zip->filename, 0777) permission to that zipped folder then its showing an error?
Error 500
chmod(): No such file or directory
In fact file is present there.
If I am trying without chmod() then its showing me error of
Error 500
filesize(): stat failed for /home/demo.user/myapp/public_html/backend/uploads/1/USR_1_kj_2013-12-23.zip
and then its not downloading the zip file.
This is really weird issue I am facing. It seem to be some permission issue of zip file that's why filesize() is not able to perform any operation on that file but strange thing is chmod() also not working.
Need Help on this.
Thanks
If www-data has read permissions, the file permissions are properly set. No chmod required.
You need to call $zip->close() before the download, as only on $zip->close() the file will be written to disk. readfile() will not work unless the file is written to disk.
A smarter way, could be to create the archive in memory only using the php://memory stream wrapper. However this is only an option if you need the archive for a single download only.