php.de

Zurück   php.de > Webentwicklung > PHP Einsteiger > PHP Tipps 2009

 
 
LinkBack Themen-Optionen Thema bewerten
Alt 01.09.2009, 14:30  
Neuer Benutzer
 
Registriert seit: 06.08.2009
Beiträge: 8
PHP-Kenntnisse:
Anfänger
celindir befindet sich auf einem aufstrebenden Ast
Standard Rekursive Dateisuche :::: Verzeichnistiefe begrenzen

Hallo zusammen,

ich bastele immer noch an meiner rekursiven Dateisuche.

Derzeit sieht der Code folgendermaßen aus

PHP-Code:
$source "./"//oder jedes andere Startverzeichnis
$php_maxdepth 2//Maximale Verzeichnisebene die durchsucht werden soll
$size 50//Mindestgröße der Datei
$filter "jpg" //Dateiendung nach der gesucht werden soll

$it = new RecursiveDirectoryIterator$source );
foreach( new 
RecursiveIteratorIterator$it ) as $f 
{
  
$path_parts pathinforealpath$f->getPathname() ) );
  
$extension $path_parts['extension'];
  
$depth = ( substr_count $f->getPathname(), "/" ) - substr_count$source"/" ) );
  
$f_size filesize$f->getPath()."/".$f->getFilename() )/1024;

  if ( 
$f_size $size && $depth <= $php_maxdepth && $extension == $filter )
  {
        
$results[] = $f->getPath()."/".$f->getFilename();
  }


Es funktioniert auch alles grundsätzlich richtig nur ist es sehr langsam.
Grund: Bei grossen Verzeichnisstrukturen mit sehr vielen Dateien wird trotz der Begrenzung zunächst alles durchsucht und nur bei dem Ergebnis geprüft, ob es mit aufgenommen werden soll.

Besser wäre es natürlich, wenn das Script nur in die Verzeichnisse abtaucht, die innerhalb der Vorgabe liegen.

Beispiel: Baum hat 100 Unterverzeichnisse auf 5 Ebenen.
Dann werden im Moment 100 Verzeichnisse durchsucht und das Ergebnis listet nur die aus z.B. zwei Ebenen auf. (sagen wir mal 20)

Würde die Begrenzung vorher greifen, müsste das Script nur 20 Verzeichnisse durchsuchen und wäre sicherlich schneller.

Ich hatte auch schon versucht ein break einzubauen, wenn $depth > $php_maxdepth aber da das ja in jedem Ast vorkommen kann bricht das Skript dann schon beim ersten Ast ab, der mehr Verzeichnisebene hat.

Gibt es hierzu irgendwelche Ansätze?
RecursiveDirectoryIterator und Konsorten sind wohl bisher wenig dokumentiert.

Freue mich über sachdienliche Hinweise.

Eurer Celindir

P.S. Die Geschwindigkeit ist deshalb so wichtig, wie das Script auf einem etwas schwachbrüstigen NAS laufen soll.
celindir ist offline  
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 01.09.2009, 14:39  
Erfahrener Benutzer
 
Benutzerbild von mermshaus
 
Registriert seit: 14.06.2009
Beiträge: 1.733
PHP-Kenntnisse:
Fortgeschritten
mermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz sein
Standard

Bessere Dokumentation gibt's hier, falls du die Seite noch nicht kennst: SPL-StandardPHPLibrary: Alphabetical List (Frameseite) Zu mehr fehlt gerade die Zeit.
mermshaus ist offline  
Alt 01.09.2009, 14:45  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.989
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Sollte es nicht reichen, eine der Klassen abzuleiten und die Abbruchbedingung mit in die Methoden einzubauen?
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist gerade online  
Alt 01.09.2009, 15:06  
Neuer Benutzer
 
Registriert seit: 06.08.2009
Beiträge: 8
PHP-Kenntnisse:
Anfänger
celindir befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von nikosch Beitrag anzeigen
Sollte es nicht reichen, eine der Klassen abzuleiten und die Abbruchbedingung mit in die Methoden einzubauen?
Hallo nikosch,

möglicherweise sollte es das. Dazu muss ich aber noch viel lernen! Zum Beispiel wie ich Klassen ableite. Aber ich werd mich mal versuchen schlau zu machen.

Gruß

Celindir
celindir ist offline  
Alt 02.09.2009, 10:46  
Neuer Benutzer
 
Registriert seit: 06.08.2009
Beiträge: 8
PHP-Kenntnisse:
Anfänger
celindir befindet sich auf einem aufstrebenden Ast
Standard

Hallo zusammen,

ich habe hier einen Beitrag gefunden, der meines Erachtens genau das macht, was ich wollte.

