I'm new to SO and new to PHP. I found a script online to zip a directory and I've edited it so that it sends the zip to the browser for download and then deletes the file from the server.
It works fine, however I would like to zip multiple directories instead of just one.
How would I need to alter my script to accomplish this?
$date = date('Y-m-d');
$dirToBackup = "content";
$dest = "backups/"; // make sure this directory exists!
$filename = "backup-$date.zip";
$archive = $dest.$filename;
function folderToZip($folder, &$zipFile, $subfolder = null) {
if ($zipFile == null) {
// no resource given, exit
return false;
}
// we check if $folder has a slash at its end, if not, we append one
$folder .= end(str_split($folder)) == "/" ? "" : "/";
$subfolder .= end(str_split($subfolder)) == "/" ? "" : "/";
// we start by going through all files in $folder
$handle = opendir($folder);
while ($f = readdir($handle)) {
if ($f != "." && $f != "..") {
if (is_file($folder . $f)) {
// if we find a file, store it
// if we have a subfolder, store it there
if ($subfolder != null)
$zipFile->addFile($folder . $f, $subfolder . $f);
else
$zipFile->addFile($folder . $f);
} elseif (is_dir($folder . $f)) {
// if we find a folder, create a folder in the zip
$zipFile->addEmptyDir($f);
// and call the function again
folderToZip($folder . $f, $zipFile, $f);
}
}
}
}
// create the zip
$z = new ZipArchive();
$z->open($archive, ZIPARCHIVE::CREATE);
folderToZip($dirToBackup, $z);
$z->close();
// download the zip file
$file_name = basename($archive);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$file_name");
header("Content-Length: " . filesize($archive));
readfile($archive);
// delete the file from the server
unlink($archive);
exit;
Thanks for any help!
Irma
set $dirToBackup to
$dirToBackup = array("restricted","ci");
and then :
foreach($dirToBackup as $d){
folderToZip($d, $z, $d);
}
Thats all.
Regards,
Related
I'm trying to create zip file from a large folder which size almost 2GB. My code is working well on the localhost but it's not working on the server(Cpanel). In server, it's creating a zip file which size is only 103 MB out of 2GB. According to my strategy, first of all, I'm creating a backup folder recursively named "system_backup". And the backup folder is creating well without any problem. The next is, to create the zip file of 'system_backup' folder by calling the function ZipData and stored it to another folder. In this time, it's not creating the zip file properly.
After that, the function rrmdir will be called. And it will delete the 'system_backup' folder recursively. And the deletion is not working properly as well. And, in localhost, it works well.
Then, when I'm trying to download the created zip file by the function download_file, it also not download properly. It's downloaded as a broken zip file. And, in localhost, it also works well.
I have already checked the read and write permission of folders and files.
The code is given below:-
public function backup_app(){
//Backup System
ini_set('memory_limit', '-1');
set_time_limit(0);
$this->recurse_copy(FCPATH,'system_backup');
$backup_name = 'Customs-system-backup-on_'. date("Y-m-d-H-i-s") .'.zip';
$path = FCPATH.'system_backup';
$destination = FCPATH.'bdCustomsBackup/'.$backup_name;
$this->zipData($path, $destination);
//Delete directory
$this->rrmdir($path);
$message = "Application Backup on ".date("Y-m-d-H-i-s");
$this->submit_log($message);
echo 1;
}
function zipData($source, $destination) {
if (extension_loaded('zip')) {
if (file_exists($source)) {
$zip = new ZipArchive();
if ($zip->open($destination, ZIPARCHIVE::CREATE)) {
$source = realpath($source);
if (is_dir($source)) {
$iterator = new RecursiveDirectoryIterator($source);
// skip dot files while iterating
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$counter = 1;
foreach ($files as $file) {
$file = realpath($file);
if (is_dir($file)) {
$zip->addEmptyDir(str_replace($source . '/', 'system_backup/', $file . '/'));
} else if (is_file($file)) {
$zip->addFromString(str_replace($source . '/', 'system_backup/', $file), file_get_contents($file));
}
}
} else if (is_file($source)) {
$zip->addFromString(basename($source), file_get_contents($source));
}
}
return $zip->close();
}
}
return false;
}
public function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' ) && ( $file != $dst ) && ( $file != "bdCustomsBackup" )) {
if ( is_dir($src . '/' . $file) ) {
$this->recurse_copy($src . '/' . $file, $dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
public function rrmdir($src) {
$dir = opendir($src);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
$full = $src . '/' . $file;
if ( is_dir($full) ) {
$this->rrmdir($full);
}
else {
unlink($full);
}
}
}
closedir($dir);
rmdir($src);
}
public function download_file($file){
$message = "Download ".$file." on ".date("Y-m-d-H-i-s");
$this->submit_log($message);
$path = FCPATH.'bdCustomsBackup/'.$file;
$this->load->helper('download_helper');
force_download($file, $path);
}
Here is the custom download_helper:-
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if ( ! function_exists('force_download'))
{
function force_download($filename = '', $file = '')
{
if ($filename == '' OR $file == '')
{
return FALSE;
}
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
{
return FALSE;
}
// Grab the file extension
$x = explode('.', $filename);
$extension = end($x);
// Load the mime types
#include(APPPATH.'config/mimes'.EXT);
// Set a default mime if we can't find it
if ( ! isset($mimes[$extension]))
{
$mime = 'application/octet-stream';
}
else
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".filesize($file));
}
else
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize($file));
}
readfile_chunked($file);
die;
}
}
if ( ! function_exists('readfile_chunked'))
{
function readfile_chunked($file, $retbytes=TRUE)
{
$chunksize = 1 * (1024 * 1024);
$buffer = '';
$cnt =0;
$handle = fopen($file, 'r');
if ($handle === FALSE)
{
return FALSE;
}
while (!feof($handle))
{
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes)
{
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes AND $status)
{
return $cnt;
}
return $status;
}
}
/* End of file download_helper.php */
/* Location: ./application/helpers/download_helper.php */
The below code is using PHP:
$zip = new ZipArchive;
if ($zip->open('test_new.zip', ZipArchive::CREATE) === TRUE)
{
// Add files to the zip file
$zip->addFile('test.txt');
$zip->addFile('test.pdf');
// Add random.txt file to zip and rename it to newfile.txt
$zip->addFile('random.txt', 'newfile.txt');
// Add a file new.txt file to zip using the text specified
$zip->addFromString('new.txt', 'text to be added to the new.txt file');
// All files are added, so close the zip file.
$zip->close();
}
Explanation of code
Line 1 creates an object of the ZipArchive class
Line 2 opens a file with filename as test_new.zip so that we can add files to it. The flag ZipArchive::CREATE specifies that we want to create a new zip file
Lines 5 & 6 are used to add files to the zip file
Line 9 is used to add a file with name random.txt to the zip file and rename it in the zipfile as newfile.txt
Line 12 is used to add a new file new.txt with contents of the file as ‘text to be added to the new.txt file’
Line 15 closes and saves the changes to the zip file
Note: Sometimes there can be issues when using relative paths for files. If there are any issues using paths then we can also use absolute paths for files
Overwrite an existing zip file
If you want to overwrite an existing zip file then we can use code similar to following. The flag ZipArchive::OVERWRITE overwrites the existing zip file.
$zip = new ZipArchive;
if ($zip->open('test_overwrite.zip', ZipArchive::OVERWRITE) === TRUE)
{
// Add file to the zip file
$zip->addFile('test.txt');
$zip->addFile('test.pdf');
// All files are added, so close the zip file.
$zip->close();
}
Explanation of code
This code will create a file test_overwrite.zip if it already exists the file will be overwritten with this new file
Create a new zip file and add files to be inside a folder
$zip = new ZipArchive;
if ($zip->open('test_folder.zip', ZipArchive::CREATE) === TRUE)
{
// Add files to the zip file inside demo_folder
$zip->addFile('text.txt', 'demo_folder/test.txt');
$zip->addFile('test.pdf', 'demo_folder/test.pdf');
// Add random.txt file to zip and rename it to newfile.txt and store in demo_folder
$zip->addFile('random.txt', 'demo_folder/newfile.txt');
// Add a file demo_folder/new.txt file to zip using the text specified
$zip->addFromString('demo_folder/new.txt', 'text to be added to the new.txt file');
// All files are added, so close the zip file.
$zip->close();
}
Explanation of code
The above code will add different files inside the zip file to be inside a folder demo_folder
The 2nd parameter to addfile function can be used to store the file in a new folder
The 1st parameter in the addFromString function can be used to store the file in a new folder
Create a new zip file and move the files to be in different folders
$zip = new ZipArchive;
if ($zip->open('test_folder_change.zip', ZipArchive::CREATE) === TRUE)
{
// Add files to the zip file
$zip->addFile('text.txt', 'demo_folder/test.txt');
$zip->addFile('test.pdf', 'demo_folder1/test.pdf');
// All files are added, so close the zip file.
$zip->close();
}
Explanation of code
We store the file test.txt into demo_folder and test.pdf into demo_folder1
Create a zip file with all files from a directory
$zip = new ZipArchive;
if ($zip->open('test_dir.zip', ZipArchive::OVERWRITE) === TRUE)
{
if ($handle = opendir('demo_folder'))
{
// Add all files inside the directory
while (false !== ($entry = readdir($handle)))
{
if ($entry != "." && $entry != ".." && !is_dir('demo_folder/' . $entry))
{
$zip->addFile('demo_folder/' . $entry);
}
}
closedir($handle);
}
$zip->close();
}
Explanation of code
Lines 5-16 opens a directory and creates a zip file with all files within that directory
Line 5 opens the directory
Line 7 gets the name of each file in the dir
Line 9 skips the “.” and “..” and any other directories
Line 11 adds the file into the zip file
Line 14 closes the directory
Line 17 closes the zip file
I am having a very strange problem when zipping a directory and try to download using codeigniter.
Here is the code
$this->load->library('zip'); //Loading the zip library
$directory = $_SESSION['directory-download-path']; //Getting the directory from session
$name = basename($directory); //get the name of the folder
$name = str_replace(" ", "_", $name).".zip"; //create the zip name
unset($_SESSION['directory-download-path']); //removing it from session
$this->zip->read_dir($directory); //read the directory
$this->zip->download($name); //download the zip
It is very simple. The problem occurs with the download. I get the zip file but when i extract it i get a file with .zip.cpgz and continues to extract similar files. Thus i think it is corrupted. Can you please help me why is this occurring. I have permissions and everything on the directory because i am doing other operations.
EDIT:
I found after some more research to add the second parameter as follows:
$this->zip->read_dir($directory, false); //read the directory
But still not working.
Another solution was to add
ob_end_clean();
just before the line: $this->zip->download($name); //download the zip
but still no success!
Since I had no response i made a function outside of codeigniter that zips files and folder recursively which is below:
public 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);
if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..', "Thumbs.db")) )
continue;
$file = realpath($file);
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
After this in the codeigniter controller i made this:
$this->projects->Zip($source, $destination);
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$name");
header("Content-length: " . filesize($destination));
header("Pragma: no-cache");
header("Expires: 0");
readfile($destination);
unlink($destination);
Of course the $destination should be to a temp folder where you have permissions 777 or equivalent so that when the file is sent to the client it will be deleted.
Hope this helps!
I'm very new to php and I just made my first script, which is working fine, but is missing a final touch.
The script zips all files in the folder containing the php and creates a downloadable archive.
Here's the code
<?php
$zipname = 'test.zip';
$zip = new ZipArchive;
$zip->open('D://mypath//zip//$zipname', ZipArchive::CREATE);
if ($dir_handle = opendir('./')) {
while (false !== ($entry = readdir($dir_handle))) {
if ($entry != "." && $entry != ".." && !strstr($entry,'.php') && !strstr($entry,'.zip')) {
$zip->addFile($entry);
}
}
closedir($dir_handle);
}
else {
die('file not found');
}
$zip->close();
header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=$zipname");
header('Content-Length: ' . filesize($zipname));
header("Location: $zipname");
?>
What I'd like to achieve is having $zipname = "the name of the folder.zip"
So, if the php is inside "/mypath/blablabla/" i want my zip $zipname to be "blablabla.zip"
Any help will be appreciated!
EDIT:
here's the working code:
<?php
$zipname = getcwd();
$zipname = substr($zipname,strrpos($zipname,'\\')+1);
$zipname = $zipname.'.zip';
$zip = new ZipArchive;
$zip->open('D:/inetpub/webs/mydomaincom/zip/'.basename($zipname).'', ZipArchive::CREATE);
if ($dir_handle = opendir('./')) {
while (false !== ($entry = readdir($dir_handle))) {
if ($entry != "." && $entry != ".." && !strstr($entry,'.php')) {
$zip->addFile($entry);
}
}
closedir($dir_handle);
}
else {
die('file not found');
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
header('Content-Length: ' . filesize($zipname));
header('Location: /zip/'.$zipname);
?>
You could use getcwd() :
http://php.net/manual/fr/function.getcwd.php
$zipname = getcwd();
It'll return the path of the current folder, then you could just hash the result to get only the name of the folder :
// We remove all the uneeded part of the path
$zipname = substr($zipname,strrpos($zipname,'\\')+1);
//Then we add .zip to the result :
$zipname = $zipname.'.zip';
This should do the trick.
And if you want to also use the name of the parent folder :
$zipname = getcwd();
// We remove the uneeded part of the path
$parentFolderPath = substr($zipname, 0,strrpos($zipname,'\\'));
$parentFolder = substr($parentFolderPath, strrpos($parentFolderPath,'\\')+1);
//Keep current folder name
$currentFolder = substr($zipname,strrpos($zipname,'\\')+1);
//Join both
$zipname = $parentFolder.'_'.$currentFolder;
//Then we add .zip to the result :
$zipname = $zipname.'.zip';
Instead of redirecting with header(), you could use readfile():
header('Content-Disposition: attachment; filename="'.basename($zipname).'"');
readfile($zipname);
With basename() only the last part is shown to the user and with readfile() you are giving out the actual file, no matter where it is.
I am able to Zip and download the folder from my local machine using the following code. But I want to download a folder from my web server. How can i do it. please help. I searched a lot on google but i couldn't find a solution.
$the_folder = 'C:/Program Files/Red5/webapps/SOSample/streams/';
$zip_file_name = 'getaaa.zip';
$download_file= true;
//$delete_file_after_download= true; doesnt work!!
class FlxZipArchive extends ZipArchive {
// $location="http://localhost/SOSample";
public function addDir($location, $name) {
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
} // EO addDir;
private function addDirDo($location, $name) {
$name .= '/';
$location .= '/';
// Read all Files in Dir
$dir = opendir ($location);
while ($file = readdir($dir))
{
if ($file == '.' || $file == '..') continue;
// Rekursiv, If dir: FlxZipArchive::addDir(), else ::File();
$do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
}
} // EO addDirDo();
}
$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';}
if ($download_file)
{
ob_get_clean();
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($zip_file_name) . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($zip_file_name));
readfile($zip_file_name);
//deletes file when its done...
//if ($delete_file_after_download)
//{ unlink($zip_file_name); }
}
?>
You can't "download a folder." You have to zip it up.
Instead of giving $location="http://localhost/SOSample"; give full absolute path of your web server palce it in your web server and it will make zip file from your web server. Is your eb server windows or linux based on it give the path to $location variable.
As said you cant download a folder. However, if you have a file path, you can download files separated from each other. Using file_get_contents makes it easy. http://nl1.php.net/file_get_contents
=============== Edit: ===============
You need to recursively add files in the directory. Something like this (untested):
function createZipFromDir($dir, $zip_file) {
$zip = new ZipArchive;
if (true !== $zip->open($zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) {
return false;
}
zipDir($dir, $zip);
return $zip;
}
function zipDir($dir, $zip, $relative_path = DIRECTORY_SEPARATOR) {
$dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (file === '.' || $file === '..') {
continue;
}
if (is_file($dir . $file)) {
$zip->addFile($dir . $file, $file);
} elseif (is_dir($dir . $file)) {
zipDir($dir . $file, $zip, $relative_path . $file);
}
}
}
closedir($handle);
}
Then call $zip = createZipFromDir('/tmp/dir', 'files.zip');
Some examples of zip, see: http://www.php.net/manual/en/zip.examples.php
(code from: How to zip a folder and download it using php?)
=============== Edit 2: ===============
Based on your comment:
opendir() is used to open a local directory and since PHP 5.0.0 on an ftp directory.
If your PHP code runs on www.domain.com then /pages/to/path is actually a local directory and you can do this:
$dir ='<wwwroot>/pages/to/path';
if ($handle = opendir($dir)) {
where wwwroot is the root of the filesystem as seen by your php code.
If you're trying to download content from another website, try e.g. file_get_contents(). Note that if the remote server lists the content of a directory the listing is in fact an HTML page generated on the fly by the server. You may find yourself needing to parse that page. A better approach is to check whether the server offers some sort of API where it sends back the content in a standardized form, e.g. in JSON format.
This question already has answers here:
Unzip a file with php
(12 answers)
Closed 8 years ago.
I have a zip file with some files and folders inside, and I want to extract the contents of the folder "/files" from the zip file to the a specified path (the root path of my application).
If there is a non existing folder it should just be created.
So for example if the path inside the zip is: "/files/includes/test.class.php" it should be extracted to
$path . "/includes/test.class.php"
How can I do this?
The only function i found to switch inside the zip file should be
http://www.php.net/manual/en/ziparchive.getstream.php
but i actually don't know how i can do that with this function.
Try this:
$zip = new ZipArchive;
$archiveName = 'test.zip';
$destination = $path . '/includes/';
$pattern = '#^files/includes/(.)+#';
$patternReplace = '#^files/includes/#';
function makeStructure($entry, $destination, $patternReplace)
{
$entry = preg_replace($patternReplace, '', $entry);
$parts = explode(DIRECTORY_SEPARATOR, $entry);
$dirArray = array_slice($parts, 0, sizeof($parts) - 1);
$dir = $destination . join(DIRECTORY_SEPARATOR, $dirArray);
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
if ($dir !== $destination) {
$dir .= DIRECTORY_SEPARATOR;
}
$fileExtension = pathinfo($entry, PATHINFO_EXTENSION);
if (!empty($fileExtension)) {
$fileName = $dir . pathinfo($entry, PATHINFO_BASENAME);
return $fileName;
}
return null;
}
if ($zip->open($archiveName) === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if (preg_match($pattern, $entry)) {
$file = makeStructure($entry, $destination, $patternReplace);
if ($file === null) {
continue;
}
copy('zip://' . $archiveName . '#' . $entry, $file);
}
}
$zip->close();
}
I think you need zziplib extension for this to work
$zip = new ZipArchive;
if ($zip->open('your zip file') === TRUE) {
//create folder if does not exist
if (!is_dir('path/to/directory')) {
mkdir('path/to/directory');
}
//then extract the zip
$zip->extractTo('destination to which zip is to be extracted');
$zip->close();
echo 'Zip successfully extracted.';
} else {
echo 'An error occured while extracting.';
}
Read this link for more info http://www.php.net/manual/en/ziparchive.extractto.php
Hope this helps :)