I have just now discovered that my hosting server does not support the ZIP class for PHP.
However, it has the Zlib installed and supported .
Is there any library / function / hack / class / that will let me handle ZIP files on such a server ?
Basically I want to create zip files. I am afraid my users will be scared of the GZ extension and i would like to serve them ZIP extension (that they will open normally on win systems) ?
(please do not tell me to change hosting - I already know I have to , but it will take time and the thing is quite urgent..)
UPDATE I . thanks to #Mark Baker - i was able to extract a file with the pclzip class and this simple code
<?php
include('pclzip.lib.php');
$archive = new PclZip('wp.zip');
$location = $_SERVER['DOCUMENT_ROOT'];
if ($archive->extract(PCLZIP_OPT_PATH, $location ,
PCLZIP_OPT_REMOVE_PATH, 'install/release') == 0) {
die("Error : ".$archive->errorInfo(true));
}
?>
(I just wanted to post the code here , it was too lng for comment , and I did not wanted to post another answer )
Still did not tested the creation, but if it works the same - then I really want to kiss the developers of that class ! :-)
Zlib doesn't help you create zip files.
As an alternative to your missing ZipArchive, you might take a look at the PCLZip library. This is pure PHP, so no need for additional extensions, and allows you to create zip files without ZipArchive.
I believe that on windows the extension only tells it what application to use to open it.
So you could just save it as something winzip will open, and then just rename it...
Related
I am writing a php extension for a library. I have a generic swig file to build wrappers for the library. This has been very successful so far on Python.
A user is trying to build the library for php and I am trying to help out. I generated the code using swig, and I can build the .dll extension using Visual Studio. The problem is getting it into php. When I build php_mylib.dll, it needs to find mylib.dll and it can't.
So I am trying to build via the command line a la:
http://blog.benoitblanchon.fr/build-php-extension-on-windows/
I have put all the files to be compiled and the libraries needed (i.e. mylib64.lib and mylib64.dll) in a folder called mylib in the C:\php-src\ext folder with all the other extension folders.
The problem is I that I can't get the config.w32 file to communicate the location of mylib. Here is my config.w32 file (pretty standard -- you can see that I copied it from the curl config.w32 file):
// $Id$
// vim:ft=javascript
ARG_ENABLE("mylib", "mylib support", "no");
if (PHP_MYLIB != "no") {
if (CHECK_LIB("mylib64.lib", "mylib", PHP_MYLIB) &&
CHECK_HEADER_ADD_INCLUDE("mylib_cpp.h", "CFLAGS_MYLIB")
) {
EXTENSION("mylib", "mylib_c_wrap.cpp", true);
AC_DEFINE('HAVE_MYLIB', 1, 'Have mylib library');
// TODO: check for curl_version_info
} else {
WARNING("mylib not enabled; libraries and headers not found");
}
}
When I run buildconf and then configure --disable-all --enable-cli --enable-mylib it always shoots me the 'libraries and headers not found' warning from the script.
On Unix systems (config.m4) there appears to be a PHP_ADD_LIBRARY_WITH_PATH macro but I don't see any equivalent for windows. It seems like this is what I need.
I have also tried adding the full path to mylib into the system's path but to no avail. It seems like there might be an environment variable somewhere in the PHP build cosmos that needs to be set to find external dependencies, but I can't find any information about this.
It would also be good to do all this as a Visual Studio project -- easier for Windows users the world over. I have not seen anything on the web that looks like this.
By the way, I have successfully phpized this library using the same swig+phpize procedure on Linux (I followed this guide for the php part:http://www.sitepoint.com/install-php-extensions-source/) and it works beautifully.
In most cases you can use this info to build a PECL extension https://wiki.php.net/internals/windows/stepbystepbuild#building_pecl_extensions . Your config.w32 looks ok, though please note that that when depending on some additional library, usually it should be ARG_WITH(...) for semantics. Your lib stuff can be then put into the deps dir as in the wiki.
Another way could be passing --with-extra-libs and --with-extra-includes to configure. Those have to contain paths to *.lib and *.h dirs respectively. When using a static lib, that should be it, otherwise you'll need to place the corresponding *.dll onto the %path% for the ext to work.
Hope this helps, otherwise you can also gain some attention on the PHP mailing lists or specifically on #winphp-dev at freenode.
Thanks.
what i'm trying to do is to basically extract the contents of Zip archives on my server.Here is some code:
$entry="test.zip";
$zip = new ZipArchive;
if ($zip->open($entry,ZIPARCHIVE::OVERWRITE) === TRUE)
{
$zip->extractTo('unpacked');
$zip->close();
}else
{
echo ‘failed’;
}
the directory "unpacked" is writeable for everyone and all the used methods of the ZipArchive Class return true. However nothing is being extracted. Does anyone happen to have an idea what could cause this behaviour? Any hint will be highly appreciated...Thanks in advance!
If you are using PHP 5.2.0 or later can you check zlib extension first http://www.zlib.net/
You also check PECL extensions, In order to access ZipArchive, you can also try zip_open, zip_read just for checking.
If this code is in-house, and you can safely make the assumption that you won't move this code from Linux to Windows (or vice versa), you also have the option to execute local system commands, which may help solve your problem.
<?php
echo `unzip myarchive.zip`;
echo `tar -xzf myotherarchive.tar.gz`;
?>
When developing internal-use and/or maintenance scripts, I used to opt for straight-up system calls, as it was more in-line with the commands sysadmins were used to using.
In case of failure you should echo out $zip as it contains the error.
Furthermore I'd guess that you may not have the needed permissions for test.zip
If your zip archive is big, sometimes you cannot extract all files during the maximum allowed execution time of your server.
The only solution, if you cannot change the maximum_execution_time in your php.ini, is to use a javascript to extract one file after the other. On the first javascript request you take the number of files in the archive
$nbr_of_files = $zip->numFiles;
And after you extract one file after another using the id number in the zip archive for each file
$zip->extractTo('unpacked', array($zip->getNameIndex($file_nbr)));
Please try removing the ZIPARCHIVE::OVERWRITE flag from the ZipArchive open method. (The flag may not be functioning as expected and may be the root of the issue if you have followed the advice in the other answers.)
I had the same issue too. The solution:
$zip->extractTo(public_path() .'/restoreDb/extracted/');
add the public_path() helper function.
I have a PHP site with a lot of media files and users need to be able to download multiple files at a time as a .zip. I'm trying to use ZipStream to serve the zips on the fly with "store" compression so I don't actually have to create a zip on the server, since some of the files are huge and it's prohibitively slow to compress them all.
This works great and the resulting files can be opened by every zip program I've tried with no errors except for OS X's default unzipping program, Archive Utility. You double click the .zip file and Archive Utility decides it doesn't look a real zip and instead compresses into a .cpgz file.
Using unzip or ditto in the OS X terminal or StuffIt Expander unzips the file with no problem but I need the default program (Archive Utility) to work for the sake of our users.
What sort of things (flags, etc.) in otherwise acceptable zip files can trip Archive Utility into thinking a file isn't a valid zip?
I've read this question, which seems to describe a similar issue but I don't have any of the general purpose bitfield bits set so it's not the third bit issue and I'm pretty sure I have valid crc-32's because when I don't, WinRAR throws a fit.
I'm happy to post some code or a link to a "bad" zip file if it would help but I'm pretty much just using ZipStream, forcing it into "large file mode" and using "store" as the compression method.
Edit - I've tried the "deflate" compression algorithm as well and get the same results so I don't think it's the "store". It's also worth pointing out that I'm pulling down the files one a time from a storage server and sending them out as they arrive so a solution that requires all the files to be downloaded before sending anything isn't going to be viable (extreme example is 5GB+ of 20MB files. User can't wait for all 5GB to transfer to zipping server before their download starts or they'll think it's broken)
Here's a 140 byte, "store" compressed, test zip file that exhibits this behavior: http://teknocowboys.com/test.zip
The problem was in the "version needed to extract" field, which I found by doing a hex diff on a file created by ZipStream vs a file created by Info-zip and going through the differences, trying to resolve them.
ZipStream by default sets it to 0x0603. Info-zip sets it to 0x000A. Zip files with the former value don't seem to open in Archive Utility. Perhaps it doesn't support the features at that version?
Forcing the "version needed to extract" to 0x000A made the generated files open as well in Archive Utility as they do everywhere else.
Edit: Another cause of this issue is if the zip file was downloaded using Safari (user agent version >= 537) and you under-reported the file size when you sent out your Content-Length header.
The solution we employ is to detect Safari >= 537 server side and if that's what you're using, we determine the difference between the Content-Length size and the actual size (how you do this depends on your specific application) and after calling $zipStream->finish(), we echo chr(0) to reach the correct length. The resulting file is technically malformed and any comment you put in the zip won't be displayed, but all zip programs will be able to open it and extract the files.
IE requires the same hack if you're misreporting your Content-Length but instead of downloading a file that doesn't work, it just won't finish downloading and throws a "download interrupted".
use ob_clean(); and flush();
Example :
$file = __UPLOAD_PATH . $projectname . '/' . $fileName;
$zipname = "watherver.zip"
$zip = new ZipArchive();
$zip_full_path_name = __UPLOAD_PATH . $projectname . '/' . $zipname;
$zip->open($zip_full_path_name, ZIPARCHIVE::CREATE);
$zip->addFile($file); // Adding one file for testing
$zip->close();
if(file_exists($zip_full_path_name)){
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zipname.'"');
ob_clean();
flush();
readfile($zip_full_path_name);
unlink($zip_full_path_name);
}
I've had this exact issue but with a different cause.
In my case the php generated zip would open from the command line, but not via finder in OSX.
I had made the mistake of allowing some HTML content into the output buffer prior to creating the zip file and sending that back as the response.
<some html></....>
<?php
// Output a zip file...
The command line unzip program was evidently tolerant of this but the Mac unarchive function was not.
No idea. If the external ZipString class doesn't work, try another option. The PHP ZipArchive extension won't help you, since it doesn't support streaming but only ever writes to files.
But you could try the standard Info-zip utility. It can be invoked from within PHP like this:
#header("Content-Type: archive/zip");
passthru("zip -0 -q -r - *.*");
That would lead to an uncompressed zip file directly send back to the client.
If that doesn't help, then the MacOS zip frontend probably doesn't like uncompressed stuff. Remove the -0 flag then.
The InfoZip commandline tool I'm using, both on Windows and Linux, uses version 20 for the zip's "version needed to extract" field. This is needed on PHP as well, as the default compression is the Deflate algorithm. Thus the "version needed to extract" field should really be 0x0014. If you alter the "(6 << 8) +3" code in the referenced ZipStream class to just "20", you should get a valid Zip file across platforms.
The author is basically telling you that the zip file was created in OS/2 using the HPFS file system, and the Zip version needed predates InfoZip 1.0. Not many implementations know what to do about that one any longer ;)
For those using ZipStream in Symfony, here's your solution: https://stackoverflow.com/a/44706446/136151
use Symfony\Component\HttpFoundation\StreamedResponse;
use Aws\S3\S3Client;
use ZipStream;
//...
/**
* #Route("/zipstream", name="zipstream")
*/
public function zipStreamAction()
{
//test file on s3
$s3keys = array(
"ziptestfolder/file1.txt"
);
$s3Client = $this->get('app.amazon.s3'); //s3client service
$s3Client->registerStreamWrapper(); //required
$response = new StreamedResponse(function() use($s3keys, $s3Client)
{
// Define suitable options for ZipStream Archive.
$opt = array(
'comment' => 'test zip file.',
'content_type' => 'application/octet-stream'
);
//initialise zipstream with output zip filename and options.
$zip = new ZipStream\ZipStream('test.zip', $opt);
//loop keys useful for multiple files
foreach ($s3keys as $key) {
// Get the file name in S3 key so we can save it to the zip
//file using the same name.
$fileName = basename($key);
//concatenate s3path.
$bucket = 'bucketname';
$s3path = "s3://" . $bucket . "/" . $key;
//addFileFromStream
if ($streamRead = fopen($s3path, 'r')) {
$zip->addFileFromStream($fileName, $streamRead);
} else {
die('Could not open stream for reading');
}
}
$zip->finish();
});
return $response;
}
If your controller action response is not a StreamedResponse, you are likely going to get a corrupted zip containing html as I found out.
It's an old question but I leave what it worked for me just in case it helps someone else.
When setting the options you need set Zero header to true and enable zip 64 to false (this will limit the archive to archive to 4 Gb though):
$options->setZeroHeader(true);
$opt->setEnableZip64(false)
Everything else as described by Forer.
Solution found on https://github.com/maennchen/ZipStream-PHP/issues/71
i'm trying to create a zip script based on what I've found here but I seem to be getting a Fatal error: Class 'ZipArchive' not found error on the new ZipArchive(); function.
Researching this it seems that this is usually due to the way PHP is compiled. I have a shared hosting account, so i've not configured any of this stuff...and I assume that I can't make any changes to the build. Out of interest I took a look in my phpinfo() and I found some things that looked associated:
PHP Version 5.2.6
BZip2 Support Enabled <--maybe not so relevant
ZLib Support enabled
Stream Wrapper support compress.zlib://
Stream Filter support zlib.inflate, zlib.deflate
Compiled Version 1.1.4
Linked Version 1.1.4
I'm not entirly sure if any of this means that I have the ability to create zips.
For further info (although I don't think it's relivent) here's my script so far....this is untested mind you as I can't get pased this Class not found error.
$file = tempnam("tmp", "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);
//the string "file1" is the name we're assigning the file in the archive
$zip->addFile('show1.jpg', 'file1.jpg');
$zip->addFile('show2.jpg', 'file2.jpg');
$zip->addFile('show3.jpg', 'file3.jpg');
$zip->addFile('show4.jpg', 'file4.jpg');
$zip->addFile('show5.jpg', 'file5.jpg');
$zip->addFile('show6.jpg', 'file6.jpg');
// echo $zip->file(); //this sends the compressed archive to the output buffer instead of writing it to a file.
$zip->close();
header('Content-Type: application/zip');
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename="' . $file.'"');
readfile($file);
unlink($file);
So my question(s) really are:
Am I doing anything in my script to cause this error?
Does any of that stuff from my phpinfo() mean I should be able to create zip files, ..if not what should I be looking for in there that will let me know if i have the capability.
It looks like this ZLib is some soft of library, but I've got no idea if it does what I want it do, or even how to use it....this is a bit of a hunch, but if it can help me create zip files can anyone point me in the right direction of how to use it?
Thanks in advance.
Dan
ZipArchive is apparently not compiled into PHP by default. You need to either recompile it with the '--with-zip=' option or simply install it via PECL.
Here is the manual page explaining the different methods:
http://www.php.net/manual/en/zip.installation.php
While zlib is an important compression library, it sounds like you're missing the zip extension itself. It looks like you got your information from phpinfo -- look for the exact words "zip extension." If you can't find them, you don't have it installed, and thus can not use the functions and methods provided by it.
You could try dl("zip.so"); as last resort. But that extension is rarely built as external module. You might be able to find it downloadable somewhere, or even compile it by hand from the PHP sources or http://pecl.php.net/package/zip using pecl build
Otherwise you will have to look for an alternative. http://pear.php.net/package/Archive_Zip comes to mind.
If you have upgrade php version or zip extension is not there
So you have to install it .
1) Open terminal
2) sudo apt-get install php7.0-zip
3) sudo service apache2 restart
Is there any way to unpack or extract a zip file with PHP that does not rely on any installed extension? Has anyone written a class or something that can handle it?
Alternatively, is there a solution that uses an extension that is relatively commonly installed on most servers?
I need this to work on as many different servers that I have no control over as possible.
Thanks for any help!
Check this lib it helps to solve same problem
require_once('pclzip.lib.php');
$archive = new PclZip(dirname(__FILE__).'/Archive.zip');
if ($archive->extract(PCLZIP_OPT_PATH, dirname(__FILE__).'/extract') == 0) {
echo "\n error while extract";
} else {
echo "\n extract ok";
}
Well, it looks like most of them require php.ini settings, which you may be able to override in your script:
http://www.w3schools.com/php/php_ref_zip.asp
http://devzone.zend.com/article/2105
and here is how to edit the php.ini file without direct access:
http://www.whenpenguinsattack.com/2006/01/20/how-to-override-phpini/