PHP ZipArchive::addGlob() does not work as expected - php

I have a bunch of large CSV files which need to zip for later exports. I thought it should be easy with ZipArchive class but it is not. My code looks like:
$zip = new ZipArchive();
$open = $zip->open("$zipDirName/reports.zip", ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($open !== TRUE) throw new \Exception("CampaignsDeviceDays::saveCsvDaysDataZip() error. \$zip->open() failed with error code $open");
$addGlob = $zip->addGlob("$tempDirName/*", GLOB_BRACE, ['add_path' => DIRECTORY_SEPARATOR, 'remove_all_path' => TRUE]);
This code successfuly creates zip file but it is empty.
I want to have all csv files on the top level in zip file. If I use
'add_path' => 'whatever/'
it works. But I want to have it on top level.
The second problem is that I want to owerwrite the files which are in archive but do not remove files which has been in archive before I run the script. I tried constants like
ZipArchive::CREATE | ZipArchive::OVERWRITE but it always rewrite all files in archive. But I dont want to generate all files always. I want previous files saved as they are.
How to achieve this simple solution in PHP? I

Related

ZipArchive - Problem with the generated archive file

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?

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!

add zip won't do anything

I am trying to zip some folders with this function:
public function generate_zip($directory,$name_of_the_folder){
$rootPath = realpath($directory);
$zip = new ZipArchive();
$zip->open('path/to/my/zip/compressed.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->addFile($rootPath,$name_of_the_folder);
$zip->close();
}
This does literally nothing. I have already checked the permissions and they seem to be correct.
When using ZipArchive, you cannot add an empty directory using ZipArchive::addFile(). You have to use ZipArchive::addEmptyDir() .
For your case, I think what you want is ZipArchive::addGlob()
According to the documentation, the function 'addFile' wants two filenames: the first is the path to the local file (which you want to add to the zip) and the second (optional) argument is how you want the file to appear inside the zip.
You have a variable '$name_of_the_folder'. Does that contain the right value?
Php.net documentation: http://php.net/manual/en/ziparchive.addfile.php

Zipping up a folder without extra folders in the zipped file

So, I understand it's pretty easy to zip a folder and its contents given that php.net and stackoverflow are full of sample codes. I am trying to zip up a folder as well. This is my code:
$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder/*") as $file) {
$zip->addFile($file);
}
$zip->close();
My script is running in a folder, say on Desktop, and I want to zip thisFolder and its contents. The above code WORKS. But, the problem is that when I unzip the myzip.zip created, I get a structure like
Volumes>Data>Users>username>Desktop>Archive>some>thisFolder
and then I find the contents inside the 8th folder (thisFolder) in this case. How can I change this code so that when I unzip myzip.zip,I would straightaway see the folder thisFolder with the contents inside it instead of having to navigate through folders 7 times before getting my content?
I tried to change the path and silly things like that. But, it doesn't work.
Thanks
If you want everything in the file to be a name relative to your starting folder, use chdir() to start from there:
chdir("/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder");
foreach (glob("*") as $file) {
$zip->addFile($file);
}
Actually, I don't think this will work when $file is a subdirectory -- addFile doesn't recurse automatically. There's a comment in the documentation that shows how to write a recursive zip function:
http://www.php.net/manual/en/ziparchive.addemptydir.php
bool ZipArchive::addFile ( string $filename [, string $localname ] )
filename
The path to the file to add.
localname
local name inside ZIP archive.
You can use the pathinfo function to each $file in your loop, in order to retrieve the filename without the path, and then, use it as second parameter to the addFile method.
pathinfo doc here
Here is an example that could solve your problem:
// Create your zip archive
$zip = new ZipArchive;
// open it in creation mode
$zip->open('myzip.zip', ZipArchive::CREATE);
// Loop on all your file
$mask = "/Volumes/Data/Users/username/Desktop/Archive/some/thisFolder";
$allAvailableFiles = glob($mask . "/*")
foreach ($allAvailableFiles as $file)
{
// Retrieve pathinfo
$info = pathinfo($file);
// Generate the internal directory
$internalDir = str_replace($mask, "", $info['dirname']);
// Add the file with internal directory
$zip->addFile($file, $internalDir . "/" . $info['basename']);
}
$zip->close();

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