PHP – ZIP-file creation results in ZIP-file zipping itself - php

The script I'm using to create a ZIP-file out of multiple files results in a russian ZIP doll: instead of overwriting a current ZIP-file with the same name as intended, it's zipping the existing ZIP-file plus the actual files.
The ZIP-file (always with the same name) is being created after a page update (= file-upload/deletion) in the CMS.
Although it's the CMS' syntax, I hope it's readable;
'file.create:after' => function ($file) {
$page = $file->page();
$files_to_zip = $page->files(); // array
$parent_folder = $page->parent()->dirname(); // string
$target_folder = $page->dirname(); // string
$zip = new ZipArchive();
$zip_file = "content/" . $parent_folder . "/" . $target_folder . "/somefile.zip";
$zip->open($zip_file, (ZipArchive::CREATE | ZipArchive::OVERWRITE));
foreach ($files_to_zip as $file_to_zip) {
$zip->addFile($file_to_zip->root(), basename($file_to_zip->filename()));
}
$zip->close();
}
Am I missing something concerning the overwriting if existing of the file?
Thanks for any input!

AFTER "rotation" you need to call $file->page->files()
You need to manually "rotate" the zip archives, or just delete it (not recomended since it can result in data loss)
'file.create:after' => function ($file) {
$page = $file->page();
$parent_folder = $page->parent()->dirname(); // string
$target_folder = $page->dirname(); // string
$zip = new ZipArchive();
$zip_file = "content/" . $parent_folder . "/" . $target_folder ."/somefile.zip";
//delete old rotation if exists
unlink($zip_file.'.backup');
//rotate current zip file to '****.backup'
rename($zip_file, $zip_file.'.backup');
$files_to_zip = $file->page()->files(); // array
$zip->open($zip_file, (ZipArchive::CREATE | ZipArchive::OVERWRITE));
foreach ($files_to_zip as $file_to_zip) {
$zip->addFile($file_to_zip->root(), basename($file_to_zip->filename()));
}
$zip->close();
}

Related

How to save extracted zip file with specific filename

