Get the hierarchy of a directory with PHP - php

I'm trying to find all the files and folders under a specified directory
For example I have /home/user/stuff
I want to return
/home/user/stuff/folder1/image1.jpg
/home/user/stuff/folder1/image2.jpg
/home/user/stuff/folder2/subfolder1/image1.jpg
/home/user/stuff/image1.jpg
Hopefully that makes sense!

function dir_contents_recursive($dir) {
// open handler for the directory
$iter = new DirectoryIterator($dir);
foreach( $iter as $item ) {
// make sure you don't try to access the current dir or the parent
if ($item != '.' && $item != '..') {
if( $item->isDir() ) {
// call the function on the folder
dir_contents_recursive("$dir/$item");
} else {
// print files
echo $dir . "/" .$item->getFilename() . "<br>";
}
}
}
}

foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $f) {
echo "$f \r\n";
}

The working solution (change with your folder name)
<?php
$path = realpath('yourfolder/subfolder');
## or use like this
## $path = '/home/user/stuff/folder1';
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename)
{
echo "$filename\n";
}
?>

$dir = "/home/user/stuff/";
$scan = scandir($dir);
foreach ($scan as $output) {
echo "$output" . "<br />";
}

Find all the files and folders under a specified directory.
function getDirRecursive($dir, &$output = []) {
$scandir = scandir($dir);
foreach ($scandir as $a => $name) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $name);
if (!is_dir($path)) {
$output[] = $path;
} else if ($name != "." && $name != "..") {
getDirRecursive($path, $output);
$output[] = $path;
}
}
return $output;
}
var_dump(getDirRecursive('/home/user/stuff'));
Output (example) :
array (size=4)
0 => string '/home/user/stuff/folder1/image1.jpg' (length=35)
1 => string '/home/user/stuff/folder1/image2.jpg' (length=35)
2 => string '/home/user/stuff/folder2/subfolder1/image1.jpg' (length=46)
3 => string '/home/user/stuff/image1.jpg' (length=27)

listAllFiles( '../cooktail/' ); //send directory path to get the all files and floder of root dir
function listAllFiles( $strDir ) {
$dir = new DirectoryIterator( $strDir );
foreach( $dir as $fileinfo ) {
if( $fileinfo == '.' || $fileinfo == '..' ) continue;
if( $fileinfo->isDir() ) {
listAllFiles( "$strDir/$fileinfo" );
}
echo $fileinfo->getFilename() . "<br/>";
}
}

Beside RecursiveDirectoryIterator solution there is also glob() solution:
// do some extra filtering here, if necessary
function recurse( $item ) {
return is_dir( $item ) ? array_map( 'recurse', glob( "$item/*" ) ) : $item;
};
// array_walk_recursive: any key that holds an array will not be passed to the function.
array_walk_recursive( ( recurse( 'home/user/stuff' ) ), function( $item ) { print_r( $item ); } );

You can use the RecursiveDirectoryIterator or even the glob function.
Alternatively, the scandir function will do the job.

Related

How do I write a code that repeats itself within itself? [duplicate]

