Barey: Unterordner durchsuchen und alles in EINEM Array setzen

Hi Leute,

folgenden Code habe ich, funktioniert auch.
Nur ich möchte alles in einem Array haben und nicht für jeden Unterordner ein Array.
Kann mir einer zeigen wie das geht, oder wo und wie muss ich das mit dem array_push machen?

array sollte einfach so sein:
Array([0] => 'Pfad', [1] => 'Pfad',...)

momentan habe ich den array so:
Array([0] => 'Pfad', [1] => 'Pfad',...) Array([0] => 'Pfad', [1] => 'Pfad',...) Array([0] => 'Pfad', [1] => 'Pfad',...) ...

kann mir einer helfen?

  
session_start();  
$linkURLImpressionen = $_SESSION['link'];  
$ordner = $_SERVER['DOCUMENT_ROOT'].$linkURLImpressionen;  
$handle = opendir($ordner);  
  
// function start  
$bilder = array();  
function scan($folder){  
  if($content = opendir($folder)){  
    while(false !== ($file = readdir($content))){  
      if(is_dir($folder.'/'.$file) && $file != "." && $file != ".." ){  
           scan($folder.'/'.$file);  
      } elseif($file != "." && $file != ".." && (stristr($file, '.jpg') || stristr($file, '.gif') || stristr($file, '.png'))) {  
		$bilder[]= $file;  
	  }  
    }  
    closedir($content);  
  }  
}  
// function end  
  
scan($ordner);  

