I have compressed_file.zip on a site with this structure:
I want to extract all content from version_1.x folder to my root folder:
How can I do that? is possible without recursion?
It's possible, but you have to read and write the file yourself using ZipArchive::getStream:
$source = 'version_1.x';
$target = '/path/to/target';
$zip = new ZipArchive;
$zip->open('myzip.zip');
for($i=0; $i<$zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
// Skip files not in $source
if (strpos($name, "{$source}/") !== 0) continue;
// Determine output filename (removing the $source prefix)
$file = $target.'/'.substr($name, strlen($source)+1);
// Create the directories if necessary
$dir = dirname($file);
if (!is_dir($dir)) mkdir($dir, 0777, true);
// Read from Zip and write to disk
$fpr = $zip->getStream($name);
$fpw = fopen($file, 'w');
while ($data = fread($fpr, 1024)) {
fwrite($fpw, $data);
}
fclose($fpr);
fclose($fpw);
}
I was getting similar errors to #quantme when using #netcoder's solution. I made a change to that solution and it works without any errors.
$source = 'version_1.x';
$target = '/path/to/target';
$zip = new ZipArchive;
if($zip->open('myzip.zip') === TRUE) {
for($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
// Skip files not in $source
if (strpos($name, "{$source}/") !== 0) continue;
// Determine output filename (removing the $source prefix)
$file = $target.'/'.substr($name, strlen($source)+1);
// Create the directories if necessary
$dir = dirname($file);
if (!is_dir($dir)) mkdir($dir, 0777, true);
// Read from Zip and write to disk
if($dir != $target) {
$fpr = $zip->getStream($name);
$fpw = fopen($file, 'w');
while ($data = fread($fpr, 1024)) {
fwrite($fpw, $data);
}
fclose($fpr);
fclose($fpw);
}
}
$zip->close();
}
Look at the docs for extractTo. Example 1.
Related
I've read other posts about this error but I couldn't find the one that suit my case.
This is the problem: after uploading a content (text file) on a specific server path (I'm using an Apache local server), I can't read it with the file() function, except when the file is contained also in the main directory (__DIR__).
This is the problematic portion of the script:
$uploaddir = __DIR__.'/cbi_files/';
if (!is_dir($uploaddir))
mkdir($uploaddir);
chmod($uploaddir, 0600);
// Recovering temporary directory
$userfile_tmp = $_FILES['cbi_file']['tmp_name'];
// Recovering originary file's name
$userfile_name = $_FILES['cbi_file']['name'];
$count=0;
$operazione = 0;
$file_caricati = array();
foreach ($_FILES['cbi_file']['name'] as $filename) {
$destination = $uploaddir;
$origin = $_FILES['cbi_file']['tmp_name'][$count];
$count++;
$destination = $destination.basename($filename);
// moving files from temporary directory to destination
$operazione = move_uploaded_file($origin, $destination);
$file_caricati[] = $filename;
}
$file_cbi = array();
$righe = array();
if (is_dir($uploaddir)) {
if ($dh = opendir($uploaddir)) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..') {
$righe = file($file, FILE_IGNORE_NEW_LINES); // I get the error on this line
$last_row = count($righe)-1;
include(__DIR__.'/scriptCBI.php');
$file_cbi[] = array(
'nome_file' => $file,
'codice_RH' => $righe[0],
'codice_EF' => $righe[$last_row],
'recs' => $rec_array
);
}
}
closedir($dh);
}
}
I get the error if I keep the file only in $uploaddir = __DIR__'/cbi_files/', but if I keep it both in this directory and in the main directory (__DIR__) it works properly.
How's that possible?
Basically when I click my submit button the code should create a random string that is 5 characters in length. Then it should make a folder (relative position) with the name being the random string generated. Then it should create an index file and write the "content" variable to the file. Unfortunately it never even makes the directory. Any help? I can't figure out what's wrong.
<?php
$characters = "abcdefghijklmnopqrstuvwxyz"; // Valid Folder Characters
if(isset($_POST["submit"])) {
$folder = randomString($characters, 5);
$file = fopen($folder . "/index.html", "w");
$content = "File Content";
mkdir($folder, 0777);
fwrite($file, $content);
fclose($file);
}
// Generate Random Folder Name
function randomString($valid_chars, $length) {
$random_string = "";
$num_valid_chars = strlen($valid_chars);
for($i = 0; $i < $length; $i++) {
$random_pick = mt_rand(1, $num_valid_chars);
$random_char = $valid_chars[$random_pick - 1];
$random_string .= $random_char;
}
return $random_string;
}
?>
Make sure you have writable permission where or in which directory you are creating new directory and for check try
if (!mkdir($folder, 0777, true)) {
die('Failed to create folders...');
}
Also you need to first create dir then file open
if(isset($_POST["submit"])) {
$folder = randomString($characters, 5);
if (!mkdir($folder, 0777, true)) {
die('Failed to create folders...');
}
$file = fopen($folder . "/index.html", "w");
$content = "File Content";
fwrite($file, $content);
fclose($file);
}
Try this out
$oldmask = umask(0);
if(!file_exists($dir)) mkdir($dir, 0777);
umask($oldmask);
I have a folder and have multiple files over there. The file has the below pattern for example.
The file names should be renamed from
file1.mp4.png
file2.flv.png
file3.xxx.png (xxx - can be anything)
to as follows (the last extension remains).
file1.png
file2.png
file3.png
Files having non-png extension should be left untouched.
I am using the logic mentioned in Bulk Rename Files in a Folder - PHP
$handle = opendir("path to directory");
if ($handle) {
while (false !== ($fileName = readdir($handle))) {
$newName = (how to get new filename) // I am struck here
rename($fileName, $newName);
}
closedir($handle);
}
How best I can do this to do a bulk update?
<?php
// Select all PNG Files
$matches = glob("*.[pP][nN][gG]");
// check if we found any results
if ( is_array ( $matches ) ) {
// loop through all files
foreach ( $matches as $filename) {
// rename your files here
$newfilename = current(explode(".", $filename)).".png";
rename($filename, $newfilename);
echo "$filename -> $newfilename";
}
}
?>
try this
$handle = opendir("path to directory");
if ($handle) {
while (false !== ($fileName = readdir($handle))) {
$arr_names = explode(".", $fileName);
$size = sizeof($arr_names);
$ext = $arr_names[$size-1];
if($fileName=="." || $fileName==".." || is_dir($fileName))
{
continue; // skip png
}
if($ext=='png' || $ext=='PNG')
{
$newName = $arr_names[0].".".$ext;
rename($fileName, $newName);
}
}
closedir($handle);
}
Shortest using regex
$handle = opendir("path to directory");
if ($handle) {
while (false !== ($fileName = readdir($handle))) {
$newName = preg_replace("/\.(.*?)\.png$/", '', $fileName); // removes .xxx.png
rename($fileName, ($newName . '.png')); // renames file1.png
}
closedir($handle);
}
This question already has answers here:
Unzip a file with php
(12 answers)
Closed 8 years ago.
I have a zip file with some files and folders inside, and I want to extract the contents of the folder "/files" from the zip file to the a specified path (the root path of my application).
If there is a non existing folder it should just be created.
So for example if the path inside the zip is: "/files/includes/test.class.php" it should be extracted to
$path . "/includes/test.class.php"
How can I do this?
The only function i found to switch inside the zip file should be
http://www.php.net/manual/en/ziparchive.getstream.php
but i actually don't know how i can do that with this function.
Try this:
$zip = new ZipArchive;
$archiveName = 'test.zip';
$destination = $path . '/includes/';
$pattern = '#^files/includes/(.)+#';
$patternReplace = '#^files/includes/#';
function makeStructure($entry, $destination, $patternReplace)
{
$entry = preg_replace($patternReplace, '', $entry);
$parts = explode(DIRECTORY_SEPARATOR, $entry);
$dirArray = array_slice($parts, 0, sizeof($parts) - 1);
$dir = $destination . join(DIRECTORY_SEPARATOR, $dirArray);
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
if ($dir !== $destination) {
$dir .= DIRECTORY_SEPARATOR;
}
$fileExtension = pathinfo($entry, PATHINFO_EXTENSION);
if (!empty($fileExtension)) {
$fileName = $dir . pathinfo($entry, PATHINFO_BASENAME);
return $fileName;
}
return null;
}
if ($zip->open($archiveName) === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if (preg_match($pattern, $entry)) {
$file = makeStructure($entry, $destination, $patternReplace);
if ($file === null) {
continue;
}
copy('zip://' . $archiveName . '#' . $entry, $file);
}
}
$zip->close();
}
I think you need zziplib extension for this to work
$zip = new ZipArchive;
if ($zip->open('your zip file') === TRUE) {
//create folder if does not exist
if (!is_dir('path/to/directory')) {
mkdir('path/to/directory');
}
//then extract the zip
$zip->extractTo('destination to which zip is to be extracted');
$zip->close();
echo 'Zip successfully extracted.';
} else {
echo 'An error occured while extracting.';
}
Read this link for more info http://www.php.net/manual/en/ziparchive.extractto.php
Hope this helps :)
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();
}
?>