I'm trying to go through all of the files in a directory, and if there is a directory, go through all of its files and so on until there are no more directories to go to. Each and every processed item will be added to a results array in the function below. It is not working though I'm not sure what I can do/what I did wrong, but the browser runs insanely slow when this code below is processed, any help is appreciated, thanks!
Code:
function getDirContents($dir){
$results = array();
$files = scandir($dir);
foreach($files as $key => $value){
if(!is_dir($dir. DIRECTORY_SEPARATOR .$value)){
$results[] = $value;
} else if(is_dir($dir. DIRECTORY_SEPARATOR .$value)) {
$results[] = $value;
getDirContents($dir. DIRECTORY_SEPARATOR .$value);
}
}
}
print_r(getDirContents('/xampp/htdocs/WORK'));
Get all the files and folders in a directory, don't call function when you have . or ...
Your code :
<?php
function getDirContents($dir, &$results = array()) {
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path)) {
$results[] = $path;
} else if ($value != "." && $value != "..") {
getDirContents($path, $results);
$results[] = $path;
}
}
return $results;
}
var_dump(getDirContents('/xampp/htdocs/WORK'));
Output (example) :
array (size=12)
0 => string '/xampp/htdocs/WORK/iframe.html' (length=30)
1 => string '/xampp/htdocs/WORK/index.html' (length=29)
2 => string '/xampp/htdocs/WORK/js' (length=21)
3 => string '/xampp/htdocs/WORK/js/btwn.js' (length=29)
4 => string '/xampp/htdocs/WORK/js/qunit' (length=27)
5 => string '/xampp/htdocs/WORK/js/qunit/qunit.css' (length=37)
6 => string '/xampp/htdocs/WORK/js/qunit/qunit.js' (length=36)
7 => string '/xampp/htdocs/WORK/js/unit-test.js' (length=34)
8 => string '/xampp/htdocs/WORK/xxxxx.js' (length=30)
9 => string '/xampp/htdocs/WORK/plane.png' (length=28)
10 => string '/xampp/htdocs/WORK/qunit.html' (length=29)
11 => string '/xampp/htdocs/WORK/styles.less' (length=30)
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('path/to/folder'));
$files = array();
/** #var SplFileInfo $file */
foreach ($rii as $file) {
if ($file->isDir()){
continue;
}
$files[] = $file->getPathname();
}
var_dump($files);
This will bring you all the files with paths.
This is a function to get all the files and folders in a directory with RecursiveIteratorIterator.
See contructor doc : https://www.php.net/manual/en/recursiveiteratoriterator.construct.php
function getDirContents($path) {
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$files = array();
foreach ($rii as $file)
if (!$file->isDir())
$files[] = $file->getPathname();
return $files;
}
var_dump(getDirContents($path));
This could help if you wish to get directory contents as an array, ignoring hidden files and directories.
function dir_tree($dir_path)
{
$rdi = new \RecursiveDirectoryIterator($dir_path);
$rii = new \RecursiveIteratorIterator($rdi);
$tree = [];
foreach ($rii as $splFileInfo) {
$file_name = $splFileInfo->getFilename();
// Skip hidden files and directories.
if ($file_name[0] === '.') {
continue;
}
$path = $splFileInfo->isDir() ? array($file_name => array()) : array($file_name);
for ($depth = $rii->getDepth() - 1; $depth >= 0; $depth--) {
$path = array($rii->getSubIterator($depth)->current()->getFilename() => $path);
}
$tree = array_merge_recursive($tree, $path);
}
return $tree;
}
The result would be something like;
dir_tree(__DIR__.'/public');
[
'css' => [
'style.css',
'style.min.css',
],
'js' => [
'script.js',
'script.min.js',
],
'favicon.ico',
]
Source
Get all the files with filter (2nd argument) and folders in a directory, don't call function when you have . or ...
Your code :
<?php
function getDirContents($dir, $filter = '', &$results = array()) {
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
if(empty($filter) || preg_match($filter, $path)) $results[] = $path;
} elseif($value != "." && $value != "..") {
getDirContents($path, $filter, $results);
}
}
return $results;
}
// Simple Call: List all files
var_dump(getDirContents('/xampp/htdocs/WORK'));
// Regex Call: List php files only
var_dump(getDirContents('/xampp/htdocs/WORK', '/\.php$/'));
Output (example) :
// Simple Call
array(13) {
[0]=> string(69) "/xampp/htdocs/WORK.htaccess"
[1]=> string(73) "/xampp/htdocs/WORKConverter.php"
[2]=> string(69) "/xampp/htdocs/WORKEvent.php"
[3]=> string(70) "/xampp/htdocs/WORKdefault_filter.json"
[4]=> string(68) "/xampp/htdocs/WORKdefault_filter.xml"
[5]=> string(80) "/xampp/htdocs/WORKCaching/ApcCache.php"
[6]=> string(84) "/xampp/htdocs/WORKCaching/CacheFactory.php"
}
// Regex Call
array(13) {
[0]=> string(69) "/xampp/htdocs/WORKEvent.php"
[1]=> string(73) "/xampp/htdocs/WORKConverter.php"
[2]=> string(80) "/xampp/htdocs/WORKCaching/ApcCache.php"
[3]=> string(84) "/xampp/htdocs/WORKCaching/CacheFactory.php"
}
James Cameron's proposition.
My proposal without ugly "foreach" control structures is
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$allFiles = array_filter(iterator_to_array($iterator), fn($file) $file->isFile());
You may only want to extract the filepath, which you can do so by:
array_keys($allFiles);
Still 4 lines of code, but more straight forward than using a loop or something.
Here is what I came up with and this is with not much lines of code
function show_files($start) {
$contents = scandir($start);
array_splice($contents, 0,2);
echo "<ul>";
foreach ( $contents as $item ) {
if ( is_dir("$start/$item") && (substr($item, 0,1) != '.') ) {
echo "<li>$item</li>";
show_files("$start/$item");
} else {
echo "<li>$item</li>";
}
}
echo "</ul>";
}
show_files('./');
It outputs something like
..idea
.add.php
.add_task.php
.helpers
.countries.php
.mysqli_connect.php
.sort.php
.test.js
.test.php
.view_tasks.php
** The dots are the dots of unoordered list.
Hope this helps.
Add relative path option:
function getDirContents($dir, $relativePath = false)
{
$fileList = array();
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $file) {
if ($file->isDir()) continue;
$path = $file->getPathname();
if ($relativePath) {
$path = str_replace($dir, '', $path);
$path = ltrim($path, '/\\');
}
$fileList[] = $path;
}
return $fileList;
}
print_r(getDirContents('/path/to/dir'));
print_r(getDirContents('/path/to/dir', true));
Output:
Array
(
[0] => /path/to/dir/test1.html
[1] => /path/to/dir/test.html
[2] => /path/to/dir/index.php
)
Array
(
[0] => test1.html
[1] => test.html
[2] => index.php
)
Here's a modified version of Hors answer, works slightly better for my case, as it strips out the base directory that is passed as it goes, and has a recursive switch that can be set to false which is also handy. Plus to make the output more readable, I've separated the file and subdirectory files, so the files are added first then the subdirectory files (see result for what I mean.)
I tried a few other methods and suggestions around and this is what I ended up with. I had another working method already that was very similar, but seemed to fail where there was a subdirectory with no files but that subdirectory had a subsubdirectory with files, it didn't scan the subsubdirectory for files - so some answers may need to be tested for that case.)... anyways thought I'd post my version here too in case someone is looking...
function get_filelist_as_array($dir, $recursive = true, $basedir = '', $include_dirs = false) {
if ($dir == '') {return array();} else {$results = array(); $subresults = array();}
if (!is_dir($dir)) {$dir = dirname($dir);} // so a files path can be sent
if ($basedir == '') {$basedir = realpath($dir).DIRECTORY_SEPARATOR;}
$files = scandir($dir);
foreach ($files as $key => $value){
if ( ($value != '.') && ($value != '..') ) {
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if (is_dir($path)) {
// optionally include directories in file list
if ($include_dirs) {$subresults[] = str_replace($basedir, '', $path);}
// optionally get file list for all subdirectories
if ($recursive) {
$subdirresults = get_filelist_as_array($path, $recursive, $basedir, $include_dirs);
$results = array_merge($results, $subdirresults);
}
} else {
// strip basedir and add to subarray to separate file list
$subresults[] = str_replace($basedir, '', $path);
}
}
}
// merge the subarray to give the list of files then subdirectory files
if (count($subresults) > 0) {$results = array_merge($subresults, $results);}
return $results;
}
I suppose one thing to be careful of it not to pass a $basedir value to this function when calling it... mostly just pass the $dir (or passing a filepath will work now too) and optionally $recursive as false if and as needed. The result:
[0] => demo-image.png
[1] => filelist.php
[2] => tile.png
[3] => 2015\header.png
[4] => 2015\08\background.jpg
Enjoy! Okay, back to the program I'm actually using this in...
UPDATE Added extra argument for including directories in the file list or not (remembering other arguments will need to be passed to use this.) eg.
$results = get_filelist_as_array($dir, true, '', true);
This solution did the job for me. The RecursiveIteratorIterator lists all directories and files recursively but unsorted. The program filters the list and sorts it.
I'm sure there is a way to write this shorter; feel free to improve it.
It is just a code snippet. You may want to pimp it to your purposes.
<?php
$path = '/pth/to/your/directories/and/files';
// an unsorted array of dirs & files
$files_dirs = iterator_to_array( new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),RecursiveIteratorIterator::SELF_FIRST) );
echo '<html><body><pre>';
// create a new associative multi-dimensional array with dirs as keys and their files
$dirs_files = array();
foreach($files_dirs as $dir){
if(is_dir($dir) AND preg_match('/\/\.$/',$dir)){
$d = preg_replace('/\/\.$/','',$dir);
$dirs_files[$d] = array();
foreach($files_dirs as $file){
if(is_file($file) AND $d == dirname($file)){
$f = basename($file);
$dirs_files[$d][] = $f;
}
}
}
}
//print_r($dirs_files);
// sort dirs
ksort($dirs_files);
foreach($dirs_files as $dir => $files){
$c = substr_count($dir,'/');
echo str_pad(' ',$c,' ', STR_PAD_LEFT)."$dir\n";
// sort files
asort($files);
foreach($files as $file){
echo str_pad(' ',$c,' ', STR_PAD_LEFT)."|_$file\n";
}
}
echo '</pre></body></html>';
?>
This will print the full path of all files in the given directory, you can also pass other callback functions to recursiveDir.
function printFunc($path){
echo $path."<br>";
}
function recursiveDir($path, $fileFunc, $dirFunc){
$openDir = opendir($path);
while (($file = readdir($openDir)) !== false) {
$fullFilePath = realpath("$path/$file");
if ($file[0] != ".") {
if (is_file($fullFilePath)){
if (is_callable($fileFunc)){
$fileFunc($fullFilePath);
}
} else {
if (is_callable($dirFunc)){
$dirFunc($fullFilePath);
}
recursiveDir($fullFilePath, $fileFunc, $dirFunc);
}
}
}
}
recursiveDir($dirToScan, 'printFunc', 'printFunc');
This is a little modification of majicks answer.
I just changed the array structure returned by the function.
From:
array() => {
[0] => "test/test.txt"
}
To:
array() => {
'test/test.txt' => "test.txt"
}
/**
* #param string $dir
* #param bool $recursive
* #param string $basedir
*
* #return array
*/
function getFileListAsArray(string $dir, bool $recursive = true, string $basedir = ''): array {
if ($dir == '') {
return array();
} else {
$results = array();
$subresults = array();
}
if (!is_dir($dir)) {
$dir = dirname($dir);
} // so a files path can be sent
if ($basedir == '') {
$basedir = realpath($dir) . DIRECTORY_SEPARATOR;
}
$files = scandir($dir);
foreach ($files as $key => $value) {
if (($value != '.') && ($value != '..')) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (is_dir($path)) { // do not combine with the next line or..
if ($recursive) { // ..non-recursive list will include subdirs
$subdirresults = self::getFileListAsArray($path, $recursive, $basedir);
$results = array_merge($results, $subdirresults);
}
} else { // strip basedir and add to subarray to separate file list
$subresults[str_replace($basedir, '', $path)] = $value;
}
}
}
// merge the subarray to give the list of files then subdirectory files
if (count($subresults) > 0) {
$results = array_merge($subresults, $results);
}
return $results;
}
Might help for those having the exact same expected results like me.
To whom needs list files first than folders (with alphabetical older).
Can use following function.
This is not self calling function. So you will have directory list, directory view, files
list and folders list as seperated array also.
I spend two days for this and do not want someone will wast his time for this also, hope helps someone.
function dirlist($dir){
if(!file_exists($dir)){ return $dir.' does not exists'; }
$list = array('path' => $dir, 'dirview' => array(), 'dirlist' => array(), 'files' => array(), 'folders' => array());
$dirs = array($dir);
while(null !== ($dir = array_pop($dirs))){
if($dh = opendir($dir)){
while(false !== ($file = readdir($dh))){
if($file == '.' || $file == '..') continue;
$path = $dir.DIRECTORY_SEPARATOR.$file;
$list['dirlist_natural'][] = $path;
if(is_dir($path)){
$list['dirview'][$dir]['folders'][] = $path;
// Bos klasorler while icerisine tekrar girmeyecektir. Klasorun oldugundan emin olalım.
if(!isset($list['dirview'][$path])){ $list['dirview'][$path] = array(); }
$dirs[] = $path;
//if($path == 'D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-content\upgrade'){ press($path); press($list['dirview']); die; }
}
else{
$list['dirview'][$dir]['files'][] = $path;
}
}
closedir($dh);
}
}
// if(!empty($dirlist['dirlist_natural'])) sort($dirlist['dirlist_natural'], SORT_LOCALE_STRING); // delete safe ama gerek kalmadı.
if(!empty($list['dirview'])) ksort($list['dirview']);
// Dosyaları dogru sıralama yaptırıyoruz. Deniz P. - info[at]netinial.com
foreach($list['dirview'] as $path => $file){
if(isset($file['files'])){
$list['dirlist'][] = $path;
$list['files'] = array_merge($list['files'], $file['files']);
$list['dirlist'] = array_merge($list['dirlist'], $file['files']);
}
// Add empty folders to the list
if(is_dir($path) && array_search($path, $list['dirlist']) === false){
$list['dirlist'][] = $path;
}
if(isset($file['folders'])){
$list['folders'] = array_merge($list['folders'], $file['folders']);
}
}
//press(array_diff($list['dirlist_natural'], $list['dirlist'])); press($list['dirview']); die;
return $list;
}
will output something like this.
[D:\Xampp\htdocs\exclusiveyachtcharter.localhost] => Array
(
[files] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\.htaccess
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\index.php
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\license.txt
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\php.php
[4] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\readme.html
[5] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-activate.php
[6] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-blog-header.php
[7] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-comments-post.php
[8] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config-sample.php
[9] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config.php
[10] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-cron.php
[11] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-links-opml.php
[12] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-load.php
[13] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-login.php
[14] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-mail.php
[15] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-settings.php
[16] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-signup.php
[17] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-trackback.php
[18] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\xmlrpc.php
)
[folders] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-admin
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-content
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-includes
)
)
dirview output
[dirview] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\.htaccess
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\index.php
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\license.txt
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\php.php
[4] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\readme.html
[5] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-activate.php
[6] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-blog-header.php
[7] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-comments-post.php
[8] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config-sample.php
[9] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config.php
[10] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-cron.php
[11] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-links-opml.php
[12] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-load.php
[13] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-login.php
[14] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-mail.php
[15] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-settings.php
[16] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-signup.php
[17] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-trackback.php
[18] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\xmlrpc.php
[19] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost
[20] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql\exclusiv_excluwl.sql
[21] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql\exclusiv_excluwl.sql.zip
[22] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql
)
#A-312's solution may cause memory problems as it may create a huge array if /xampp/htdocs/WORK contains a lot of files and folders.
If you have PHP 7 then you can use Generators and optimize PHP's memory like this:
function getDirContents($dir) {
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
yield $path;
} else if($value != "." && $value != "..") {
yield from getDirContents($path);
yield $path;
}
}
}
foreach(getDirContents('/xampp/htdocs/WORK') as $value) {
echo $value."\n";
}
yield from
Ready for copy and paste function for common use cases, improved/extended version of one answer above:
function getDirContents(string $dir, int $onlyFiles = 0, string $excludeRegex = '~/\.git/~', int $maxDepth = -1): array {
$results = [];
$scanAll = scandir($dir);
sort($scanAll);
$scanDirs = []; $scanFiles = [];
foreach($scanAll as $fName){
if ($fName === '.' || $fName === '..') { continue; }
$fPath = str_replace(DIRECTORY_SEPARATOR, '/', realpath($dir . '/' . $fName));
if (strlen($excludeRegex) > 0 && preg_match($excludeRegex, $fPath . (is_dir($fPath) ? '/' : ''))) { continue; }
if (is_dir($fPath)) {
$scanDirs[] = $fPath;
} elseif ($onlyFiles >= 0) {
$scanFiles[] = $fPath;
}
}
foreach ($scanDirs as $pDir) {
if ($onlyFiles <= 0) {
$results[] = $pDir;
}
if ($maxDepth !== 0) {
foreach (getDirContents($pDir, $onlyFiles, $excludeRegex, $maxDepth - 1) as $p) {
$results[] = $p;
}
}
}
foreach ($scanFiles as $p) {
$results[] = $p;
}
return $results;
}
And if you need relative paths:
function updateKeysWithRelPath(array $paths, string $baseDir, bool $allowBaseDirPath = false): array {
$results = [];
$regex = '~^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($baseDir)), '~') . '(?:/|$)~s';
$regex = preg_replace('~/~', '/(?:(?!\.\.?/)(?:(?!/).)+/\.\.(?:/|$))?(?:\.(?:/|$))*', $regex); // limited to only one "/xx/../" expr
if (DIRECTORY_SEPARATOR === '\\') {
$regex = preg_replace('~/~', '[/\\\\\\\\]', $regex) . 'i';
}
foreach ($paths as $p) {
$rel = preg_replace($regex, '', $p, 1);
if ($rel === $p) {
throw new \Exception('Path relativize failed, path "' . $p . '" is not within basedir "' . $baseDir . '".');
} elseif ($rel === '') {
if (!$allowBaseDirPath) {
throw new \Exception('Path relativize failed, basedir path "' . $p . '" not allowed.');
} else {
$results[$rel] = './';
}
} else {
$results[$rel] = $p;
}
}
return $results;
}
function getDirContentsWithRelKeys(string $dir, int $onlyFiles = 0, string $excludeRegex = '~/\.git/~', int $maxDepth = -1): array {
return updateKeysWithRelPath(getDirContents($dir, $onlyFiles, $excludeRegex, $maxDepth), $dir);
}
This version solves/improves:
warnings from realpath when PHP open_basedir does not cover the .. directory.
does not use reference for the result array
allows to exclude directories and files
allows to list files/directories only
allows to limit the search depth
it always sort output with directories first (so directories can be removed/emptied in reverse order)
allows to get paths with relative keys
heavy optimized for hundred of thousands or even milions of files
write for more in the comments :)
Examples:
// list only `*.php` files and skip .git/ and the current file
$onlyPhpFilesExcludeRegex = '~/\.git/|(?<!/|\.php)$|^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath(__FILE__)), '~') . '$~is';
$phpFiles = getDirContents(__DIR__, 1, $onlyPhpFilesExcludeRegex);
print_r($phpFiles);
// with relative keys
$phpFiles = getDirContentsWithRelKeys(__DIR__, 1, $onlyPhpFilesExcludeRegex);
print_r($phpFiles);
// with "include only" regex to include only .html and .txt files with "/*_mails/en/*.(html|txt)" path
'~/\.git/|^(?!.*/(|' . '[^/]+_mails/en/[^/]+\.(?:html|txt)' . ')$)~is'
If you're using Laravel you can use the allFiles method on the Storage facade to recursively get all files as shown in the docs here: https://laravel.com/docs/8.x/filesystem#get-all-files-within-a-directory.
use Illuminate\Support\Facades\Storage;
class TestClass {
public function test() {
// Gets all the files in the 'storage/app' directory.
$files = Storage::allFiles(storage_path('app'))
}
}
Here is mine :
function recScan( $mainDir, $allData = array() )
{
// hide files
$hidefiles = array(
".",
"..",
".htaccess",
".htpasswd",
"index.php",
"php.ini",
"error_log" ) ;
//start reading directory
$dirContent = scandir( $mainDir ) ;
foreach ( $dirContent as $key => $content )
{
$path = $mainDir . '/' . $content ;
// if is readable / file
if ( ! in_array( $content, $hidefiles ) )
{
if ( is_file( $path ) && is_readable( $path ) )
{
$allData[] = $path ;
}
// if is readable / directory
// Beware ! recursive scan eats ressources !
else
if ( is_dir( $path ) && is_readable( $path ) )
{
/*recursive*/
$allData = recScan( $path, $allData ) ;
}
}
}
return $allData ;
}
here I have example for that
List all the files and folders in a Directory csv(file) read with PHP recursive function
<?php
/** List all the files and folders in a Directory csv(file) read with PHP recursive function */
function getDirContents($dir, &$results = array()){
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
$results[] = $path;
} else if($value != "." && $value != "..") {
getDirContents($path, $results);
//$results[] = $path;
}
}
return $results;
}
$files = getDirContents('/xampp/htdocs/medifree/lab');//here folder name where your folders and it's csvfile;
foreach($files as $file){
$csv_file =$file;
$foldername = explode(DIRECTORY_SEPARATOR,$file);
//using this get your folder name (explode your path);
print_r($foldername);
if (($handle = fopen($csv_file, "r")) !== FALSE) {
fgetcsv($handle);
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$num = count($data);
for ($c=0; $c < $num; $c++) {
$col[$c] = $data[$c];
}
}
fclose($handle);
}
}
?>
http://myphpinformation.blogspot.in/2016/05/list-all-files-and-folders-in-directory-csv-file-read-with-php-recursive.html
I improved with one check iteration the good code of Hors Sujet to avoid including folders in the result array:
function getDirContents($dir, &$results = array()){
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(is_dir($path) == false) {
$results[] = $path;
}
else if($value != "." && $value != "..") {
getDirContents($path, $results);
if(is_dir($path) == false) {
$results[] = $path;
}
}
}
return $results;
}
I found this simple code:
https://stackoverflow.com/a/24981012
$Directory = new RecursiveDirectoryIterator($path);
$Iterator = new RecursiveIteratorIterator($Directory);
//Filter to get only PDF, JPEG, JPG, GIF, TIF files.
$Regex = new RegexIterator($Iterator, '/^.+(.jpe?g|.gif|.png|.tif|.pdf)$/i', RecursiveRegexIterator::GET_MATCH);
foreach($Regex as $val => $Regex){
echo "$val\n<br>";
}

