How to zip and unzip zip files between linux host and windows - php

I have lot's of problem with ziping and unziping zip files between xammp windows server and linux host.
What's the way to zip files in xammp on windows and unzip it in linux host and vise versa?

PHP has built-in extension for zipping and unzipping:
<?php
$zip = new ZipArchive;
$res = $zip->open('file.zip');
if ($res === TRUE) {
$zip->extractTo('/myzips/extract_path/');
$zip->close();
echo 'woot!';
} else {
echo 'doh!';
}
?>

I would recommend Zippy it abstracts the platform and does a good job, BTW, it supports a couple of compression methods, please take a look at it.
Archive listing and extraction:
use Alchemy\Zippy\Zippy;
$zippy = Zippy::load();
$zippy->create('archive.zip', '/path/to/folder');
$archive = $zippy->open('build.tar');
// extract content to `/tmp`
$archive->extract('/tmp');
// iterates through members
foreach ($archive as $member) {
echo "archive contains $member \n";
}
Archive creation
use Alchemy\Zippy\Zippy;
$zippy = Zippy::load();
// creates an archive.zip that contains a directory "folder" that contains
// files contained in "/path/to/directory" recursively
$archive = $zippy->create('archive.zip', array(
'folder' => '/path/to/directory'
), recursive = true);

Related

Create a zip archive with a password