Wenn ich aber nun den Quelltext in eine Datei list.php packe

PHP-Code:
<?php
/**
 * Limit Depth RecursiveIteratorIterator class
 *
 */
class LimitRecursiveIteratorIterator extends RecursiveIteratorIterator
{
   protected 
$depth_limit;

   
/**
     * No depth limit by default
     *
   **/
   
public function __construct (Iterator $it$mode RIT_SELF_FIRST$depth_limit = -1)
   {
       
parent::__construct($it$mode);
       
$this->depth_limit $depth_limit;
   }

   
/**
     * After the call to next() if depth is bigger than limit then
     * just skip all subIterators for that depth until depth end.
     *
   **/
   
public function next ()
   {
       
parent::next();

       if (
$this->getDepth() == $this->depth_limit)
       {
           while (
$this->getSubIterator()->valid())
               
$this->getSubIterator()->next();
           
parent::next();
       }
   }
}
?>

Then you can try this:

<?php
/**
 * Directories only filter iterator class
 *
 */
class DirectoriesOnlyIterator extends FilterIterator implements RecursiveIterator
{
   public function 
__construct ($path)
   {
       
parent::__construct(new RecursiveDirectoryIterator($path));
   }

   public function 
accept()
   {
       return 
$this->getInnerIterator()->hasChildren();
   }

   public function 
hasChildren ()
   {
       return 
$this->getInnerIterator()->hasChildren();
   }
  
   public function 
getChildren ()
   {
       return new 
self($this->getInnerIterator()->getPathname());
   }
}

$it = new LimitRecursiveIteratorIterator(new DirectoriesOnlyIterator('c:'), RIT_SELF_FIRST2);

// list all dirs and 1st subdir of the c: drive (might take a while depending on how many you have)
foreach ($it as $key => $value)
{
   echo 
str_repeat('    '$it->getDepth()) . "$value\n";
}

?>
und den Pfad c: in einen absoluten Pfad meines Webservers /is/htdocs/irgendwas/www/irgendwas/bilder/

umändere erhalte ich eine Fatal Error:
Code:
Fatal error: Uncaught exception 'InvalidArgumentException' with message 
'An instance of RecursiveIterator or IteratorAggregate creating it is required' 
in /is/htdocs/irgendwas/www/irgendwas/bilder/list.php:16 
Stack trace: #0 /is/htdocs/irgendwas/www/irgendwas/bilder/list.php(16): 
RecursiveIteratorIterator->__construct(Object(DirectoriesOnlyIterator),
'RIT_SELF_FIRST') #1 /is/htdocs/irgendwas/www/irgendwas/bilder/list.php(68):
LimitRecursiveIteratorIterator->__construct(Object(DirectoriesOnlyIterator),
'RIT_SELF_FIRST', 2) #2 {main} thrown in 
/is/htdocs/irgendwas/www/irgendwas/bilder/list.php on line 16
Da ich mich bisher in php noch nicht mit solchen Themen beschäftigt habe bin ich mit dieser Fehlermeldung echt überfordert.

Viellicht hat hier ja jemand eine Idee und kann mir etwas auf die Sprünge helfen.

Wahrscheinlich liegt der Fehler auch hier wieder 1 Meter vor dem Monitor

Vielen Dank

Euer Celindir
celindir ist offline  
Alt 02.09.2009, 14:30  
Erfahrener Benutzer
 
Benutzerbild von mermshaus
 
Registriert seit: 14.06.2009
Beiträge: 1.733
PHP-Kenntnisse:
Fortgeschritten
mermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz sein
Standard

Ich habe das Beispiel auch nur so weit zum Laufen gebracht, dass die für $depth_limit angegebene Ebene ausgelassen wird, die darunter aber wieder angezeigt werden. Zudem spult der LimitIterator im Beispiel meiner Ansicht nach ebenfalls durch alle Einträge durch.

Vielleicht so:

PHP-Code:
<?php

/**
 * A filter iterator to constrain a RecursiveDirectoryIterator to a certain path
 * depth
 *
 * @author  Marc Ermshaus (http://ermshaus.org/)
 * @version 2009-09-02
 */