Auto include/require all files under all directories

I would like to automatically include/require all .php files under all directories. For example:
(Directory structure)
-[ classes
--[ loader (directory)
---[ plugin.class.php
--[ main.class.php
--[ database.class.php
I need a function that automatically loads all files that end in .php
I have tried all-sorts:
$scan = scandir('classes/');
foreach ($scan as $class) {
if (strpos($class, '.class.php') !== false) {
include($scan . $class);
}
}
Well, if you want to include all php files with a certain ending even in subdirectories, you have to make a recursive function. Something like this:
function load_classphp($directory) {
if(is_dir($directory)) {
$scan = scandir($directory);
unset($scan[0], $scan[1]); //unset . and ..
foreach($scan as $file) {
if(is_dir($directory."/".$file)) {
load_classphp($directory."/".$file);
} else {
if(strpos($file, '.class.php') !== false) {
include_once($directory."/".$file);
}
}
}
}
}
load_classphp('./classes');
This is probably the simplest way to recursively find patterned files:
$dir = new RecursiveDirectoryIterator('classes/');
$iter = new RecursiveIteratorIterator($dir);
$files = new RegexIterator($iter, '/^.+\.class\.php$/', RecursiveRegexIterator::GET_MATCH); // an Iterator, not an array
foreach ( $files as $file ) {
include $file; // $file includes `classes/`
}
RecursiveDirectoryIterator is a tricky beast, so learning all about it is probably not doable. The interwebs has many specific examples though. The trick is to search for it.
If the php files you want to include are PHP classes, then you should use PHP Autoloader
It's not a safe practice to include all php files in all directories automatically. Performance might be degraded if you're including unnecessary files.
Here's the code that should work (I have not tested it):
$scan = scandir('classes/');
foreach ($scan as $class) {
if (strpos($class, '.class.php') !== false) {
include('classes/' . $class);
}
}
If you want recursive include RecursiveIteratorIterator will help you.
$dir = new RecursiveDirectoryIterator('change this to your custom root directory');
foreach (new RecursiveIteratorIterator($dir) as $file) {
if (!is_dir($file)) {
if( fnmatch('*.php', $file) ) // you can change the file extension to any that you require.
/* do anything here */
}
}
function autoload( $path ) {
$items = glob( $path . DIRECTORY_SEPARATOR . "*" );
foreach( $items as $item ) {
$isPhp = pathinfo( $item )["extension"] === "php";
if ( is_file( $item ) && $isPhp ) {
require_once $item;
} elseif ( is_dir( $item ) ) {
autoload( $item );
}
}
}
autoload( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . "classes" );
An easy way : a simple function using RecursiveDirectoryIterator instead of glob().
function include_dir_r( $dir_path ) {
$path = realpath( $dir_path );
$objects = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path ), \RecursiveIteratorIterator::SELF_FIRST );
foreach( $objects as $name => $object ) {
if( $object->getFilename() !== "." && $object->getFilename() !== ".." ) {
if( !is_dir( $name ) ){
include_once $name;
}
}
}
}
One that I use is
function fileLoader($dir) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file == '.' || $file == '..') {
continue;
}
$path = $dir . '/' . $file;
if (is_dir($path)) {
__DIR__.$path;
} else {
require_once $path;
}
}
}
# calling the function
fileLoader('mydirectory')

