I m trying to rename files to lowercase within a directory, however the problem I'm having is being able to scan the sub-directories for the files.
So in this case $app_dir is the main directory and the files I need to change exist within multiple sub-folders.
Heres my code so far:
$files = scandir($app_dir);
foreach($files as $key=>$name){
$oldName = $name;
$newName = strtolower($name);
rename("$app_dir/$oldName","$app_dir/$newName");
}
Thanks for your help.
If you are trying to lowercase all file names you can try this:
Using this filesystem:
Josh#laptop:~$ find josh
josh
josh/A
josh/B
josh/f1
josh/f2
josh/is
josh/is/awesome
josh/is/awesome/e
josh/is/awesome/t
Code:
<?php
$app_dir = 'josh';
$dir = new RecursiveDirectoryIterator($app_dir, FilesystemIterator::SKIP_DOTS);
$iter = new RecursiveIteratorIterator($dir);
foreach ($iter as $file) {
if ($file != strtolower($file)) {
rename($file, strtolower($file));
}
}
Results:
Josh#laptop:~$ find josh
josh
josh/a
josh/b
josh/f1
josh/f2
josh/is
josh/is/awesome
josh/is/awesome/e
josh/is/awesome/t
This code does not take into account uppercase letters in directories but that exercise is up to you.
You could do this with a recursive function.
function renameFiles($dir){
$files = scandir($dir);
foreach($files as $key=>$name){
if($name == '..' || $name == '.') continue;
if(is_dir("$dir/$name"))
renameFiles("$dir/$name");
else{
$oldName = $name;
$newName = strtolower($name);
rename("$dir/$oldName", "$dir/$newName");
}
}
}
This basically loops through a directory, if something is a file it renames it, if something is a directory it runs itself on that directory.
Try like that
public function renameFiles($dir)
{
$files = scandir($dir);
foreach ($files as $key => $name) {
if (is_dir("$dir/$name")) {
if ($name == '.' || $name == '..') {
continue;
}
$this->renameFiles("$dir/$name");
} else {
$oldName = $name;
$newName = strtoupper($name);
rename("$dir/$oldName", "$dir/$newName");
}
}
}
Related
Let's say I have the following directory tree
tmp
---cat
---dog
---mouse
My index.php is in the same directory as tmp folder. How would I use PHP to save a random folder name as a variable? I've tried the following code but it didn't work.
<?php
function listFolderFiles(){
$dir = './tmp';
$ffs = scandir($dir);
$randomFolder = '';
foreach($ffs as $ff){
if($ff != '.' && $ff != '..'){
$randomFolder = $randomFolder + $ff;
}
}
echo $randomFolder;
echo '</ol>';
}
listFolderFiles();
?>
Another solution can be the built in DirectoryIterator object for iterating through file systems. Just have a look at the following example.
$results = [];
$dir = new DirectoryIterator(dirname(__FILE__));
foreach ($dir as $fileinfo) {
if (!$fileinfo->isDot() && $fileinfo->isDir()) {
$results[] = $fileinfo->getFilename();
}
}
The given code iterates through a given directory and gives back all directories included in the given directory except the dots.
By create, do you mean return/echo?
I don't think your function will produce a random folder. It will return the last folder.
function listFolderFiles(){
$dir = './tmp';
$Ignore = array('.','..'); // build an ignore array
$Results = array();
$ffs = scandir($dir);
foreach($ffs as $ff){
if(!in_array($ff,$Ignore) && is_dir("./tmp/".$ff)){ // if filename is folder and not in ignore array
$Results[] = $ff; // add filename to results
}
}
shuffle($Results); // shuffle/randomize the results
echo $Results[0];
}
listFolderFiles();
I've come up with a basic file navigator that accepts user input to jump to different directories. The only problem I have with it is that I'm basically looping over the data three times:
Get a valid list of all directories for comparison against user input
Build a "sorted" list of directories and files
Output final list
Any tips on optimizing or improving this code?
define('ROOT', '/path/to/somewhere');
// get a list of valid paths
$valid = array();
$dir = new RecursiveDirectoryIterator(ROOT);
$dir->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$iter = new ParentIterator($dir);
foreach(new RecursiveIteratorIterator($iter, RecursiveIteratorIterator::SELF_FIRST) as $file) {
$path = str_replace(ROOT, '', $file->getPathname());
$valid[] = $path;
}
// user input
$subpath = isset($_GET['path']) && in_array($_GET['path'], $valid) ? $_GET['path'] : NULL;
$cwd = isset($subpath) ? ROOT.$subpath : ROOT;
// build and sort directory tree
$files = array();
foreach(new DirectoryIterator($cwd) as $file) {
if($file->isDot()) {
continue;
}
if($file->isDir()) {
$path = str_replace(ROOT, '', $file->getPathname());
$count = iterator_count(new RecursiveDirectoryIterator($file->getRealPath(), FilesystemIterator::SKIP_DOTS));
$files[$path]['name'] = $file->getFilename();
$files[$path]['count'] = $count;
} else {
$files[] = $file->getFilename();
}
asort($files);
}
// output directory tree
if(!empty($files)) {
foreach($files as $key=>$value) {
if(is_array($value)) {
echo "{$value['name']} ({$value['count']})<br />";
} else {
echo "$value<br />";
}
}
}
How often is the directory structure going to change? Can it be cached and the whitelist be re-generated only when there are changes instead of on each request? This would be my approach depending on requirements and load factors.Beyond that probably lies the realm of micro-optimizations.
Can any one please let me know how to read the directory and find what are the files and directories inside that directory.
I've tried with checking the directories by using the is_dir() function as follows
$main = "path to the directory";//Directory which is having some files and one directory
readDir($main);
function readDir($main) {
$dirHandle = opendir($main);
while ($file = readdir($dirHandle)) {
if ($file != "." && $file != "..") {
if (is_dir($file)) {
//nothing is coming here
}
}
}
}
But it is not checking the directories.
Thanks
The most easy way in PHP 5 is with RecursiveDirectoryIterator and RecursiveIteratorIterator:
$dir = '/path/to/dir';
$directoryIterator = new RecursiveDirectoryIterator($dir);
$iterator = new RecursiveIteratorIterator($directoryIterator, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $path) {
if ($path->isDir()) {
// ...
}
}
You don't need to recurse by yourself as these fine iterators handle it by themselves.
For more information about these powerful iterators see the linked documentation articles.
You have to use full path to subdirectory:
if(is_dir($main.'/'.$file)) { ... }
Use scandir
Then parse the result and eliminate '.' and '..' and is_file()
$le_map_to_search = $main;
$data_to_use_maps[] = array();
$data_to_use_maps = read_dir($le_map_to_search, 'dir');
$aantal_mappen = count($data_to_use_maps);
$counter_mappen = 1;
while($counter_mappen < $aantal_mappen){
echo $data_to_use_maps[$counter_mappen];
$counter_mappen++;
}
$data_to_use_files[] = array();
$data_to_use_files = read_dir($le_map_to_search, 'files');
$aantal_bestanden = count($data_to_use_files);
$counter_files = 1;
while($counter_files < $aantal_files){
echo $data_to_use_files [$counter_files ];
$counter_files ++;
}
Look at the reference here:
http://php.net/manual/en/function.scandir.php
Try this
$handle = opendir($directory); //Open the directory
while (false !== ($file = readdir($handle))) {
$filepath = $directory.DS.$file; //Get all files/directories in the directory
}
I have a folder. I want to put every file in this folder into an array and afterwards I want to echo them all in an foreach loop.
What's the best way to do this?
Thanks!
Scandir is what you're looking for
http://php.net/manual/en/function.scandir.php
<?php
$dir = '/tmp';
$files1 = scandir($dir);
print_r($files1);
?>
Or use combination of opendir and readdir
http://php.net/manual/en/function.readdir.php
Doesn't get much easier than this
http://ca3.php.net/manual/en/function.scandir.php
Don't forget to filter out hidden and parent directories (they start with a dot) on linux.
An Alternative:
define('PATH', 'files/');
$filesArray = array();
$filesArray = glob(PATH . '*', GLOB_ONLYDIR);
This method allow you to specify/filter a by file type. E.G.,
define('PATH', 'files/');
define('FILE_TYPE', '.jpg');
$filesArray = array();
$filesArray = glob(PATH . '*' . FILE_TYPE, GLOB_ONLYDIR);
You can also get the FULL path name to the file by removing the parameter 'GLOB_ONLYDIR'
This works for files and folders in subfolders too. Return list of folders and list of files with their path.
$dir = __DIR__; //work only for this current dir
function listFolderContent($dir,$path=''){
$r = array();
$list = scandir($dir);
foreach ($list as $item) {
if($item!='.' && $item!='..'){
if(is_file($path.$item)){
$r['files'][] = $path.$item;
}elseif(is_dir($path.$item)){
$r['folders'][] = $path.$item;
$sub = listFolderContent($path.$item,$path.$item.'/');
if(isset($sub['files']) && count($sub['files'])>0)
$r['files'] = isset ($r['files'])?array_merge ($r['files'], $sub['files']):$sub['files'];
if(isset($sub['folders']) && count($sub['folders'])>0)
$r['folders'] = array_merge ($r['folders'], $sub['folders']);
}
}
}
return $r;
}
$list = listFolderContent($dir);
var_dump($list['files']);
var_dump($list['folders']);
Edit: dwich answer is better. I will leave this just for information.
readdir.
<?php
if ($handle = opendir('/path/to/dir')) {
echo "Directory handle: $handle\n";
echo "Files:\n";
while (false !== ($file = readdir($handle))) {
echo "$file\n";
}
closedir($handle);
}
?>
Hope this helps.
—Alberto
I am using PHP and I need to script something like below:
I have to compare two folder structure
and with reference of source folder I
want to delete all the files/folders
present in other destination folder
which do not exist in reference source
folder, how could i do this?
EDITED:
$original = scan_dir_recursive('/var/www/html/copy2');
$mirror = scan_dir_recursive('/var/www/html/copy1');
function scan_dir_recursive($dir) {
$all_paths = array();
$new_paths = scandir($dir);
foreach ($new_paths as $path) {
if ($path == '.' || $path == '..') {
continue;
}
$path = $dir . DIRECTORY_SEPARATOR . $path;
if (is_dir($path)) {
$all_paths = array_merge($all_paths, scan_dir_recursive($path));
} else {
$all_paths[] = $path;
}
}
return $all_paths;
}
foreach($mirror as $mirr)
{
if($mirr != '.' && $mirr != '..')
{
if(!in_array($mirr, $original))
{
unlink($mirr);
// delete the file
}
}
}
The above code shows what i did..
Here My copy1 folder contains extra files than copy2 folders hence i need these extra files to be deleted.
EDITED:
Below given output is are arrays of original Mirror and of difference of both..
Original Array
(
[0] => /var/www/html/copy2/Copy (5) of New Text Document.txt
[1] => /var/www/html/copy2/Copy of New Text Document.txt
)
Mirror Array
(
[0] => /var/www/html/copy1/Copy (2) of New Text Document.txt
[1] => /var/www/html/copy1/Copy (3) of New Text Document.txt
[2] => /var/www/html/copy1/Copy (5) of New Text Document.txt
)
Difference Array
(
[0] => /var/www/html/copy1/Copy (2) of New Text Document.txt
[1] => /var/www/html/copy1/Copy (3) of New Text Document.txt
[2] => /var/www/html/copy1/Copy (5) of New Text Document.txt
)
when i iterate a loop to delete on difference array all files has to be deleted as per displayed output.. how can i rectify this.. the loop for deletion is given below.
$dirs_to_delete = array();
foreach ($diff_path as $path) {
if (is_dir($path)) {
$dirs_to_delete[] = $path;
} else {
unlink($path);
}
}
while ($dir = array_pop($dirs_to_delete)) {
rmdir($dir);
}
First you need a recursive listing of both directories. A simple function like this will work:
function scan_dir_recursive($dir, $rel = null) {
$all_paths = array();
$new_paths = scandir($dir);
foreach ($new_paths as $path) {
if ($path == '.' || $path == '..') {
continue;
}
if ($rel === null) {
$path_with_rel = $path;
} else {
$path_with_rel = $rel . DIRECTORY_SEPARATOR . $path;
}
$full_path = $dir . DIRECTORY_SEPARATOR . $path;
$all_paths[] = $path_with_rel;
if (is_dir($full_path)) {
$all_paths = array_merge(
$all_paths, scan_dir_recursive($full_path, $path_with_rel)
);
}
}
return $all_paths;
}
Then you can compute their difference with array_diff.
$diff_paths = array_diff(
scan_dir_recursive('/foo/bar/mirror'),
scan_dir_recursive('/qux/baz/source')
);
Iterating over this array, you will be able to start deleting files. Directories are a bit trickier because they must be empty first.
// warning: test this code yourself before using on real data!
$dirs_to_delete = array();
foreach ($diff_paths as $path) {
if (is_dir($path)) {
$dirs_to_delete[] = $path;
} else {
unlink($path);
}
}
while ($dir = array_pop($dirs_to_delete)) {
rmdir($dir);
}
I've tested things and it should be working well now. Of course, don't take my word for it. Make sure to setup your own safe test before deleting real data.
For recursive directories please use:
$modified_directory = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('path/to/modified'), true
);
$modified_files = array();
foreach ($modified_directory as $file)
{
$modified_files []= $file->getPathname();
}
You can do other things like $file->isDot(), or $file->isFile(). For more file commands with SPLFileInfo visit http://www.php.net/manual/en/class.splfileinfo.php
Thanks all for the precious time given to my work, Special Thanks to erisco for his dedication for my problem, Below Code is the perfect code to acomplish the task I was supposed to do, with a little change in the erisco's last edited reply...
$source = '/var/www/html/copy1';
$mirror = '/var/www/html/copy2';
function scan_dir_recursive($dir, $rel = null) {
$all_paths = array();
$new_paths = scandir($dir);
foreach ($new_paths as $path) {
if ($path == '.' || $path == '..') {
continue;
}
if ($rel === null) {
$path_with_rel = $path;
} else {
$path_with_rel = $rel . DIRECTORY_SEPARATOR . $path;
}
$full_path = $dir . DIRECTORY_SEPARATOR . $path;
$all_paths[] = $path_with_rel;
if (is_dir($full_path)) {
$all_paths = array_merge(
$all_paths, scan_dir_recursive($full_path, $path_with_rel)
);
}
}
return $all_paths;
}
$diff_paths = array_diff(
scan_dir_recursive($mirror),
scan_dir_recursive($source)
);
echo "<pre>Difference ";print_r($diff_paths);
$dirs_to_delete = array();
foreach ($diff_paths as $path) {
$path = $mirror."/".$path;//added code to unlink.
if (is_dir($path)) {
$dirs_to_delete[] = $path;
} else {
if(unlink($path))
{
echo "File ".$path. "Deleted.";
}
}
}
while ($dir = array_pop($dirs_to_delete)) {
rmdir($dir);
}
First do a scandir() of the original folder, then do a scandir on mirror folder. start traversing the mirror folder array and check if that file is present in the scandir() of original folder. something like this
$original = scandir('path/to/original/folder');
$mirror = scandir('path/to/mirror/folder');
foreach($mirror as $mirr)
{
if($mirr != '.' && $mirr != '..')
{
if(in_array($mirr, $original))
{
// do not delete the file
}
else
{
// delete the file
unlink($mirr);
}
}
}
this should solve your problem. you will need to modify the above code accordingly (include some recursion in the above code to check if the folder that you are trying to delete is empty or not, if it is not empty then you will first need to delete all the file/folders in it and then delete the parent folder).