Danke

  1. Moin!

    folgenden Code habe ich, funktioniert auch.
    Nur ich möchte alles in einem Array haben und nicht für jeden Unterordner ein Array.
    Kann mir einer zeigen wie das geht, oder wo und wie muss ich das mit dem array_push machen?

    Die Frage ist: Was willst du eigentlich grundsätzlich erreichen?

    kann mir einer helfen?

    session_start();
    $linkURLImpressionen = $_SESSION['link'];
    $ordner = $_SERVER['DOCUMENT_ROOT'].$linkURLImpressionen;
    $handle = opendir($ordner);

    // function start
    $bilder = array();
    function scan($folder){
      if($content = opendir($folder)){
        while(false !== ($file = readdir($content))){
          if(is_dir($folder.'/'.$file) && $file != "." && $file != ".." ){
               scan($folder.'/'.$file);
          } elseif($file != "." && $file != ".." && (stristr($file, '.jpg') || stristr($file, '.gif') || stristr($file, '.png'))) {
    $bilder[]= $file;
      }
        }
        closedir($content);
      }
    }
    // function end

    scan($ordner);

      
    Wozu session\_start()?  
      
    Ich sag mal, wie das da oben aussieht: Offenbar willst du eine beliebig tiefe Ordnerstruktur nach Dateien mit den Endungen .jpg, .gif und .png durchsuchen, und am Ende eine Liste genau dieser Dateien haben. Und dann ggf. abarbeiten.  
      
    Lösungsvorschlag: Lass PHP die meiste Arbeit erledigen, für solche Aufgaben gibt es seit Version 5.1 tolle Iteratoren als Standardklassen mitgeliefert.  
      
    Der [RecursiveDirectoryIterator](http://de2.php.net/manual/de/class.recursivedirectoryiterator.php) erledigt für dich, rekursiv durch eine Directorystruktur durchgehen zu müssen. Dazu musst du nur das oberste Verzeichnis angeben, was durchsucht werden soll.  
      
    Der [RecursiveFilterIterator](http://de2.php.net/manual/de/class.recursivefilteriterator.php) filtert für dich das Ergebnis eines rekursiven Iterators, wie der RecursiveDirectoryIterator einer ist. Dazu musst du nur eine eigene Klasse schreiben, die RecursiveFilterIterator extended, und dort eine Methode "accept" reinschreiben, die true zurückgibt, wenn das aktuelle Einzelergebnis deinem Filterwunsch entspricht.  
      
    Der [RecursiveIteratorIterator](http://de2.php.net/manual/de/class.recursiveiteratoriterator.php) schließlich nimmt ebenfalls einen rekursiven Iterator entgegen und macht die rekursive Struktur flach, so dass man ganz leicht mit einer einzelnen foreach-Schleife das gesamte Ergebnis durchlaufen kann, ohne selbst die Rekursion nachvollziehen zu müssen.  
      
    Diese ganze Konstruktion ist dann SOOO kurz:  
    ~~~php
    $dirItr    = new RecursiveDirectoryIterator('/sample/path');  
    $filterItr = new MyRecursiveFilterIterator($dirItr);  
    $itr       = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST);  
      
    foreach ($itr as $filePath => $fileInfo) {  
        echo $fileInfo->getFilename() . PHP_EOL;  
    }  
    
    

    Drei Zeilen Code zur Vorbereitung des Iterierens über die Directory-Struktur.

    Und eine Schleife über die Variable mit dem RecursiveIteratorIterator, die dann das Verzeichnis ausliest und dort nur die Ergebnisse findet, die der RecursiveFilterIterator durchgelassen hat.

    So ein Filter ist sehr leicht zu bauen:

    class MyRecursiveFilterIterator extends RecursiveFilterIterator {  
      
        public function accept() {  
            if ($this->current()->getExtension() == "jpg") {  
                return true;  
            }  
            return false;  
        }  
      
    }
    

    Im RecursiveFilterIterator erhältst du mit $this->current() das aktuelle Element des inneren Iterators. Das ist der gesamte Dateisysteminhalt aller Unterverzeichnisse, durch den der RecursiveDirectoryIterator durchläuft. Dieser Iterator liefert für alle gefundenen Verzeichniseinträge ein SplFileInfo-Objekt zurück, welches viele nette Funktionen hat, um Eigenschaften der jeweiligen Datei zu ermitteln. getExtension() liefert beispielsweise die letzte Dateiendung zurück (ohne Punkt).

    Dasselbe gilt auch für die einzelnen Elemente in der foreach-Schleife. Die sind ebenfalls SplFileInfo-Objekte, und damit viel mächtiger, als nur ein simpler Dateiname. Alle Funktionen auf der SplFileInfo-Seite stehen dir auch in deiner Schleife zur Verfügung.

    - Sven Rautenberg

    1. Erstmal Vielen Dank
      Wiedermal was neues gelernt.

      Nun kommt bei mir
      $this->current()->getExtension()
      Fatal error: Call to undefined method SplFileInfo::getExtension()

      Hab nicht gefunden
      PHP Version 5.3.1

      1. Moin!

        Erstmal Vielen Dank
        Wiedermal was neues gelernt.

        Nun kommt bei mir
        $this->current()->getExtension()
        Fatal error: Call to undefined method SplFileInfo::getExtension()

        Hab nicht gefunden
        PHP Version 5.3.1

        Diese Version ist ja auch nicht mehr ganz frisch: Vom 19. November 2009, also schon 2 Jahre alt. SplFileInfo::getExtension() gibts erst seit 5.3.6 (seit März 2011). Gibts die Möglichkeit zum Update? Solltest du unbedingt versuchen.

        Ansonsten musst du mit getFilename() arbeiten und dort wieder die Extension am Namensende checken.

        - Sven Rautenberg

        1. Hallo

          Leider kann ich dies nicht updaten.

          hier mein code

          class MyRecursiveFilterIterator extends RecursiveFilterIterator {  
            
              public static $FILTERS = array(  
                  '.jpg','.png','.gif'  
              );  
            
              public function accept() {  
                  return !in_array(  
                      $this->current()->getFilename(),  
                      self::$FILTERS,  
                      true  
                  );  
              }  
            
          }  
            
          $dirItr    = new RecursiveDirectoryIterator('../');  
          $filterItr = new MyRecursiveFilterIterator($dirItr);  
          $itr       = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST);  
          foreach ($itr as $filePath => $fileInfo) {  
              echo $fileInfo->getFilename() . PHP_EOL .'<br />';  
          }
          

          ich möchte nur die .jpg, .gif, .png alle in einem einzigen array.

          ich möchte dann links machen

          <a href="unterordner/bild1.jpg">BILD1</a>  
          <a href="unterordner/bild2.jpg">BILD2</a>  
          <a href="unterordner1/unterordner2/bild3.jpg">BILD3</a>
          

          so in etwa, kannst du mir helfen ich bin verzweifelt und brauche eine Lösung :'(

          Danke

          1. Moin!

            class MyRecursiveFilterIterator extends RecursiveFilterIterator {

            public static $FILTERS = array(
                    '.jpg','.png','.gif'
                );

            public function accept() {
                    return !in_array(
                        $this->current()->getFilename(),
                        self::$FILTERS,
                        true
                    );
                }

            }

              
            Ich hatte schon etwas bewußt das Beispiel von PHP.net nicht 1:1 kopiert, sondern abgewandelt auf "einfache Erweiterbarkeit".  
              
            Dieser Filter dort oben schaut, ob der aktuelle Dateiname aufgelistet in dem Array drinsteht. Dort sind die Dateinamen ".jpg", ".png" und ".gif" aufgeführt, und sicherlich heißt keine einzige Datei bei dir so.  
              
            Nein, du musst an den Dateinamen von getFilename() schon mit Stringfunktionen ran und vergleichen, ob das Ende des Dateinamens mit einer der gewünschten Endungen übereinstimmt. Und das entwickelt man am besten erstmal ganz normal und schrittweise, nämlich als ersten Schritt mal für nur eine Dateiendung, damit alle auftretenden Probleme wirklich nur mit dem Finden dieser einen Endung zu tun haben, und nicht vielleicht mit irgendwas anderem.  
              
            PHP hat zum Glück noch einige Funktionen, die das Parsen von Dateinamen einfacher machen. [pathinfo()](http://de3.php.net/manual/de/function.pathinfo.php) passt z.B.  
              
            Wenn du dann also deine erste Extension korrekt findest, fügst du die zweite Extension hinzu und checkst, ob das auch funktioniert. Und dann die dritte. Und idealerweise hast du ein kleines Testverzeichnis zum Prüfen, in dem sich eine dir bekannte, hinreichend kleine Anzahl von Dateien befindet, damit du nicht riesige Ergebnislisten erhältst, sondern was überschaubares.  
              
            
            > ich möchte dann links machen  
            > ~~~php
            
            <a href="unterordner/bild1.jpg">BILD1</a>  
            
            > <a href="unterordner/bild2.jpg">BILD2</a>  
            > <a href="unterordner1/unterordner2/bild3.jpg">BILD3</a>
            
            

            so in etwa, kannst du mir helfen ich bin verzweifelt und brauche eine Lösung :'(

            Wenn dein Iterator-Filter erstmal die Dateien korrekt ausspuckt, ist das Link-Erstellen fast kein Problem mehr. Allerdings: In dem Dateipfad steckt das gesamte Verzeichnis auf der Festplatte drin, der Pfad für die Links ist aber im URL-Bereich und deshalb kürzer. Da musst du also "nur noch" den Pfad vorne korrekt kürzen. Ich würde auch immer absolute Pfade ausgeben lassen, beginnend mit einem "/", weil das die Ausgabe unabhängig macht von der tatsächlichen Position der Ausgabe des Links - du kannst die Funktion dann unabhängig davon benutzen, wo die Seite sich befinden, in der die Bilder ausgegeben werden.

            - Sven Rautenberg

    2. Im Foreach kommen die Unterordner auch, wie kann nur die Bilder im foreach ausgeben ohni die Unterordner Namen?

      Danke

      1. Moin!

        Im Foreach kommen die Unterordner auch, wie kann nur die Bilder im foreach ausgeben ohni die Unterordner Namen?

        Zeig mal deinen Gesamtcode. Da hast du bestimmt irgendwas nur halb angepasst, und das kann ich nicht raten oder telepathisch ermitteln.

        - Sven Rautenberg

    3. Hello,

      Die Frage ist: Was willst du eigentlich grundsätzlich erreichen?

      kann mir einer helfen?

      Lösungsvorschlag: Lass PHP die meiste Arbeit erledigen, für solche Aufgaben gibt es seit Version 5.1 tolle Iteratoren als Standardklassen mitgeliefert.

      Der RecursiveDirectoryIterator erledigt für dich, rekursiv durch eine Directorystruktur durchgehen zu müssen. Dazu musst du nur das oberste Verzeichnis angeben, was durchsucht werden soll.

      Auch der hat noch das Problem mit dem zyklischen Verlauf bei Symbolic Link Directories.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Moin!

        Der RecursiveDirectoryIterator erledigt für dich, rekursiv durch eine Directorystruktur durchgehen zu müssen. Dazu musst du nur das oberste Verzeichnis angeben, was durchsucht werden soll.

        Auch der hat noch das Problem mit dem zyklischen Verlauf bei Symbolic Link Directories.

        Nein. Und das hättest du auch selbst herausfinden können!

        Es gibt Optionen, die man zur Konfiguration des Iterators dem Konstruktor mitgeben kann. FilesystemIterator::FOLLOW_SYMLINKS gehört nicht zum Default.

        Doku lesen hilft. Aber Hauptsache, was gemeckert haben. :-P

        - Sven Rautenberg

        1. Hello,

          Es gibt Optionen, die man zur Konfiguration des Iterators dem Konstruktor mitgeben kann. FilesystemIterator::FOLLOW_SYMLINKS gehört nicht zum Default.

          Doku lesen hilft. Aber Hauptsache, was gemeckert haben. :-P

          Genau. Und was gelernt :-)

          Also ist das Standardverhalten "Nofollow Symlinks"? Habe ich das richtig verstanden?

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  2. Tach!

    Wie es in "modern" besser geht, hat Sven ja schon aufgezeigt. Aber auch in "herkömmlich" lässt sich einiges verbessern.

    Kann mir einer zeigen wie das geht, oder wo und wie muss ich das mit dem array_push machen?

    array_push() braucht man im Prinzip gar nicht. $array[] = ...; ist die bevorzugte und schnellere (weil ohne Funktionsaufruf) Methode beim Anfügen von einzelnen Werten.

    opendir/readdir/closedir sind schon recht alte Gesellen. Deswegen findet man Lösungen mit ihnen an jeder Ecke. glob() findet man seltener, dabei kommt man damit komfortabler zum Ziel, weil man mit nur einem Aufruf genau das Gesuchte und nichts überflüssiges bekommt. Ich nehme mal an, dass dich auch der Pfad zum Bild interessiert und nicht nur der nackige Dateiname.

    glob("/path/to/images/*.{png,gif,jpg}", GLOB_BRACE)

    liefert alle Dateien mit den angegebenen Endungen nebst dem angegebenen Pfad. Wenn er nicht so lang sein soll, kannst du mit chdir() ins gewünschte Ausgangsverzeichnis wechseln und von dort aus relativ suchen. Fürs rekursive Durchlaufen werden außerdem noch die Unterverzeichnisse benötigt, die man mit

    glob("/path/to/images/*", GLOB_ONLYDIR)

    bekommt.

    $bilder = array();
    function scan($folder){
      if($content = opendir($folder)){
        while(false !== ($file = readdir($content))){
          if(is_dir($folder.'/'.$file) && $file != "." && $file != ".." ){
               scan($folder.'/'.$file);
          } elseif($file != "." && $file != ".." && (stristr($file, '.jpg') || stristr($file, '.gif') || stristr($file, '.png'))) {
    $bilder[]= $file;
      }
        }
        closedir($content);
      }
    }
    // function end

    Du schriebst einleitend, dass das so schon funktioniert hat, was aber mit dem Code nicht stimmen kann. $bilder ist ein Array im globalen Scope, innerhalb der Funktion scan() ist $bilder eine andere und auch nur lokale Variable. Du sammelst zwar die Dateinamen, aber nach dem Funktionsende sind sie nicht mehr verfügbar. Da fehlt also noch eine globals-Deklaration oder besser ein Zurückliefern als Funktionsergebnis nebst Verarbeiten desselben.

    Wie müsste man nun stattdessen mit glob() arbeiten? Wegen der benötigten Rekursivität ist weiterhin das Erstellen einer Funktion angebracht, welche wieder das zu durchsuchende Verzeichnis übergeben bekommt und als zweiten Parameter das Dateinamenmuster. In der Funktion liefert der erste glob-Aufruf bereits alle Dateien in einem Array, was sich schon mit print_r() und var_dump() überprüfen lässt. glob() bekam dafür natürlich Pfad und Muster zusammengefügt übergeben. In einer Schleife muss man nun noch für jedes vom zweiten glob-Aufruf (nur mit Pfad und angehängtem *) zurückgegebene Unterverzeichnis die Funktion erneut aufrufen, mit dem Pfad zum Unterverzeichnis und dem durchgereichten Muster als Parameter. Das Funktionsergebnis ist, wie gleich noch zu sehen sein wird, ein Array mit Dateinamen. Das muss noch an das Array des ersten glob() angehängt werden, wofür sich array_merge() eignet. Das mit return zurückgegebene Funktionsergebnis ist dann dieses zusammengefügte Array. Wenn man das effizient notiert, bekommt man die Funktion in insgesamt 6 Zeilen hin.

    dedlfix.

    1. Tach!

      Nachtrag für die nachgereichte Bedingung "ohni die Unterordner Namen":

      Wenn man das effizient notiert, bekommt man die Funktion in insgesamt 6 Zeilen hin.

      Nur die Dateinamen ohne Pfad bekommt man auch mit glob(), allerdings muss man dafür in das Verzeichnis wechseln. Damit man sich wegen der rekursiven Aufrufe nicht "verläuft" sollte man sich am Funktionsanfang das aktuelle Verzeichnis merken (getcwd()), dann in das zu scannende Verzeichnis wechseln (chdir()). Die beiden glob-Aufrufe bekommen nun nur noch das Dateinamen-Muster beziehungsweise einen einzelnen * übergeben. Am Ende vor dem return stellt man das Verzeichnis wieder auf den zuerst gemerkten Wert zurück. Ergibt drei zusätzliche Zeilen.

      dedlfix.

    2. Hello,

      Wenn man das effizient notiert, bekommt man die Funktion in insgesamt 6 Zeilen hin.

      Nicht ganz. Denn in den Array der Verzeichnisse muss man jeweils noch die Symbolic Links berücksichtigen und dafür sorgen, das aus der Rekusion kein zyklischer Verlauf wird.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Tach!

        Denn in den Array der Verzeichnisse muss man jeweils noch die Symbolic Links berücksichtigen und dafür sorgen, das aus der Rekusion kein zyklischer Verlauf wird.

        Wenn man solche Links erwartet, kann man das mit der Prüfung auf is_link() vor dem Abtauchen in ein Verzeichnis ausschließen.

        dedlfix.

        1. Hello,

          Denn in den Array der Verzeichnisse muss man jeweils noch die Symbolic Links berücksichtigen und dafür sorgen, das aus der Rekusion kein zyklischer Verlauf wird.

          Wenn man solche Links erwartet, kann man das mit der Prüfung auf is_link() vor dem Abtauchen in ein Verzeichnis ausschließen.

          Das sollte man auch tun, wenn man die Symbolic Links nicht erwaretet ;-P

          Ein einziger reicht, um das System zum Stehen zu bringen, zumindest bis zur maximalen Rekursionstiefe oder dem Speicherüberlauf oder dem Script-Timeout von PHP...

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  3. Hello,

    kann mir einer helfen?

    session_start();
    $linkURLImpressionen = $_SESSION['link'];
    $ordner = $_SERVER['DOCUMENT_ROOT'].$linkURLImpressionen;
    $handle = opendir($ordner);

    // function start
    $bilder = array();
    function scan($folder){
      if($content = opendir($folder)){
        while(false !== ($file = readdir($content))){
          if(is_dir($folder.'/'.$file) && $file != "." && $file != ".." ){
               scan($folder.'/'.$file);
          } elseif($file != "." && $file != ".." && (stristr($file, '.jpg') || stristr($file, '.gif') || stristr($file, '.png'))) {
    $bilder[]= $file;
      }
        }
        closedir($content);
      }
    }
    // function end

    scan($ordner);

      
    So geht es jedenfalls nicht. Denn diese Lösung würde sich aufhängen, wenn sie auf einen Symbolischen Link läuft, der auf ein übergeordnetes Verzeichnis verweist.  
      
    Schau Dir mal <http://forum.de.selfhtml.org/archiv/2007/12/t163759/#m1066568> und die Threads drum herum an.  
      
      
      
      
    Liebe Grüße aus dem schönen Oberharz  
      
      
    Tom vom Berg  
    ![](http://selfhtml.bitworks.de/Virencheck.gif)  
      
    
    -- 
     ☻\_  
    /▌  
    / \ Nur selber lernen macht schlau  
    <http://bergpost.annerschbarrich.de>
    
    1. Hi

      Ich brauche eine Lösung die nicht alle unterverzeichnise anzeigt.
      Möchte gerne einfach alle, .jpg, .gif, .png in einem array haben, damit ich links generieren kann zu einem Bild.

      so sollte es aussehen

      Array([0] => 'unterordner1/unterordner2/bildname.jpg', [1] => 'unterordner1/bildname.png' ...)

      damit ich so ein link generieren kann

      <a href="unterordner1/unterordner2/bildname.jpg">bildname</a>

      Barey

      1. Tach!

        Ich brauche eine Lösung die nicht alle unterverzeichnise anzeigt.

        Was genau meinst du damit? Willst du bestimmte Verzeichnisse und die Dateien darin von der Suche ausschließen oder soll der Dateiname ohne Verzeichnis in der Liste erscheinen?

        Möchte gerne einfach alle, .jpg, .gif, .png in einem array haben, damit ich links generieren kann zu einem Bild.
        <a href="unterordner1/unterordner2/bildname.jpg">bildname</a>

        Also brauchst du ausgehend von einem Verzeichnis den kompletten Dateinamen inklusive relativem Pfad und dann nochmal den Dateinamen einzeln. Dann wäre doch mein erster Vorschlag eine der Lösungsmöglichkeiten. Für die Ermittlung des reinen Bilddateinamen kann man wärend der Ausgabegenerierung basename() nehmen, oder wenn es ohne Endung sein soll, lässt sich pathinfo() verwenden.

        dedlfix.

      2. Hello,

        Ich brauche eine Lösung die nicht alle unterverzeichnise anzeigt.
        Möchte gerne einfach alle, .jpg, .gif, .png in einem array haben, damit ich links generieren kann zu einem Bild.

        Und wo befinden sich die Bilddateien (zumindest logisch)? Richtig: in einem Verzeichnis!

        Also benötigst Du zunächst die Liste ALLER Verzeichnisse, in denen nach Bildern gesucht werden soll. Anschließend kannst Du diese Liste dann _linear_ abarbeiten, z.B. mit glob(), um die gewünschten Muster darin zu finden.

        Denke aber daran, dass für glob() auf Linux-Systemen '*.gif' und '*.Gif' und '*.GIF' und so weiter unterschiedliche Ziele sind.

        Um alle zu finden, könnte dabei der Parameter GLOB_BRACE helfen.

        so sollte es aussehen

        Array(

        [0] => 'unterordner1/unterordner2/bildname.jpg',
                  [1] => 'unterordner1/bildname.png',
                  ...
               )

        damit ich einen link generieren kann

        Wer hindert dich daran, dass resultierende Array beim "Dateisuchlauf" dann so aufzubauen.

        Denke aber auch daran, dass per http die Verzeichnispfade nicht identisch sind, wie die beim serverinternen Zugriff per 'file'.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de