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
Related
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!
Here's a very stripped down version of the code I'm using.
$url = "http://server.com/getDaFile";
//Get the file from the server
$zip_file_contents = file_get_contents($url);
//Write file to disk
file_put_contents("file.zip", $zip_file_contents);
//open zip file
$zip = zip_open("file.zip");
if(is_resource($zip))
{
while($zip_entry = zip_read($zip))
{
if(zip_entry_open($zip, $zip_entry, 'r'))
{
//Read the whole file
$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
/*
Do stuff with $buf!!!
*/
zip_entry_close($zip_entry);
}
}
zip_close($zip);
}
else
{
echo "Not a resource. Oh noes!\n";
}
So : get the file, save it to disk, unzip it to extract files it contains, do stuff with files. The problem here is that, for some reason I cannot figure out, zip_read returns FALSE, as if it couldn't read files inside the ZIP archive. $zip does contain a resource, I've checked with var_dump.
What makes this even stranger is that I downloaded the ZIP file on my PC using the URL on top, manually uploaded it to the PHP server, and commented out the calls to file_get_contents and file_put_contents so PHP uses the local version. When I do this, zip_read correctly finds the right amount of files inside the ZIP and processing proceeds as it should.
I also tried doing this : $zip = zip_open($url) but $zip fails the is_resource($zip) check.
Something is obviously wrong with my code since the URL works and returns a valid ZIP archive. What is it?
So I finally found out the problem. Following #diolemo's suggestion, I opened my server's ZIP archive in a hex editor. Here's what I found at the top, followed by the usual ZIP binary data : http://pastebin.com/vQEXJtTN
It turns out there was a PHP error mixed in with the actual content of the ZIP file. Unsure of how to fix this (but knowing it certainly had to do with HTTP headers), I tried this guy's code and, what do you know, my code works perfectly now!
Lessons learned? Never trust your data, even if it seems all right (both 7-Zip and Winrar managed to open the file without problem).
I have gone through the various post regarding zip and to read zip that is extracting zip downloading it and then access it. But i want to check the format and name convention for the files enclosed in Zip file that is going to be uploaded. I am using drag drop feature here and planning that when user drop the zip file it should extract the file but don't store it any where and check that all the image uploaded in the zip are of same format and name convention are followed like img1.jpg, img2.jpg.
Any help is deeply appreciated. I am using codeignitor framework and is it possible to extract and manipulate zip using backbone or java script.
I don't think you can check the contents of the zip before uploading.. Here's a code , you can very well use to check if the content inside is legit. [In this example... Assuming img1.zip contains an image file img1.jpg]
Maybe a start
<?php
$zip = new ZipArchive;
$res = $zip->open('img1.zip');
if ($res) {
$legitImage=explode('.',$zip->statIndex(0)['name']);
if($legitImage[1]=='jpg')
{
echo "It's an image";
//do your operations
$zip->close();
}
else
{
unlink('img1.zip');//Delete the zip file since it does not contain image
}
}
?>
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.");
}
I am currently building a backend to a site using the codeigniter framework, I have hit a bit of a problem, I needing a way to allow the user to upload a zipped folder of images, on completing the form, zipped folder must be unzipped, and the files need to be moved to a folder else where on the server, have thumbnail version of each image created and have there file name add to the DB, and also if the images are for a content type that does not already exist then I need to make a directory with that content type.
I know there is an upload class in Codeigniter, but I am not sure that, that has the capabilities do what I need, I could really do with some advice please?
Thanks
As Jan pointed out, this is a broad question (like 3 or 4 questions). I'm not up to date with the CodeIgniter framework but to Unzip the files you can do something like this:
function Unzip($source, $destination)
{
if (extension_loaded('zip') === true)
{
if (file_exists($source) === true)
{
$zip = new ZipArchive();
if ($zip->open($source) === true)
{
$zip->extractTo($destination);
}
return $zip->close();
}
}
return false;
}
Unzip('/path/to/uploaded.zip', '/path/to/extract/');
You wont be able to do any of the image or file checking using the Upload class. The upload class will let you accept the file and check it is a ZIP but that's as far as it will go.
From there, unzip the file and just do some simple PHP on the files to check they are the right type and make your folders etc. I would put this logic in a new library to keep it separated correctly.