ZipArchive - Problem with the generated archive file - php

I've got a problem with the class : ZipArchive.
My ZIP file is well created and my folders and files are in the archive.
However, I've got 2 problems:
I can't extract a file from the generated archive unless if the file is located on the root of the archive;
If I extract the entire archive, the tree is deleted, the files are all at the same level, while the tree is good if I browse the archive with an archive manager;
I've tried to creating the folders first with $archive->addEmptyDir, but it doesn't change anything.
I think that It's an Index problem or something like this but I'm not sure.
Here's my code:
$archive = new ZipArchive;
foreach($files as $file_origin_path) {
if($error === FALSE) {
$error = !$archive->addFile($file_origin_path, str_ireplace($path, '', $file_origin_path));
}
}
$archive->close();
Would anyone have a way that would allow me to move forward?

Related

How to copy the source code of my website recursively into a zip file and download using PHP

Since my file manager doesn't allow me to download multiple files, instead only allowing me to download them one by one (which is tedious, and, eventually will become inefficient), I want to know how to download all my website file contents into a single zip folder. I found a code that works from geeksForGeeks, however it only zips on that current directory level (not recursively). I want every file on my website put into a zip folder while preserving their place in their corresponding folders.
The code I found:
// Enter the name of directory
$pathdir = "./";
// Enter the name to creating zipped directory
$zipcreated = "BackupFiles.zip";
// Create new zip class
$zip = new ZipArchive;
if($zip -> open($zipcreated, ZipArchive::CREATE ) === TRUE) {
// Store the path into the variable
$dir = opendir($pathdir);
while($file = readdir($dir)) {
if(is_file($pathdir.$file)) {
$zip -> addFile($pathdir.$file, $file);
}
}
$zip ->close();
}
How do I add the folders as well? It only zips the files of the current directory and not all the subfolders.

Unable to extract zip file which generated using php

I have written the PHP script to generate the zip file. it's working fine when I use rar software to extract it but not getting extract with rar software. I can't ask to users to install rar software to extract downloaded zip file.
I don't know where i am commiting mistakes.
Here i attached error screen shot which i get when try to open zip file.
// Here is code snippet
$obj->create_zip($files_to_zip, $dir . '/download.zip');
// Code for create_zip function
//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) {
$filearr = explode('/', $file);
$zip->addFile($file, end($filearr));
}
$zip->close();
If $valid_files is a glob'd array, use basename() instead of end(), your zip might not actually have added any files causing for it to be an invalid zip (however that would be visible in the size of the zip file).
Also try winrar/winzip/7zip and see what they return, microsoft's internal zip engine might not be up to date enough to open the zips.
I have also encountered this problem, using 7z solved the problem but we need to send the zip to somebody else so 7z is a nono.
I found that, in my case it is that the file path is too long:
When I use this:
$zip->addFile($files_path.'/people.txt');
And it generated a zip folder nested very deep e.g. ["/tmp/something/something1/something2/people.txt"]
So I need to use this instead
$zip->addFile($files_path.'/people.txt', 'people.txt');
Which generate a a zip folder with only 1 layer ["people.txt"], and Windows Zip read perfectly~
Hope this helps somebody that also have this problem!

PHP ZipArchive file iteration ignores directories

I'm using the ZipArchive class in PHP for the first time, and I'm having a bit of trouble. All I'm trying to do is iterate through the files in the ZIP archive, and it all works, except it doesn't seem there's any way to get subdirectory names inside the ZIP file, and I need that information. If there are files inside the subdirectoy, I suppose I could parse the directory names out of the file names, but if there are empty directories, they're completely lost.
For instance, if I have this directory tree in a ZIP:
root_folder
root_folder -> test_file.ext
root_folder -> empty_dir
Now I try to read that ZIP file's entries into memory like this in PHP:
<?php
$zip = new ZipArchive;
if ($zip->open('test.zip') == TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
echo $filename."<br />";
}
$zip->close();
}
?>
If I do this, then root_folder\test_file.ext is found correctly, but root_folder\empty_dir is just lost entirely.
So how do I use the ZipArchive class to find all the files and directories, including empty ones inside the archive?

Saving Archive Comment to ePub file

