Using PHP, how can I find all .php files in a folder or its subfolders (of any depth)?
You can use RecursiveDirectoryIterator and RecursiveIteratorIterator:
$di = new RecursiveDirectoryIterator(__DIR__,RecursiveDirectoryIterator::SKIP_DOTS);
$it = new RecursiveIteratorIterator($di);
foreach($it as $file) {
if (pathinfo($file, PATHINFO_EXTENSION) == "php") {
echo $file, PHP_EOL;
}
}
just add something like:
function listFolderFiles($dir){
$ffs = scandir($dir);
$i = 0;
$list = array();
foreach ( $ffs as $ff ){
if ( $ff != '.' && $ff != '..' ){
if ( strlen($ff)>=5 ) {
if ( substr($ff, -4) == '.php' ) {
$list[] = $ff;
//echo dirname($ff) . $ff . "<br/>";
echo $dir.'/'.$ff.'<br/>';
}
}
if( is_dir($dir.'/'.$ff) )
listFolderFiles($dir.'/'.$ff);
}
}
return $list;
}
$files = array();
$files = listFolderFiles(dirname(__FILE__));
I modified the code a bit created by supajason
Because the code provided did not return a consistent result:
Mainly due to the nomenclature used.
I also added some functionality.
<?php
define('ROOT', str_replace('\\', '/', getcwd()).'/');
///########-------------------------------------------------------------
///########-------------------------------------------------------------
///######## FUNCTION TO LIST ALL FILES AND FOLDERS WITHIN A CERTAIN PATH
///########-------------------------------------------------------------
///########-------------------------------------------------------------
function list_folderfiles(
$dir, // *** TARGET DIRECTORY TO SCAN
$return_flat = true, // *** DEFAULT FLAT ARRAY TO BE RETURNED
$iteration = 0 // *** INTERNAL PARAM TO COUNT THE FUNCTIONS OWN ITERATIONS
){
///######## PREPARE ALL VARIABLES
$dir = rtrim($dir, '/'); // *** REMOVE TRAILING SLASH (* just for being pretty *)
$files_folders = scandir($dir); // *** SCAN FOR ALL FILES AND FOLDERS
$nested_folders = []; // *** THE NESTED FOLDERS BUILD ARRAY
static $total_files = []; // *** THE TOTAL FILES ARRAY
///######## MAKE SURE THAT THE STATIC $fileS ARE WILL BE CLEARED AFTER THE FIRST ITERATION, RESET AS EMPTY ARRAY
if($iteration === 0) $total_$files = [];
///######## RUN THROUGH ALL $fileS AND FOLDERS
foreach($files_folders as $file){
///######### IF THE CURRENT ``file`` IS A DIRECTORY UP
if($file === '.' || $file === '..') continue;
///######### IF IT CONCERNS A $file
if(is_dir($dir.'/'.$file)){
$iteration++; // *** RAISE THE ITERATION
$nested_folders[] = list_folderfiles($dir.'/'.$file, false, $iteration); // *** EXECUTE THE FUNCTION ITSELF
}
///######### IF IT CONCERNS A $file
else{
$total_files[] = $dir.'/'.$file; // *** ADD THE $file TO THE TOTAL $fileS ARRAY
$nested_folders[] = $file; // *** ADD THE $file TO THE NESTED FOLDERS ARRAY
}
}
///########==================================================
///######## IF A FLAT LIST SHOULD BE RETURNED
///########==================================================
if($return_flat) return $total_files;
///######## IF A NESTED LIST SHOULD BE RETURNED
else return $nested_folders;
///########==================================================
}
$files = list_folderfiles(ROOT, true); // *** FLAT ARRAY
///$files = list_folderfiles(ROOT, false); // *** NESTED ARRAY
echo print_r($files, true);
This is similar to another answer here, but removes SKIP_DOTS as it's not needed, and and works with strict_types:
<?php
$o_dir = new RecursiveDirectoryIterator('.');
$o_iter = new RecursiveIteratorIterator($o_dir);
foreach ($o_iter as $o_info) {
if ($o_info->getExtension() == 'php') {
echo $o_info->getPathname(), "\n";
}
}
https://php.net/splfileinfo.getextension
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 am yet to work on a very large project which has too many files. I am trying to find out few vaiables where it is present and list all the file names which contains the specific word or variable or string.
What I have tried so far!
$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($fileList as $item) {
if ($item->isFile() && stripos($item->getPathName(), 'php') !== false) {
$file_contents = file_get_contents($item->getPathName());
$file_contents = strpos($file_contents,"wordtofind");
echo $file_contents;
}
}
I use the same code for replacing text which I found it on stackoverflow. But I need to find out few strings before replacing specific words in specific files. Hence this has become most important task to me.
How can I further code and get the file names?
Edit:
I want to search for a specific word, for example: word_to_find
And there are more than 200 files in a folder called abc.
When I run that code, searching for the word, then it should search in all 200 files and list all the file names which contains word_to_find word.
Then I would know, in which all files, the specific word exists and then I can work on.
Output would be:
123.php
111.php
199.php
I created you a nice function. This will return filenames (Not any paths, yield $item->getPathName() instead if you want the path, or probably better yet, just yield $item, which will return the SplFileInfo class which you can then use any of the helper functions to get info about that file.):
function findStringInPath($needle, $path = __DIR__) {
//$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($fileList as $item) {
if ($item->isFile() && strtolower($item->getExtension()) === 'php') {
$file_contents = file_get_contents($item->getPathName());
if ( strpos($file_contents, $needle) !== false )
yield $item->getFileName();
}
}
}
foreach ( findStringInPath('stringtofind') as $file ) {
echo $file . '<br />';
}
?>
For older PHP versions:
<?php
function findStringInPath($needle, $path = __DIR__) {
//$path = realpath(__DIR__); // Path to your textfiles
$fileList = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST);
$ret = array();
foreach ($fileList as $item) {
if ($item->isFile() && strtolower($item->getExtension()) === 'php') {
$file_contents = file_get_contents($item->getPathName());
if ( strpos($file_contents, $needle) !== false )
$ret[] = $item->getFileName();
}
}
return $ret;
}
foreach ( findStringInPath('stringtofind') as $file ) {
echo $file . '<br />';
}
?>
I have an directory tree which has been passed to array.
I would like to there empty folders inside this array.
How can I determine empty folders like /wp-content/uploads/2014/02/ and /wp-content/uploads/2014/.
How can I delete them recursively.
Here is my array
array (
0 => './do-update.php',
5 => './wp-config.php',
6 => './wp-content/',
7 => './wp-content/uploads/',
8 => './wp-content/uploads/2013/',
9 => './wp-content/uploads/2013/05/',
10 => './wp-content/uploads/2013/05/kabeduvarkad-1024x768.jpg',
26 => './wp-content/uploads/2013/05/kabeduvarkad2.jpg',
27 => './wp-content/uploads/2013/10/',
28 => './wp-content/uploads/2014/',
29 => './wp-content/uploads/2014/02/',
30 => './wp-content/uploads/de.php',
31 => './wp-update.tar.gz',
32 => './wp-update/',
33 => './wp-update/wp-update.tar',
)
Thank you very much to Andresch Serj for him effords.
Who wants to delete empty folders recursively with performance, you can use this solution.
function list_directory($dir) {
$file_list = array();
$stack[] = $dir;
while ($stack) {
$current_dir = array_pop($stack);
if ($dh = opendir($current_dir)){
while (($file = readdir($dh)) !== false) {
if ($file !== '.' AND $file !== '..') {
$current_file = "{$current_dir}/{$file}";
$report = array();
if (is_file($current_file)) {
$file_list[] = "{$current_dir}/{$file}";
} elseif (is_dir($current_file)) {
$stack[] = $current_file;
$file_list[] = "{$current_dir}/{$file}/";
}
}
}
}
}
sort($file_list, SORT_LOCALE_STRING);
return $file_list;
}
function remove_emptyfolders($array_filelist){
$files = array();
$folders = array();
foreach($array_filelist as $path){
// better performance for is_dir function
if ($path[strlen($path)-1] == '/'){ // check for last character if it is / which is a folder.
$folders[] = $path;
}
else{
$files[] = $path;
}
}
// bos olmayan klasorleri buluyoruz.
// eger klasor ismi dosya isimlerinin icerisinde gecmiyorsa bos demektir? right?
$folders_notempty = array();
foreach($files as $file){
foreach($folders as $folder){
if(strpos($file,$folder) !== false){
// dublicate olmasin diye key isimlerinin ismine yazdırdık.
$folders_notempty[$folder] = $folder;
}
}
}
// bos olmayanla klasorleri, digerlerinden cikariyoruz.
$folders_empty = array();
foreach($folders as $folder){
// eger bos olmayanlarin icerisinde bu dosya yoksa
if(!in_array($folder, $folders_notempty)){
$folders_empty[] = $folder;
}
}
// once en uzaktan silmeye baslamaliyiz. kisaca tersten.
$folders_empty = array_reverse($folders_empty);
$folders_deleted = array();
foreach($folders_empty as $k){
try{
$folders_deleted[$k] = 'NOT Succesfull';
if(rmdir($k)){ $folders_deleted[$k] = 'Deleted'; continue; }
chmod($k, 0777);
if(rmdir($k)){ $folders_deleted[$k] = 'Deleted after chmod'; }
}catch (Exception $e) {
print_r($e);
}
}
return $folders_deleted;
}
$files = list_directory(getcwd());
//print_r($files);
$files_deleted = remove_emptyfolders($files);
print_r($files_deleted);
Simply iterate over your array using foreach.
foreach ($filesArray as $file) {
Then for each file, check if it is a folder using is_dir like this
if (is_dir ($file)) {
If it is a folder/directory, read the directory, for instanse using scandir.
$directoryContent = scandir($file);
If the result of scandir is empty, you have an empty folder that you can delete with unlink.
if (count($directoryContent) <= 2) { // checkig if there is moire than . and ..
unlink($file);
If you have trouble with unlink, you may have to set file permissions accordingly.
If instead you need a function that recursively deletes empty subfolders given some paht, you should consider reading the SO question that was linkes in the comments.
EDIT
After taking into consideration your comments, what you do want is a function that deletes parent folders as well. So for a geiven level1/level2/level3 where level3 is empty and the only folder/file in level2 you want level2 to be deleted as well.
So from your example array, you want ./wp-content/uploads/2014/ deleted and not just ./wp-content/uploads/2014/10, but only if ./wp-content/uploads/2014/10 has no content or subfolders with content.
So how to do that?
Simle: Extend your check for weather that folder is empty. If it is empty, manipoulate the given file/path string to get the parent folder. By now you should outsource this to a recursive functions indeed.
function doesDirectoryOnlyContainEmptyFolders($path) {
if(is_dir($path) {
$directoryContent = scandir($path);
if (count($directoryContent) <= 2) {
return true;
}
else {
foreach ($directoryContent as $subPath) {
if($filePath !== '.' && $filePath !== '..' && !doesDirectoryOnlyContainEmptyFolders($subPath)) {
return false;
}
}
return true;
}
}
return false;
}
So this function checks recursively if a path has only empty folders or folders containing empty folders - recursively.
Now you want to check your paths and maybe delete them, recursively downwards and upwards.
function deleteEmptyFoldersRecursivelyUpAndDown($path) {
if (is_dir($path)) {
if(doesDirectoryOnlyContainEmptyFolders($path)) {
unlink($path);
$parentFolder = substr($path, 0, strripos ($path, '/'));
deleteEmptyFoldersRecursivelyUpAndDown($parentFolder);
}
else {
$directoryContent = scandir($path);
foreach ($directoryContent as $subPath) {
deleteEmptyFoldersRecursivelyUpAndDown($subPath);
}
}
}
}
If the given path is a directory, we check if it is empty using our recursive function.
If it is, we delete it and recursively check the parent directory.
If it is not, we iterate over its content to find empty folders, again calling the function itself recursively.
With these two function you have all you need. Simply iterate over your path array and use deleteEmptyFoldersRecursivelyUpAndDownon all entries. If they are faulty, you'll manage to debug them i presume.
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).
I want to use a function to recursively scan a folder, and assign the contents of each scan to an array.
It's simple enough to recurse through each successive index in the array using either next() or foreach - but how to dynamically add a layer of depth to the array (without hard coding it into the function) is giving me problems. Here's some pseudo:
function myScanner($start){
static $files = array();
$files = scandir($start);
//do some filtering here to omit unwanted types
$next = next($files);
//recurse scan
//PROBLEM: how to increment position in array to store results
//$next_position = $files[][][].... ad infinitum
//myScanner($start.DIRECTORY_SEPARATOR.$next);
}
any ideas?
Try something like this:
// $array is a pointer to your array
// $start is a directory to start the scan
function myScanner($start, &$array){
// opening $start directory handle
$handle = opendir($start);
// now we try to read the directory contents
while (false !== ($file = readdir($handle))) {
// filtering . and .. "folders"
if ($file != "." && $file != "..") {
// a variable to test if this file is a directory
$dirtest = $start . DIRECTORY_SEPARATOR . $file;
// check it
if (is_dir($dirtest)) {
// if it is the directory then run the function again
// DIRECTORY_SEPARATOR here to not mix files and directories with the same name
myScanner($dirtest, $array[$file . DIRECTORY_SEPARATOR]);
} else {
// else we just add this file to an array
$array[$file] = '';
}
}
}
// closing directory handle
closedir($handle);
}
// test it
$mytree = array();
myScanner('/var/www', $mytree);
print "<pre>";
print_r($mytree);
print "</pre>";
Try to use this function (and edit it for your demands):
function getDirTree($dir,$p=true) {
$d = dir($dir);$x=array();
while (false !== ($r = $d->read())) {
if($r!="."&&$r!=".."&&(($p==false&&is_dir($dir.$r))||$p==true)) {
$x[$r] = (is_dir($dir.$r)?array():(is_file($dir.$r)?true:false));
}
}
foreach ($x as $key => $value) {
if (is_dir($dir.$key."/")) {
$x[$key] = getDirTree($dir.$key."/",$p);
}
}
ksort($x);
return $x;
}
It returns sorted array of directories.