I have this code which downloads several images from private sites. I want all these images to be placed in a zip file.
how do I do this?
<?php
$num = $_POST['num'];
for ($i=1; $i <= $num ; $i++) {
$url_to_image = $_POST['img'].$i.'.jpg';
$my_save_dir = "manga/" ;
$filename = basename($url_to_image);
$complete_save_loc = $my_save_dir . $filename;
file_put_contents($complete_save_loc,
file_get_contents($url_to_image));
echo $i ."jpg". " /download" . '<br>';
}
?>
You can use the php-ZipArchive class. http://php.net/manual/de/zip.examples.php
If you dont have compiled your php-interpreter with the option --enable-zip you can use otherwise the php shell execution functions (exec, shell_exec, passthru) to use the host-systems zip.
you can try ZipArchive like below
$zip = new ZipArchive();
$my_save_dir = "manga/files.zip";
$zip->open($my_save_dir, ZipArchive::CREATE);
$num = $_POST['num'];
for ($i=1; $i <= $num ; $i++) {
$url_to_image = $_POST['img'].$i.'.jpg';
$download_file = file_get_contents($url_to_image);
$zip->addFromString(basename($url_to_image), $download_file);
}
$zip->close();
echo $my_save_dir;
Related
The following code unzips my uploaded file and extracts everything in a directory called PDF. It then proceeds to iterate through the files and return files to download.
My problem is I need to check the file extension. I would only like to return the PDF file back to the user but some of the uploaded files have unnecessary images.
How can I check the contents of the file to ensure the unzipped file is a PDF & only the PDF is returned back to the user?
<?php
$zip = new ZipArchive;
$res = $zip->open('/download/xxxx.zip');
if ($res === TRUE) {
$zip->extractTo('/download/pdf/');
for($i = 0; $i < $zip->numFiles; $i++)
{
echo 'download';
}
$zip->close();
} else {
echo 'Something went wrong :( ';
}
?>
Thank you
Dexas solution worked for me. Here's the code if you need it
I've added in comments to show what I've changed.
<?php
$zip = new ZipArchive;
$res = $zip->open('/download/xxxxx.zip');
if ($res === TRUE) {
$zip->extractTo('/download/pdf/');
for($i = 0; $i < $zip->numFiles; $i++)
{
//Load files into variable which can be used with the following... ['dirname'], ['basename'], ['extension'], ['filename']
$path_parts = pathinfo('/download/pdf/' . $zip->getNameIndex($i));
//If the extension is equal to PDF echo the code out
if($path_parts['extension'] === 'pdf')
{
echo 'download';
}
}
$zip->close();
} else {
echo 'Something went wrong :( ';
}
?>
You can check it's MIME type using finfo
$finfo = new finfo(FILEINFO_MIME);
$type = $finfo->file('/path/to/file');
if($type === 'application/pdf')
{
//do your stuff
}
For the extension part you can use pathinfo
$ext = pathinfo('/path/to/file', PATHINFO_EXTENSION);
In the end you should check both and decide is it PDF or not.
I got this working but when i look into the zip folder all the files size is 0. I tryed not adding the files to the zip and that worked, but when i try to add them to a zip the size goes to 0. Why is this.
here is my php
if(isset($_FILES['file'])){
$file_folder = "uploads/";
$zip = new ZipArchive();
$zip_name = time().".zip";
$open = $zip->open("zip/".$zip_name, ZipArchive::CREATE);
if($open === true){
for($i = 0; $i < count($_FILES['file']['name']); $i++)
{
$filename = $_FILES['file']['name'][$i];
$tmpname = $_FILES['file']['tmp_name'][$i];
move_uploaded_file($tmpname, "uploads/".$filename);
$zip->addFile($file_folder, $filename);
}
$zip->close();
if(file_exists("zip/".$zip_name)){
// zip is in there, delete the temp files
echo "Works";
for($i = 0; $i < count($_FILES['file']['name']); $i++)
{
$filenameu = $_FILES['file']['name'][$i];
unlink("uploads/".$filenameu);
}
} else {
// zip not created, give error
echo "something went wrong, try again";
}
}
}
Your problem lies with this line: $zip->addFile($file_folder, $filename);
Currently that passes a path to the /uploads/ directory as the first argument.
According to Zip::addFile documentation you should be passing the path to the file to add (this includes the file and extension).
So change your code to include the file name (you already have it as a variable $filename which is handy).
$zip->addFile($file_folder.$filename, $filename);
I'm in need of unziping uploaded content. But for security purposes must verify the files are only image files so that somebody can't add a php into the zip and then run it later.
While doing the unzip I need to preseverve the file structure as well.
$zip->extractTo($save_path . $file_name, array('*.jpg','*.jpeg','*.png','*.gif') );
doesn't return null. Is there a parameter I can use for this or must I iterate with a loop through the zip file using regex to match extensions and create the folders and save the files with code??
Thanks
from php.net, handling .txt files
<?php
$value="test.zip";
$filename="zip_files/$value";
$zip = new ZipArchive;
if ($zip->open($filename) === true) {
echo "Generating TEXT file.";
for($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if(preg_match('#\.(txt)$#i', $entry))
{
////This copy function will move the entry to the root of "txt_files" without creating any sub-folders unlike "ZIP->EXTRACTO" function.
copy('zip://'.dirname(__FILE__).'/zip_files/'.$value.'#'.$entry, 'txt_files/'.$value.'.txt');
}
}
$zip->close();
}
else{
echo "ZIP archive failed";
}
?>
for anyone who would need this in the future here is my solution. Thanks Ciro for the post, I only had to extend yours a bit. To make sure all folders are created I loop first for the folders and then do the extarction.
$ZipFileName = dirname(__FILE__)."/test.zip";
$home_folder = dirname(__FILE__)."/unziped";
mkdir($home_folder);
$zip = new ZipArchive;
if ($zip->open($ZipFileName ) === true)
{
//make all the folders
for($i = 0; $i < $zip->numFiles; $i++)
{
$OnlyFileName = $zip->getNameIndex($i);
$FullFileName = $zip->statIndex($i);
if ($FullFileName['name'][strlen($FullFileName['name'])-1] =="/")
{
#mkdir($home_folder."/".$FullFileName['name'],0700,true);
}
}
//unzip into the folders
for($i = 0; $i < $zip->numFiles; $i++)
{
$OnlyFileName = $zip->getNameIndex($i);
$FullFileName = $zip->statIndex($i);
if (!($FullFileName['name'][strlen($FullFileName['name'])-1] =="/"))
{
if (preg_match('#\.(jpg|jpeg|gif|png)$#i', $OnlyFileName))
{
copy('zip://'. $ZipFileName .'#'. $OnlyFileName , $home_folder."/".$FullFileName['name'] );
}
}
}
$zip->close();
} else
{
echo "Error: Can't open zip file";
}
I have a zip file uploaded to server for automated extract.
the zip file construction is like this:
/zip_file.zip/folder1/image1.jpg
/zip_file.zip/folder1/image2.jpg
/zip_file.zip/folder1/image3.jpg
Currently I have this function to extract all files that have extension of jpg:
$zip = new ZipArchive();
if( $zip->open($file_path) ){
$files = array();
for( $i = 0; $i < $zip->numFiles; $i++){
$entry = $zip->statIndex($i);
// is it an image?
if( $entry['size'] > 0 && preg_match('#\.(jpg)$#i', $entry['name'] ) ){
$f_extract = $zip->getNameIndex($i);
$files[] = $f_extract;
}
}
if ($zip->extractTo($dir_name, $files) === TRUE) {
} else {
return FALSE;
}
$zip->close();
}
But by using the function extractTo, it will extract to myFolder as ff:
/myFolder/folder1/image1.jpg
/myFolder/folder1/image2.jpg
/myFolder/folder1/image3.jpg
Is there any way to extract the files in folder1 to the root of myFolder?
Ideal:
/myFolder/image1.jpg
/myFolder/image2.jpg
/myFolder/image3.jpg
PS: incase of conflict file name I only need to not extract or overwrite the file.
Use this little code snippet instead. It removes the folder structure in front of the filename for each file so that the whole content of the archive is basically extracted to one folder.
<?php
$path = "zip_file.zip";
$zip = new ZipArchive();
if ($zip->open($path) === true) {
for($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = pathinfo($filename);
copy("zip://".$path."#".$filename, "/myDestFolder/".$fileinfo['basename']);
}
$zip->close();
}
?>
Here: (i tried to manage everything)
$zip = new ZipArchive();
if( $zip->open($file_path) ){
$files = array();
for( $i = 0; $i < $zip->numFiles; $i++){
$entry = $zip->statIndex($i);
// is it an image?
if( $entry['size'] > 0 && preg_match('#\.(jpg)$#i', $entry['name'] ) ){
$f_extract = $zip->getNameIndex($i);
$files[] = $f_extract; /* you man want to keep this array (use it to show result or something else) */
if ($zip->extractTo($dir_name, $f_extract) === TRUE) {
$solid_name = basename($f_extract);
if(strpos($f_extract, "/")) // make sure zipped file is in a directory
{
if($dir_name{strlen($dir_name)-1} == "/") $dir_name = substr($dir_name, 0, strlen($dir_name)-1); // to prevent error if $dir_name have slash in end of it
if(!file_exists($dir_name."/".$solid_name)) // you said you don't want to replace existed file
copy($dir_name."/".$f_extract, $dir_name."/".$solid_name); // taking file back to where you need [$dir_name]
unlink($dir_name."/".$f_extract); // [removing old file]
rmdir(str_replace($solid_name, "", $dir_name."/".$f_extract)); // [removing directory of it]
}
} else {
echo("error on export<br />\n");
}
}
}
$zip->close();
}
You can do so by using the zip:// syntax instead of Zip::extractTo as described in the php manual on extractTo().
You have to match the image file name and then copy it:
if ($entry['size'] > 0 && preg_match('#\.(jpg)$#i', $entry['name'])) {
copy('zip://' . $file_path . '#' . $entry['name'], '/root_dir/' . md5($entry['name']) . '.jpg');
}
The above replaces your for loop's if statement and makes your extractTo unnecessary. I used the md5 hash of the original filename to make a unique name. It is extremely unlikely you will have any issues with overwriting files, since hash collisions are rare. Note that this is a bit heavy duty, and instead you could do str_replace('/.', '', $entry['name']) to make a new, unique filename.
Full solution (modified version of your code):
<?php
$zip = new ZipArchive();
if ($zip->open($file_path)) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->statIndex($i);
// is it an image?
if ($entry['size'] > 0 && preg_match('#\.(jpg)$#i', $entry['name'])) {
# use hash (more expensive, but can be useful depending on what you're doing
$new_filename = md5($entry['name']) . '.jpg';
# or str_replace for cheaper, potentially longer name:
# $new_filename = str_replace('/.', '', $entry['name']);
copy('zip://' . $file_path . '#' . $entry['name'], '/myFolder/' . $new_filename);
}
}
$zip->close();
}
?>
I have a zip file.
I need a simple way to read the name of the files from the zip and read the contents of one of the files.
Can this be done directly in memory without saving,opening and reading the files ?
You need to open the archive and then can iterate over the files by index:
$zip = new ZipArchive();
if ($zip->open('archive.zip'))
{
for($i = 0; $i < $zip->numFiles; $i++)
{
echo 'Filename: ' . $zip->getNameIndex($i) . '<br />';
}
}
else
{
echo 'Error reading .zip!';
}
To read the content of a single file you can use ZipArchive::getStream($name).
$zip = new ZipArchive();
$zip->open("archive.zip");
$fstream = $zip->getStream("index.txt");
if(!$fp) exit("failed\n");
while (!feof($fp)) {
$contents .= fread($fp, 2);
}
Another way to directly do it is using the zip:// stream wrapper:
$file = fopen('zip://' . dirname(__FILE__) . '/test.zip#test', 'r');
...