class styleFinder{
function styleFinder(){
}
function getFilesNFolders($folder){
$this->folder = $folder ;
if($this->folder==""){
$this->folder = '.';
}
if ($handle = opendir($this->folder)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
echo "$file<br /> ";
if(is_dir($file)){
echo "<b>" . $file . " is a folder</b><br /> with contents ";
$this::getFilesNFolders($file);
# echo "Found folder";
}
}
}
closedir($handle);
}
}
}
I wan to print out a complete tree of folders and files, the script is going into the first folders and finding the files, then finding any sub folders, but not subfolders of those (and yes there is some). Any ideas please?
$this::getFilesNFolders($file);
Should Be
$this->getFilesNFolders($file);
Since PHP 5.1.2 you have this usefull class available: http://www.php.net/manual/en/class.recursivedirectoryiterator.php
Accessing a class function is done like this:
$this->functionName():
Since no one provided that yet, here is the RecursiveDirectoryIterator version of your code:
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('/path/to/directory'),
RecursiveIteratorIterator::SELF_FIRST);
foreach($iterator as $fileObject) {
if($fileObject->isDir()) {
echo "<strong>$fileObject is a folder:</strong><br>\n";
} else {
echo $fileObject, "<br>\n";
}
}
As others have said, within the method itself, you need to call getFilesNFolders with $this -> getFilesNFolders($file). Also, the way the code is posted you're missing a } at the end, but since there is one starting the text after the code, that is probably a typo. The code below worked for me (I ran via the command line, so added code to indent different directory levels and also to output \n's):
<?php
class StyleFinder{
function StyleFinder(){
}
function getFilesNFolders($folder, $spaces){
$this->folder = $folder ;
if($this->folder==""){
$this->folder = '.';
}
if ($handle = opendir($this->folder)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if(is_dir($file)){
echo $spaces . "<b>" . $file . " is a folder</b><br/> with contents:\n";
$this -> getFilesNFolders($file, $spaces . " ");
} else {
echo $spaces . "$file<br />\n";
}
}
}
closedir($handle);
}
}
}
$sf = new StyleFinder();
$sf -> getFilesNFolders(".", "");
?>
Related
I'd like my script to scandir recursively,
$files = scandir('/dir');
foreach($files as $file){
if(is_dir($file)){
echo '<li><label class="tree-toggler nav-header"><i class="fa fa-folder-o"></i>'.$file.'</label>';
$subfiles = scandir($rooturl.'/'.$file);
foreach($subfiles as $subfile){
// and so on and on and on
}
echo '<li>';
} else {
echo $file.'<br />';
}
}
I'd like to loop this in a way that for each dir found by scandir, it runs another scandir on the folders that have been found within that dir,
So dir 'A' contains dir 1/2/3, it should now scandir(1), scandir(2), scandir(3)
and so on for each dir found.
How can I manage to implement this easily without copy pasting the code over and over in every foreach?
EDIT: Since the answers are nearly the very same as I already tried, I'll update the question a bit.
With this script I need to create a treeview list. With the current posted scripts the following get's echo'd happens:
/images/dir1/file1.png
/images/dir1/file2.png
/images/dir1/file3.png
/images/anotherfile.php
/data/uploads/avatar.jpg
/data/config.php
index.php
What I actually need is:
<li><label>images</label>
<ul>
<li><label>dir1</label>
<ul>
<li>file1.png</li>
<li>file2.png</li>
<li>file3.png</li>
</ul>
</li>
<li>anotherfile.php</li>
</ul>
</li>
<li><label>data</label>
<ul>
<li><label>uploads</label>
<ul>
<li>avatar.jpg</li>
</ul>
</li>
<li>config.php</li>
</ul>
</li>
<li>index.php</li>
And so on, Thank you for the already posted answers!
I know this is an old question but I wrote a version of this that was more functional. It doesn't use global state and uses pure functions to figure things out:
function scanAllDir($dir) {
$result = [];
foreach(scandir($dir) as $filename) {
if ($filename[0] === '.') continue;
$filePath = $dir . '/' . $filename;
if (is_dir($filePath)) {
foreach (scanAllDir($filePath) as $childFilename) {
$result[] = $filename . '/' . $childFilename;
}
} else {
$result[] = $filename;
}
}
return $result;
}
You can scan directory recursively in this way the target is your top most directory:
function scanDir($target) {
if(is_dir($target)){
$files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned
foreach( $files as $file )
{
scanDir( $file );
}
}
}
You can adapt this function for your need easily.
For example if would use this to delete the directory and its content you could do:
function delete_files($target) {
if(is_dir($target)){
$files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned
foreach( $files as $file )
{
delete_files( $file );
}
rmdir( $target );
} elseif(is_file($target)) {
unlink( $target );
}
You can not do this in the way you are doing.
The following function gets recursively all the directories, sub directories so deep as you want and the content of them:
function assetsMap($source_dir, $directory_depth = 0, $hidden = FALSE)
{
if ($fp = #opendir($source_dir))
{
$filedata = array();
$new_depth = $directory_depth - 1;
$source_dir = rtrim($source_dir, '/').'/';
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.'))
{
continue;
}
if (($directory_depth < 1 OR $new_depth > 0) && #is_dir($source_dir.$file))
{
$filedata[$file] = assetsMap($source_dir.$file.'/', $new_depth, $hidden);
}
else
{
$filedata[] = $file;
}
}
closedir($fp);
return $filedata;
}
echo 'can not open dir';
return FALSE;
}
Pass your path to the function:
$path = 'elements/images/';
$filedata = assetsMap($path, $directory_depth = 5, $hidden = FALSE);
$filedata is than an array with all founded directories and sub directories with their content. This function lets you scan the directories structure ($directory_depth) so deep as you want as well get rid of all the boring hidden files (e.g. '.','..')
All you have to do now is to use the returned array, which is the complete tree structure, to arrange the data in your view as you like.
What you are trying to do is in fact a kind of file manager and as you know there are a lot of those in the wild, open source and free.
I hope this will help you and I wish you a merry Christmas.
function getFiles(string $directory, array $allFiles = []): array
{
$files = array_diff(scandir($directory), ['.', '..']);
foreach ($files as $file) {
$fullPath = $directory. DIRECTORY_SEPARATOR .$file;
if( is_dir($fullPath) )
$allFiles += getFiles($fullPath, $allFiles);
else
$allFiles[] = $file;
}
return $allFiles;
}
I know this is old but i wanted to show a slightly different version of the other answers. Uses array_diff to discard the "." and ".." folders. Also the + operator to combine 2 arrays ( i rarely see this used so it might be useful for someone )
Though the question is old. But my answer could help people who visit this question.
This recursively scans the directory and child directories and stores the output in a global variable.
global $file_info; // All the file paths will be pushed here
$file_info = array();
/**
*
* #function recursive_scan
* #description Recursively scans a folder and its child folders
* #param $path :: Path of the folder/file
*
* */
function recursive_scan($path){
global $file_info;
$path = rtrim($path, '/');
if(!is_dir($path)) $file_info[] = $path;
else {
$files = scandir($path);
foreach($files as $file) if($file != '.' && $file != '..') recursive_scan($path . '/' . $file);
}
}
recursive_scan('/var/www/html/wp-4.7.2/wp-content/plugins/site-backup');
print_r($file_info);
Create a scan function and call it recursively...
e.g:
<?php
function scandir_rec($root)
{
echo $root . PHP_EOL;
// When it's a file or not a valid dir name
// Print it out and stop recusion
if (is_file($root) || !is_dir($root)) {
return;
}
// starts the scan
$dirs = scandir($root);
foreach ($dirs as $dir) {
if ($dir == '.' || $dir == '..') {
continue; // skip . and ..
}
$path = $root . '/' . $dir;
scandir_rec($path); // <--- CALL THE FUNCTION ITSELF TO DO THE SAME THING WITH SUB DIRS OR FILES.
}
}
// run it when needed
scandir_rec('./rootDir');
You can do a lot variation of this function. Printing a 'li' tag instead of PHP_EOL for instance, to create a tree view.
[EDIT]
<?php
function scandir_rec($root)
{
// if root is a file
if (is_file($root)) {
echo '<li>' . basename($root) . '</li>';
return;
}
if (!is_dir($root)) {
return;
}
$dirs = scandir($root);
foreach ($dirs as $dir) {
if ($dir == '.' || $dir == '..') {
continue;
}
$path = $root . '/' . $dir;
if (is_file($path)) {
// if file, create list item tag, and done.
echo '<li>' . $dir . '</li>';
} else if (is_dir($path)) {
// if dir, create list item with sub ul tag
echo '<li>';
echo '<label>' . $dir . '</label>';
echo '<ul>';
scandir_rec($path); // <--- then recursion
echo '</ul>';
echo '</li>';
}
}
}
// init call
$rootDir = 'rootDir';
echo '<ul>';
scandir_rec($rootDir);
echo '</ul>';
Modern way:
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
$path = '/var/www/path/to/your/files/';
foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path, RecursiveDirectoryIterator::SKIP_DOTS ) ) as $file ) {
// TODO: Uncomment to see additional information. Do your manipulations with the files here.
// var_dump( $file->getPathname() ); // Or simple way: echo $file;
// var_dump( $file->isFile() );
// var_dump( $file->isDir() );
// var_dump( $file->getFileInfo() );
// var_dump( $file->getExtension() );
// var_dump( $file->getDepth() );
}
function deepScan($dir = __DIR__){
static $allFiles = [];
$allFiles[$dir] = [];
$directories = array_values(array_diff(scandir($dir), ['.', '..']));
foreach($directories as $directory){
if(is_dir("$dir\\$directory")){
foreach(deepScan("$dir\\$directory") as $key => $value) $allFiles[$key] = $value;
}
else{
$allFiles[$dir][] = "$directory";
}
}
return $allFiles;
}
I'd like my script to scandir recursively,
$files = scandir('/dir');
foreach($files as $file){
if(is_dir($file)){
echo '<li><label class="tree-toggler nav-header"><i class="fa fa-folder-o"></i>'.$file.'</label>';
$subfiles = scandir($rooturl.'/'.$file);
foreach($subfiles as $subfile){
// and so on and on and on
}
echo '<li>';
} else {
echo $file.'<br />';
}
}
I'd like to loop this in a way that for each dir found by scandir, it runs another scandir on the folders that have been found within that dir,
So dir 'A' contains dir 1/2/3, it should now scandir(1), scandir(2), scandir(3)
and so on for each dir found.
How can I manage to implement this easily without copy pasting the code over and over in every foreach?
EDIT: Since the answers are nearly the very same as I already tried, I'll update the question a bit.
With this script I need to create a treeview list. With the current posted scripts the following get's echo'd happens:
/images/dir1/file1.png
/images/dir1/file2.png
/images/dir1/file3.png
/images/anotherfile.php
/data/uploads/avatar.jpg
/data/config.php
index.php
What I actually need is:
<li><label>images</label>
<ul>
<li><label>dir1</label>
<ul>
<li>file1.png</li>
<li>file2.png</li>
<li>file3.png</li>
</ul>
</li>
<li>anotherfile.php</li>
</ul>
</li>
<li><label>data</label>
<ul>
<li><label>uploads</label>
<ul>
<li>avatar.jpg</li>
</ul>
</li>
<li>config.php</li>
</ul>
</li>
<li>index.php</li>
And so on, Thank you for the already posted answers!
I know this is an old question but I wrote a version of this that was more functional. It doesn't use global state and uses pure functions to figure things out:
function scanAllDir($dir) {
$result = [];
foreach(scandir($dir) as $filename) {
if ($filename[0] === '.') continue;
$filePath = $dir . '/' . $filename;
if (is_dir($filePath)) {
foreach (scanAllDir($filePath) as $childFilename) {
$result[] = $filename . '/' . $childFilename;
}
} else {
$result[] = $filename;
}
}
return $result;
}
You can scan directory recursively in this way the target is your top most directory:
function scanDir($target) {
if(is_dir($target)){
$files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned
foreach( $files as $file )
{
scanDir( $file );
}
}
}
You can adapt this function for your need easily.
For example if would use this to delete the directory and its content you could do:
function delete_files($target) {
if(is_dir($target)){
$files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned
foreach( $files as $file )
{
delete_files( $file );
}
rmdir( $target );
} elseif(is_file($target)) {
unlink( $target );
}
You can not do this in the way you are doing.
The following function gets recursively all the directories, sub directories so deep as you want and the content of them:
function assetsMap($source_dir, $directory_depth = 0, $hidden = FALSE)
{
if ($fp = #opendir($source_dir))
{
$filedata = array();
$new_depth = $directory_depth - 1;
$source_dir = rtrim($source_dir, '/').'/';
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.'))
{
continue;
}
if (($directory_depth < 1 OR $new_depth > 0) && #is_dir($source_dir.$file))
{
$filedata[$file] = assetsMap($source_dir.$file.'/', $new_depth, $hidden);
}
else
{
$filedata[] = $file;
}
}
closedir($fp);
return $filedata;
}
echo 'can not open dir';
return FALSE;
}
Pass your path to the function:
$path = 'elements/images/';
$filedata = assetsMap($path, $directory_depth = 5, $hidden = FALSE);
$filedata is than an array with all founded directories and sub directories with their content. This function lets you scan the directories structure ($directory_depth) so deep as you want as well get rid of all the boring hidden files (e.g. '.','..')
All you have to do now is to use the returned array, which is the complete tree structure, to arrange the data in your view as you like.
What you are trying to do is in fact a kind of file manager and as you know there are a lot of those in the wild, open source and free.
I hope this will help you and I wish you a merry Christmas.
function getFiles(string $directory, array $allFiles = []): array
{
$files = array_diff(scandir($directory), ['.', '..']);
foreach ($files as $file) {
$fullPath = $directory. DIRECTORY_SEPARATOR .$file;
if( is_dir($fullPath) )
$allFiles += getFiles($fullPath, $allFiles);
else
$allFiles[] = $file;
}
return $allFiles;
}
I know this is old but i wanted to show a slightly different version of the other answers. Uses array_diff to discard the "." and ".." folders. Also the + operator to combine 2 arrays ( i rarely see this used so it might be useful for someone )
Though the question is old. But my answer could help people who visit this question.
This recursively scans the directory and child directories and stores the output in a global variable.
global $file_info; // All the file paths will be pushed here
$file_info = array();
/**
*
* #function recursive_scan
* #description Recursively scans a folder and its child folders
* #param $path :: Path of the folder/file
*
* */
function recursive_scan($path){
global $file_info;
$path = rtrim($path, '/');
if(!is_dir($path)) $file_info[] = $path;
else {
$files = scandir($path);
foreach($files as $file) if($file != '.' && $file != '..') recursive_scan($path . '/' . $file);
}
}
recursive_scan('/var/www/html/wp-4.7.2/wp-content/plugins/site-backup');
print_r($file_info);
Create a scan function and call it recursively...
e.g:
<?php
function scandir_rec($root)
{
echo $root . PHP_EOL;
// When it's a file or not a valid dir name
// Print it out and stop recusion
if (is_file($root) || !is_dir($root)) {
return;
}
// starts the scan
$dirs = scandir($root);
foreach ($dirs as $dir) {
if ($dir == '.' || $dir == '..') {
continue; // skip . and ..
}
$path = $root . '/' . $dir;
scandir_rec($path); // <--- CALL THE FUNCTION ITSELF TO DO THE SAME THING WITH SUB DIRS OR FILES.
}
}
// run it when needed
scandir_rec('./rootDir');
You can do a lot variation of this function. Printing a 'li' tag instead of PHP_EOL for instance, to create a tree view.
[EDIT]
<?php
function scandir_rec($root)
{
// if root is a file
if (is_file($root)) {
echo '<li>' . basename($root) . '</li>';
return;
}
if (!is_dir($root)) {
return;
}
$dirs = scandir($root);
foreach ($dirs as $dir) {
if ($dir == '.' || $dir == '..') {
continue;
}
$path = $root . '/' . $dir;
if (is_file($path)) {
// if file, create list item tag, and done.
echo '<li>' . $dir . '</li>';
} else if (is_dir($path)) {
// if dir, create list item with sub ul tag
echo '<li>';
echo '<label>' . $dir . '</label>';
echo '<ul>';
scandir_rec($path); // <--- then recursion
echo '</ul>';
echo '</li>';
}
}
}
// init call
$rootDir = 'rootDir';
echo '<ul>';
scandir_rec($rootDir);
echo '</ul>';
Modern way:
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
$path = '/var/www/path/to/your/files/';
foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path, RecursiveDirectoryIterator::SKIP_DOTS ) ) as $file ) {
// TODO: Uncomment to see additional information. Do your manipulations with the files here.
// var_dump( $file->getPathname() ); // Or simple way: echo $file;
// var_dump( $file->isFile() );
// var_dump( $file->isDir() );
// var_dump( $file->getFileInfo() );
// var_dump( $file->getExtension() );
// var_dump( $file->getDepth() );
}
function deepScan($dir = __DIR__){
static $allFiles = [];
$allFiles[$dir] = [];
$directories = array_values(array_diff(scandir($dir), ['.', '..']));
foreach($directories as $directory){
if(is_dir("$dir\\$directory")){
foreach(deepScan("$dir\\$directory") as $key => $value) $allFiles[$key] = $value;
}
else{
$allFiles[$dir][] = "$directory";
}
}
return $allFiles;
}
I have searched on google and on this site for something similar to what I want but nothing fits exactly and all my efforts to adapt them have failed, I want to make a script that will map out its directory and all its subfolders and the folders be at the top of the subdirectory and files after them. So far I have come up with this:
<?php
$rawParent = scandir('.');
$parentDir = array_diff($rawParent, array('.', '..','cgi-bin','error_log'));
$arrayOfDirectories = array();
$arrayOfFiles = array();
foreach ($parentDir as $child){
if(is_dir($child)){
array_push($arrayOfDirectories,$child);
}else{
array_push($arrayOfFiles,$child);
}
}
foreach ($arrayOfDirectories as $directory){
echo $directory.'<br>';
}
echo "<br>";
foreach ($arrayOfFiles as $file){
echo "<a href='".$file."'>".$file.'</a><br>';
}
?>
It's good so far but it only does the first level of the directory, can this code be adapted to go through all levels of folders and nest them? If so how? I need a few pointers, I will further use javascript to have toggles on the folders to see the contents, so I will need PHP to output something nested.
Sorry if I am not making much sense, don't really know how to explain.
Use recursive function like this :
<?php
function list_directory($directory)
{
$the_directory = opendir($directory) or die("Error $directory doesn't exist");
while($file = #readdir($the_directory))
{
if ($file == "." || $file == "..") continue;
if(is_dir($directory.'/'.$file))
{
print '<ul>'.$directory.'/'.$file;
list_directory($directory.'/'.$file);
print '</ul>';
}
else
{
print "<li> $file </li>";
}
}
closedir($the_directory);
}
$path_to_search = '/var/www';
list_directory($path_to_search);
?>
Version with storage in array :
<?php
function list_directory($directory, &$storage)
{
$the_directory = opendir($directory) or die("Error $directory doesn't exist");
while($file = #readdir($the_directory))
{
if ($file == "." || $file == "..") continue;
if(is_dir($directory.'/'.$file))
{
list_directory($directory.'/'.$file, $storage);
}
else
{
$storage[] = $file;
}
}
closedir($the_directory);
}
$storage = array();
$path_to_search = '/var/www';
list_directory($path_to_search, $storage);
echo '<pre>', print_r($storage,true) , '</pre>';
?>
This will do what you asked for, it only returns the sub directory names in a given path, and you can make hyperlinks and use them.
$yourStartingPath = "your string path";
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($yourStartingPath),
RecursiveIteratorIterator::SELF_FIRST);
foreach($iterator as $file) {
if($file->isDir()) {
$path = strtoupper($file->getRealpath()) ;
$path2 = PHP_EOL;
$path3 = $path.$path2;
$result = end(explode('/', $path3));
echo "<br />". basename($result);
}
}
I have a piece of code that I would like to modify to list all files in folders and sub-folders in the current path. I have found several possible solutions. I tried to implement them actually, but nothing seemed to work so I am not sure if they are actually working or not or it was just me implemented them wrong. Either way this is my current code:
<?php
$currentdir = 'C:/xampp/htdocs/test/'; //change to your directory
$dir = opendir($currentdir);
echo '<select name="workout">';
$file = preg_grep('/^([^.])/', scandir($dir));
while($file = readdir($dir))
{
if ($file != "." && $file != "..") {
echo "<option value='$file'>$file</option>";
}
else {
continue;
}
}
echo '</select>';
closedir($dir);
?>
Currently this code shows results:
$currentdir
Option1
Option2
Option3
SUB-FOLDER1
SUB-FOLDER2
Can someone help me and show me how to write/rewrite the code using existing one to display files from folders and other sub-folders to look something like this:
$currentdir
Option1
Option2
Option3
SUB-FOLDER1
Option1
Option2
Option3
SUB-FOLDER2
Option1
Option2
Option3
I became really desperate for a solution and thank you all in advance.
While the other answers are fine and correct, allow me to add my solution as well:
function dirToOptions($path = __DIR__, $level = 0) {
$items = scandir($path);
foreach($items as $item) {
// ignore items strating with a dot (= hidden or nav)
if (strpos($item, '.') === 0) {
continue;
}
$fullPath = $path . DIRECTORY_SEPARATOR . $item;
// add some whitespace to better mimic the file structure
$item = str_repeat(' ', $level * 3) . $item;
// file
if (is_file($fullPath)) {
echo "<option>$item</option>";
}
// dir
else if (is_dir($fullPath)) {
// immediatly close the optgroup to prevent (invalid) nested optgroups
echo "<optgroup label='$item'></optgroup>";
// recursive call to self to add the subitems
dirToOptions($fullPath, $level + 1);
}
}
}
echo '<select>';
dirToOptions();
echo '</select>';
It uses a recursive call to fetch the subitems. Note that I added some whitespace before each item to better mimic the file structure. Also I closed the optgroup immediatly, to prevent ending up with nested optgroup elements, which is invalid HTML.
Find all the files and folders under a specified directory.
function scanDirAndSubdir($dir, &$out = []) {
$sun = scandir($dir);
foreach ($sun as $a => $filename) {
$way = realpath($dir . DIRECTORY_SEPARATOR . $filename);
if (!is_dir($way)) {
$out[] = $way;
} else if ($filename != "." && $filename != "..") {
scanDirAndSubdir($way, $out);
$out[] = $way;
}
}
return $out;
}
var_dump(scanDirAndSubdir('C:/xampp/htdocs/test/'));
Sample :
array (size=4)
0 => string 'C:/xampp/htdocs/test/text1.txt' (length=30)
1 => string 'C:/xampp/htdocs/test/text1.txt' (length=30)
2 => string 'C:/xampp/htdocs/test/subfolder1/text8.txt' (length=41)
3 => string 'C:/xampp/htdocs/test/subfolder4/text9.txt' (length=41)
Use DirectoryIterator for looking into folder here is my approch
$di = new DirectoryIterator("/dir");
foreach($di as $dir){
if ($dir->isDot()) continue;
echo "<option value='", $dir->getFilename(), "'>", $dir->getFilename(), "</option>";
}
anyway for looking into sub directories as well
$ri = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($ri as $dir){
if ($dir->isDot()) continue;
echo "<option value='", $dir->getFilename(), "'>", $dir->getFilename(), "</option>";
}
In case you don't want to use above statement then this another alternative:
<?php
function listdir($currentdir){
$dir = opendir($currentdir);
$file = readdir($dir);
echo "<optgroup label='$currentdir'>";
do {
if (is_dir($currentdir."/".$file) && $file != "." && $file != ".."){
listdir($currentdir."/".$file);
echo $currentdir."/".$file;
} else if($file != "." && $file != "..") {
echo "<option value='$file'>$file</option>";
} else {
continue;
}
} while($file = readdir($dir));
echo "</optgroup>";
closedir($dir);
}
echo '<select name="workout">';
listdir('/var/www'); //change to your directory
echo '</select>';
?>
I want to list the contents of a folder in php.
But i would like to display only the folder and not the files.
In addition, i would like to display a maximum of one sub-folder!
Could you help me please !
My code :
<?php
function mkmap($dir){
echo "<ul>";
$folder = opendir ($dir);
while ($file = readdir ($folder)) {
if ($file != "." && $file != "..") {
$pathfile = $dir.'/'.$file;
echo "<li><a href=$pathfile>$file</a></li>";
if(filetype($pathfile) == 'dir'){
mkmap($pathfile);
}
}
}
closedir ($folder);
echo "</ul>";
}
?>
<?php mkmap('.'); ?>
Pass the maximum recursion level to the function. This way you can decide how many levels deep you want to go, at runtime.
Also, it would be a good idea (I think) to have the "I want the dirs or maybe not" decision done externally and passed as a parameter. This way one function can do both.
And finally it's rarely a good idea having a function output HTML. It's best to return it as a string, so that you're more free to move code around. Ideally, you want to have all your logic separated from your presentation View (and more than that; google 'MVC').
Even better would be to pass a HTML template to the mkmap function and have it use that to create the HTML snippet. This way, if in one place you want a <ul> and in another a <ul id="another-tree" class="fancy">, you needn't use two versions of the same function; but that's probably overkill (you might do it easily with str_replace, or XML functions, though, if you ever need it).
function mkmap($dir, $depth = 1, $only_dirs = True){
$response = '<ul>';
$folder = opendir ($dir);
while ($file = readdir ($folder)) {
if ($file != '.' && $file != '..') {
$pathfile = $dir.'/'.$file;
if ($only_dirs && !is_dir($pathfile))
continue;
$response .= "<li>$file</li>";
if (is_dir($pathfile) && ($depth !== 0))
$response .= mkmap($file, $depth - 1, $only_dirs);
}
}
closedir ($folder);
$response .= '</ul>';
return $response;
}
// Reach depth 5
echo mkmap('Main Dir', 5, True);
// The explicit check for depth to be different from zero means
// that if you start with a depth of -1, it will behave as "infinite depth",
// which might be desirable in some use cases.
Templating
There's many way of templating the function, but maybe the simplest is this (for more elaborate customization, XML is mandatory - managing HTML with string functions has nasty space-time continuum implications):
function mkmap($dir, $depth = 1, $only_dirs = True,
$template = False) {
if (False === $template) {
$template = array('<ul>','<li>{file}</li>','</ul>');
}
$response = '';
$folder = opendir ($dir);
while ($file = readdir ($folder)) {
if ($file != '.' && $file != '..') {
$pathfile = $dir.'/'.$file;
if ($only_dirs && !is_dir($pathfile))
continue;
$response .= str_replace(array('{path}','{file}'), array($pathfile, $file), $template[1]);
if (is_dir($pathfile) && ($depth !== 0))
$response .= mkmap($file, $depth - 1, $only_dirs, $template);
}
}
closedir ($folder);
return $template[0] . $response . $template[2];
}
The function works like before, but you can pass a further argument to customize it:
echo mkmap('Main Dir', 5, True, array(
'<ul class="filetree">',
'<li><img src="file.png" /><tt>{file}</tt></li>',
'</ul>'));
To check if a file is a folder use is_dir() function.
This recursive solution will list folders and subfolders :
<?php
function mkmap($dir){
$ffs = scandir($dir);
echo '<ul>';
foreach($ffs as $file){
if($file != '.' && $file!= '..' ){
$path=$dir.'/'.$file;
echo "<li><a href='".$path."'>$file</a></li>";
if(is_dir($dir.'/'.$file)) mkmap($dir.'/'.$file);
}
}
echo '</ul>';
}
mkmap('main dir');
?>