Wie kann ich mit PHP prüfen, ob ein Verzeichnis leer ist?

83

Ich verwende das folgende Skript, um ein Verzeichnis zu lesen. Wenn sich keine Datei im Verzeichnis befindet, sollte leer angezeigt werden. Das Problem ist, es wird immer wieder gesagt, dass das Verzeichnis leer ist, obwohl sich darin Dateien befinden und umgekehrt.

<?php
$pid = $_GET["prodref"];
$dir = '/assets/'.$pid.'/v';
$q   = (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
    
if ($q=="Empty") 
    echo "the folder is empty"; 
else
    echo "the folder is NOT empty";
?>
TheBlackBenzKid
quelle
8
Es ist nur ein Tippfehler in Ihrer if-Anweisung. Verwenden Sie == (vergleichen) anstelle von single = (zuweisen).
Bas Slagter

Antworten:

134

Es scheint, dass Sie scandiranstelle von glob benötigen , da glob keine versteckten Unix-Dateien sehen kann.

<?php
$pid = basename($_GET["prodref"]); //let's sanitize it a bit
$dir = "/assets/$pid/v";

if (is_dir_empty($dir)) {
  echo "the folder is empty"; 
}else{
  echo "the folder is NOT empty";
}

function is_dir_empty($dir) {
  if (!is_readable($dir)) return NULL; 
  return (count(scandir($dir)) == 2);
}
?>

Beachten Sie, dass dieser Code nicht der Höhepunkt der Effizienz ist, da nicht alle Dateien gelesen werden müssen, um festzustellen, ob das Verzeichnis leer ist. Die bessere Version wäre also

function dir_is_empty($dir) {
  $handle = opendir($dir);
  while (false !== ($entry = readdir($handle))) {
    if ($entry != "." && $entry != "..") {
      closedir($handle);
      return FALSE;
    }
  }
  closedir($handle);
  return TRUE;
}

Verwenden Sie übrigens keine Wörter, um boolesche Werte zu ersetzen . Der eigentliche Zweck des letzteren ist es, Ihnen zu sagen, ob etwas leer ist oder nicht. Ein

a === b

Ausdruck bereits zurückkehrt Emptyoder Non Emptyin Bezug auf die Programmiersprache, FALSEoder TRUEjeweils - so können Sie die in Kontrollstrukturen sehr ergeben verwenden wie IF()ohne Zwischenwerte

Ihr gesunder Menschenverstand
quelle
2
Ich denke, unser Code ist falsch, weil ich alle Dateien aus dem Ordner entfernt habe und immer noch steht, dass der Ordner nicht leer ist. Gibt es eine Möglichkeit, unter Linux nach versteckten Dateien wie thumbs.db usw. zu suchen?
TheBlackBenzKid
Ich denke der FTP-Ordner ist sagen .. und. in der Datei ist leer. Wie kann ich überprüfen, ob und entfernen Sie die .. und thumbs.db etc?
TheBlackBenzKid
glob unterstützt keine versteckten Linux-Dateien. Wenn Sie sie wollen, müssen Sie sich für eine Openir-Lösung entscheiden, wie in der gelöschten Antwort
Your Common Sense
es scheint, dass Sie Scandir anstelle von Glob brauchen.
Ihr gesunder Menschenverstand
2
Erstellen Sie eine Testumgebung. Erstellen Sie ein leeres Verzeichnis in demselben Ordner, in dem sich das Skript befindet. $dir = 'testfolder';manuell machen . Führen Sie dann diesen Code aus. Beim Debuggen werden so viele Informationen wie möglich ausgedruckt, um festzustellen, was falsch läuft. $dir = 'testfolder';var_dump(scan_dir($dir));wird Ihnen sagen, was in diesem Verzeichnis ist
Ihr gesunder Menschenverstand
69

Ich denke mit dem FilesystemIterator sollte der schnellste und einfachste Weg sein:

// PHP 5 >= 5.3.0
$iterator = new \FilesystemIterator($dir);
$isDirEmpty = !$iterator->valid();

Oder Verwenden des Zugriffs für Klassenmitglieder bei der Instanziierung:

// PHP 5 >= 5.4.0
$isDirEmpty = !(new \FilesystemIterator($dir))->valid();

Dies funktioniert, da eine neue FilesystemIteratorDatei zunächst auf die erste Datei im Ordner verweist. Wenn sich keine Dateien im Ordner befinden, valid()wird zurückgegebenfalse . (siehe Dokumentation hier .)

Überprüfen Sie, wie von abdulmanov.ilmir ausgeführt, optional, ob das Verzeichnis vorhanden ist, bevor Sie das verwenden, FileSystemIteratorda es sonst ein Verzeichnis auslöst UnexpectedValueException.

Grippe
quelle
7
Mmm ... Kribbeln in meinen Lenden für diesen einen.
Matt Fletcher
3
Sie sollten berücksichtigen, dass $direine Ausnahme ausgelöst wird , wenn sie nicht vorhanden ist.
abdulmanov.ilmir
10

Ich habe eine schnelle Lösung gefunden

<?php
  $dir = 'directory'; // dir path assign here
  echo (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
?>
Frank
quelle
Die Lösung verwende ich in PHP 5.2 für den einfachen Fall.
Lucas Morgan
Beachten Sie, dass glob keine versteckten Dateien sieht. Ein Verzeichnis mit ".htaccess" wird mit diesem Code als leer behandelt
rosell.dk
7

verwenden

if ($q == "Empty")

Anstatt von

if ($q="Empty")
Toto
quelle
5

Für einen objektorientierten Ansatz mit der RecursiveDirectoryIteratoraus der Standard PHP Library (SPL) .

<?php

namespace My\Folder;

use RecursiveDirectoryIterator;

class FileHelper
{
    /**
     * @param string $dir
     * @return bool
     */
    public static function isEmpty($dir)
    {
        $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
        return iterator_count($di) === 0;
    }
}

Sie müssen keine Instanz von Ihrer FileHelpererstellen, wann immer Sie sie benötigen. Sie können auf diese statische Methode zugreifen, wo immer Sie sie benötigen:

FileHelper::isEmpty($dir);

Die FileHelperKlasse kann um andere nützliche Methoden zum Kopieren, Löschen, Umbenennen usw. erweitert werden.

Es ist nicht erforderlich, die Gültigkeit des Verzeichnisses innerhalb der Methode zu überprüfen, da der Konstruktor des Verzeichnisses, wenn es ungültig ist, ein Element RecursiveDirectoryIteratorauslöst UnexpectedValueException, das diesen Teil ausreichend abdeckt.

Verwelken
quelle
4

Versuche dies:

<?php
$dirPath = "Add your path here";

$destdir = $dirPath;

$handle = opendir($destdir);
$c = 0;
while ($file = readdir($handle)&& $c<3) {
    $c++;
}

if ($c>2) {
    print "Not empty";
} else {
    print "Empty";
} 

?>
Drmzindec
quelle
Vielen Dank! Ich habe es ziemlich schnell geschrieben und es ist mein erster Beitrag hier @Piotr Nowicki
Drmzindec
Klar Kumpel, es ist nur meine Bürgerpflicht ;-) Willkommen bei StackOverflow!
Piotr Nowicki
4

Wahrscheinlich wegen Zuweisungsoperator in ifAnweisung.

Veränderung:

if ($q="Empty")

Zu:

if ($q=="Empty")
Robik
quelle
4

Dies ist ein sehr alter Thread, aber ich dachte, ich würde meine zehn Cent geben. Die anderen Lösungen haben bei mir nicht funktioniert.

Hier ist meine Lösung:

function is_dir_empty($dir) {
    foreach (new DirectoryIterator($dir) as $fileInfo) {
        if($fileInfo->isDot()) continue;
        return false;
    }
    return true;
}

Kurz und bündig. Klappt wunderbar.

Narfie
quelle
4

@ Ihr gesunder Menschenverstand

Ich denke, Ihr performantes Beispiel könnte mit einem strengen Vergleich performanter sein:

function is_dir_empty($dir) {
  if (!is_readable($dir)) return null; 
  $handle = opendir($dir);
  while (false !== ($entry = readdir($handle))) {
    if ($entry !== '.' && $entry !== '..') { // <-- better use strict comparison here
      closedir($handle); // <-- always clean up! Close the directory stream
      return false;
    }
  }
  closedir($handle); // <-- always clean up! Close the directory stream
  return true;
}
André Fiedler
quelle
1
Guter Punkt in Bezug auf Aufräumen: Der return falseFall kümmert sich nicht darum ;-)
Beat Christen
@BeatChristen Thx für den Hinweis! Repariert.
André Fiedler
Was ich nicht verstehe, ist, warum Sie sagen, dass es besser ist, einen strengen Vergleich zu verwenden, wenn Sie mit "vergleichen". und "..". Die Funktion readdir () gibt immer einen String (oder den Wert false) zurück, sodass ich den Punkt nicht sehe. Ich möchte auch hinzufügen, dass das Aufräumen nach sich selbst in der Tat immer eine gute Idee ist. Man würde denken, dass nach der Rückkehr, wenn die Variable $ handle den Gültigkeitsbereich verlässt, Closedir () automatisch erfolgt, aber ich habe gerade ein kleines Testprogramm geschrieben. und das tut es nicht. Was seltsam ist, weil andere Dinge wie Herde automatisch passieren.
Soger
@ AndréFiedler Du bist eine geniale, brillante und verantwortungsbewusste Person. Bei allen anderen Antworten berechnen sie zuerst die Gesamtzahl der Dateien und prüfen dann, ob die Anzahl> 0 ist. Wenn ein Verzeichnis jedoch nur eine Datei enthält, ist es nicht leer.
Ashish Doneriya
4