php - list folders that contain a specific file

A php script should list all available "modules". A module is a subdirectory that contains at least an info.php file.
Now I want a list of all subdirectories that contain the "info.php" file (i.e. a list of all modules) and came up with this code:
$modules = array();
if ( $handle = opendir( MODULE_DIR ) ) {
while ( false !== ( $entry = readdir( $handle ) ) ) {
if ( $entry === '.' || $entry === '..' ) { continue; }
$info_file = MODULE_DIR . $entry . '/info.php';
if ( ! is_file( $info_file ) ) { continue; }
$modules[] = $entry;
}
closedir( $handle );
}
Question: Is there a shorter/nicer way to get the list, preferably without the loop?
A nice and clean solution can be achieved using the function glob():
foreach(glob('src/*/info.php') as $path) {
echo basename(dirname($path)) . PHP_EOL;
}
Take a look at the RecursiveDirectoryIterator
http://php.net/manual/en/class.recursivedirectoryiterator.php
In your case the code would look like this:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'));
foreach($it as $key => $item) {
if(basename($key) === 'info.php') {
echo dirname($key) . PHP_EOL;
}
}

List all the files and folders in a Directory with PHP recursive function

I'm trying to go through all of the files in a directory, and if there is a directory, go through all of its files and so on until there are no more directories to go to. Each and every processed item will be added to a results array in the function below. It is not working though I'm not sure what I can do/what I did wrong, but the browser runs insanely slow when this code below is processed, any help is appreciated, thanks!
Code:
function getDirContents($dir){
$results = array();
$files = scandir($dir);
foreach($files as $key => $value){
if(!is_dir($dir. DIRECTORY_SEPARATOR .$value)){
$results[] = $value;
} else if(is_dir($dir. DIRECTORY_SEPARATOR .$value)) {
$results[] = $value;
getDirContents($dir. DIRECTORY_SEPARATOR .$value);
}
}
}
print_r(getDirContents('/xampp/htdocs/WORK'));
Get all the files and folders in a directory, don't call function when you have . or ...
Your code :
<?php
function getDirContents($dir, &$results = array()) {
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path)) {
$results[] = $path;
} else if ($value != "." && $value != "..") {
getDirContents($path, $results);
$results[] = $path;
}
}
return $results;
}
var_dump(getDirContents('/xampp/htdocs/WORK'));
Output (example) :
array (size=12)
0 => string '/xampp/htdocs/WORK/iframe.html' (length=30)
1 => string '/xampp/htdocs/WORK/index.html' (length=29)
2 => string '/xampp/htdocs/WORK/js' (length=21)
3 => string '/xampp/htdocs/WORK/js/btwn.js' (length=29)
4 => string '/xampp/htdocs/WORK/js/qunit' (length=27)
5 => string '/xampp/htdocs/WORK/js/qunit/qunit.css' (length=37)
6 => string '/xampp/htdocs/WORK/js/qunit/qunit.js' (length=36)
7 => string '/xampp/htdocs/WORK/js/unit-test.js' (length=34)
8 => string '/xampp/htdocs/WORK/xxxxx.js' (length=30)
9 => string '/xampp/htdocs/WORK/plane.png' (length=28)
10 => string '/xampp/htdocs/WORK/qunit.html' (length=29)
11 => string '/xampp/htdocs/WORK/styles.less' (length=30)
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('path/to/folder'));
$files = array();
/** #var SplFileInfo $file */
foreach ($rii as $file) {
if ($file->isDir()){
continue;
}
$files[] = $file->getPathname();
}
var_dump($files);
This will bring you all the files with paths.
This is a function to get all the files and folders in a directory with RecursiveIteratorIterator.
See contructor doc : https://www.php.net/manual/en/recursiveiteratoriterator.construct.php
function getDirContents($path) {
$rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$files = array();
foreach ($rii as $file)
if (!$file->isDir())
$files[] = $file->getPathname();
return $files;
}
var_dump(getDirContents($path));
This could help if you wish to get directory contents as an array, ignoring hidden files and directories.
function dir_tree($dir_path)
{
$rdi = new \RecursiveDirectoryIterator($dir_path);
$rii = new \RecursiveIteratorIterator($rdi);
$tree = [];
foreach ($rii as $splFileInfo) {
$file_name = $splFileInfo->getFilename();
// Skip hidden files and directories.
if ($file_name[0] === '.') {
continue;
}
$path = $splFileInfo->isDir() ? array($file_name => array()) : array($file_name);
for ($depth = $rii->getDepth() - 1; $depth >= 0; $depth--) {
$path = array($rii->getSubIterator($depth)->current()->getFilename() => $path);
}
$tree = array_merge_recursive($tree, $path);
}
return $tree;
}
The result would be something like;
dir_tree(__DIR__.'/public');
[
'css' => [
'style.css',
'style.min.css',
],
'js' => [
'script.js',
'script.min.js',
],
'favicon.ico',
]
Source
Get all the files with filter (2nd argument) and folders in a directory, don't call function when you have . or ...
Your code :
<?php
function getDirContents($dir, $filter = '', &$results = array()) {
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
if(empty($filter) || preg_match($filter, $path)) $results[] = $path;
} elseif($value != "." && $value != "..") {
getDirContents($path, $filter, $results);
}
}
return $results;
}
// Simple Call: List all files
var_dump(getDirContents('/xampp/htdocs/WORK'));
// Regex Call: List php files only
var_dump(getDirContents('/xampp/htdocs/WORK', '/\.php$/'));
Output (example) :
// Simple Call
array(13) {
[0]=> string(69) "/xampp/htdocs/WORK.htaccess"
[1]=> string(73) "/xampp/htdocs/WORKConverter.php"
[2]=> string(69) "/xampp/htdocs/WORKEvent.php"
[3]=> string(70) "/xampp/htdocs/WORKdefault_filter.json"
[4]=> string(68) "/xampp/htdocs/WORKdefault_filter.xml"
[5]=> string(80) "/xampp/htdocs/WORKCaching/ApcCache.php"
[6]=> string(84) "/xampp/htdocs/WORKCaching/CacheFactory.php"
}
// Regex Call
array(13) {
[0]=> string(69) "/xampp/htdocs/WORKEvent.php"
[1]=> string(73) "/xampp/htdocs/WORKConverter.php"
[2]=> string(80) "/xampp/htdocs/WORKCaching/ApcCache.php"
[3]=> string(84) "/xampp/htdocs/WORKCaching/CacheFactory.php"
}
James Cameron's proposition.
My proposal without ugly "foreach" control structures is
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$allFiles = array_filter(iterator_to_array($iterator), fn($file) $file->isFile());
You may only want to extract the filepath, which you can do so by:
array_keys($allFiles);
Still 4 lines of code, but more straight forward than using a loop or something.
Here is what I came up with and this is with not much lines of code
function show_files($start) {
$contents = scandir($start);
array_splice($contents, 0,2);
echo "<ul>";
foreach ( $contents as $item ) {
if ( is_dir("$start/$item") && (substr($item, 0,1) != '.') ) {
echo "<li>$item</li>";
show_files("$start/$item");
} else {
echo "<li>$item</li>";
}
}
echo "</ul>";
}
show_files('./');
It outputs something like
..idea
.add.php
.add_task.php
.helpers
.countries.php
.mysqli_connect.php
.sort.php
.test.js
.test.php
.view_tasks.php
** The dots are the dots of unoordered list.
Hope this helps.
Add relative path option:
function getDirContents($dir, $relativePath = false)
{
$fileList = array();
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $file) {
if ($file->isDir()) continue;
$path = $file->getPathname();
if ($relativePath) {
$path = str_replace($dir, '', $path);
$path = ltrim($path, '/\\');
}
$fileList[] = $path;
}
return $fileList;
}
print_r(getDirContents('/path/to/dir'));
print_r(getDirContents('/path/to/dir', true));
Output:
Array
(
[0] => /path/to/dir/test1.html
[1] => /path/to/dir/test.html
[2] => /path/to/dir/index.php
)
Array
(
[0] => test1.html
[1] => test.html
[2] => index.php
)
Here's a modified version of Hors answer, works slightly better for my case, as it strips out the base directory that is passed as it goes, and has a recursive switch that can be set to false which is also handy. Plus to make the output more readable, I've separated the file and subdirectory files, so the files are added first then the subdirectory files (see result for what I mean.)
I tried a few other methods and suggestions around and this is what I ended up with. I had another working method already that was very similar, but seemed to fail where there was a subdirectory with no files but that subdirectory had a subsubdirectory with files, it didn't scan the subsubdirectory for files - so some answers may need to be tested for that case.)... anyways thought I'd post my version here too in case someone is looking...
function get_filelist_as_array($dir, $recursive = true, $basedir = '', $include_dirs = false) {
if ($dir == '') {return array();} else {$results = array(); $subresults = array();}
if (!is_dir($dir)) {$dir = dirname($dir);} // so a files path can be sent
if ($basedir == '') {$basedir = realpath($dir).DIRECTORY_SEPARATOR;}
$files = scandir($dir);
foreach ($files as $key => $value){
if ( ($value != '.') && ($value != '..') ) {
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if (is_dir($path)) {
// optionally include directories in file list
if ($include_dirs) {$subresults[] = str_replace($basedir, '', $path);}
// optionally get file list for all subdirectories
if ($recursive) {
$subdirresults = get_filelist_as_array($path, $recursive, $basedir, $include_dirs);
$results = array_merge($results, $subdirresults);
}
} else {
// strip basedir and add to subarray to separate file list
$subresults[] = str_replace($basedir, '', $path);
}
}
}
// merge the subarray to give the list of files then subdirectory files
if (count($subresults) > 0) {$results = array_merge($subresults, $results);}
return $results;
}
I suppose one thing to be careful of it not to pass a $basedir value to this function when calling it... mostly just pass the $dir (or passing a filepath will work now too) and optionally $recursive as false if and as needed. The result:
[0] => demo-image.png
[1] => filelist.php
[2] => tile.png
[3] => 2015\header.png
[4] => 2015\08\background.jpg
Enjoy! Okay, back to the program I'm actually using this in...
UPDATE Added extra argument for including directories in the file list or not (remembering other arguments will need to be passed to use this.) eg.
$results = get_filelist_as_array($dir, true, '', true);
This solution did the job for me. The RecursiveIteratorIterator lists all directories and files recursively but unsorted. The program filters the list and sorts it.
I'm sure there is a way to write this shorter; feel free to improve it.
It is just a code snippet. You may want to pimp it to your purposes.
<?php
$path = '/pth/to/your/directories/and/files';
// an unsorted array of dirs & files
$files_dirs = iterator_to_array( new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),RecursiveIteratorIterator::SELF_FIRST) );
echo '<html><body><pre>';
// create a new associative multi-dimensional array with dirs as keys and their files
$dirs_files = array();
foreach($files_dirs as $dir){
if(is_dir($dir) AND preg_match('/\/\.$/',$dir)){
$d = preg_replace('/\/\.$/','',$dir);
$dirs_files[$d] = array();
foreach($files_dirs as $file){
if(is_file($file) AND $d == dirname($file)){
$f = basename($file);
$dirs_files[$d][] = $f;
}
}
}
}
//print_r($dirs_files);
// sort dirs
ksort($dirs_files);
foreach($dirs_files as $dir => $files){
$c = substr_count($dir,'/');
echo str_pad(' ',$c,' ', STR_PAD_LEFT)."$dir\n";
// sort files
asort($files);
foreach($files as $file){
echo str_pad(' ',$c,' ', STR_PAD_LEFT)."|_$file\n";
}
}
echo '</pre></body></html>';
?>
This will print the full path of all files in the given directory, you can also pass other callback functions to recursiveDir.
function printFunc($path){
echo $path."<br>";
}
function recursiveDir($path, $fileFunc, $dirFunc){
$openDir = opendir($path);
while (($file = readdir($openDir)) !== false) {
$fullFilePath = realpath("$path/$file");
if ($file[0] != ".") {
if (is_file($fullFilePath)){
if (is_callable($fileFunc)){
$fileFunc($fullFilePath);
}
} else {
if (is_callable($dirFunc)){
$dirFunc($fullFilePath);
}
recursiveDir($fullFilePath, $fileFunc, $dirFunc);
}
}
}
}
recursiveDir($dirToScan, 'printFunc', 'printFunc');
This is a little modification of majicks answer.
I just changed the array structure returned by the function.
From:
array() => {
[0] => "test/test.txt"
}
To:
array() => {
'test/test.txt' => "test.txt"
}
/**
* #param string $dir
* #param bool $recursive
* #param string $basedir
*
* #return array
*/
function getFileListAsArray(string $dir, bool $recursive = true, string $basedir = ''): array {
if ($dir == '') {
return array();
} else {
$results = array();
$subresults = array();
}
if (!is_dir($dir)) {
$dir = dirname($dir);
} // so a files path can be sent
if ($basedir == '') {
$basedir = realpath($dir) . DIRECTORY_SEPARATOR;
}
$files = scandir($dir);
foreach ($files as $key => $value) {
if (($value != '.') && ($value != '..')) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (is_dir($path)) { // do not combine with the next line or..
if ($recursive) { // ..non-recursive list will include subdirs
$subdirresults = self::getFileListAsArray($path, $recursive, $basedir);
$results = array_merge($results, $subdirresults);
}
} else { // strip basedir and add to subarray to separate file list
$subresults[str_replace($basedir, '', $path)] = $value;
}
}
}
// merge the subarray to give the list of files then subdirectory files
if (count($subresults) > 0) {
$results = array_merge($subresults, $results);
}
return $results;
}
Might help for those having the exact same expected results like me.
To whom needs list files first than folders (with alphabetical older).
Can use following function.
This is not self calling function. So you will have directory list, directory view, files
list and folders list as seperated array also.
I spend two days for this and do not want someone will wast his time for this also, hope helps someone.
function dirlist($dir){
if(!file_exists($dir)){ return $dir.' does not exists'; }
$list = array('path' => $dir, 'dirview' => array(), 'dirlist' => array(), 'files' => array(), 'folders' => array());
$dirs = array($dir);
while(null !== ($dir = array_pop($dirs))){
if($dh = opendir($dir)){
while(false !== ($file = readdir($dh))){
if($file == '.' || $file == '..') continue;
$path = $dir.DIRECTORY_SEPARATOR.$file;
$list['dirlist_natural'][] = $path;
if(is_dir($path)){
$list['dirview'][$dir]['folders'][] = $path;
// Bos klasorler while icerisine tekrar girmeyecektir. Klasorun oldugundan emin olalım.
if(!isset($list['dirview'][$path])){ $list['dirview'][$path] = array(); }
$dirs[] = $path;
//if($path == 'D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-content\upgrade'){ press($path); press($list['dirview']); die; }
}
else{
$list['dirview'][$dir]['files'][] = $path;
}
}
closedir($dh);
}
}
// if(!empty($dirlist['dirlist_natural'])) sort($dirlist['dirlist_natural'], SORT_LOCALE_STRING); // delete safe ama gerek kalmadı.
if(!empty($list['dirview'])) ksort($list['dirview']);
// Dosyaları dogru sıralama yaptırıyoruz. Deniz P. - info[at]netinial.com
foreach($list['dirview'] as $path => $file){
if(isset($file['files'])){
$list['dirlist'][] = $path;
$list['files'] = array_merge($list['files'], $file['files']);
$list['dirlist'] = array_merge($list['dirlist'], $file['files']);
}
// Add empty folders to the list
if(is_dir($path) && array_search($path, $list['dirlist']) === false){
$list['dirlist'][] = $path;
}
if(isset($file['folders'])){
$list['folders'] = array_merge($list['folders'], $file['folders']);
}
}
//press(array_diff($list['dirlist_natural'], $list['dirlist'])); press($list['dirview']); die;
return $list;
}
will output something like this.
[D:\Xampp\htdocs\exclusiveyachtcharter.localhost] => Array
(
[files] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\.htaccess
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\index.php
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\license.txt
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\php.php
[4] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\readme.html
[5] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-activate.php
[6] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-blog-header.php
[7] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-comments-post.php
[8] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config-sample.php
[9] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config.php
[10] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-cron.php
[11] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-links-opml.php
[12] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-load.php
[13] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-login.php
[14] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-mail.php
[15] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-settings.php
[16] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-signup.php
[17] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-trackback.php
[18] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\xmlrpc.php
)
[folders] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-admin
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-content
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-includes
)
)
dirview output
[dirview] => Array
(
[0] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\.htaccess
[1] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\index.php
[2] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\license.txt
[3] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\php.php
[4] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\readme.html
[5] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-activate.php
[6] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-blog-header.php
[7] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-comments-post.php
[8] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config-sample.php
[9] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-config.php
[10] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-cron.php
[11] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-links-opml.php
[12] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-load.php
[13] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-login.php
[14] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-mail.php
[15] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-settings.php
[16] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-signup.php
[17] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\wp-trackback.php
[18] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\xmlrpc.php
[19] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost
[20] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql\exclusiv_excluwl.sql
[21] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql\exclusiv_excluwl.sql.zip
[22] => D:\Xampp\htdocs\exclusiveyachtcharter.localhost\exclusiv_excluwlsql
)
#A-312's solution may cause memory problems as it may create a huge array if /xampp/htdocs/WORK contains a lot of files and folders.
If you have PHP 7 then you can use Generators and optimize PHP's memory like this:
function getDirContents($dir) {
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
yield $path;
} else if($value != "." && $value != "..") {
yield from getDirContents($path);
yield $path;
}
}
}
foreach(getDirContents('/xampp/htdocs/WORK') as $value) {
echo $value."\n";
}
yield from
Ready for copy and paste function for common use cases, improved/extended version of one answer above:
function getDirContents(string $dir, int $onlyFiles = 0, string $excludeRegex = '~/\.git/~', int $maxDepth = -1): array {
$results = [];
$scanAll = scandir($dir);
sort($scanAll);
$scanDirs = []; $scanFiles = [];
foreach($scanAll as $fName){
if ($fName === '.' || $fName === '..') { continue; }
$fPath = str_replace(DIRECTORY_SEPARATOR, '/', realpath($dir . '/' . $fName));
if (strlen($excludeRegex) > 0 && preg_match($excludeRegex, $fPath . (is_dir($fPath) ? '/' : ''))) { continue; }
if (is_dir($fPath)) {
$scanDirs[] = $fPath;
} elseif ($onlyFiles >= 0) {
$scanFiles[] = $fPath;
}
}
foreach ($scanDirs as $pDir) {
if ($onlyFiles <= 0) {
$results[] = $pDir;
}
if ($maxDepth !== 0) {
foreach (getDirContents($pDir, $onlyFiles, $excludeRegex, $maxDepth - 1) as $p) {
$results[] = $p;
}
}
}
foreach ($scanFiles as $p) {
$results[] = $p;
}
return $results;
}
And if you need relative paths:
function updateKeysWithRelPath(array $paths, string $baseDir, bool $allowBaseDirPath = false): array {
$results = [];
$regex = '~^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($baseDir)), '~') . '(?:/|$)~s';
$regex = preg_replace('~/~', '/(?:(?!\.\.?/)(?:(?!/).)+/\.\.(?:/|$))?(?:\.(?:/|$))*', $regex); // limited to only one "/xx/../" expr
if (DIRECTORY_SEPARATOR === '\\') {
$regex = preg_replace('~/~', '[/\\\\\\\\]', $regex) . 'i';
}
foreach ($paths as $p) {
$rel = preg_replace($regex, '', $p, 1);
if ($rel === $p) {
throw new \Exception('Path relativize failed, path "' . $p . '" is not within basedir "' . $baseDir . '".');
} elseif ($rel === '') {
if (!$allowBaseDirPath) {
throw new \Exception('Path relativize failed, basedir path "' . $p . '" not allowed.');
} else {
$results[$rel] = './';
}
} else {
$results[$rel] = $p;
}
}
return $results;
}
function getDirContentsWithRelKeys(string $dir, int $onlyFiles = 0, string $excludeRegex = '~/\.git/~', int $maxDepth = -1): array {
return updateKeysWithRelPath(getDirContents($dir, $onlyFiles, $excludeRegex, $maxDepth), $dir);
}
This version solves/improves:
warnings from realpath when PHP open_basedir does not cover the .. directory.
does not use reference for the result array
allows to exclude directories and files
allows to list files/directories only
allows to limit the search depth
it always sort output with directories first (so directories can be removed/emptied in reverse order)
allows to get paths with relative keys
heavy optimized for hundred of thousands or even milions of files
write for more in the comments :)
Examples:
// list only `*.php` files and skip .git/ and the current file
$onlyPhpFilesExcludeRegex = '~/\.git/|(?<!/|\.php)$|^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath(__FILE__)), '~') . '$~is';
$phpFiles = getDirContents(__DIR__, 1, $onlyPhpFilesExcludeRegex);
print_r($phpFiles);
// with relative keys
$phpFiles = getDirContentsWithRelKeys(__DIR__, 1, $onlyPhpFilesExcludeRegex);
print_r($phpFiles);
// with "include only" regex to include only .html and .txt files with "/*_mails/en/*.(html|txt)" path
'~/\.git/|^(?!.*/(|' . '[^/]+_mails/en/[^/]+\.(?:html|txt)' . ')$)~is'
If you're using Laravel you can use the allFiles method on the Storage facade to recursively get all files as shown in the docs here: https://laravel.com/docs/8.x/filesystem#get-all-files-within-a-directory.
use Illuminate\Support\Facades\Storage;
class TestClass {
public function test() {
// Gets all the files in the 'storage/app' directory.
$files = Storage::allFiles(storage_path('app'))
}
}
Here is mine :
function recScan( $mainDir, $allData = array() )
{
// hide files
$hidefiles = array(
".",
"..",
".htaccess",
".htpasswd",
"index.php",
"php.ini",
"error_log" ) ;
//start reading directory
$dirContent = scandir( $mainDir ) ;
foreach ( $dirContent as $key => $content )
{
$path = $mainDir . '/' . $content ;
// if is readable / file
if ( ! in_array( $content, $hidefiles ) )
{
if ( is_file( $path ) && is_readable( $path ) )
{
$allData[] = $path ;
}
// if is readable / directory
// Beware ! recursive scan eats ressources !
else
if ( is_dir( $path ) && is_readable( $path ) )
{
/*recursive*/
$allData = recScan( $path, $allData ) ;
}
}
}
return $allData ;
}
here I have example for that
List all the files and folders in a Directory csv(file) read with PHP recursive function
<?php
/** List all the files and folders in a Directory csv(file) read with PHP recursive function */
function getDirContents($dir, &$results = array()){
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(!is_dir($path)) {
$results[] = $path;
} else if($value != "." && $value != "..") {
getDirContents($path, $results);
//$results[] = $path;
}
}
return $results;
}
$files = getDirContents('/xampp/htdocs/medifree/lab');//here folder name where your folders and it's csvfile;
foreach($files as $file){
$csv_file =$file;
$foldername = explode(DIRECTORY_SEPARATOR,$file);
//using this get your folder name (explode your path);
print_r($foldername);
if (($handle = fopen($csv_file, "r")) !== FALSE) {
fgetcsv($handle);
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$num = count($data);
for ($c=0; $c < $num; $c++) {
$col[$c] = $data[$c];
}
}
fclose($handle);
}
}
?>
http://myphpinformation.blogspot.in/2016/05/list-all-files-and-folders-in-directory-csv-file-read-with-php-recursive.html
I improved with one check iteration the good code of Hors Sujet to avoid including folders in the result array:
function getDirContents($dir, &$results = array()){
$files = scandir($dir);
foreach($files as $key => $value){
$path = realpath($dir.DIRECTORY_SEPARATOR.$value);
if(is_dir($path) == false) {
$results[] = $path;
}
else if($value != "." && $value != "..") {
getDirContents($path, $results);
if(is_dir($path) == false) {
$results[] = $path;
}
}
}
return $results;
}
I found this simple code:
https://stackoverflow.com/a/24981012
$Directory = new RecursiveDirectoryIterator($path);
$Iterator = new RecursiveIteratorIterator($Directory);
//Filter to get only PDF, JPEG, JPG, GIF, TIF files.
$Regex = new RegexIterator($Iterator, '/^.+(.jpe?g|.gif|.png|.tif|.pdf)$/i', RecursiveRegexIterator::GET_MATCH);
foreach($Regex as $val => $Regex){
echo "$val\n<br>";
}

