Quello che state cercando è chiamato anche directory ricorsiva attraversamento. Il che significa che stai esaminando tutte le directory e elenchi sottodirectory e file. Se c'è una sottodirectory viene anche attraversata e così via e così via - quindi è ricorsiva.
Come potete immaginare questo è un po 'una cosa comune di cui avete bisogno quando scrivete un software e PHP vi supporta con quello. Offre uno RecursiveDirectoryIterator
in modo che le directory possano essere ripetute ripetutamente e lo standard RecursiveIteratorIterator
per eseguire l'attraversamento. È quindi possibile accedere facilmente a tutti i file e le directory con un semplice iterazione, ad esempio attraverso foreach
:
$rootpath = '.';
$fileinfos = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootpath)
);
foreach($fileinfos as $pathname => $fileinfo) {
if (!$fileinfo->isFile()) continue;
var_dump($pathname);
}
Questo esempio prima di tutto specifica la directory che si desidera percorrere.Ho preso quella attuale:
$rootpath = '.';
La successiva linea di codice è un po 'lunga, non un'istanza the directory iterator e poi the iterator-iterator modo che la struttura ad albero può essere attraversato in un singolo ciclo/piatto :
$fileinfos = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootpath)
);
Questi $fileinfos
vengono poi iterati con un semplice foreach
:
foreach($fileinfos as $pathname => $fileinfo) {
Dentro di esso, c'è un test per saltare tutte le directory dall'output. Questo viene fatto utilizzando l'oggetto SplFileInfo
su cui è stata ripetuta l'iterazione. Viene fornito dall'iteratore di directory ricorsivo e contiene molte proprietà e metodi utili quando si lavora con i file. Puoi anche ad esempio restituire l'estensione del file, le informazioni sul nome di base su dimensioni e tempo e così via e così via.
if (!$fileinfo->isFile()) continue;
Infine ho appena uscita la percorso che è il percorso completo del file:
var_dump($pathname);
Un'uscita esemplare sarebbe simile a questa (qui su un sistema operativo Windows):
string(12) ".\.buildpath"
string(11) ".\.htaccess"
string(33) ".\dom\xml-attacks\attacks-xml.php"
string(38) ".\dom\xml-attacks\billion-laughs-2.xml"
string(36) ".\dom\xml-attacks\billion-laughs.xml"
string(40) ".\dom\xml-attacks\quadratic-blowup-2.xml"
string(40) ".\dom\xml-attacks\quadratic-blowup-3.xml"
string(38) ".\dom\xml-attacks\quadratic-blowup.xml"
string(22) ".\dom\xmltree-dump.php"
string(25) ".\dom\xpath-list-tags.php"
string(22) ".\dom\xpath-search.php"
string(27) ".\dom\xpath-text-search.php"
string(29) ".\encrypt-decrypt\decrypt.php"
string(29) ".\encrypt-decrypt\encrypt.php"
string(26) ".\encrypt-decrypt\test.php"
string(13) ".\favicon.ico"
Se è presente una sottodirectory non accessibile, la seguente operazione genera un'eccezione. Questo comportamento può essere controllato con alcune bandiere quando si crea un'istanza della RecursiveIteratorIterator
:
$fileinfos = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('.'),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
Spero che questo è stata istruttiva. Puoi anche eseguire il wrapping di questo in una classe personalizzata e puoi anche fornire un FilterIterator
per decidere se un file debba essere elencato o meno dal ciclo foreach
.
La potenza della combinazione RecursiveDirectoryIterator
e RecursiveIteratorIterator
esce dalla sua flessibilità. Ciò che non era coperto sopra sono i cosiddetti FilterIterator
s. Ho pensato di aggiungere un altro esempio che sta facendo uso di due di loro auto-scritti, messi l'uno nell'altro per combinarli.
- Uno è quello di filtrare tutti i file e le directory che iniziano con un punto (quelli sono considerati file nascosti sui sistemi UNIX, quindi non si dovrebbe dare tali informazioni al di fuori) e
- Un altro che sta filtrando il elenca solo i file. Questo è il controllo che in precedenza era all'interno di il foreach.
Un altro cambiamento in questo esempio di utilizzo è quello di utilizzare il getSubPathname()
function che restituisce il sottotracciato a partire dal ROOTPATH del iterazione, in modo da quello che stai cercando.
Inoltre ho esplicitamente aggiungere il SKIP_DOTS
flag che impedisce l'attraversamento .
e ..
(tecnicamente non davvero necessario in quanto i filtri sarebbero filtrare quelli così come essi sono directory, ma penso che sia più corretto) e di ritorno, percorsi come UNIX_PATHS
così le corde di sentieri sono percorsi sempre unix-like indipendentemente dal sistema operativo sottostante che è normalmente una buona idea se questi valori vengono richiesti tramite HTTP in seguito come nel tuo caso:
$rootpath = '.';
$fileinfos = new RecursiveIteratorIterator(
new FilesOnlyFilter(
new VisibleOnlyFilter(
new RecursiveDirectoryIterator(
$rootpath,
FilesystemIterator::SKIP_DOTS
| FilesystemIterator::UNIX_PATHS
)
)
),
RecursiveIteratorIterator::LEAVES_ONLY,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
foreach ($fileinfos as $pathname => $fileinfo) {
echo $fileinfos->getSubPathname(), "\n";
}
Questo esempio è simile al precedente uno anche se come lo $fileinfos
è costruito è un po 'diversamente configurato. Soprattutto la parte sui filtri è nuovo:
new FilesOnlyFilter(
new VisibleOnlyFilter(
new RecursiveDirectoryIterator($rootpath, ...)
)
),
Così l'iteratore directory viene messo in un filtro e il filtro stesso viene messo in un altro filtro. Il resto non è cambiato.
Il codice per questi filtri è piuttosto semplice, lavorano con la funzione accept
che è o true
o false
che è quello di prendere o di filtrare:
class VisibleOnlyFilter extends RecursiveFilterIterator
{
public function accept()
{
$fileName = $this->getInnerIterator()->current()->getFileName();
$firstChar = $fileName[0];
return $firstChar !== '.';
}
}
class FilesOnlyFilter extends RecursiveFilterIterator
{
public function accept()
{
$iterator = $this->getInnerIterator();
// allow traversal
if ($iterator->hasChildren()) {
return true;
}
// filter entries, only allow true files
return $iterator->current()->isFile();
}
}
E questo è tutto nuovo. Naturalmente puoi usare questi filtri anche per altri casi. Per esempio. se hai un altro tipo di elenco di directory.
E un'altra uscita esemplare con la $rootpath
tagliato via:
test.html
test.rss
tests/test-pad-2.php
tests/test-pad-3.php
tests/test-pad-4.php
tests/test-pad-5.php
tests/test-pad-6.php
tests/test-pad.php
TLD/PSL/C/dkim-regdom.c
TLD/PSL/C/dkim-regdom.h
TLD/PSL/C/Makefile
TLD/PSL/C/punycode.pl
TLD/PSL/C/test-dkim-regdom.c
TLD/PSL/C/test-dkim-regdom.sh
TLD/PSL/C/tld-canon.h
TLD/PSL/generateEffectiveTLDs.php
Non più .git
o .svn
directory traversal o elenco di file come .builtpath
o .project
.
Nota per FilesOnlyFilter
e LEAVES_ONLY
: Il filtro nega esplicitamente l'uso delle directory e collegamenti basati sull'oggetto SplFileInfo
(only regular files that do exist). Quindi è un vero filtro basato sul file system.
Un altro metodo per ottenere solo voci non di directory viene fornito con RecursiveIteratorIterator
a causa del valore predefinito LEAVES_ONLY
flag (qui utilizzato anche negli esempi). Questo flag non funziona come filtro ed è indipendente dall'iteratore sottostante. Specifica solo che l'iterazione non deve restituire le diramazioni (qui: directory in caso di iteratore di directory).
Capisco la struttura della cartella che hai, ora che cosa vuoi che il tuo output sia. Aggiorna il ** output desiderato ** nella tua domanda! :) –
perché vorresti farlo. Ho poca esperienza con il php ma a mio avviso ucciderebbe il tuo povero server. Immagina 5000 persone che leggono la tua struttura di directory !!! – Tanmay
Beh, perché voglio farlo è perché ho uno script in flash as3 che può scaricare un file alla volta. Flash non può scaricare una cartella e il suo contenuto, quindi vorrei che il php crei una stringa di tutti i contenuti delle cartelle/sottocartelle e invii il messaggio a Flash e può iniziare a scaricare il contenuto nell'app. :) –