Creating a Password Protected Zip File using PHP in Windows - php

I am creating a zip file of a given file in PHP. Following is the function
function create_zip($file, $file_name)
{
$zip = new ZipArchive();
$zip_name = $file_name. ".zip"; // Zip name
$zip->open($zip_name, ZipArchive::CREATE);
if (file_exists($file)) {
$zip->addFromString(basename($file), file_get_contents($file));
} else {
return "file does not exist";
}
$zip->close();
return $zip_name;
}
I want to add password protection for the Zip files. I have found following code to create a password protected zip file
system('zip -P password file.zip file.txt');
But it is not working properly. Can you please Guide me How can I add the Password protection on the Zip file?

PHP Zip - http://php.net/manual/en/book.zip.php - doesn't support password protected zip files, you will need do it via command line.
To password protect a file, you need to use zip command line, make sure that the zip command line program is present, it is not installed by default on many systems.

In new PHP 5.6 (currently in beta) you can use your ZipArchive to create password protected archives. All you need is to add this code ZipArchive::setPassword($password)
Edit: Apparently it only supports decryption, not encryption yet.

I realize this is an old thread, but anyone struggling with adding a password to an archive in windows environment, I solved this using winrar command line and exec in PHP.
Download winrar from http://www.rarlab.com/ and include the WinRAR.exe in your PHP script directory, or call it from the right directory in your exec command.
exec("winrar a -p[password] [archive name] [file or folders to include]");
winrar in the above example refers to winrar.exe in the same directory as your script. If winrar.exe is NOT in the same directory as your script, you can simply include the path:
exec("C:\Program Files\Winrar...
So, for example:
exec("winrar a -ppassword archive.zip file.txt");
Will result in an archive named "archive.zip" being created with "file.txt" inside, and a password of "password".
For more information on winrar command line: http://acritum.com/software/manuals/winrar/

Related

PHP8 ZipArchive EM constant TRAD_PKWARE not working

i used ZipArchive::EM_TRAD_PKWARE, with password, but zip file is not encrypted. I think that pkware not working. Have solutions ?
Thx
$zip->setEncryptionName('test.txt', ZipArchive::EM_TRAD_PKWARE, 'PASSWORD');
I got it working by the following example and rules:
Two rules to make it work
I got inconsistent results when not following these 2 rules:
Make sure the file to be encrypted contains data
Make sure addFile is called before setEncryptionName
Working example
test.txt
Create the following test.txt file with the following content:
test
test.php
Add the following PHP code to test.php:
$zip = new ZipArchive();
$zip->open("test.zip", ZipArchive::CREATE);
$zip->addFile("test.txt");
$zip->setEncryptionName('test.txt', ZipArchive::EM_TRAD_PKWARE, 'PASSWORD');
$zip->close();
Run test.php
php test.php
A zip file is now created which prompts for a password on unzip.

Unzipped files change owner, php

I have a zip file into a directory like this:
drwxr-xr-x 2 salome salome 4096 Dec 16 17:41 staff.zip
When I unzip the file with ZipArchive class, all the upzipped files are owner by nobody user. Is there a way to avoid this owner change?
I am able to use ftp if it is required (only as salome user).
This script eventually will be shared at multiple hosts, so the idea is keep it as generic as possible.
You might consider extending the zipArchive class and override the extractTo method to also perform a chown() on the files in the directory.
Based on the use case you discussed in the comments, you also might want to consider the use of the Phar archive format. php.net/manual/en/intro.phar.php
Phar's would allow your module submitters to submit a file file of executable PHP code that you would not need to extract at all.
Ok, I have resolved the problem of nobody user. I will try to explain all my workaround.
#Mike Brant's answer
Mike suggest to me make use of chown() function overriding extractTo() method. Well, before to willing with it, I tested the chown() function standalone constantly it printed the error:
failed to create stream: Permission denied in ...
Looks like chown will not work for the major shared hostings
FTP functions
So, keeping going I though that FTP functions I made a script that works fine, at least for now xD. This is a resume what the script does for one zipped file:
Create a temp file using tmpfile().
Using ftp_fput() to put the temp file in the current directory with the zipped file.
Give write permissions using ftp_site and CHMOD 0777.
Read the zipped file content with $content = $zip->getFromName('zipped-file.txt');.
Put the content to the new file using fputs($fp, $content);.
Close connections
The code below illustrates the complete process
$zip = new ZipArchive;
$ftp_path_to_unzip = '/public_html/ejemplos/php/ftp/upload/';
$local_path_to_unzip = '/home/user/public_html/ejemplos/php/ftp/upload/';
if ($zip->open('test.zip') == TRUE) {
//connect to the ftp server
$conn_id = ftp_connect('ftp.example.com');
$login_result = ftp_login($conn_id, 'user', 'password');
//if the connection is ok, then...
if ($login_result) {
//iterate each zipped file
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
//create a "local" temp file in order to put it "remotely" in the same machine
$temp = tmpfile();
//create the new file with the same name from the extracted file in question
ftp_fput($conn_id, $ftp_path_to_unzip . $filename, $temp, FTP_ASCII);
//set write permissions, eventually we will put its content
ftp_site($conn_id, "CHMOD 0777 " . $ftp_path_to_unzip . $filename);
//open the new file that we have created
$fp = fopen($local_path_to_unzip . $filename, 'w');
//put the content from zipped file
$content = $zip->getFromName($filename);
fputs($fp, $content);
//close the file
fclose($fp);
//now only the owner can write the file
ftp_site($conn_id, "CHMOD 0644 " . $ftp_path_to_unzip . $filename);
}
}
// close the connection and the file handler
ftp_close($conn_id);
//close the zip file
$zip->close();
}
This is the firt step to start a more complex customization, because the code above is not able to know if the zipped file is a "directory" or "file".

