简体   繁体   中英

Rename all subdirectories within a directory recursively

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 />";
    }
}

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/

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);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM