I have found here at stackoveflow some code on how to ZIP a specific file, but how about a specific folder?
Folder/
index.html
picture.jpg
important.txt
inside in My Folder, there are files. after zipping the My Folder, i also want to delete the whole content of the folder except important.txt.
Found this here at stack
Code updated 2015/04/22.
Zip a whole folder:
// Get real path for our folder
$rootPath = realpath('folder-to-zip');
// 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();
Zip a whole folder + delete all files except "important.txt":
// Get real path for our folder
$rootPath = realpath('folder-to-zip');
// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Initialize empty "delete list"
$filesToDelete = array();
// 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);
// Add current file to "delete list"
// delete it later cause ZipArchive create archive only after calling close function and ZipArchive lock files until archive created)
if ($file->getFilename() != 'important.txt')
{
$filesToDelete[] = $filePath;
}
}
}
// Zip archive will be created only after closing object
$zip->close();
// Delete all files from "delete list"
foreach ($filesToDelete as $file)
{
unlink($file);
}
There is a useful undocumented method in the ZipArchive class: addGlob();
$zipFile = "./testZip.zip";
$zipArchive = new ZipArchive();
if ($zipArchive->open($zipFile, (ZipArchive::CREATE | ZipArchive::OVERWRITE)) !== true)
die("Failed to create archive\n");
$zipArchive->addGlob("./*.txt");
if ($zipArchive->status != ZIPARCHIVE::ER_OK)
echo "Failed to write files to zip\n";
$zipArchive->close();
Now documented at: www.php.net/manual/en/ziparchive.addglob.php
I assume this is running on a server where the zip application is in the search path. Should be true for all unix-based and I guess most windows-based servers.
exec('zip -r archive.zip "My folder"');
unlink('My\ folder/index.html');
unlink('My\ folder/picture.jpg');
The archive will reside in archive.zip afterwards. Keep in mind that blanks in file or folder names are a common cause of errors and should be avoided where possible.
Try this:
$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("target_folder/*") as $file) {
$zip->addFile($file);
if ($file != 'target_folder/important.txt') unlink($file);
}
$zip->close();
This will not zip recursively though.
I tried with the code below and it is working. The code is self explanatory, please let me know if you have any questions.
<?php
class FlxZipArchive extends ZipArchive
{
public function addDir($location, $name)
{
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
}
private function addDirDo($location, $name)
{
$name .= '/';
$location .= '/';
$dir = opendir ($location);
while ($file = readdir($dir))
{
if ($file == '.' || $file == '..') continue;
$do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
}
}
}
?>
<?php
$the_folder = '/path/to/folder/to/be/zipped';
$zip_file_name = '/path/to/zip/archive.zip';
$za = new FlxZipArchive;
$res = $za->open($zip_file_name, ZipArchive::CREATE);
if($res === TRUE)
{
$za->addDir($the_folder, basename($the_folder));
$za->close();
}
else{
echo 'Could not create a zip archive';
}
?>
This is a function that zips a whole folder and its contents in to a zip file and you can use it simple like this :
addzip ("path/folder/" , "/path2/folder.zip" );
function :
// compress all files in the source directory to destination directory
function create_zip($files = array(), $dest = '', $overwrite = false) {
if (file_exists($dest) && !$overwrite) {
return false;
}
if (($files)) {
$zip = new ZipArchive();
if ($zip->open($dest, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
foreach ($files as $file) {
$zip->addFile($file, $file);
}
$zip->close();
return file_exists($dest);
} else {
return false;
}
}
function addzip($source, $destination) {
$files_to_zip = glob($source . '/*');
create_zip($files_to_zip, $destination);
echo "done";
}
Use this function:
function zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = str_replace('\\', '/', $file);
// Ignore "." and ".." folders
if (in_array(substr($file, strrpos($file, '/')+1), array('.', '..'))) {
continue;
}
$file = realpath($file);
if (is_dir($file) === true) {
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
} elseif (is_file($file) === true) {
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
} elseif (is_file($source) === true) {
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
Example use:
zip('/folder/to/compress/', './compressed.zip');
Why not Try EFS PhP-ZiP MultiVolume Script ... I zipped and transferred hundreds of gigs and millions of files ... ssh is needed to effectively create archives.
But i belive that resulting files can be used with exec directly from php:
exec('zip -r backup-2013-03-30_0 . -i#backup-2013-03-30_0.txt');
I do not know if it works. I have not tried ...
"the secret" is that the execution time for archiving should not exceed the time allowed for execution of PHP code.
This is a working example of making ZIPs in PHP:
$zip = new ZipArchive();
$zip_name = time().".zip"; // Zip name
$zip->open($zip_name, ZipArchive::CREATE);
foreach ($files as $file) {
echo $path = "uploadpdf/".$file;
if(file_exists($path)){
$zip->addFromString(basename($path), file_get_contents($path));---This is main function
}
else{
echo"file does not exist";
}
}
$zip->close();
If you have subfolders and you want to preserve the structure of the folder do this:
$zip = new \ZipArchive();
$fileName = "my-package.zip";
if ($zip->open(public_path($fileName), \ZipArchive::CREATE) === true)
{
$files = \Illuminate\Support\Facades\File::allFiles(
public_path('/MY_FOLDER_PATH/')
);
foreach ($files as $file) {
$zip->addFile($file->getPathname(), $file->getRelativePathname());
}
$zip->close();
return response()
->download(public_path($fileName))
->deleteFileAfterSend(true);
}
deleteFileAfterSend(true) to delete the file my-package.zip from the server.
Don't forget to change /MY_FOLDER_PATH/ with the path of your folder that you want to download.
This will resolve your issue. Please try it.
$zip = new ZipArchive;
$zip->open('testPDFZip.zip', ZipArchive::CREATE);
foreach (glob(APPLICATION_PATH."pages/recruitment/uploads/test_pdf_folder/*") as $file) {
$new_filename = end(explode("/",$file));
$zip->addFile($file,"emp/".$new_filename);
}
$zip->close();
I found this post in google as the second top result, first was using exec :(
Anyway, while this did not suite my needs exactly.. I decided to post an answer for others with my quick but extended version of this.
SCRIPT FEATURES
Backup file naming day by day, PREFIX-YYYY-MM-DD-POSTFIX.EXTENSION
File Reporting / Missing
Previous Backups Listing
Does not zip / include previous backups ;)
Works on windows/linux
Anyway, onto the script.. While it may look like a lot.. Remember there is excess in here.. So feel free to delete the reporting sections as needed...
Also it may look messy as well and certain things could be cleaned up easily... So dont comment about it, its just a quick script with basic comments thrown in.. NOT FOR LIVE USE.. But easy to clean up for live use!
In this example, it is run from a directory that is inside of the root www / public_html folder.. So only needs to travel up one folder to get to the root.
<?php
// DIRECTORY WE WANT TO BACKUP
$pathBase = '../'; // Relate Path
// ZIP FILE NAMING ... This currently is equal to = sitename_www_YYYY_MM_DD_backup.zip
$zipPREFIX = "sitename_www";
$zipDATING = '_' . date('Y_m_d') . '_';
$zipPOSTFIX = "backup";
$zipEXTENSION = ".zip";
// SHOW PHP ERRORS... REMOVE/CHANGE FOR LIVE USE
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);
// ############################################################################################################################
// NO CHANGES NEEDED FROM THIS POINT
// ############################################################################################################################
// SOME BASE VARIABLES WE MIGHT NEED
$iBaseLen = strlen($pathBase);
$iPreLen = strlen($zipPREFIX);
$iPostLen = strlen($zipPOSTFIX);
$sFileZip = $pathBase . $zipPREFIX . $zipDATING . $zipPOSTFIX . $zipEXTENSION;
$oFiles = array();
$oFiles_Error = array();
$oFiles_Previous = array();
// SIMPLE HEADER ;)
echo '<center><h2>PHP Example: ZipArchive - Mayhem</h2></center>';
// CHECK IF BACKUP ALREADY DONE
if (file_exists($sFileZip)) {
// IF BACKUP EXISTS... SHOW MESSAGE AND THATS IT
echo "<h3 style='margin-bottom:0px;'>Backup Already Exists</h3><div style='width:800px; border:1px solid #000;'>";
echo '<b>File Name: </b>',$sFileZip,'<br />';
echo '<b>File Size: </b>',$sFileZip,'<br />';
echo "</div>";
exit; // No point loading our function below ;)
} else {
// NO BACKUP FOR TODAY.. SO START IT AND SHOW SCRIPT SETTINGS
echo "<h3 style='margin-bottom:0px;'>Script Settings</h3><div style='width:800px; border:1px solid #000;'>";
echo '<b>Backup Directory: </b>',$pathBase,'<br /> ';
echo '<b>Backup Save File: </b>',$sFileZip,'<br />';
echo "</div>";
// CREATE ZIPPER AND LOOP DIRECTORY FOR SUB STUFF
$oZip = new ZipArchive;
$oZip->open($sFileZip, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$oFilesWrk = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathBase),RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($oFilesWrk as $oKey => $eFileWrk) {
// VARIOUS NAMING FORMATS OF THE CURRENT FILE / DIRECTORY.. RELATE & ABSOLUTE
$sFilePath = substr($eFileWrk->getPathname(),$iBaseLen, strlen($eFileWrk->getPathname())- $iBaseLen);
$sFileReal = $eFileWrk->getRealPath();
$sFile = $eFileWrk->getBasename();
// WINDOWS CORRECT SLASHES
$sMyFP = str_replace('\\', '/', $sFileReal);
if (file_exists($sMyFP)) { // CHECK IF THE FILE WE ARE LOOPING EXISTS
if ($sFile!="." && $sFile!="..") { // MAKE SURE NOT DIRECTORY / . || ..
// CHECK IF FILE HAS BACKUP NAME PREFIX/POSTFIX... If So, Dont Add It,, List It
if (substr($sFile,0, $iPreLen)!=$zipPREFIX && substr($sFile,-1, $iPostLen + 4)!= $zipPOSTFIX.$zipEXTENSION) {
$oFiles[] = $sMyFP; // LIST FILE AS DONE
$oZip->addFile($sMyFP, $sFilePath); // APPEND TO THE ZIP FILE
} else {
$oFiles_Previous[] = $sMyFP; // LIST PREVIOUS BACKUP
}
}
} else {
$oFiles_Error[] = $sMyFP; // LIST FILE THAT DOES NOT EXIST
}
}
$sZipStatus = $oZip->getStatusString(); // GET ZIP STATUS
$oZip->close(); // WARNING: Close Required to append files, dont delete any files before this.
// SHOW BACKUP STATUS / FILE INFO
echo "<h3 style='margin-bottom:0px;'>Backup Stats</h3><div style='width:800px; height:120px; border:1px solid #000;'>";
echo "<b>Zipper Status: </b>" . $sZipStatus . "<br />";
echo "<b>Finished Zip Script: </b>",$sFileZip,"<br />";
echo "<b>Zip Size: </b>",human_filesize($sFileZip),"<br />";
echo "</div>";
// SHOW ANY PREVIOUS BACKUP FILES
echo "<h3 style='margin-bottom:0px;'>Previous Backups Count(" . count($oFiles_Previous) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles_Previous as $eFile) {
echo basename($eFile) . ", Size: " . human_filesize($eFile) . "<br />";
}
echo "</div>";
// SHOW ANY FILES THAT DID NOT EXIST??
if (count($oFiles_Error)>0) {
echo "<h3 style='margin-bottom:0px;'>Error Files, Count(" . count($oFiles_Error) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles_Error as $eFile) {
echo $eFile . "<br />";
}
echo "</div>";
}
// SHOW ANY FILES THAT HAVE BEEN ADDED TO THE ZIP
echo "<h3 style='margin-bottom:0px;'>Added Files, Count(" . count($oFiles) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
foreach ($oFiles as $eFile) {
echo $eFile . "<br />";
}
echo "</div>";
}
// CONVERT FILENAME INTO A FILESIZE AS Bytes/Kilobytes/Megabytes,Giga,Tera,Peta
function human_filesize($sFile, $decimals = 2) {
$bytes = filesize($sFile);
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . #$sz[$factor];
}
?>
WHAT DOES IT DO??
It will simply zip the complete contents of the variable $pathBase and store the zip in that same folder. It does a simple detection for previous backups and skips them.
CRON BACKUP
This script i've just tested on linux and worked fine from a cron job with using an absolute url for the pathBase.
Use this is working fine.
$dir = '/Folder/';
$zip = new ZipArchive();
$res = $zip->open(trim($dir, "/") . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($res === TRUE) {
foreach (glob($dir . '*') as $file) {
$zip->addFile($file, basename($file));
}
$zip->close();
} else {
echo 'Failed to create to zip. Error: ' . $res;
}
Create a zip folder in PHP.
Zip create method
public function zip_creation($source, $destination){
$dir = opendir($source);
$result = ($dir === false ? false : true);
if ($result !== false) {
$rootPath = realpath($source);
// Initialize archive object
$zip = new ZipArchive();
$zipfilename = $destination.".zip";
$zip->open($zipfilename, 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();
return TRUE;
} else {
return FALSE;
}
}
Call the zip method
$source = $source_directory;
$destination = $destination_directory;
$zipcreation = $this->zip_creation($source, $destination);
I did some small improvement in the script.
<?php
$directory = "./";
//create zip object
$zip = new ZipArchive();
$zip_name = time().".zip";
$zip->open($zip_name, ZipArchive::CREATE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($directory),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
$path = $file->getRealPath();
//check file permission
if(fileperms($path)!="16895"){
$zip->addFromString(basename($path), file_get_contents($path)) ;
echo "<span style='color:green;'>{$path} is added to zip file.<br /></span> " ;
}
else{
echo"<span style='color:red;'>{$path} location could not be added to zip<br /></span>";
}
}
$zip->close();
?>
For anyone reading this post and looking for a why to zip the files using addFile instead of addFromString, that does not zip the files with their absolute path (just zips the files and nothing else), see my question and answer here
If you are sure you are doing everything correctly and it is still not working. Check your PHP (user) permissions.
My 2 cents :
class compressor {
/**
* public static $NOT_COMPRESS
* use: compressor::$NOT_COMPRESS
* no compress thoses files for upload
*/
public static $NOT_COMPRESS = array(
'error_log',
'cgi-bin',
'whatever/whatever'
);
/**
* end public static $NOT_COMPRESS
*/
/**
* public function compress_folder( $dir, $version, $archive_dest );
* #param {string} $dir | absolute path to the directory
* #param {string} $version_number | ex: 0.1.1
* #param {string} $archive_dest | absolute path to the future compressed file
* #return {void} DO A COMPRESSION OF A FOLDER
*/
public function compress_folder( $dir, $version, $archive_dest ){
// name of FUTURE .zip file
$archive_name = $version_number.'.zip';
// test dir exits
if( !is_dir($dir) ){ exit('No temp directory ...'); }
// Iterate and archive API DIRECTORIES AND FOLDERS
// create zip archive + manager
$zip = new ZipArchive;
$zip->open( $archive_dest,
ZipArchive::CREATE | ZipArchive::OVERWRITE );
// iterator / SKIP_DOTS -> ignore '..' and '.'
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $dir,
RecursiveDirectoryIterator::SKIP_DOTS )
);
// loop iterator
foreach( $it as $file ){
// check files not to add for compress
// loop list for not add to upload .zip
foreach( compressor::$NOT_COMPRESS as $k => $v) {
if( preg_match( '/^('.preg_quote($v,'/').')/', $it->getSubPathName() ) == true ){
// break this loop and parent loop
continue 2;
}
}
// end loop list
// for Test
// echo $it->getSubPathName()."\r\n";
// no need to check if is a DIRECTORY with $it->getSubPathName()
// DIRECTORIES are added automatically
$zip->addFile( $it->getPathname(), $it->getSubPathName() );
}
// end loop
$zip->close();
// END Iterate and archive API DIRECTORIES AND FOLDERS
}
/**
* public function compress_folder( $version_number );
*/
}
// end class compressor
use :
// future name of the archive
$version = '0.0.1';
// path of directory to compress
$dir = $_SERVER['DOCUMENT_ROOT'].'/SOURCES';
// real path to FUTURE ARCHIVE
$archive_dest = $_SERVER['DOCUMENT_ROOT'].'/COMPRESSED/'.$version.'.zip';
$Compress = new compressor();
$Compress->compress_folder( $dir, $version, $archive_dest );
// this create a .zip file like :
$_SERVER['DOCUMENT_ROOT'].'/COMPRESSED/0.0.1.zip
This is the best solution for me which is working fine in my Codecanyon project and well tested.
function zipper($space_slug)
{
// Get real path for our folder
$rootPath = realpath('files/' . $space_slug);
// Initialize archive object
$zip = new ZipArchive();
/* Opening the zip file and creating it if it doesn't exist. */
$zip->open('files/' . $space_slug . '.zip', ZipArchive::CREATE |
ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** #var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::SELF_FIRST
);
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();
}
includes all sub-folders:
zip_folder('path/to/input/folder', 'path/to/output_zip_file.zip') ;
Here is source-code (there might have been an update, but below I put the copy of that code):
function zip_folder ($input_folder, $output_zip_file) {
$zipClass = new ZipArchive();
if($input_folder !== false && $output_zip_file !== false)
{
$res = $zipClass->open($output_zip_file, \ZipArchive::CREATE);
if($res === TRUE) {
// Add a Dir with Files and Subdirs to the archive
$foldername = basename($input_folder);
$zipClass->addEmptyDir($foldername);
$foldername .= '/'; $input_folder .= '/';
// Read all Files in Dir
$dir = opendir ($input_folder);
while ($file = readdir($dir)) {
if ($file == '.' || $file == '..') continue;
// Rekursiv, If dir: GoodZipArchive::addDir(), else ::File();
$do = (filetype( $input_folder . $file) == 'dir') ? 'addDir' : 'addFile';
$zipClass->$do($input_folder . $file, $foldername . $file);
}
$zipClass->close();
}
else { exit ('Could not create a zip archive, migth be write permissions or other reason. Contact admin.'); }
}
}
I am creating script zipping files from an array.
/* creates a compressed zip file */
function create_zip($files = array(),$destination = '',$overwrite = false) {
//if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) { return false; }
//vars
$valid_files = array();
//if files were passed in...
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
//make sure the file exists
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
//if we have good files...
if(count($valid_files)) {
//create the archive
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile($file,$file);
}
//debug
//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
//close the zip -- done!
$zip->close();
//check to make sure the file exists
return file_exists($destination);
}
else
{
return false;
}
}
#Mysql connect
$files_to_zip = array();
while($row = mysql_fetch_assoc($shots)) {
$files_to_zip[] = '/home/username/domains/example.com/public_html/components/items/images/item/' . $row["name"] . '_thb.' . $row["ext"];
}
if(isset($_POST['create'])){
//if true, good; if false, zip creation failed
$result = create_zip($files_to_zip,'my-archive5.zip');
}
After form submitting zip is created, but there's full directory tree inside files.
How to only zip files without directories?
Second thing:
When I open zip in total commander - I can see directories and files. When I open it normally - zip is empty.
The second argument to the addFile() method is the name of the file inside the zip. You're doing this:
$zip->addFile($file, $file);
So you're getting something like:
$zip->addFile('/path/to/some/file', '/path/to/some/file');
Which just copies the path from the source into the zip. If you want all the files to be in one dir in the zip, remove the path from the file name:
$zip->addFile($file, basename($file));
This will give you:
$zip->addFile('/path/to/some/file', 'file');
Note this won't work too well if you have files with the same name in different directories.
Check the docs on addFile method of Zip extension. You can specify local name as second argument.
Example from the documentation
<?php
$zip = new ZipArchive;
if ($zip->open('test.zip') === TRUE) {
$zip->addFile('/path/to/index.txt', 'newname.txt');
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
?>
I am using this function to generate zip files:
function create_zip($files = array(),$destination = '',$overwrite = false) {
//if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) { return false; }
//vars
$valid_files = array();
//if files were passed in...
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
//make sure the file exists
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
//if we have good files...
if(count($valid_files)) {
//create the archive
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile($file,$file);
//echo $file;
}
//debug
//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
//close the zip -- done!
$zip->close();
//check to make sure the file exists
echo $destination;
return file_exists($destination);
}
else
{
return false;
}
}
I am using this to zip a vanilla, unaltered Wordpress install.(http://wordpress.org/) However for some reason the wp-content folder is having a 'ghost' empty file generated with it's name. The folder (and everything else) itself compresses correctly, but most unzip applications (including php's own extractTo()) break when they reach this unwanted file due to the name conflict.
I've looked into the folder/file structure and as far as I can see the only difference of note between this and the other folders in the site is that it is the biggest at 5.86 mb.
Can anyone suggest a fix / workaround?
This is the sample example to zip a folder.
<?php
function Create_zipArch($archive_name, $archive_folder)
{
$zip = new ZipArchive;
if ($zip->open($archive_name, ZipArchive::CREATE) === TRUE)
{
$dir = preg_replace('/[\/]{2,}/', '/', $archive_folder . "/");
$dirs = array($dir);
while (count($dirs))
{
$dir = current($dirs);
$zip->addEmptyDir($dir);
$dh = opendir($dir);
while ($file = readdir($dh))
{
if ($file != '.' && $file != '..')
{
if (is_file($file))
$zip->addFile($dir . $file, $dir . $file);
elseif (is_dir($file))
$dirs[] = $dir . $file . "/";
}
}
closedir($dh);
array_shift($dirs);
}
$zip->close();
$result='success';
}
else
{
$result='failed';
}
return $result;
}
$zipArchName = "ZipFileName.zip"; // zip file name
$FolderToZip = "zipthisfolder"; // folder to zip
echo Create_zipArch($zipArchName, $FolderToZip);
?>
I'm trying to use php to create a zip file (which it does - taken from this page - http://davidwalsh.name/create-zip-php), however inside the zip file are all of the folder names to the file itself.
Is it possible to just have the file inside the zip minus all the folders?
Here's my code:
function create_zip($files = array(), $destination = '', $overwrite = true) {
if(file_exists($destination) && !$overwrite) { return false; };
$valid_files = array();
if(is_array($files)) {
foreach($files as $file) {
if(file_exists($file)) {
$valid_files[] = $file;
};
};
};
if(count($valid_files)) {
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
};
foreach($valid_files as $file) {
$zip->addFile($file,$file);
};
$zip->close();
return file_exists($destination);
} else {
return false;
};
};
$files_to_zip = array('/media/138/file_01.jpg','/media/138/file_01.jpg','/media/138/file_01.jpg');
$result = create_zip($files_to_zip,'/...full_site_path.../downloads/138/138_files.zip');
The problem here is that $zip->addFile is being passed the same two parameters.
According to the documentation:
bool ZipArchive::addFile ( string $filename [, string $localname ] )
filename
The path to the file to add.
localname
local name inside ZIP archive.
This means that the first parameter is the path to the actual file in the filesystem and the second is the path & filename that the file will have in the archive.
When you supply the second parameter, you'll want to strip the path from it when adding it to the zip archive. For example, on Unix-based systems this would look like:
$new_filename = substr($file,strrpos($file,'/') + 1);
$zip->addFile($file,$new_filename);
I think a better option would be:
$zip->addFile($file,basename($file));
Which simply extracts the filename from the path.
This is just another method that I found that worked for me
$zipname = 'file.zip';
$zip = new ZipArchive();
$tmp_file = tempnam('.','');
$zip->open($tmp_file, ZipArchive::CREATE);
$download_file = file_get_contents($file);
$zip->addFromString(basename($file),$download_file);
$zip->close();
header('Content-disposition: attachment; filename='.$zipname);
header('Content-type: application/zip');
readfile($tmp_file);
I use this to remove root folder from zip
D:\xampp\htdocs\myapp\assets\index.php
wil be in zip:
assets\index.php
our code:
echo $main_path = str_replace("\\", "/", __DIR__ );// get current folder, which call scipt
$zip_file = 'myapp.zip';
if (file_exists($main_path) && is_dir($main_path))
{
$zip = new ZipArchive();
if (file_exists($zip_file)) {
unlink($zip_file); // truncate ZIP
}
if ($zip->open($zip_file, ZIPARCHIVE::CREATE)!==TRUE) {
die("cannot open <$zip_file>\n");
}
$files = 0;
$paths = array($main_path);
while (list(, $path) = each($paths))
{
foreach (glob($path.'/*') as $p)
{
if (is_dir($p)) {
$paths[] = $p;
} else {
// special here: we remove root folder ("D:\xampp\htdocs\myapp\") :D
$new_filename = str_replace($main_path."/" , "", $p);
$zip->addFile($p, $new_filename);
$files++;
echo $p."<br>\n";
}
}
}
echo 'Total files: '.$files;
$zip->close();
}