class RecursiveDirectoryDepthFilterIterator extends RecursiveFilterIterator
{
    
/**
     * Relative maximum depth to iterate
     *
     * @var int
     */
    
protected $maxDepth;

    
/**
     * As we have to create a child iterator in hasChildren to check whether a
     * directory can be accessed, why not reuse it for getChildren
     *
     * @var RecursiveDirectoryIterator
     */
    
protected $newNestedIterator;

    
/**
     * Constructor
     *
     * @param RecursiveDirectoryIterator $it Directory iterator to filter
     * @param int $maxDepth Iterate nested paths up to this depth. If not set,
     *            every path will be iterated to its full extent
     */
    
public function __construct(RecursiveDirectoryIterator $it,
                                
$maxDepth null)
    {
        
parent::__construct($it);
        
$this->maxDepth $maxDepth;
    }

    
/**
     * Checks whether a path has children (= is a directory) and whether its
     * relative depth is beneath the specified threshold
     *
     * @return bool
     */
    
public function accept()
    {
        return (
            
$this->hasChildren()
            && ((
$this->maxDepth === null) || ($this->maxDepth >= 0))
        );
    }

    
/**
     * Returns whether the current path contains accessible child paths
     *
     * This method will return false if the user under which the script is run
     * can't access the path in question.
     *
     * @return bool
     */
    
public function hasChildren()
    {
        try {
            
$this->newNestedIterator = new RecursiveDirectoryIterator(
                
$this->getInnerIterator()->getPathName()
            );
        } catch (
UnexpectedValueException $e) {
            return 
false;
        }

        return 
$this->getInnerIterator()->hasChildren();
    }

    
/**
     * Returns an iterator for the child elements of the current path
     *
     * @return RecursiveDirectoryDepthFilterIterator
     */
    
public function getChildren()
    {
        
$newMaxDepth = ($this->maxDepth === null) ? null $this->maxDepth 1;
        return new 
self($this->newNestedIterator$newMaxDepth);
    }
}

$fi = new RecursiveDirectoryDepthFilterIterator(
    new 
RecursiveDirectoryIterator('/home/marc'),
    
1
);

$it = new RecursiveIteratorIterator($fiRecursiveIteratorIterator::SELF_FIRST);



header('Content-Type: text/plain; charset=UTF-8');

foreach (
$it as $v) {
    echo 
str_repeat('    '$it->getDepth()) . $v "\n";
}
mermshaus ist offline  
Alt 02.09.2009, 15:07  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.989
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Es gibt ja auch keinen Abbruch. Bspw. getChildren() dürfte sich dayr anbieten.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist gerade online  
Alt 02.09.2009, 15:08  
Neuer Benutzer
 
Registriert seit: 06.08.2009
Beiträge: 8
PHP-Kenntnisse:
Anfänger
celindir befindet sich auf einem aufstrebenden Ast
Standard

Hallo zusammen,

habe das Problem nun endlich gelöst.

In meinem obigen Beispiel war folgendes Problem:

Zitat:
RIT_CHILD_FIRST
funktioniert ab PHP 5.1 nicht mehr. Stattdessen muss es lauten:

RecursiveIteratorIterator::CHILD_FIRST
Quelle: mikey.log

Ich habe das in meinem Script entsprechend verändert und nungeht der Suchvorgang erheblich schneller.

PHP-Code:
/**
 * Limit Depth RecursiveIteratorIterator class
 *
 */