I have zip files with only one file inside it, but it has new name every time. I need to extract file and save it with specific file name, not extracted one.
$zip = new ZipArchive;
$res = $zip->open($tmp_name);
if ($res === TRUE) {
$path = _PATH."/files/";
$zip->extractTo($path);
$zip->close();
echo 'Unzip!';
}
Abowe code works, but I need to have specific filename. For example anyfile located under zip (eg. pricelist025.xml should be named temp.xml
Rename your specific file before you extract it.
$zip = new ZipArchive;
$res = $zip->open($tmp_name);
if ($res === TRUE) {
$zip->renameName('pricelist025.xml','temp.xml');
$path = _PATH."/files/";
$zip->extractTo($path);
$zip->close();
echo 'Unzip!';
} else {
echo 'failed, code:' . $res;
}
I hope this works.
UPDATE 1
There is two options if you want to change the file names.
1. change the file names before extracting -This way zip files will be modified
2. change the file names after extracting -Zip files will remain as they were before
Changing file names before extracting
We have to define a pattern for filenames. Here, Files will be in this patter : myfile0.xml, myfile1.html, adn so on..
Note: extension will be preserved.
$zip = new ZipArchive;
$res = $zip->open('hello.zip');
$newfilename = 'myfile';
for($i=0;$i<$zip->count();$i++)
{
$extension = pathinfo($zip->getNameIndex($i))['extension'];
$zip->renameName($zip->getNameIndex($i), $newfilename.$i.'.'.$extension);
}
Chaning file names after extracting
File names will in the same pattern as above.
$directory = 'hello/'; //your extracted directory
$newfilename = 'myfile';
foreach (glob($directory."*.*") as $index=>$filename) {
$basename = pathinfo($filename)['basename'];
if(!preg_match('/myfile\d\./', $basename)) {
$extension = pathinfo($filename)['extension'];
rename($filename,$newfilename.$index.'.'.$extension);
}
}
What we are here scanning the all the files from the extracted directory for which doesn't have a filename in the patter myfile[num]. and then we are changing it's name.
UPDATE 2
I just noticed you have updated your question.
As you have just one file and you want to extract it every time with different name. You should rename it every time you extract.
$zip = new ZipArchive;
$newfilename = "myfile".rand(1,999); //you can define any safe pattern here that suites you
if($zip->open('help.zip')===TRUE)
{
$path = '/your/path/to/directory';
$filename = $zip->getNameIndex(0);
if($zip->extractTo($path))
{
echo "Extracted";
}else{
echo "Extraction Failed";
exit();
}
$extension = pathinfo($filename)['extension'];
rename($path."/$filename",$path."/$newfilename".'.'.$extension);
echo "Extracted with different name successfully!";
} else {
echo "Failed";
}

On creating zip file by php I get two files instead of one

I'm struggling around with a simple PHP functionality: Creating a ZIP Archive with some files in.
The problem is, it does not create only one file called filename.zip but two files called filename.zip.a07600 and filename.zip.b07600. Pls. see the following screenshot:
The two files are perfect in size and I even can rename each of them to filename.zip and extract it without any problems.
Can anybody tell me what is going wrong???
function zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path = array(), $files_array = array()) {
// Archive File Name
$archive_file = $archiveDir."/".$archive_file_name;
// Time-to-live
$archiveTTL = 86400; // 1 day
// Delete old zip file
#unlink($archive_file);
// Create the object
$zip = new ZipArchive();
// Create the file and throw the error if unsuccessful
if ($zip->open($archive_file, ZIPARCHIVE::CREATE) !== TRUE) {
$response->res = "Cannot open '$archive_file'";
return $response;
}
// Add each file of $file_name array to archive
$i = 0;
foreach($files_array as $value){
$expl = explode("/", $value);
$file = $expl[(count($expl)-1)];
$path_file = $file_path[$i] . "/" . $file;
$size = round((filesize ($path_file) / 1024), 0);
if(file_exists($path_file)){
$zip->addFile($path_file, $file);
}
$i++;
}
$zip->close();
// Then send the headers to redirect to the ZIP file
header("HTTP/1.1 303 See Other"); // 303 is technically correct for this type of redirect
header("Location: $archive_file");
exit;
}
The code which calls the function is a file with a switch-case... it is called itself by an ajax-call:
case "zdl":
$files_array = array();
$file_path = array();
foreach ($dbh->query("select GUID, DIRECTORY, BASENAME, ELEMENTID from SMDMS where ELEMENTID = ".$osguid." and PROJECTID = ".$osproject.";") as $subrow) {
$archive_file_name = $subrow['ELEMENTID'].".zip";
$archiveDir = "../".$subrow['DIRECTORY'];
$files_array[] = $archiveDir.DIR_SEPARATOR.$subrow['BASENAME'];
$file_path[] = $archiveDir;
}
zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path, $files_array);
break;
One more code... I tried to rename the latest 123456.zip.a01234 file to 123456.zip and then unlink the old 123456.zip.a01234 (and all prior added .a01234 files) with this function:
function zip_file_exists($pathfile){
$arr = array();
$dir = dirname($pathfile);
$renamed = 0;
foreach(glob($pathfile.'.*') as $file) {
$path_parts = pathinfo($file);
$dirname = $path_parts['dirname'];
$basename = $path_parts['basename'];
$extension = $path_parts['extension'];
$filename = $path_parts['filename'];
if($renamed == 0){
$old_name = $file;
$new_name = str_replace(".".$extension, "", $file);
#copy($old_name, $new_name);
#unlink($old_name);
$renamed = 1;
//file_put_contents($dir."/test.txt", "old_name: ".$old_name." - new_name: ".$new_name." - dirname: ".$dirname." - basename: ".$basename." - extension: ".$extension." - filename: ".$filename." - test: ".$test);
}else{
#unlink($file);
}
}
}
In short: copy works, rename didn't work and "unlink"-doesn't work at all... I'm out of ideas now... :(
ONE MORE TRY: I placed the output of $zip->getStatusString() in a variable and wrote it to a log file... the log entry it produced is: Renaming temporary file failed: No such file or directory.
But as you can see in the graphic above the file 43051221.zip.a07200 is located in the directory where the zip-lib opens it temporarily.
Thank you in advance for your help!
So, after struggling around for days... It was so simple:
Actually I work ONLY on *nix Servers so in my scripts I created the folders dynamically with 0777 Perms. I didn't know that IIS doesn't accept this permissions format at all!
So I remoted to the server, right clicked on the folder Documents (the hierarchically most upper folder of all dynamically added files and folders) and gave full control to all users I found.
Now it works perfect!!! The only thing that would be interesting now is: is this dangerous of any reason???
Thanks for your good will answers...
My suspicion is that your script is hitting the PHP script timeout. PHP zip creates a temporary file to zip in to where the filename is yourfilename.zip.some_random_number. This file is renamed to yourfilename.zip when the zip file is closed. If the script times out it will probably just get left there.
Try reducing the number of files to zip, or increasing the script timeout with set_time_limit()
http://php.net/manual/en/function.set-time-limit.php

