0

I'm currently using the following code to list all of the subdirectories within a specific directory.

$dir = realpath('custom_design_copy/');

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::SELF_FIRST);

foreach($objects as $name => $object){
    if(is_dir($object)){
        echo "$name<br />";
    }
}

This gives me results that look something like this.

C:\Data\Web\custom_design_copy\Product
C:\Data\Web\custom_design_copy\Product\images
C:\Data\Web\custom_design_copy\Product\Scripts

What I want to do is rename all of these subdirectories with strtoupper() in order to normalize all of their names. I'm aware of the rename() function but I fear that if I try the following:

rename($name, strtoupper($name));

I'll wind up modifying one of custom_design_copy's parent directory names, which is what I hope to avoid. How can I avoid this issue? I was considering using substr() and searching for the last occurrence of "\" in order to isolate the directory name at the end, but there has to be an easier solution to this. The end result I'm looking for is this.

C:\Data\Web\custom_design_copy\PRODUCT
C:\Data\Web\custom_design_copy\PRODUCT\IMAGES
C:\Data\Web\custom_design_copy\PRODUCT\SCRIPTS

EDIT: While waiting for advice, I attempted my initial approach and found that it worked.

$dir = realpath('custom_design_copy/');

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::SELF_FIRST);

foreach($objects as $name => $object){
    if(is_dir($object)){
        $slashPos = strrpos($name, '\\');
        $newName  = substr($name, 0, $slashPos + 1) . strtoupper(substr($name, $slashPos + 1));

        rename($name, $newName);

        echo "$name<br />";
    }
}
user3308219
  • 157
  • 2
  • 11
  • 1
    Why don't you check if the path is one of the paths that you don't want to rename and just ignore them? – Spoody Apr 25 '18 at 16:54
  • The only part I don't want to rename is `C:\Data\Web\custom_design_copy`. Everything after that should be capitalized but I don't know how to properly isolate it. I already have it so that I only pull directories from within custom_design_copy. – user3308219 Apr 25 '18 at 18:44

2 Answers2

1

Your example uses the RecursiveIteratorIterator::SELF_FIRST flag, which lists leaves and parents in iteration with parents coming first (from the docs).

This means that with a directory structure like:

foo/
foo/bar/
foo/bar/bat.txt

The iteration order is from parents towards leaves:

  1. foo/
  2. foo/bar/
  3. foo/bat/bat.txt

This can be problematic, as you have noted already.


For your needs, the RecursiveIteratorIterator::CHILD_FIRST flag should be used. This flag instructs the iterator to go in the other direction, from leaves towards parents.

  1. foo/bar/bat.txt
  2. foo/bar/
  3. foo/
salathe
  • 51,324
  • 12
  • 104
  • 132
0

You can store all directories in an array and after that you can loop the array in descending order changing the last folder to uppercase.

Here is an example:

$path = 'custom_design_copy' . DIRECTORY_SEPARATOR;

$main_dir = realpath($path);

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($main_dir), RecursiveIteratorIterator::SELF_FIRST);

foreach ($objects as $name => $object) {

    if ($object->isDir() && !in_array($object->getFilename(), array('.', '..'))) {

        $directories[] = $name;

    }
}

foreach (array_reverse($directories) as $dir) {
    rename($dir, last_path_upper($dir));
}

function last_path_upper($str) {

    $arr = explode(DIRECTORY_SEPARATOR, $str);

    $last = array_pop($arr);

    return join(DIRECTORY_SEPARATOR, $arr) . DIRECTORY_SEPARATOR . strtoupper($last);

}
  • I haven't tested this one but I'm sure it works. While I was waiting, I tried the initial approach I planned on using and to my surprise, it worked as expected. I'll edit my post momentarily. – user3308219 Apr 25 '18 at 19:19