I am currently working on a tool made with PHP (quite newbie with this technology...) which should generate zip files with a set of files inside. This set of files can be:
Basic files (mutliple formats)
Full directories (will be added into the resulting zip as a new zipped file - ZIP inside the final ZIP)
The thing is that when the zip files contains simple files it is downloaded properly but when the file contains the "Full directory zip file" then the resulting ZIP file get corrupted...
Below the code I am currently using (sorry if its a bit messy but is the first time I work with PHP...)
function ZipFiles($fileArr,$id) {
$destination = "{$_SERVER['DOCUMENT_ROOT']}/wmdmngtools/tempFiles/WMDConfigFiles_".$id.".zip";
$valid_files = array();
//if files were passed in...
if(is_array($fileArr)) {
//cycle through each file
foreach($fileArr as $file) {
if(is_dir($file)) {
//If path is a folder we zip it and put it on $valid_files[]
$resultingZipPath = "{$_SERVER['DOCUMENT_ROOT']}/wmdmngtools/tempFiles/".basename($file)."_FOLDER.zip";
ZipFolder($file,$resultingZipPath );
$valid_files[] = $resultingZipPath ;
}
else {
//If path is not a folder then we make sure the file exists
if(file_exists("{$_SERVER['DOCUMENT_ROOT']}/wmdmngtools/tempFiles/".$file)) {
$valid_files[] = $file;
}
}
}
}
//if we have good files...
if(count($valid_files)) {
//create the archive
$zip = new ZipArchive();
if($zip->open($destination,ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile("{$_SERVER['DOCUMENT_ROOT']}/wmdmngtools/tempFiles/".$file,$file);
}
$zip->close();
return $destination;
}
else
{
return "";
}
}
function ZipFolder($source, $destination) {
// Initialize archive object
$folderZip = new ZipArchive();
$folderZip->open($destination, ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($source) + 1);
// Add current file to archive
$folderZip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$folderZip->close();
}
On it we can see two functions:
ZipFiles: is the main fucntion that is called by passing a list/array (contains the list of files and folders that will be added into the final ZIP) and an ID parameter which is simply used for generatig different file names... (can be ignored)
ZipFolder: this fucntion is called for each of the folders (not files) on the above mentioned list/array in order to zip that folder and create a zip file to add it on the final file. (based on what I found in How to zip a whole folder using PHP)
I have tried many things like mentioned in above post like closing all files, or avoiding empty zips inside the zip but nothing worked...
Zip inside zip (php)
Maybe I missed something (most probably :) ) but am running out of aces so any help/guideance would be appreciated.
In case more info is needed please let me know and will post it.
Thanks a lot in advance!!
Finally found the issue. Seems that the file was generated properly but when downloading it from PHP there was a problem when size was bigger than a concrete number.
THis was due to wrong definition of the message length on the header definition:
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Length: ".filesize($zippedFile));
header("Content-Disposition: attachment; filename=".$zippedFile);
header("Content-type: application/zip");
header("Content-Transfer-Encoding: binary");
Even if I guess it may not be a correct practice I removed the Content-Length entry and now I get the correct file despite of its size.
Related
1 - I have a folder has a lot of users folder inside it, and every user's folder has others folders inside it has ismages inside them like this:
localhost/cm/app/model/uploads/mark/3/small/car.jpg
localhost/cm/app/model/uploads/mark/3/big/car.jpg
localhost/cm/app/model/uploads/stiven/9/small/pc.jpg
localhost/cm/app/model/uploads/stiven/9/big/pc.jpg
2 - I want that i donwload this folders with all its content.
3 - I prefer that I download it without zipping it with the same name, if it's not possible with zipping it with any name.
4 - I've used this code and it's not working because when I try to open the zip folder after downloading it an error message appear and tell me that "the archive is either unknown format or damaged", and this my code:
<?php
$dir = 'http://localhost/cm/app/model/uploads'; //folder path
$archive = time().'download.zip';
$zip = new ZipArchive;
$zip->open($archive, ZipArchive::CREATE);
$files = scandir($dir);
unset($files[0], $files[1]);
foreach ($files as $file) {
$zip->addFile($dir.'/'.$file);
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$archive);
header('Content-Length: '.filesize($archive));
readfile($archive);
unlink($archive);
?>
*So how to download my folder with all its folders and images without zipping it or with zipping if not possible?
I suspect you've got an error in you're code. maybe ext-zip isn't install one way of checking this is by running php -m in a terminal which will display all install and enabled modules.
If you open up the zip file with a text editor it's like there be an error message instead of archived data.
This is The best way that i found:
<?php
// Get real path for our folder
$rootPath = realpath('folder_for_ziping');
// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
$archive = "file.zip";
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$archive);
header('Content-Length: '.filesize($archive));
readfile($archive);
unlink($archive);
?>
To put it simply, I would like my users to be able to download their website files, so I created a "Download Website" button which uses this script to add all files/folders in their directory which is in the variable $direc and archive those files/folders.
<?
///////// DOWNLOAD ENTIRE WEBSITE:
if(isset($_POST['download_site'])){
// define some basics
$rootPath = '../useraccounts/'.$direc.'';
$archiveName = ''.$direc.'.zip';
// initialize the ZIP archive
$zip = new ZipArchive;
$zip->open($archiveName, ZipArchive::CREATE);
// create recursive directory iterator
$files = new RecursiveIteratorIterator (new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
// let's iterate
foreach ($files as $name => $file) {
$filePath = $file->getRealPath();
$zip->addFile($filePath);
}
// close the zip file
if (!$zip->close()) {
echo '<p>There was a problem writing the ZIP archive.</p>';
} else {
echo '<p>Successfully created the ZIP Archive!</p>';
}
}
?>
To my surprise, this code works. Although, there are a few hiccups:
It doesn't automatically force a download of that archive.
It adds the archive in to my main directory rather than moving it to a separate directory of my choice such as site_downloads or deletes it up on completed download.
Are these problems at all fixable or if not, is there a better way to do it so my main directory does not get filled with constant downloads? I guess it will cause a problem once a Archive is created more than once, as it uses the Directory name.
Solved this by using a few different combinations:
<?
///////// DOWNLOAD ENTIRE WEBSITE:
if(isset($_POST['download_site'])){
// define some basics
$rootPath = '../useraccounts/'.$direc.'';
$archiveName = ''.$direc.'.zip';
// initialize the ZIP archive
$zip = new ZipArchive;
$zip->open($archiveName, ZipArchive::CREATE);
// create recursive directory iterator
$files = new RecursiveIteratorIterator (new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
// let's iterate
foreach ($files as $name => $file) {
$filePath = $file->getRealPath();
$zip->addFile($filePath);
}
// close the zip file
if (!$zip->close()) {
echo '<p>There was a problem writing the ZIP archive.</p>';
} else {
rename($archiveName, 'user_archives/'.$archiveName.'');
$yourfile = "user_archives/".$archiveName."";
$file_name = basename($yourfile);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$file_name");
header("Content-Length: " . filesize($yourfile));
readfile($yourfile);
ignore_user_abort(true);
if (connection_aborted()) {
unlink('user_archives/'.$archiveName.'');
} else {
unlink('user_archives/'.$archiveName.'');
}
echo '<p>Successfully created the ZIP Archive!</p>';
}
}
?>
This seems to fix all problems.
I am trying to randomly download some files.
I apologize because I posted it earlier but can someone explain what I am doing wrong in detail?
I can not seem to debug it as I know minimal php.
<?php
$rootPath = realpath('./uploads');
//make zip file
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$nfiles = glob($rootPath.'*.{aiff}', GLOB_BRACE);
$files = array_rand($nfiles, 20);
foreach($files as $file) {
$pathtofile = $nfiles[$file];
if (!$file->isDir())
{
// Get path for current file
$filePath = $pathtofile->getRealPath();
$relativePath = str_replace($rootPath, "", $file);
// Add file to zip
$zip->addFile($filePath, $relativePath);
}
}
//-------------------------------------------//
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment;
filename='.'generatedsounds.zip');
header('Content-Length: ' . filesize('file.zip'));
readfile('file.zip');
if(file_exists('file.zip'))
{
unlink('file.zip');
}
?>
You're calling ->isDir() method which is not defined, And you're calling ->getRealPath() which is also not defined.
And you're getting all files then selecting 20 random files from the array (why??)
While you are rewriting the headers, errors won't be shown in browser, try without rewriting headers which means it's kept as html header and test until you get a binary file output then add the headers back so you have a working code.
I have the following code, which as you can see i use to create a new directory then unzip a file.
<?php
function unzip_to_s3() {
// Set temp path
$temp_path = 'wp-content/uploads/gravity_forms/1-9e5dc27086c8b2fd2e48678e1f54f98c/2013/02/tmp/';
// Get filename from Zip file
$zip_file = 'archive.zip';
// Create full Zip file path
$zip_file_path = $temp_path.$zip_file;
// Generate unique name for temp sub_folder for unzipped files
$temp_unzip_folder = uniqid('temp_TMS_', true);
// Create full temp sub_folder path
$temp_unzip_path = $temp_path.$temp_unzip_folder;
// Make the new temp sub_folder for unzipped files
if (!mkdir($temp_unzip_path, '0755', true)) {
die('Error: Could not create path: '.$temp_unzip_path);
}
// Unzip files to temp unzip folder, ignoring anything that is not a .mp3 extension
$zip = new ZipArchive();
$filename = $zip_file_path;
if ($zip->open($filename)!==TRUE) {
exit("cannot open <$filename>\n");
}
for ($i=0; $i<$zip->numFiles;$i++) {
$info = $zip->statIndex($i);
$file = pathinfo($info['name']);
if(strtolower($file['extension']) == "mp3") {
file_put_contents(basename($info['name']), $zip->getFromIndex($i));
} else {
$zip->deleteIndex($i);
}
}
$zip->close();
}
unzip_to_s3();
?>
The unzip code was courtesy of #TotalWipeOut from one of my other posts. It currently unzips just mp3 files to my base directory, but i want to put them in my newly created folder.
I'm very new to PHP so have been trying my best with this, but i can't figure out how to change the file_put_contents(basename($info['name']), $zip->getFromIndex($i)); line to get it to put the files in my new folder?
As Marc B. mentioned you need to include the path to the directory you are putting the file in.
using your code:
file_put_contents($temp_unzip_path."/".basename($info['name']), $zip->getFromIndex($i));
I would also suggest reading a little more about the basics of PHP.
<?php
$error = "";
$file_folder = "temp/";
// folder to load files
if (extension_loaded('zip')) {
// Checking ZIP extension is available
$zip = new ZipArchive();
// Load zip library
$zip_name = "images_".date("d-m-Y") . ".zip";
// Zip name
if ($zip -> open($zip_name, ZIPARCHIVE::CREATE) !== TRUE) {
// Opening zip file to load files
$error .= "* Sorry ZIP creation failed at this time";
}
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("../uploads/"));
$files = iterator_to_array($iterator, true);
foreach ($iterator as $file) {
$zip -> addFile($file_folder . $file);
// Adding files into zip
}
print_r($zip);
//echo $zip_name;
if (file_exists($file_folder.$zip_name)) {
// push to download the zip
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="' . $zip_name . '"');
readfile($zip_name);
// remove zip file is exists in temp path
unlink($zip_name);
} else {
echo "error";
}
$zip -> close();
//} else
// $error .= "* Please select file to zip ";
} else
$error .= "* You dont have ZIP extension";
?>
I have tried outputting $zip object and got following response:
ZipArchive Object ( [status] => 0 [statusSys] => 0 [numFiles] => 12 [filename] => /var/www/bigb/ajax/images_24-12-2012.zip [comment] => )
Status Zero explains there were no errors while creating zip (reference: http://www.php.net/manual/en/zip.constants.php)
I have referred posts:
1) Download all images from a single directory of a website
2) How to create a zip file using php and delete it after user downloads it?
3) http://www.9lessons.info/2012/06/creating-zip-file-with-php.html
Third one helped me the most and in the other 2 i was getting status as 23.
Issue: I am able to create a zip & no issue downloading it but when i open the zip i don't see any files inside but zip has memory in mbs.
Please Help me out...
Update: Error 23 occurs because of print_r / echo and or trying to overwrite same file.
Update2: Issue solved. It was due to path in RecursiveDirectoryIterator (i.e ../uploads/) once i moved the code to main folder and changed the path to (uploads/) everything started working as it should be. Kudos!!!
It was due to path in RecursiveDirectoryIterator (i.e ../uploads/) once i moved the code to main folder and changed the path to (uploads/) everything started working as it should be. Kudos!!!
I think the file path you are providing to $zip->addFile() is incorrect. You don't need to append anything to $file. Following will work:
foreach ($iterator as $file) {
$zip -> addFile($file);
}
In your case the $file will contain exact relative path of file like ../uploads/file.ext.