class LimitRecursiveIteratorIterator extends RecursiveIteratorIterator
{
    protected 
$depth_limit;

    
/**
     * No depth limit by default
     *
    **/
    
public function __construct (Iterator $it$mode RecursiveIteratorIterator::CHILD_FIRST$depth_limit = -1)
    {
        
parent::__construct($it$mode);
        
$this->depth_limit $depth_limit;
    }

    
/**
     * After the call to next() if depth is bigger than limit then
     * just skip all subIterators for that depth until depth end.
     *
    **/
    
public function next ()
    {
        
parent::next();

        if (
$this->getDepth() == $this->depth_limit)
        {
            while (
$this->getSubIterator()->valid())
                
$this->getSubIterator()->next();
            
parent::next();
        }
    }

Aufruf:
PHP-Code:
$fileSPLObjects =  new LimitRecursiveIteratorIterator(
                new 
RecursiveDirectoryIterator($basedir),
                
RecursiveIteratorIterator::CHILD_FIRST$php_maxdepth
            
);

foreach( 
$fileSPLObjects as $fullFileName => $fileSPLObject )
{
print 
"FILESPLOBJECT: $fileSPLObject <br>";


Vielleicht hilft es ja jemandem.

Danke fürs Kopfzerbrechen!

Euer Celindir
celindir ist offline  
Alt 02.09.2009, 16:34  
Erfahrener Benutzer
 
Benutzerbild von mermshaus
 
Registriert seit: 14.06.2009
Beiträge: 1.733
PHP-Kenntnisse:
Fortgeschritten
mermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz sein
Standard

Hm. Sicher, dass das funktioniert? (Bin auf dem Sprung, Testcase liefere ich ansonsten nachher.)
mermshaus ist offline  
Alt 02.09.2009, 19:35  
Erfahrener Benutzer
 
Benutzerbild von mermshaus
 
Registriert seit: 14.06.2009
Beiträge: 1.733
PHP-Kenntnisse:
Fortgeschritten
mermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz seinmermshaus kann auf vieles stolz sein
Standard

Ich mache mal vorsichtshalber einen neuen Beitrag:

Testverzeichnis:

Code:
$ find ./demo -print
./demo
./demo/a
./demo/a/b
./demo/a/b/c
./demo/a/b/c/test
Eingesetzter Code:

PHP-Code:
$basedir './demo';

$fileSPLObjects =  new LimitRecursiveIteratorIterator(
                new 
RecursiveDirectoryIterator($basedir),
                
RecursiveIteratorIterator::SELF_FIRST2
            
);

foreach (
$fileSPLObjects as $fullFileName => $fileSPLObject) {
    echo 
str_repeat('  '$fileSPLObjects->getDepth()) . $fileSPLObject->getFilename() . "\n";

Erwartete Ausgabe:

Code:
a
  b
Tatsächliche Ausgabe:

Code:
a
  b
      c
        test
Ausgabe mit CHILD_FIRST:

Code:
      test
  b
a
Keine Ahnung, was da passiert. Das Problem scheint auch nur beim jeweils ersten (letzten?) Unterverzeichnis des durchsuchten Basisverzeichnisses aufzutreten. (Bei meinem ersten Test der ursprünglichen Funktion habe ich zufällig ein ähnlich aufgebautes Verzeichnis probiert und deshalb schnell entschieden, dass die Funktion insgesamt kaputt ist.)

Setz außerdem mal ein "echo 'x';" oder so in die "while ($this->getSubIterator()->valid()) {"-Schleife. Wie ich bereits schrieb, scheint dort trotz allem jede Datei jedes Unterverzeichnisses "durchgestept" zu werden.

Noch allgemein zu Iteratoren: Die Dinger sind generell ganz entsetzlich ineffizient.
mermshaus ist offline  
 


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Rekursive Dateisuche :::: Mit exec oder RecursiveDirectoryIterator unterschiedlich celindir PHP Tipps 2009 2 06.08.2009 15:32
Rekursive Abfrage #Avedo Datenbanken 14 05.05.2009 18:18
Rekursive Funktion funktioniert lokal, aber nicht remote? Anotherone PHP-Fortgeschrittene 1 21.06.2008 08:11
rekursive Funktionen ?? usima PHP Tipps 2008 2 04.05.2008 11:25
Traffic pro IP begrenzen PHP Tipps 2006 6 17.01.2006 21:42
Anzahl der Datensätze je Seite begrenzen Loenne PHP Tipps 2006 14 04.01.2006 16:02
abfrage begrenzen Cyrus Datenbanken 4 26.10.2005 11:29
Textfeld begrenzen von der Anzahl der Zeichen PHP Tipps 2005-2 11 13.10.2005 11:15
[Erledigt] Anzahl von Einträgen begrenzen + Formulareinträge prüfen PHP Tipps 2005-2 32 07.07.2005 17:33
Betteln begrenzen PHP Tipps 2004-2 16 30.12.2004 14:12
Zeilenumbrüche Begrenzen I-Spy PHP Tipps 2004-2 12 30.11.2004 20:49
Ausgabelänge eines Feldes begrenzen? db PHP Tipps 2004 3 07.10.2004 16:08
Rekursive Funktion ... finde fehler nicht ... PHP-Fortgeschrittene 1 27.09.2004 03:44
Rekursive Funktion tut nicht richtig??? PHP-Fortgeschrittene 8 09.07.2004 15:39

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
c rekursive dateisuche, c# rekursive dateisuche, php dateisuche, an instance of recursiveiterator or iteratoraggregate creating it is required, uncaught exception \'invalidargumentexception\' with message \'an instance of recursiveiterator or iteratoraggregate creating it is required, rekursion begrenzen, find tiefe begrenzen, php rekursive dateisuche, verzeichnistiefe beschränken, recursiverecursiveiterator nur 2. ebene, verzeichnistiefe begrenzen, recursivedirectoryiterator stack trace, http://www.php.de/php-einsteiger/58642-rekursive-dateisuche-verzeichnistiefe-begrenzen.html, verzeichnistiefe, rekursiv dateisuche php, rekursive dateisuche php, fehler max verzeichnistiefe erreicht, find verzeichnistiefe abbruch, fatal error: uncaught exception \'invalidargumentexception\' with message \'an instance of recursiveiterator, recursivedirectoryiterator . und ,,

Alle Zeitangaben in WEZ +2. Es ist jetzt 19:50 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum