2009-12-02 4 views
6

Я работаю над функцией PHP, которая будет рекурсивно удалять все подпапки, которые не содержат файлов, начинающихся с данного абсолютного пути.Удалить пустые подпапки с PHP

Вот код, разработанный до сих пор:

function RemoveEmptySubFolders($starting_from_path) { 

    // Returns true if the folder contains no files 
    function IsEmptyFolder($folder) { 
     return (count(array_diff(glob($folder.DIRECTORY_SEPARATOR."*"), Array(".", ".."))) == 0); 
    } 

    // Cycles thorugh the subfolders of $from_path and 
    // returns true if at least one empty folder has been removed 
    function DoRemoveEmptyFolders($from_path) { 
     if(IsEmptyFolder($from_path)) { 
      rmdir($from_path); 
      return true; 
     } 
     else { 
      $Dirs = glob($from_path.DIRECTORY_SEPARATOR."*", GLOB_ONLYDIR); 
      $ret = false; 
      foreach($Dirs as $path) { 
       $res = DoRemoveEmptyFolders($path); 
       $ret = $ret ? $ret : $res; 
      } 
      return $ret; 
     } 
    } 

    while (DoRemoveEmptyFolders($starting_from_path)) {} 
} 

По моим тестам эта функция работает, хотя я был бы очень рад видеть какие-либо идеи для лучшего кода исполнительской.

+2

Так что это вопрос? –

+0

@Ben - от TS - «Я был бы очень рад увидеть любые идеи для лучшего выполнения кода». – mauris

+0

Возможно, лучше опубликуйте это на http://refactormycode.com/? – ChristopheD

ответ

20

Если у вас пустая папка в пустой папке в пустой папке, вам нужно будет пропустить все папки три раза. Все это, потому что вы сначала выбираете ширину - тестовую папку перед тестированием своих детей. Вместо этого вы должны перейти в дочерние папки перед тестированием, если родительский пуст, таким образом, одного прохода будет достаточно.

function RemoveEmptySubFolders($path) 
{ 
    $empty=true; 
    foreach (glob($path.DIRECTORY_SEPARATOR."*") as $file) 
    { 
    if (is_dir($file)) 
    { 
     if (!RemoveEmptySubFolders($file)) $empty=false; 
    } 
    else 
    { 
     $empty=false; 
    } 
    } 
    if ($empty) rmdir($path); 
    return $empty; 
} 

К слову, glob не возвращается. и .. записи.

Сокращенный вариант:

function RemoveEmptySubFolders($path) 
{ 
    $empty=true; 
    foreach (glob($path.DIRECTORY_SEPARATOR."*") as $file) 
    { 
    $empty &= is_dir($file) && RemoveEmptySubFolders($file); 
    } 
    return $empty && rmdir($path); 
} 
+0

Отличный алгоритм! Для того, чтобы функция работала, нужно исправить две небольшие ошибки: 1. В инструкции foreach переменная $$ должна быть изменена на $ path. 2. Файл $ file должен передаваться как параметр для вызова рекурсивной функции вместо $ start_from_path. –

+0

Обратите внимание, что если ваша функция работает под Linux, скрытые вспомогательные каталоги (с именами, начинающимися с точки) также ошибочно будут сопоставляться как «пустые» каталоги. – Werner

+1

Как это можно изменить так, чтобы он не удалял корневую папку? Если исходный $ path содержит только пустые папки, то он тоже удаляется. Нет ничего страшного, мне просто любопытно :) – swl1020

1

Эта линия

$ret = $ret ? $ret : $res; 

Может быть немного более читаемым:

$ret = $ret || $res; 

Или, если PHP имеет оператор побитового:

$ret |= $res; 
0

Это будет означать неприятности, потому что вызов RemoveEmptySubFolders несколько раз, вероятно, будут исправлять ошибки, потому что каждый раз, когда вы вызываете функцию, остальные 2 функции определены снова. Если они уже определены, PHP будет вызывать ошибку, заявив, что функция с тем же именем уже определена.

Вместо этого попробуйте рекурсивно:

function removeEmptySubfolders($path){ 

    if(substr($path,-1)!= DIRECTORY_SEPARATOR){ 
    $path .= DIRECTORY_SEPARATOR; 
    } 
    $d2 = array('.','..'); 
    $dirs = array_diff(glob($path.'*', GLOB_ONLYDIR),$d2); 
    foreach($dirs as $d){ 
    removeEmptySubfolders($d); 
    } 

    if(count(array_diff(glob($path.'*'),$d2))===0){ 
    rmdir($path); 
    } 

} 

испытано, работает хорошо. Windows 7 PHP 5.3.0 XAMPP

+0

Ну, конечно, если проверка того, является ли папка пустой, производится после рекурсивного вызова, это позволит использовать гораздо более эффективный алгоритм ...Позор мне: - | Вы тоже были правы в проблеме с функциями вложенности, PHP вызывает фатальную ошибку при втором вызове внешней функции. Спасибо большое! –

+0

если он отвечает, поставьте галочку =) – mauris

+0

Готово. Я должен сказать, что код, предложенный yu_sha, кажется, лучше отвечает на мой вопрос с точки зрения повышения производительности, и я бы отметил его как принятый ответ, при условии, что в коде не будет ошибок, поэтому его можно было бы скопировать. –

0

Вы можете попробовать это.

function removeEmptySubfolders($path){ 

    if(substr($path,-1)!= DIRECTORY_SEPARATOR){ 
    $path .= DIRECTORY_SEPARATOR; 
    } 
    $d2 = array('.','..'); 
    $dirs = array_diff(glob($path.'*', GLOB_ONLYDIR),$d2); 
    foreach($dirs as $d){ 
    removeEmptySubfolders($d); 
    } 

    if(count(array_diff(glob($path.'*'),$d2))===0){ 
    $checkEmpSubDir = explode(DIRECTORY_SEPARATOR,$path); 
    for($i=count($checkEmpSubDir)-1;$i>0;$i--){ 
     $path = substr(str_replace($checkEmpSubDir[$i],"",$path),0,-1); 

     if(($files = @scandir($path)) && count($files) <= 2){ 
     rmdir($path); 
     } 
    } 
    } 
} 
1

Вы можете выполнить команду unix для удаления пустых каталогов.

exec ("find $ start_from_path -type d -empty -exec rmdir {} \; 2>/dev/null");

+1

Почему бы просто не найти 'dir -empty -type d -delete'? – Pavel

+0

Нет, вы не можете. Потому что НИКОГДА НИКОГДА не используйте функцию «exec». Это опасно и должно быть отключено в любой среде веб-сервера. Единственное приемлемое использование - при использовании php-cli. – Geeklab

0

Solution для Linux, используя инструмент командной строки, но быстрее и проще, чем с чистым PHP

/** 
* Remove all empty subdirectories 
* @param string $dirPath path to base directory 
* @param bool $deleteBaseDir - Delete also basedir if it is empty 
*/ 
public static function removeEmptyDirs($dirPath, $deleteBaseDir = false) { 

    if (stristr($dirPath, "'")) { 
     trigger_error('Disallowed character `Single quote` (\') in provided `$dirPath` parameter', E_USER_ERROR); 
    } 

    if (substr($dirPath, -1) != '/') { 
     $dirPath .= '/'; 
    } 

    $modif = $deleteBaseDir ? '' : '*'; 
    exec("find '".$dirPath."'".$modif." -empty -type d -delete", $out); 
} 

Если вам нужна поддержка Windows, использовать PHP_OS константу, и это один вкладыш

for /f "delims=" %d in ('dir /s /b /ad ^| sort /r') do rd "%d"`enter code here