Inspect file in zip archive without extracting - php

I wrote a short code, which opens up a Zip File and searches for a file called "index.html".
Now I want to open the file and perform several actions.
- Search for links.
- Search for clicktags.
Please keep in mind, that this is done while the user is uploading his file.
I dont want to extract is somewhere on the server.
Is there a good method to achieve this?
Regards
$zip = new ZipArchive();
$zip -> open($filepath);
//Assign filescount to variable
$this ->adFileCount = $zip -> numFiles;
//Scan all files and find index.html
if($zip ->getFromName("index.html") == true)
{
//specific action done with index.html
}

Read the contents of the file and do whatever you need to with it.
$zip -> open($filepath);
for($floop = 0; $floop < $zip->numFiles; $floop++ ) {
$stat = $zip->statIndex($floop);
if (stripos($stat['name'],'index.html') !== false) {
$indexcontents = $zip->getFromIndex($floop);
//
// do whatever you need to do with the array
// named indexcontents that contains index.html
//
}
} // end of for loop through the files in the zipped file uploaded
$zip->close();

Related

Reading filenames from a zip file inside another zip file

I am trying to get all filenames from the files inside a zip file. It all works perfectly until the zip file contains another zip file and I try to get the included file names from the included zip as well.
I want to get all included filenames without extracting the file.
For some reason it always refuses to open the included zip file, as if it does not recognie it as a zip file.
To make 100% sure it is a zip for testing I simply included the same zip inside the main zip.
While it properly reads the main zipfile it returns false if I want to read the included file.
I have been trying to get this script to work for 3 days now but I keep failing so I decided to see if someone here can help me out with this.
This is the script I am using to read a zipfile contents:
function firstzipper($file) {
global $filesroot, $pagefile;
$zipinc = new ZipArchive();
if ($zipinc->open($file) === TRUE) {
for ($i = 0; $i < $zipinc->numFiles; $i++) {
$filename_full = $zipinc->getNameIndex($i);
$filename = substr($filename_full, strrpos($filename_full, '/') + 1);
if (!is_dir($filename)) {
$filename = filter_var($filename, FILTER_SANITIZE_STRING);
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($ext == 'zip') {
secondzipper($filesroot.$pagefile.'/'.$filename_full);
}
}
array_push($inc_files_arr,$filename);
}
return $inc_files_arr;
}
}
firstzipper($filesroot.$url);
secondzipper inside the function above is simply the same function, copied and renamed.
The zipfile looks like this:
E:/myfolder/fileserver/temper.zip/myincluded.zip
The function opens temper.zip but returns false on myincluded.zip.
I hope I have included all info needed, if not let me know and I add what else is required.

On creating zip file by php I get two files instead of one

I'm struggling around with a simple PHP functionality: Creating a ZIP Archive with some files in.
The problem is, it does not create only one file called filename.zip but two files called filename.zip.a07600 and filename.zip.b07600. Pls. see the following screenshot:
The two files are perfect in size and I even can rename each of them to filename.zip and extract it without any problems.
Can anybody tell me what is going wrong???
function zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path = array(), $files_array = array()) {
// Archive File Name
$archive_file = $archiveDir."/".$archive_file_name;
// Time-to-live
$archiveTTL = 86400; // 1 day
// Delete old zip file
#unlink($archive_file);
// Create the object
$zip = new ZipArchive();
// Create the file and throw the error if unsuccessful
if ($zip->open($archive_file, ZIPARCHIVE::CREATE) !== TRUE) {
$response->res = "Cannot open '$archive_file'";
return $response;
}
// Add each file of $file_name array to archive
$i = 0;
foreach($files_array as $value){
$expl = explode("/", $value);
$file = $expl[(count($expl)-1)];
$path_file = $file_path[$i] . "/" . $file;
$size = round((filesize ($path_file) / 1024), 0);
if(file_exists($path_file)){
$zip->addFile($path_file, $file);
}
$i++;
}
$zip->close();
// Then send the headers to redirect to the ZIP file
header("HTTP/1.1 303 See Other"); // 303 is technically correct for this type of redirect
header("Location: $archive_file");
exit;
}
The code which calls the function is a file with a switch-case... it is called itself by an ajax-call:
case "zdl":
$files_array = array();
$file_path = array();
foreach ($dbh->query("select GUID, DIRECTORY, BASENAME, ELEMENTID from SMDMS where ELEMENTID = ".$osguid." and PROJECTID = ".$osproject.";") as $subrow) {
$archive_file_name = $subrow['ELEMENTID'].".zip";
$archiveDir = "../".$subrow['DIRECTORY'];
$files_array[] = $archiveDir.DIR_SEPARATOR.$subrow['BASENAME'];
$file_path[] = $archiveDir;
}
zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path, $files_array);
break;
One more code... I tried to rename the latest 123456.zip.a01234 file to 123456.zip and then unlink the old 123456.zip.a01234 (and all prior added .a01234 files) with this function:
function zip_file_exists($pathfile){
$arr = array();
$dir = dirname($pathfile);
$renamed = 0;
foreach(glob($pathfile.'.*') as $file) {
$path_parts = pathinfo($file);
$dirname = $path_parts['dirname'];
$basename = $path_parts['basename'];
$extension = $path_parts['extension'];
$filename = $path_parts['filename'];
if($renamed == 0){
$old_name = $file;
$new_name = str_replace(".".$extension, "", $file);
#copy($old_name, $new_name);
#unlink($old_name);
$renamed = 1;
//file_put_contents($dir."/test.txt", "old_name: ".$old_name." - new_name: ".$new_name." - dirname: ".$dirname." - basename: ".$basename." - extension: ".$extension." - filename: ".$filename." - test: ".$test);
}else{
#unlink($file);
}
}
}
In short: copy works, rename didn't work and "unlink"-doesn't work at all... I'm out of ideas now... :(
ONE MORE TRY: I placed the output of $zip->getStatusString() in a variable and wrote it to a log file... the log entry it produced is: Renaming temporary file failed: No such file or directory.
But as you can see in the graphic above the file 43051221.zip.a07200 is located in the directory where the zip-lib opens it temporarily.
Thank you in advance for your help!
So, after struggling around for days... It was so simple:
Actually I work ONLY on *nix Servers so in my scripts I created the folders dynamically with 0777 Perms. I didn't know that IIS doesn't accept this permissions format at all!
So I remoted to the server, right clicked on the folder Documents (the hierarchically most upper folder of all dynamically added files and folders) and gave full control to all users I found.
Now it works perfect!!! The only thing that would be interesting now is: is this dangerous of any reason???
Thanks for your good will answers...
My suspicion is that your script is hitting the PHP script timeout. PHP zip creates a temporary file to zip in to where the filename is yourfilename.zip.some_random_number. This file is renamed to yourfilename.zip when the zip file is closed. If the script times out it will probably just get left there.
Try reducing the number of files to zip, or increasing the script timeout with set_time_limit()
http://php.net/manual/en/function.set-time-limit.php

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.