How to execute .sh files one after another with php

I need to run a series of six .sh files on the server.
An example of one of the .sh files:
wget ftp://xxxxxx:xxxxxx#ftp.interhome.com/accommodation.xml.zip
unzip accommodation.xml.zip
php accommodation.php
rm -rf accommodation.xml.zip
rm -rf accommodation.xml
I tried running the following from a php file:
echo shell_exec('sh accomodation.sh');
Which was stupid because the file appears to execute repeatedly and I think I've just taken down the server. Whoops.
I've inherited this site and have never used .sh files before. I'm also a php novice.
How would I go about running the files only once and then running the next?
Many thanks
you can do all this from within PHP, you do not need any shell-script.
/* get the file via ftp */
// connect to server
$ftp = ftp_connect('ftp.interhome.com');
// login
$login = ftp_login($ftp,"username","password");
// download file to tmp.zip
$file = ftp_get($ftp, 'tmp.zip', 'accommodation.xml.zip', FTP_BINARY);
// disconnect from server
ftp_close($ftp);
/* unzip the file */
// new zip-instance
$zip = new ZipArchive;
// open downloaded file
$res = $zip->open(’tmp.zip’);
// check if file is readable
if ($res === TRUE) {
// extract to current directory
$zip->extractTo(’./’);
// close zip-file
$zip->close();
}
/* your code from accommodation.php goes here */
// delete files
unlink('tmp.zip');
unlink('accommodation.xml');
voila

Dynamically created zip files by ZipStream in PHP won't open in OSX

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

PHP ZipArchive what do status values mean?

I am right at the start of trying to write some PHP code to run on a Linux box on an EC2 server that will read files from my S3 bucket, zip them then write the zip file back to the bucket.
I have instantly run in to problems with even creating a simple zip archive from some images on the local disk of the EC2 instance, I am using a script to test out the idea from the PHP manual online and also have tried out a script from David Walsh - http://davidwalsh.name/create-zip-php which looks like it will be great. Neither result in an actual zip file and both give me different status results -
the first snippet from the php manual (to which i add the variable $thisdir)-
<?php
$zip = new ZipArchive();
$filename = "test112.zip";
$thisdir = "/uploads/";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}
$zip->addFromString("testfilephp.txt" . time(), "#1 This is a test string added as testfilephp.txt.\n");
$zip->addFromString("testfilephp2.txt" . time(), "#2 This is a test string added as testfilephp2.txt.\n");
$zip->addFile($thisdir . "/too.php","/testfromfile.php");
echo "numfiles: " . $zip->numFiles . "\n";
echo "status:" . $zip->status . "\n";
$zip->close();
?>
output =
numfiles: 2 status:11
I dont see any zip file in my 'uploads' folder
The second bit of code i try ( i wont post the code here) - I pass real files and it returns
The zip archive contains 2 files with a status of 0
What are the status messages. I have checked to see if I have the correct libraries installed by looking at the output of phpinfo(); and under the ZIP heading I see -
Zip enabledExtension Version $Id: php_zip.c,v 1.1.2.43 2008/01/18 00:51:38 pajoye Exp $
Zip version 1.8.11
Libzip version 0.8.0-compatible
I have checked the permissions of the files PHP files with the code I am executing and they are set to 777 as is the folder I am trying to add the ziparchive to. I know that this should not remain at 777.
any ideas why I cannot see a zip file? what do the status values mean? Is there a good tutorial out there for using PHP to zip files on an Amazon S3 bucket? or a good utility to provide this functionality?
cheers
You can find it here:
http://www.php.net/manual/en/zip.constants.php
Error 11 is "Can't open file"
In my case i got error code 11 while opening a zip file for reading. The path and permissions are OK. I just changed the DIRECTORY SEPARATOR from back slash (\) to forward slash (/) and it worked. The strange thing is that forward slash (/) paths are in Linux where as I am working in windows server 2003.

Categories