Recursion through a directory tree in PHP

I have a set of folders that has a depth of at least 4 or 5 levels. I'm looking to recurse through the directory tree as deep as it goes, and iterate over every file. I've gotten the code to go down into the first sets of subdirectories, but no deeper, and I'm not sure why. Any ideas?
$count = 0;
$dir = "/Applications/MAMP/htdocs/site.com";
function recurseDirs($main, $count){
$dir = "/Applications/MAMP/htdocs/site.com";
$dirHandle = opendir($main);
echo "here";
while($file = readdir($dirHandle)){
if(is_dir($file) && $file != '.' && $file != '..'){
echo "isdir";
recurseDirs($file);
}
else{
$count++;
echo "$count: filename: $file in $dir/$main \n<br />";
}
}
}
recurseDirs($dir, $count);
Check out the new RecursiveDirectoryIterator.
It's still far from perfect as you can't order the search results and other things, but to simply get a list of files, it's fine.
There are simple examples to get you started in the manual like this one:
<?php
$path = realpath('/etc');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
echo "$name\n";
}
?>
There is an error in the call
recurseDirs($file);
and in
is_dir($file)
you have to give the full path:
recurseDirs($main . '/' .$file, $count);
and
is_dir($main . '/' .$file)
However, like other anwerers, I suggest to use RecursiveDirectoryIteretor.
The call to is_dir and recurseDirs is not fully correct. Also your counting didn't work correctly. This works for me:
$dir = "/usr/";
function recurseDirs($main, $count=0){
$dirHandle = opendir($main);
while($file = readdir($dirHandle)){
if(is_dir($main.$file."/") && $file != '.' && $file != '..'){
echo "Directory {$file}: <br />";
$count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting
}
else{
$count++;
echo "$count: filename: $file in $main \n<br />";
}
}
return $count;
}
$number_of_files = recurseDirs($dir);
Notice the changed calls to the function above and the new return value of the function.
So yeah: Today I was being lazy and Googled for a cookie cutter solution to a recursive directory listing and came across this. As I ended up writing my own function (as to why I even spent the time to Google for this is beyond me - I always seem to feel the need to re-invent the wheel for no suitable reason) I felt inclined to share my take on this.
While there are opinions for and against the use of RecursiveDirectoryIterator, I'll simply post my take on a simple recursive directory function and avoid the politics of chiming in on RecursiveDirectoryIterator.
Here it is:
function recursiveDirectoryList( $root )
{
/*
* this next conditional isn't required for the code to function, but I
* did not want double directory separators in the resulting array values
* if a trailing directory separator was provided in the root path;
* this seemed an efficient manner to remedy said problem easily...
*/
if( substr( $root, -1 ) === DIRECTORY_SEPARATOR )
{
$root = substr( $root, 0, strlen( $root ) - 1 );
}
if( ! is_dir( $root ) ) return array();
$files = array();
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$sub_files = recursiveDirectoryList(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
$files = array_merge( $files, $sub_files );
}
else
{
$files[] = $root . DIRECTORY_SEPARATOR . $entry;
}
}
return (array) $files;
}
With this function, the answer as to obtaining a file count is simple:
$dirpath = '/your/directory/path/goes/here/';
$files = recursiveDirectoryList( $dirpath );
$number_of_files = sizeof( $files );
But, if you don't want the overhead of an array of the respective file paths - or simply don't need it - there is no need to pass a count to the recursive function as was recommended.
One could simple amend my original function to perform the counting as such:
function recursiveDirectoryListC( $root )
{
$count = 0;
if( ! is_dir( $root ) ) return (int) $count;
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$count += recursiveDirectoryListC(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
}
else
{
$count++;
}
}
return (int) $count;
}
In both of these functions the opendir() function should really be wrapped in a conditional in the event that the directory is not readable or another error occurs. Make sure to do so correctly:
if( ( $dir_handle = opendir( $dir ) ) !== false )
{
/* perform directory read logic */
}
else
{
/* do something on failure */
}
Hope this helps someone...

Categories