Jump to content

Recursive function and too many foreach loop tangled


learner007

Recommended Posts

I been banging my head over this for sometimes now, But I cant get the result I am after, I was hoping someone can liberate me from the forever circle of mistakes..

function file_match($file_path, array $patterns) {
    
    $files = array_diff(scandir($file_path), array('.', '..'));   
    
    foreach($files as $file) {
        
         $full_path = $file_path . DIRECTORY_SEPARATOR . $file; 
        
        foreach($patterns as $pattern) {
            
            if (is_file($full_path)) {
                
               if (fnmatch(strtolower($pattern), $file)) {
                
                echo $file;
                echo "<br>";
                }
            
            } elseif (is_dir($full_path)) {
                
                echo $file;
                echo "<br>";
                
                file_match($full_path, $pattern);
            }
            
        }

    }
          
}

$file_path = 'X:/testfolder1/Monthly Files';

echo file_match($file_path, ['*.doc', '*.zip', '*.pdf]);

Expecting result:

 

Directory1

List of files resides inside this directory

 

Directory 2

List of files Resides inside this directory

 

etc

 

like:

 

This is what it should be:

Monthly Files
Test File Main 2.PDF
Test File Main 1.doc

January Files
File January 1.PDF
File January 2.zip

February Files
Files February 1.PDF
Files February 2.PDF

 

etc

Edited by learner007
Link to comment
Share on other sites

Note that PHP has several iterators and functions which can traverse directories just fine (and even filter the filenames). There's really no reason to implement that yourself.

Someone (I think it was me) originally suggested the RecursiveDirectoryIterator in another thread, but the output requirements made it easier to use scandir/glob and do the recursion manually.

 

...at least that's what I remember. I thought it was supposed to show files before directories too, but the posted code won't do that.

Link to comment
Share on other sites

Someone (I think it was me) originally suggested the RecursiveDirectoryIterator in another thread, but the output requirements made it easier to use scandir/glob and do the recursion manually.

 

...at least that's what I remember. I thought it was supposed to show files before directories too, but the posted code won't do that.

Mr requinix, I've posted this on devshed, I've taken your suggestions and got the codes to work this far, now stuck to this point. I've never done nested foreach loop before, I cant get foreach loop to behave correctly, listing same file and directory more than once? Also the root directory name should show on top and files inside it should show just below it but instead just get listed anywhere in the list of files.

 

After correcting the file_match($full_path, $patterns)

 

Also I've renamed few files so that I can follow what directory they belong to.

 

 

The output result I got:

 

February Files

February File 1.pdf

February File 2.pdf

February Files

February File 1.pdf

February File 2.pdf

February Files

February File 1.pdf

February File 2.pdf

File List.pdf

January Files

January File 1.pdf

January File 2.pdf

January Files

January File 1.pdf

January File 2.pdf

January Files

January File 1.pdf

January File 2.pdf

Read First.pdf

Zip File.zip

word.docx

 
 
Output should be like this:
 
 
Monthly Files
Read First.pdf

Zip File.zip

word.docx

 
January Files

January File 1.pdf

January File 2.pdf

 
February Files

February File 1.pdf

February File 2.pdf

Edited by learner007
Link to comment
Share on other sites

Oh, right, that was it.

 

 

If you want to separate files and directories then you need to separate the files from the directories: go through the directory putting files into one array and directories into another. Afterwards you can print out all the files and then all the directories.

// obviously not actual php code:

files = []
directories = []
for each thing in directory {
	if thing is file {
		files[] = thing
	} else {
		directories[] = thing
	}
}

for each file in files {
	show file
}

for each dir in directories {
	show header
	call file_match recursively
}
But since scandir() does not sort filenames, you'll need to do that yourself with sort() - before the output happens. You could use glob, which does sort, but it also returns the full file path so one way or another you'll have an extra line of code somewhere.

sort($files);
Link to comment
Share on other sites

Oh, right, that was it.

 

I hope I am not confusing you? I dont want the results to have all files in one list and all directories in separate list. I dont mind the way code is listing the files and directories, but it is duplicating the results, if you look at my previous post you can see the files and directories of same name listing several times. How to fix that?

Link to comment
Share on other sites

So, how does this not do what you want:

<?php

const PATH = 'X:/testfolder1/Monthly Files';
const EXTENSIONS = ['doc', 'zip', 'pdf'];

$dirIterator = new RecursiveDirectoryIterator(PATH, RecursiveDirectoryIterator::SKIP_DOTS);
$fileIterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST);

foreach ($fileIterator as $file)
{
    if ($file->isDir() || ($file->isFile() && in_array(strtolower($file->getExtension()), EXTENSIONS)))
    {
        echo "$file<br>";
    }
}
Edited by Jacques1
Link to comment
Share on other sites

 

So, how does this not do what you want:

<?php

const PATH = 'X:/testfolder1/Monthly Files';
const EXTENSIONS = ['doc', 'zip', 'pdf'];

$dirIterator = new RecursiveDirectoryIterator(PATH, RecursiveDirectoryIterator::SKIP_DOTS);
$fileIterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST);

foreach ($fileIterator as $file)
{
    if ($file->isDir() || ($file->isFile() && in_array(strtolower($file->getExtension()), EXTENSIONS)))
    {
        echo "$file<br>";
    }
}

 

 

This will work, with basename this will list the directories and files.

const PATH = 'X:/testfolder1/Monthly Files';
const EXTENSIONS = ['doc', 'zip', 'pdf'];

$dirIterator = new RecursiveDirectoryIterator(PATH, RecursiveDirectoryIterator::SKIP_DOTS);
$fileIterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST);

    
    echo basename(PATH);
    echo "<br><br>";

foreach ($fileIterator as $file)
{
    if ($file->isDir() || ($file->isFile() && in_array(strtolower($file->getExtension()), EXTENSIONS)))
    {
        echo basename($file)."<br>";
    }
}

output:

 

Monthly Files <------------root folder

 

February Files <----------------sub folder

February File 1.pdf

February File 2.pdf

File List.pdf <--------------root files

January Files <------------- sib folder

January File 1.pdf

January File 2.pdf

Read First.pdf <----------- root file

Zip File.zip <--------------- root file

 

How can I achieve this: List any root files in the root folder listing first, Then any sub folder and its contents listing?

 

Monthly Files <------------root folder

Read First.pdf <----------- root file

Zip File.zip <--------------- root file

File List.pdf <--------------root file

 

February Files <----------------sub folder

February File 1.pdf

February File 2.pdf

 

January Files <---------sub folder

January File 1.pdf

January File 2.pdf

 

Edited by learner007
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.