Application Folder backup using Codeigniter

I am trying to create a web app using codeigniter which will be used over a home or office network. Now Im looking for a backup option which can be done from the web protal. For example, in my htdocs folder i have: App1, App2 etc.
i want to backup and download the App1 folder directly from the webapp which can be done from any client machine which is connected to the server. is it possible. if yes then can you please let me know how?
~muttalebm
sorry for the late reply. I found a quite easy and simple backup option builtin with codeigniter. Hope this helps someone
$this->load->library('zip');
$path='C:\\xampp\\htdocs\\CodeIgniter\\';
$this->zip->read_dir($path);
$this->zip->download('my_backup.zip');
i used the code directly from the view and then just called it using the controller.
~muttalebm
Basically what you want to do is zip the application folder and download it, fairly simple to do. Please check out:
Download multiple files as a zip folder using php
On how to zip a folder for download.
I you do not have that extension a simple command can be used instead, I assume you are running on Linux if not replace command with zip/rar Windows equivalent:
$application_path = 'your full path to app folder without trailing slash';
exec('tar -pczf backup.tar.gz ' . $application_path . '/*');
header('Content-Type: application/tar');
readfile('backup.tar.gz');
Note: Make every effort to protect this file from being accessed by unauthorized users otherwise a malicious user will have a copy of your site code including config details.
// to intialize the path split the real path by dot .
public function init_path($string){
$array_path = explode('.', $string);
$realpath = '';
foreach ($array_path as $p)
{
$realpath .= $p;
$realpath .= '/';
}
return $realpath;
}
// backup files function
public function archive_folder($source = '' , $zip_name ='' , $save_dir = '' , $download = false){
// Get real path for our folder
$name = 'jpl';
if($zip_name == '')
{
$zip_name = $name."___(".date('H-i-s')."_".date('d-m-Y').")__".rand(1,11111111).".zip";
}
$realpath = $this->init_path($source);
if($save_dir != '')
{
$save_dir = $this->init_path($save_dir);
}else{
if (!is_dir('archives/'))
mkdir('archives/', 0777);
$save_dir = $this->init_path('archives');
}
$rootPath = realpath( $realpath);
// echo $rootPath;
// return;
// Initialize archive object
$zip = new ZipArchive();
$zip->open($save_dir . '\\' . $zip_name, 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();
if($download){
$this->download($zip);
}
}

PHP dynamic zip file creation crashes with non-image filetypes. (wp)

I have a function that takes uploaded files (WORDPRESS) and adds them to a (newly created) zip file.
every new file is added to the zip (if is not yet created - the first file will create one ) and also to a comment with the list of the files.
function Ob99_generate_zip_file($meta) {
// we always need post_id , right ?
if( isset($_GET['post_id']) ) {
$post_id = $_GET['post_id'];
} elseif( isset($_POST['post_id']) ) {
$post_id = $_POST['post_id'];
}
//setting some more variables.
$file = wp_upload_dir();// take array
$file2 = wp_upload_dir();//debug
$zipname = $file['path'].'file.zip'; // set zip file name
$file = trailingslashit($file['basedir']).$meta['file'];// construct real path
// Without this next condition the function dies. WHY ??
list($orig_w, $orig_h, $orig_type) = #getimagesize($file); // not help to comment
if (!$orig_type == IMAGETYPE_GIF || !$orig_type == IMAGETYPE_PNG|| !$orig_type == IMAGETYPE_JPEG) {
//why other filetypes not working ??
return ;
}
$zip = new ZipArchive; // initiatte class
$zip->open($zipname , ZipArchive::CREATE); // open buffer
$new_filename = substr($file,strrpos($file,'/') + 1); //we do not need nested folders
$zip->addFile($file,$sitename.'/'.$new_filename); // we add the file to the zip
if (file_exists($zipname)){
$comment = $zip->getArchiveComment(); // if the file already exist read the comment
}
else { // if not - let´s give it a cool retro header
$comment_head = '*********************************'. PHP_EOL ;
$comment_head .= '****** <<< FILE CONTENT >>> *****'. PHP_EOL ;
$comment_head .= '*********************************'. PHP_EOL ;
}
$comment = $comment_head . $comment ;// add header before comment
$comment = $comment . PHP_EOL . PHP_EOL . $meta['file'] ; // add new file name
$zip->setArchiveComment($comment); // and comment
$zip->addFromString('filelist.txt', $comment); // create txt file with the same list
$zip->close()or die('can not create zip file'.$file.print_r($meta).'---- DEBUG SEPERATOR ---- '.print_r($file2)); // FINISHED or DIE with debug
}
My problem : if I try to upload any file other than an image - the function will DIE .
I have added a condition for checking imagetype - but I would like to know why it is crashing and how to make it work without said condition ...
Does the zip function have any problems with PDF , doc or anyother ? is that a wordpress problem ?
The problem section seems to be where you're asking PDFs, etc. their image size. Why don't you try:
$image_size = getimagesize($file);
if($image_size===false)
{
// This is not an image
// Do what you want to PDFs, etc.
}
else
{
// This is an image
// Find out image type, dimensions, etc.
}

How to auto delete a zip file after using stream_get_contents(); to view a file in php?

I have this code to read a file for preview, but the downside is I have to download the file first from cloud and read from it, but it's a waste of space so I want to delete it after viewing a certain file. Is there an automatic way of doing this? Or do I have to integrate it to a close button?
// Get the container we want to use
$container = $conn->get_container('mailtemplate');
//$filename = 'template1.zip';
// upload file to Rackspace
$object = $container->get_object($filename);
//var_dump($object);
//echo '<pre>' . print_r($object,true) . '</pre>';
$localfile = $dir.$filename;
//echo $localfile;
$object->save_to_filename($localfile);
if($_GET['preview'] == "true")
{
$dir = "../mailtemplates/";
$file1 = $_GET['tfilename'];
$file = $dir.$file1;
$file2 = "index.html";
$info = pathinfo($file);
$file_name = basename($file,'.'.$info['extension']);
$path = $file_name.'/'.$file2;
$zip = new ZipArchive();
$zip->open($file);
$fp = $zip->getStream($path);
if(!$fp)
{
exit("faileds\n");
$zip->close();
unlink($dir.$filename);
}
else
{
$stuff = stream_get_contents($fp);
echo $stuff;
$zip->close();
if($stuff != null)
{
unlink($dir.$filename);
}
}
}
else
{
unlink($dir.$filename);
}
You didn't google this did ya?
Try Unlink
Edit:
Taking a look at this code, $zip->open($file); <-- is where you open the file. The file variable is set by:
"../mailtemplates/" . basename($_GET['tfilename'], '.' . $info['extension']) . '/' . "index.html"
So you're grabbing a relative directory and grabbing a filename as a folder, and going to that folder /index.html. Here's an example:
if you're in c:\ testing and you go to ../mailtemplates/ you'll be in c:\mailtemplates and then you're looking at file test.php but you're removing the file extension, so you'll be opening the location c:\mailtemplates\test\index.html so you open up that html file and read it. Then, you're trying to delete c:\mailtemplates\test.php
can you explain how any of that makes sense to you? 'cause that seems very odd to me.

Categories