I am working on a PHP application which downloads an ePub file. As part of the code I am adding a unique identifier which can be used to trace the original download information in a database to combat piracy.
I am using PHP ZipArchive functions to add an archive comment to the file but it seems that Adobe Digital editions is unable to open the ePub file if there is a comment present. When the comment is removed it opens fine so I just want to see if anyone else has had this problem before and if there is a way to add a comment to the ePub file which will allow Adobe Digital Editions to open it. Below is the code I'm using:
public function secureEpub($file, $download_id, $filepath){
//GENERATE RANDOM FILE NAME
$newFile = uniqid().".epub";
//COPY EPUB AND WORK FROM THAT VERSION
copy($file, $filepath.$newFile);
//TREAT EPUB FILE AS ORDINARY ZIP ARCHIVE
//OPEN AND EXTRACT EPUB
$zip = new ZipArchive;
$res = $zip->open($filepath.$newFile);
if($res === TRUE){
//ZIP ARCHIVE HAS OPENED SUCCESSFULLY - SET ARCHIVE COMMENT TO DOWNLOAD ID
$zip->setArchiveComment($download_id);
$zip->close();
} else {
error_log('Unable to open ePub (' . $filepath.$newFile . ') as Directory');
return false;
exit;
}
//ONCE CHANGE HAS BEEN MADE CLOSE THE ARCHIVE AND RETURN TEMP FILE
return $filepath.$newFile;
}
As you can see it copies the original, creates an Archive comment then returns the file (which is later deleted). Is there a way of achieving this without corrupting the ePub (for ADE)?
Let me know if I've not made any sense :D
P.S: Just to clarify, the download works fine and the comment is applied correctly. It is just that ADE is unable to open it while other ePub readers manage fine. Am I going about it in the wrong way?
OK, I couldn't find a way around this so I kind of came up with a solution. You can add a new file or directory inside the ZIP file which had the details included.
So, you can use something like:
$zip->addFromString('test.txt', $download_id);
or create a directory named after the download like:
$zip->addEmptyDir($download_id);
Would probably recommend being a bit more obscure with naming though if you get stuck like I did :)
Thanks

zip files in PHP from another directory without a path structure

I'm trying to zip two files in another directory without zipping the folder hierarchy as well.
The event is triggered by a button press, which causes Javascript to send information using AJAX to PHP. PHP calls a Perl script (to take advantage of Perl's XLSX writer module and the fact that PHP kind of sucks, but I digress...), which puts the files a few folders down the hierarchy. The relevant code is shown below.
system("createFiles.pl -ids ${rows} -test ${test} -path ${path}",$retVal);
`zip ${path}/{$test}_both.zip ${path}/${test}.csv ${path}/${test}.xlsx`;
`zip ${path}/{$test}_csv.zip ${path}/${test}.csv`;
The problem is the zip file has ${path} hierarchy that has to be navigated before the files are shown as seen below:
I tried doing this (cd before each zip command):
system("createFiles.pl -ids ${rows} -test ${test} -path ${path}",$retVal);
`cd ${path}; zip {$test}_both.zip ${test}.csv ${test}.xlsx`;
`cd ${path}; zip {$test}_csv.zip ${test}.csv`;
And it worked, but it seems like a hack. Is there a better way?
The ZipArchive answer by Oldskool is good. I've used ZipArchive and it works. However, I recommend PclZip instead as it is more versatile (e.g. allows for zipping with no compression, ideal if you are zipping up images which are already compressed, much faster). PclZip supports the PCLZIP_OPT_REMOVE_ALL_PATH option to remove all file paths. e.g.
$zip = new PclZip("$path/{$test}_both.zip");
$files = array("$path/$test.csv", "$path/$test.xlsx");
// create the Zip archive, without paths or compression (images are already compressed)
$properties = $zip->create($files, PCLZIP_OPT_REMOVE_ALL_PATH);
if (!is_array($properties)) {
die($zip->errorInfo(true));
}
If you use PHP 5 >= 5.2.0 you can use the ZipArchive class. You can then use the full path as source filename and just the filename as target name. Like this:
$zip = new ZipArchive;
if($zip->open("{$test}_both.zip", ZIPARCHIVE::OVERWRITE) === true) {
// Add the files here with full path as source, short name as target
$zip->addFile("${path}/${test}.csv", "${test}.csv");
$zip->addFile("${path}/${test}.xlsx", "${test}.xlsx");
$zip->close();
} else {
die("Zip creation failed.");
}
// Same for the second archive
$zip2 = new ZipArchive;
if($zip2->open("{$test}_csv.zip", ZIPARCHIVE::OVERWRITE) === true) {
// Add the file here with full path as source, short name as target
$zip2->addFile("${path}/${test}.csv", "${test}.csv");
$zip2->close();
} else {
die("Zip creation failed.");
}

Categories