Ich benutzte:

if(is_readable($dir)&&count(scandir($dir))==2) ... //then the dir is empty
Luca C.
quelle
3

Die Funktionsnutzung kann countbei großen Arrays langsam sein.issetist immer schneller

Dies funktioniert ordnungsgemäß unter PHP> = 5.4.0 (siehe Changelog hier )

function dir_is_empty($path){ //$path is realpath or relative path

    $d = scandir($path, SCANDIR_SORT_NONE ); // get dir, without sorting improve performace (see Comment below). 

    if ($d){

        // avoid "count($d)", much faster on big array. 
        // Index 2 means that there is a third element after ".." and "."

        return !isset($d[2]); 
    }

    return false; // or throw an error
}

Andernfalls ist es mit der Common Sense-Lösung von @Your besser, das Laden von Dateilisten im RAM zu vermeiden

Vielen Dank und stimmen Sie auch bei @soger ab, um diese Antwort mithilfe der SCANDIR_SORT_NONEOption zu verbessern .

Oscar Zarrus
quelle
3
Solange wir uns um die Leistung kümmern, können Sie auch den Parameter SCANDIR_SORT_NONE hinzufügen.
Soger
2

Korrigieren Sie einfach Ihren Code wie folgt:

<?php
    $pid = $_GET["prodref"];
    $dir = '/assets/'.$pid.'/v';
    $q = count(glob("$dir/*")) == 0;

    if ($q) {
        echo "the folder is empty"; 
    } else {
        echo "the folder is NOT empty";
    }
