I have a bunch of files in a directory that I would like to rename. I have a complete list of existing file names and in the column next to the old name, I have a new name (desired) filename, like below: (the list is in excel so I can apply some syntax to all the rows very easily)
OLD NAME NEW NAME
-------- --------
aslkdjal.pdf asdlkjkl.pdf
adkjlkjk.pdf asdlkjdj.pdf
I would like to keep the old name and old files in their current directory and not disturb them, but just create a copy of the file, with the new filename instead.
Not sure what language to use and how to go about doing this.
http://php.net/manual/en/function.rename.php
<?php
rename("/tmp/tmp_file.txt", "/home/user/login/docs/my_file.txt");
?>
EDIT: in case of copy -
<?php
$file = 'example.txt';
$newfile = 'example.txt.bak';
if (!copy($file, $newfile)) {
echo "failed to copy $file...\n";
}
?>
Something like this should work:
$source = '/files/folder';
$target = '/files/newFolder';
$newnames= array(
"oldfilename" => "newfilename",
"oldfilename1" => "newfilename1",
);
// Copy all files to a new dir
if (!copy($source, $target)) {
echo "failed to copy $source...\n";
}
// Iterate through this dir, rename all files.
$i = new RecursiveDirectoryIterator($target);
foreach (new RecursiveIteratorIterator($i) as $filename => $file) {
rename($filename, $newnames[$filename]);
// You might need to use $file as first parameter, here. Haven't tested the code.
}
RecursiveDirectoryIterator documentation.
Just try with the following example :
<?php
$source = '../_documents/fees';
$target = '../_documents/aifs';
$newnames= array(
"1276.aif.pdf" => "aif.10001.pdf",
"64.aif.20091127.pdf" => "aif.10002.pdf",
);
function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
// Copy all files to a new dir
recurse_copy($source, $target);
// Iterate through this dir, rename all files.
$i = new RecursiveDirectoryIterator($target);
foreach (new RecursiveIteratorIterator($i) as $filename => $file) {
#rename($filename, $target.'/'.$newnames[''.$i.'']);
}
?>
This is pretty easy to do with a shell script. Start with the file list as you presented in files.txt.
#!/bin/sh
# Set the 'line' delimiter to a newline
IFS="
"
# Go through each line of files.txt and use it to call the copy command
for line in `cat files.txt`; do
cp `echo $line | awk '{print $1;}'` `echo $line | awk '{print $2};'`;
done
Related
I want to extract only images from a zip file but i also want it to extract images that are found in subfolders as well.How can i achieve this based on my code below.Note: i am not trying to preserve directory structure here , just want to extract any image found in zip.
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);
$file_info = pathinfo($file_name);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (in_array($file_info['extension'], $this->config->getValidExtensions())) {
//extract only images
copy("zip://" . $zip_path . "#" . $file_name, $this->tmp_dir . '/images/' . $file_info['basename']);
}
}
$zip->close();
Edit
My code works fine all i need to know is how to make ziparchive go in subdirectories as well
Your code is correct. I have created a.zip with files a/b/c.png, d.png:
$ mkdir -p a/b
$ zip -r a.zip d.png a
adding: d.png (deflated 4%)
adding: a/ (stored 0%)
adding: a/b/ (stored 0%)
adding: a/b/c.png (deflated 8%)
$ unzip -l a.zip
Archive: a.zip
Length Date Time Name
--------- ---------- ----- ----
122280 11-05-2016 14:45 d.png
0 11-05-2016 14:44 a/
0 11-05-2016 14:44 a/b/
36512 11-05-2016 14:44 a/b/c.png
--------- -------
158792 4 files
The code extracted both d.png and c.png from a.zip into the destination directory:
$arch_filename = 'a.zip';
$dest_dir = './dest';
if (!is_dir($dest_dir)) {
if (!mkdir($dest_dir, 0755, true))
die("failed to make directory $dest_dir\n");
}
$zip = new ZipArchive;
if (!$zip->open($arch_filename))
die("failed to open $arch_filename");
for ($i = 0; $i < $zip->numFiles; ++$i) {
$path = $zip->getNameIndex($i);
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (!preg_match('/(?:jpg|png)/i', $ext))
continue;
$dest_basename = pathinfo($path, PATHINFO_BASENAME);
echo $path, PHP_EOL;
copy("zip://{$arch_filename}#{$path}", "$dest_dir/{$dest_basename}");
}
$zip->close();
Testing
$ php script.php
d.png
a/b/c.png
$ find ./dest -type f
./dest/d.png
./dest/c.png
So the code is correct, and the issue must be somewhere else.
Based upon file extension ( not necessarily the most reliable method ) you might find the following helpful.
/* source zip file and target location for extracted files */
$file='c:/temp2/experimental.zip';
$destination='c:/temp2/extracted/';
/* Image file extensions to allow */
$exts=array('jpg','jpeg','png','gif','JPG','JPEG','PNG','GIF');
$files=array();
/* create the ZipArchive object */
$zip = new ZipArchive();
$status = $zip->open( $file, ZIPARCHIVE::FL_COMPRESSED );
if( $status ){
/* how many files are in the archive */
$count = $zip->numFiles;
for( $i=0; $i < $count; $i++ ){
try{
$name = $zip->getNameIndex( $i );
$ext = pathinfo( $name, PATHINFO_EXTENSION );
$basename = pathinfo( $name, PATHINFO_BASENAME );
/* store a reference to the file name for extraction or copy */
if( in_array( $ext, $exts ) ) {
$files[]=$name;
/* To extract files and ignore directory structure */
$res = copy( 'zip://'.$file.'#'.$name, $destination . $basename );
echo ( $res ? 'Copied: '.$basename : 'unable to copy '.$basename ) . '<br />';
}
}catch( Exception $e ){
echo $e->getMessage();
continue;
}
}
/* To extract files, with original directory structure, uncomment below */
if( !empty( $files ) ){
#$zip->extractTo( $destination, $files );
}
$zip->close();
} else {
echo $zip->getStatusString();
}
This will allow for you traverse all of the directories in a path and will search for anything that is an image/has the extensions that you have defined. Since you told the other use that you have the ziparchive portion done I have omitted that...
<?php
function traverse($path, $images = [])
{
$files = array_diff(scandir($path), ['.', '..']);
foreach ($files as $file) {
// check if the file is an image
if (in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png', 'gif'])) {
$images[] = $file;
}
if (is_dir($path . '/' . $file)) {
$images = traverse($path . '/' . $file, $images);
}
}
return $images;
}
$images = traverse('/Users/kyle/Downloads');
You want to follow this process:
Get all of the files in the current working directory
If a file in the CWD is an image add it to the images array
If a file in the CWD is a directory, recursively call the traverse function and looking for images in the directory
In the new CWD look for images, if the file is a directory recurse, etc...
It is important to keep track of the current path so you're able to call is_dir on the file. Also you want to make sure not to search '.' or '..' or you will never hit the base recursion case/it will be infinite.
Also this will not keep the directory path for the image! If you want to do that you should do $image[] = $path . '/' . $file;. You may want to do that and then get all of the file contents wants the function finishes running. I wouldn't recommend sorting the contents in the $image array because it could use an absurd amount of memory.
First thing to follow a folder is to regard it - your code does not do this.
There are no folders in a ZIP (in fact, even in the file system a "folder" IS a file, just a special one). The file (data) has a name, maybe containing a path (most likely a relative one). If by "go in subdiectories" means, that you want the same relative folder structure of the zipped files in your file system, you must write code to create these folders. I think copy won't do that for you automatically.
I modified your code and added the creation of folders. Mind the config variables I had to add to make it runable, configure it to your environment. I also left all my debug output in it. Code works for me standalone on Windows 7, PHP 5.6
error_reporting(-1 );
ini_set('display_errors', 1);
$zip_path = './test/cgiwsour.zip';
$write_dir = './test'; // base path for output
$zip = new ZipArchive();
if (!$zip->open($zip_path))
die('could not open zip file '.PHP_EOL);
$valid_extensions = ['cpp'];
$create_subfolders = true;
//extract files in zip
for ($i = 0; $i < $zip->numFiles; $i++) {
$file_name = $zip->getNameIndex($i);var_dump($file_name, $i);
$file_info = pathinfo($file_name);//print_r($file_info);
//if ( substr( $file_name, -1 ) == '/' ) continue; // skip directories - need to improve
if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']), $valid_extensions)) {
$tmp_dir = $write_dir;
if ($create_subfolders) {
$dir_parts = explode('/', $file_info['dirname']);
print_r($dir_parts);
foreach($dir_parts as $folder) {
$tmp_dir = $tmp_dir . '/' . $folder;
var_dump($tmp_dir);
if (!file_exists($tmp_dir)) {
$res = mkdir($tmp_dir);
var_dump($res);
echo 'created '.$tmp_dir.PHP_EOL;
}
}
}
else {
$tmp_dir .= '/' . $file_info['dirname'];
}
//extract only images
$res = copy("zip://" . $zip_path . "#" . $file_name, $tmp_dir . '/' . $file_info['basename']);
echo 'match : '.$file_name.PHP_EOL;
var_dump($res);
}
}
$zip->close();
Noticeable is, that mkdir() calls may not work flawlessly on all systems due to access/rights restrictions.
I'm failing to put even a single file into a new zip archive.
makeZipTest.php:
<?php
$destination = __DIR__.'/makeZipTest.zip';
$fileToZip = __DIR__.'/hello.txt';
$zip = new ZipArchive();
if (true !== $zip->open($destination, ZIPARCHIVE::OVERWRITE)) {
die("Problem opening zip $destination");
}
if (!$zip->addFile($fileToZip)) {
die("Could not add file $fileToZip");
}
echo "numfiles: " . $zip->numFiles . "\n";
echo "status: " . $zip->status . "\n";
$zip->close();
The zip gets created, but is empty. Yet no errors are triggered.
What is going wrong?
It seems on some configuration, PHP fails to get the localname properly when adding files to a zip archive and this information must be supplied manually. It is therefore possible that using the second parameter of addFile() might solve this issue.
ZipArchive::addFile
Parameters
filename
The path to the file to add.
localname
If supplied, this is the local name inside the ZIP archive that will override the filename.
PHP documentation: ZipArchive::addFile
$zip->addFile(
$fileToZip,
basename($fileToZip)
);
You may have to adapt the code to get the right tree structure since basename() will remove everything from the path apart from the filename.
You need to give server right permission in folder where they create zip archive. You can create tmp folder with write permision chmod 777 -R tmp/
Also need to change destination where script try to find hello.txt file $zip->addFile($fileToZip, basename($fileToZip))
<?php
$destination = __DIR__.'/tmp/makeZipTest.zip';
$fileToZip = __DIR__.'/hello.txt';
$zip = new ZipArchive();
if (true !== $zip->open($destination, ZipArchive::OVERWRITE)) {
die("Problem opening zip $destination");
}
if (!$zip->addFile($fileToZip, basename($fileToZip))) {
die("Could not add file $fileToZip");
}
echo "numfiles: " . $zip->numFiles . "\n";
echo "status: " . $zip->status . "\n";
$zip->close()
check this class to add files and sub-directories in a folder to zip file,and also check the folder permissions before running the code,
i.e chmod 777 -R zipdir/
HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip');
<?php
class HZip
{
private static function folderToZip($folder, &$zipFile, $exclusiveLength) {
$handle = opendir($folder);
while (false !== $f = readdir($handle)) {
if ($f != '.' && $f != '..') {
$filePath = "$folder/$f";
// Remove prefix from file path before add to zip.
$localPath = substr($filePath, $exclusiveLength);
if (is_file($filePath)) {
$zipFile->addFile($filePath, $localPath);
} elseif (is_dir($filePath)) {
// Add sub-directory.
$zipFile->addEmptyDir($localPath);
self::folderToZip($filePath, $zipFile, $exclusiveLength);
}
}
}
closedir($handle);
}
public static function zipDir($sourcePath, $outZipPath)
{
$pathInfo = pathInfo($sourcePath);
$parentPath = $pathInfo['dirname'];
$dirName = $pathInfo['basename'];
$z = new ZipArchive();
$z->open($outZipPath, ZIPARCHIVE::CREATE);
$z->addEmptyDir($dirName);
self::folderToZip($sourcePath, $z, strlen("$parentPath/"));
$z->close();
}
}
I made a drupal module, one of function of the module is to compress some files to be a zip package. It works fine in my local environment(xampp), but fails on server. My server does has php zip extension enabled, since I can see zip information on php info and I can unzip file with php as well.
Besides, I already chmod files to be 0777 .
My code:
$folder = file_directory_path();
$zip = new ZipArchive();
if ($zip->open('b.zip', ZIPARCHIVE::CREATE) === TRUE) {
foreach ( $files as $file ) {
drupal_set_message(t($file)); // I can see the the message on this stpe
$zip->addFile($file);
}
$zip->close();
if (file_exists('b.zip')) {
copy('b.zip', $folder . '/b.zip');
unlink('b.zip');
global $base_url;
variable_set('zippath', $base_url . $folder . '/b.zip');
drupal_set_message(t('new zip package has been created'));
}
} else {
drupal_set_message(t('new zip package failed'));
}
Yes .. i know what you mean .. this are the 3 possibility
You have write permissions
You Did not use full path
You are including folders as file
You can try this
error_reporting(E_ALL);
ini_set("display_errors", "On");
$fullPath = __DIR__ ; // <-------- Full Path to directory
$fileZip = __DIR__ . "/b.zip"; // <--- Full path to zip
if(!is_writable($fullPath))
{
trigger_error("You can't Write here");
}
$files = scandir($fullPath); // <--- Just to emulate your files
touch($fileZip); // <----------------- Try Creating the file temopary
$zip = new ZipArchive();
if ($zip->open($fileZip, ZIPARCHIVE::CREATE) === TRUE) {
foreach ( $files as $file ) {
if ($file == "." || $file == "..")
continue;
$fileFull = $fullPath . "/$file";
if (is_file($fileFull)) { // <-------------- Make Sure its a file
$zip->addFile($fileFull, $file);
}
// Play your ball
}
$zip->close();
} else {
echo "Failed";
}
I would recommend you to use rar or zip command to make zip. I am using linux and doing in my php system as
$folder = 'your_folder'; // folder contains files to be archived
$zipFileName = 'Your_file_name'; // zip file name
$command = 'rar a -r ' . $zipFileName . ' ' . $folder . '/';
exec($command);
Its very quick. but you need to install rar package in your system.
Thanks
I've got a problem when using is_dir while I iterate over all the files in a certain directory.
The code is kind of small so I think you'll better understand what I mean if I post it:
$files = array();
if ($dir = #opendir($folder)){
while($file = readdir($dir)){
if (is_dir($file)) $files[] = $file;
}
closedir($dir);
}
print_r($files)
It dumps:
( [0] => . )
Otherwise, if I don't check wether the file is a dir by using this code:
$files = array();
if ($dir = #opendir($folder)){
while($file = readdir($dir)){
$files[] = $file;
}
closedir($dir);
}
print_r($files)
It dumps what expected:
( [0] => .. [1] => bla [2] => blablabla [3] =>index.php [4] => styles.css [5] => . )
I guess it's just some noob problem with using the $file var as a parameter but don't know how to make it work.
Thanks for reading!
As Kolink said in the comments, you're probably better off going the glob route, but if you decide to stick with opendir:
The path will be $folder . '/' . $file, not just $file. opendir() returns relative paths. So is_dir is returning false in your loop.
if ($dir = opendir($folder)){
while(false !== ($file = readdir($dir))) {
if ($file == '.' || $file == '..') {
continue;
} else if (is_dir($folder . '/' . $file)) {
$files[] = $file;
}
}
closedir($dir);
}
Also, note the false !==. This is necessary because a folder named "0" would evaluate to false (or a few other edge cases). Also, you'll very rarely actually care about . and .., so that code is in there to filter . and .. out.
Problem is: $file contains only the basename, not the absolute filename. So prepend the path to the folder:
is_dir($folder . '/' . $file)
<? // findfiles.php - what is in directory "videoarchive"
$dir = 'images/videoarchive/'; // path from top
$files = scandir($dir);
$files_n = count($files);
echo '<br>There are '.$files_n.' records in directory '.$dir.'<br>' ;
$i=0;
while($i<=$files_n){
// "is_dir" only works from top directory, so append the $dir before the file
if (is_dir($dir.'/'.$files[$i])){
$MyFileType[$i] = "D" ; // D for Directory
} else{
$MyFileType[$i] = "F" ; // F for File
}
// print itemNo, itemType(D/F) and itemname
echo '<br>'.$i.'. '. $MyFileType[$i].'. ' .$files[$i] ;
$i++;
}
?>
This is the starting portion of my code to list files in a directory:
$files = scandir($dir);
$array = array();
foreach($files as $file)
{
if($file != '.' && $file != '..' && !is_dir($file)){
....
I'm trying to list all files in a directory without listing subfolders. The code is working, but showing both files and folders. I added !is_dir($file) as you see in my code above, but the results are still the same.
It should be like this, I think:
$files = scandir($dir);
foreach($files as $file)
{
if(is_file($dir.$file)){
....
Just use is_file.
Example:
foreach($files as $file)
{
if( is_file($file) )
{
// Something
}
}
This will scan the files then check if . or .. is in an array. Then push the files excluding . and .. in the new files[] array.
Try this:
$scannedFiles = scandir($fullPath);
$files = [];
foreach ($scannedFiles as $file) {
if (!in_array(trim($file), ['.', '..'])) {
$files[] = $file;
}
}
What a pain for something so seemingly simple! Nothing worked for me...
To get a result I assumed the file name had an extension which it must in my case.
if ($handle = opendir($opendir)) {
while (false !== ($entry = readdir($handle))) {
$pos = strpos( $entry, '.' );
if ($entry != "." && $entry != ".." && is_numeric($pos) ) {
............ good entry
Use the DIRECTORY_SEPARATOR constant to append the file to its directory path too.
function getFileNames($directoryPath) {
$fileNames = [];
$contents = scandir($directoryPath);
foreach($contents as $content) {
if(is_file($directoryPath . DIRECTORY_SEPARATOR . $content)) {
array_push($fileNames, $content);
}
}
return $fileNames;
}
This is a quick and simple one liner to list ONLY files. Since the user wants to list only files, there is no need to scan the directory and return all the contents and exclude the directories. Just get the files of any type or specific type. Use * to return all files regardless of extension or get files with a specific extension by replacing the * with the extension.
Get all files regardless of extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*");
Get all files with the php extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*.php");
Get all files with the js extension:
$files = glob($dir . DIRECTORY_SEPARATOR . "*.js");
I use the following for my sites:
function fileList(string $directory, string $extension="") :array
{
$filetype = '*';
if(!empty($extension) && mb_substr($extension, 0, 1, "UTF-8") != '.'):
$filetype .= '.' . $extension;
else:
$filetype .= $extension;
endif;
return glob($directory . DIRECTORY_SEPARATOR . $filetype);
}
Usage :
$files = fileList($configData->includesDirectory, '');
With my custom function, I can include an extension or leave it empty. Additionally, I can forget to place the . before the extension and it will succeed.