How to achieve the following file structure when archiving a directory in PHP using ZipArchive();

I'm writing a PHP script that archives a selected directory and all its sub-folders. The code works fine, however, I'm running into a small problem with the structure of my archived file.
Imagine the script is located in var/app/current/example/two/ and that it wants to backup everything plus its sub directories starting at var/app/current
When I run the script it creates an archive with the following structure:
/var/app/current/index.html
/var/app/current/assets/test.css
/var/app/current/example/file.php
/var/app/current/example/two/script.php
Now I was wondering how:
a) How can I remove the /var/app/current/ folders so that the root directory of the archive starts beyond the folder current, creating the following structure:
index.html
assets/test.css
example/file.php
example/two/script.php
b) Why & how can I get rid of the "/" before the folder var?
//Create ZIP file
$zip = new ZipArchive();
$tmpzip = realpath(dirname(__FILE__))."/".substr(md5(TIME_NOW), 0, 10).random_str(54).".zip";
//If ZIP failed
if($zip->open($tmpzip,ZIPARCHIVE::CREATE)!== TRUE)
{
$status = "0";
}
else
{
//Fetch all files from directory
$basepath = getcwd(); // var/app/current/example/two
$basepath = str_replace("/example/two", "", $basepath); // var/app/current
$dir = new RecursiveDirectoryIterator($basepath);
//Loop through each file
foreach(new RecursiveIteratorIterator($dir) as $files => $file)
{
if(($file->getBasename() !== ".") && ($file->getBasename() !== ".."))
{
$zip->addFile(realpath($file), $file);
}
}
$zip->close();
You should try with:
$zip->addFile(realpath($file), str_replace("/var/app/current/","",$file));
I've never used the ZipArchive class before but with most archiver application it works if you change the directory and use relative path.
So you can try to use chdir to the folder you want to zip up.

extract only specific file types from zip with php

I'm creating a simple webapp my students can use to upload their projects (as a .zip file) to my server. This app takes the .zip > unzips it > displays a link to their web-project.
I'm using a php function like this, to extract the zip file:
function openZip($file_to_open) {
global $target;
$zip = new ZipArchive();
$x = $zip->open($file_to_open);
if($x === true) {
$zip->extractTo($target);
$zip->close();
unlink($file_to_open);
} else {
die("There was a problem. Please try again!");
}
}
is it possible to check the type of the files being extracted and only allow specific file types to get unzipped? Not that I don't trust my students... just want to make sure nothing malicious makes its way to my server.
my students will be uploading simple web projects, so I only want to allow .html, .css and .js (as well as image file types, and directories) to be extracted.
Check out ZipArchive::getFromName to pull just 1 file from the Zip by filename. You may also want to take a look at ZipArchive::getFromIndex
$zip = new ZipArchive;
if ($zip->open('test1.zip') === TRUE)
{
echo $zip->getFromName('testfromfile.php');
$zip->close();
}
else
{
echo 'failed';
}
You can always try finfo_file() like this:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, "yourfile.zip");
finfo_close($finfo);

Categories