?>
Alessandro.Vegna
quelle
0

Ich verwende diese Methode in meinem Wordpress CSV 2 POST-Plugin.

    public function does_folder_contain_file_type( $path, $extension ){
        $all_files  = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );

        $html_files = new RegexIterator( $all_files, '/\.'.$extension.'/' );  

        foreach( $html_files as $file) {
            return true;// a file with $extension was found
        }   

    return false;// no files with our extension found
}

Es funktioniert nach bestimmten Erweiterungen, kann jedoch leicht an Ihre Bedürfnisse angepasst werden, indem die Zeile "new RegexIterator (") entfernt wird. Count $ all_files.

    public function does_folder_contain_file_type( $path, $extension ){
        $all_files  = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );

        return count( $all_files );
    }
Ryan Bayne
quelle
0

Ich hatte kürzlich ein ähnliches Problem, obwohl die Antwort mit der höchsten Stimmenzahl für mich nicht wirklich funktionierte. Daher musste ich eine ähnliche Lösung finden. und wieder ist dies möglicherweise auch nicht der effizienteste Weg, um das Problem zu lösen.

Ich habe eine solche Funktion erstellt

function is_empty_dir($dir)
   {
       if (is_dir($dir))
       {
            $objects = scandir($dir);
            foreach ($objects as $object)
            {
                if ($object != "." && $object != "..")
                {
                    if (filetype($dir."/".$object) == "dir")
                    {
                         return false;
                    } else { 
                        return false;
                    }
                }
            }
            reset($objects);
            return true;
       }

und benutzte es, um so nach leerem Dricetory zu suchen

if(is_empty_dir($path)){
            rmdir($path);
        }
user28864
quelle
0

Sie können dies verwenden:

function isEmptyDir($dir)
{
    return (($files = @scandir($dir)) && count($files) <= 2);
}
karrtojal
quelle
0

Die erste Frage ist, wann ein Verzeichnis leer ist. In einem Verzeichnis befinden sich 2 Dateien mit dem '.' und '..'.
Daneben gibt es auf einem Mac vielleicht die Datei '.DS_Store'. Diese Datei wird erstellt, wenn dem Verzeichnis Inhalte hinzugefügt werden. Wenn sich diese 3 Dateien im Verzeichnis befinden, können Sie sagen, dass das Verzeichnis leer ist. So testen Sie, ob ein Verzeichnis leer ist (ohne zu testen, ob $ dir ein Verzeichnis ist):

function isDirEmpty( $dir ) {
  $count = 0;
  foreach (new DirectoryIterator( $dir ) as $fileInfo) {
     if ( $fileInfo->isDot() || $fileInfo->getBasename() == '.DS_Store' ) {
        continue;
     }
     $count++;
  }
  return ($count === 0);
}
Schaden
quelle
0

@Ihr gesunder Menschenverstand, @ Enyby

Einige Verbesserungen Ihres Codes:

function dir_is_empty($dir) {
    $handle = opendir($dir);
    $result = true;
    while (false !== ($entry = readdir($handle))) {
        if ($entry != "." && $entry != "..") {
            $result = false;
            break 2;
        }
    }
    closedir($handle);
    return $result;
}

Ich verwende eine Variable zum Speichern des Ergebnisses und setze es auf true.
Wenn das Verzeichnis leer ist, werden nur Dateien zurückgegeben. und .. (auf einem Linux-Server können Sie die Bedingung für Mac bei Bedarf erweitern) und daher ist die Bedingung wahr.
Dann wird der Wert von result auf false gesetzt und break 2 beendet die if- und die while-Schleife, sodass die nächste ausgeführte Anweisung geschlossen wird.
Daher hat die while-Schleife nur 3 Kreise, bevor sie endet, unabhängig davon, ob das Verzeichnis leer ist oder nicht.

Alexander Behling
quelle