So, I creating a zip file with a password:
function createZip($fileName,$fileText,$zipFileName,$zipPassword)
{
shell_exec('zip -P '.$zipPassword.' '.$zipFileName.'.zip '.$fileName);
unlink($fileName);
return file_exists($zipFileName.'.zip');
}
$filex = "/backup/home/fyewhzjp/long_location_of_a_file/temp/data/map10/data.txt";
// $file_content = 'test';
$archive = "/backup/home/fyewhzjp/long_location_of_a_file/temp/data/map10/archive";
createZip($filex,$file_content,$archive,$pass);
And it works. I'm getting a archive.zip in my /temp/data/map folder on the website. But, when I open my archive I can see a bunch of folders, and data.txt at the end, let's say it will be
/backup/home/fyewhzjp/long_location_of_a_file/temp/data/map10/data.txt
So, I need to leave only data.txt in my folder, without other folders. How can I do it?
If anyone will face the same problem as I did, here is the solution:
Just add -jrq after zip in shell_exec like this:
shell_exec('zip -jrq -P '.$zipPassword.' '.$zipFileName.'.zip '.$fileName);
After that, full path will be ignored.
In addition to #Script47...
Pure PHP Available as of PHP 7.2.0 and PECL zip 1.14.0, respectively, if built against libzip ≥ 1.2.0.
<?php
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if ($res === TRUE) {
// Add files
$zip->addFromString('test.txt', 'file content goes here');
$zip->addFile('data.txt', 'entryname.txt');
// Set global (for each file) password
$zip->setPassword('your_password_here');
// This part will set that 'data.txt' will be encrypted with your password
$zip->setEncryptionName('data.txt', ZipArchive::EM_AES_128); // Have to encrypt each file in zip
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
?>
Rather than using shell_exec why don't you just use the ZipArchive class with the functions ZipArchiveOpen::open and ZipArchive::setPassword, it seems that that would make things a lot easier.
<?php
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
if ($res === TRUE) {
$zip->addFromString('test.txt', 'file content goes here');
$zip->addFile('data.txt', 'entryname.txt');
$zip->setPassword('your_password_here');
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
?>
Note:
This function only sets the password to be used to decompress the archive; it does not turn a non-password-protected ZipArchive into a password-protected ZipArchive.

How to add a file from web to a zip file on my server using php?

Imagine there is a picture at http://example.com/icon.jpg and I want to add it to a zip file on my own sever named "Stack.zip" using php. This is my code, but it doesn't work.
$url="http://example.com/icon.jpg"
$zip = new ZipArchive;
echo $zip->open("Stack.zip");
$zip->addFile($url);
$zip->close();
P.S. I was able to do it with local files, but I had no success on doing it with internet addresses. So that's why I asked this question.
From the PHP manual: http://php.net/manual/en/ziparchive.addfile.php
(PHP 5 >= 5.2.0, PHP 7, PECL zip >= 1.1.0)
This assumes you want to add to an existing zip file on your server.
$url = 'https://www.stackoverflowbusiness.com/hubfs/logo-so-color.png?t=1499443352566';
$local_path = '/your/local/folder/';
$img = 'icon.jpg';
file_put_contents($local_path.$img, file_get_contents($url));
$zip = new ZipArchive;
if ($zip->open($local_path.'Stack.zip') === TRUE) {
$zip->addFile($local_path.$img, $img);
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
If you want to keep the same folder structure as the original source file, change this line ..
$zip->addFile($local_path.$img, $img);
...to this...
$zip->addFile($local_path.$img);
If you want the same script to create the zip, you can find a PHP function here: Add files to the zip

Archive a .wdgt folder in ZipArchive()

I'm creating a online widget creation tool in PHP, and I am able to export everything I need via .zip , just the problem is that users have to extract the zip and then add the .wdgt extension on the folder for it to work in iBooks. Is there any way I could make this part of the process easier, e.g - just unzip and the .wdgt folder is there, or even better, download as .wdgt.
Here is the code I have to create a ZIP file:
//zip name
$archiveName = 'widget.zip';
$fileNames = array();
//scan through directories, and add to array
foreach(scandir($workingDir) as $content){
$fileNames[] = $workingDir.$content;
}
foreach(scandir($resources) as $content){
$fileNames[] = $resources.$content;
}
archiveFiles($fileNames, $archiveName);
function archiveFiles($fileNames, $archiveName){
//init new ZipArchive()
$zip = new ZipArchive();
//open archive
$zip->open($archiveName);
if($zip->open($archiveName, ZIPARCHIVE::OVERWRITE ) !==TRUE){
exit("Cannot open <$archiveName>\n");
}
else{
//archive create, now add files
foreach($fileNames as $files){
if('.' === $files || '..' === $files) continue;
//get just the filename and extension
$fileName = explode("/", $files);
$num = (count($fileName) - 1);
$theFilename = $fileName[$num];
//add file into the archive - full path of file, new filename
$zip->addFile($files,$theFilename);
}
$zip->close();
header( 'Location: http://MYURL/'.$archiveName ) ; //Redirects to the zip archive
exit;
}
}
This works fine. I just need to be able to either just download a .wdgt folder with the content I need in it, or be able to ZIP up a .wdgt folder that has the content that I need.
I have tried changing $archiveName to $archiveName = "widget.wdgt.zip"; and $archiveName = "widget.wdgt";
The $archiveName = "widget.wdgt.zip"; was able to unzip fine on Windows. Although on the MAC is just gave an error. And It has to work on the MAC as it is in iBook's Author these widgets will work on
Managed to get a .wdgt folder downloaded within a zip file, all that I needed to do was when adding the file in the loop was this:
$zip->addFile($files, 'MYWIDGET.wdgt/'.$theFilename);
by adding the 'MYWIDGET.wdgt/'.$theFilename path into the addFile() it forced ZipArchive to create a MYWIDGET.wdgt folder and adding the files into it.

PHPs ZipArchive drops empty directories

Problem
I am building an online file manager, for downloading a whole directory structure I am generating a zip file of all subdirectories and files (recursively), therefore I use the RecursiveDirectoryIterator.
It all works well, but empty directories are not in the generated zip file, although the dir is handled correctly. This is what i am currently using:
<?php
$dirlist = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$filelist = new RecursiveIteratorIterator($dirlist, RecursiveIteratorIterator::SELF_FIRST);
$zip = new ZipArchive();
if ($zip->open($tmpName, ZipArchive::CREATE) !== TRUE) {
die();
}
foreach ($filelist as $key=>$value) {
$result = false;
if (is_dir($key)) {
$result = $zip->addEmptyDir($key);
//this message is correctly generated!
DeWorx_Logger::debug('added dir '.$key .'('.$this->clearRelativePath($key).')');
}
else {
$result = $zip->addFile($key, $key);
}
}
$zip->close();
If I ommit the FilesystemIterator::SKIP_DOTS I end up having a . file in all directories.
Conclusion
The iterator works, the addEmptyDir call gets executed (the result is checked too!) correctly, creating a zip file with various zip tools works with empty directories as intendet.
Is this a bug in phps ZipArchive (php.net lib or am I missing something? I don't want to end up creating dummy files just to keep the directory structure intact.

Best way to read zip file in PHP

file_get_contents("zip:///a/b/c.zip") is returning NULL. How can I read unzipped contents of a zip file in PHP 5+?
use ZipArchive class
$zip = new ZipArchive;
$zip->open('test.zip');
echo $zip->getFromName('filename.txt');
$zip->close();
Use zip_open and zip_read functions to do it.
Documentation to it you can find at http://php.net/manual/en/function.zip-read.php
<?php
/**
* This method unzips a directory within a zip-archive
*
* #author Florian 'x!sign.dll' Wolf
* #license LGPL v2 or later
* #link http://www.xsigndll.de
* #link http://www.clansuite.com
*/
function extractZip( $zipFile = '', $dirFromZip = '' )
{
define(DIRECTORY_SEPARATOR, '/');
$zipDir = getcwd() . DIRECTORY_SEPARATOR;
$zip = zip_open($zipDir.$zipFile);
if ($zip)
{
while ($zip_entry = zip_read($zip))
{
$completePath = $zipDir . dirname(zip_entry_name($zip_entry));
$completeName = $zipDir . zip_entry_name($zip_entry);
// Walk through path to create non existing directories
// This won't apply to empty directories ! They are created further below
if(!file_exists($completePath) && preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
$tmp = '';
foreach(explode('/',$completePath) AS $k)
{
$tmp .= $k.'/';
if(!file_exists($tmp) )
{
#mkdir($tmp, 0777);
}
}
}
if (zip_entry_open($zip, $zip_entry, "r"))
{
if( preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
if ($fd = #fopen($completeName, 'w+'))
{
fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
fclose($fd);
}
else
{
// We think this was an empty directory
mkdir($completeName, 0777);
}
zip_entry_close($zip_entry);
}
}
}
zip_close($zip);
}
return true;
}
// The call to exctract a path within the zip file
extractZip( 'clansuite.zip', 'core/filters' );
?>
look at the build in zip functions:
http://php.net/manual/en/book.zip.php
The zip:// protocol is provided by the ZIP extension of PHP. Check in your phpinfo() output whether the extension has been installed or not.
I am responding to the first part of the question i.e. using the file_get_contents method
'file_get_contents("zip:///a/b/c.zip")' Usually that method is used to read one particular file nested inside the zip file. In order to extract all the contents; others have given nice answers.
I am using PHP 7.2.34 on windows and later on in Linux. I kept a zip file at d:\data and this syntax works in windows. It does echo the contents of example1.py which is inside a "folder" in the ZIP file.
Possibly it is also to do with where/how the zip file was created. When I had created the zip file from within PHP, the internal delimiters were backslashes but when Windows created the zip file (by using the "Send to compressed folder" feature in Windows explorer) then Windows was using the Linux convention inside the zip file!
More testing is needed here to know which delimiter for the internal paths, is being used in the zip file
<?php
$str = file_get_contents('zip://d:/data/demo.zip#examples\\example1.py');
echo $str;
?>

Categories