Come leggere tutte le immagini in una cartella con PHP

Quante volte ti sarà capitato di dover prelevare dinamicamente tutte le immagini in una cartella?
Può sembrare una cosa poco utile, ma in realtà gli utilizzi applicativi possono essere molteplici. Qualche esempio? Il più semplice, potrebbe essere avere uno slider che preleva dinamicamente le immagini in una cartella senza doverle aggiungere manualmente al codice ogni volta. Qualche applicazione più complessa, potrebbe essere creare uno script PHP di ottimizzazione delle immagini (ritaglio, risoluzione). Stai già pensando a come utilizzare questa possibilità per i tuoi scopi, vero?
- Leggi l'articolo, ti bastano solo 1 minuto, 23 secondi
Sei di fretta? Scarica il PDF e consultalo quando vuoi!
Sommario
La teoria: la classe RecursiveIteratorIterator
Una delle classi contenute di default in PHP già dalla versione 5 è RecursiveIteratorIterator, che consente di scorrere in modo semplice e veloce una generica struttura ad albero, come ad esempio menu con diverse profondità, gerarchie di categorie, struttura del DOM e tante altre ancora.
Una delle strutture ad albero più comuni è sicuramente il filesystem. Si, forse non ci avevi mai pensato, ma la struttura di suddivisione in cartelle e sottocartelle è proprio un classico esempio di struttura ad albero! Ma come funziona?
Elenco dei files in una cartella
La prima cosa da fare però è leggere il contenuto della cartella e la struttura, così da poterla scorrere e processare. Per farlo, utilizziamo un’altra utilissima classe, anche questa contenuta di default in PHP dalla versione 5, ovvero RecursiveDirectoryIterator. RecursiveDirectoryIterator fornisce un’interfaccia per iterare ricorsivamente sulle directory del filesystem, leggibile da RecursiveIteratorIterator.
Utilizzando RecursiveIteratorIterator, hai la possibilità di leggere tutti i files contenuti in una cartella, ma non solo: la classe ha tra le sue proprietà principali la capacità di scorrere ricorsivamente la struttura ad albero, quindi è in grado di leggere i files anche nelle sottocartelle, fino all’ultimo livello di profondità. Comodo no?
L’utilizzo è molto semplice:
<?php // Scorro i files nella cartella "contents" $directory = 'contents'; $rdi = new RecursiveDirectoryIterator( $directory ); $rii = new RecursiveIteratorIterator( $rdi ); foreach ( $rii as $file ) { /* Codice per processare i files */ }
In queste poche righe, hai gettato le basi principali utili a raggiungere lo scopo finale. In particolare:
– Riga 2: è stata stabilita la directory di base a partire dalla quale inizierà la lettura dei files (contents).
– Riga 4: è stata creata una istanza della classe RecursiveDirectoryIterator, che restituisce il contenuto della directory sotto forma di struttura ad albero iterabile.
– Riga 5: è stata creata una istanza della classe RecursiveIteratorIterator, che si occupa di scorrere la struttura ad albero precedentemente creata con RecursiveDirectoryIterator.
Non ci resta che scorrere la struttura ed elaborare i files a piacimento. Ma la teoria è sempre noiosa, passiamo quindi ad una caso d’uso pratico.
Un esempio pratico: leggere i files da una cartella
Ipotizza, ad esempio, di avere una cartella “contents” sul tuo server in cui sono contenute solamente files e che tu voglia semplicemente stamparne a video il nome. Eccone una creata ad-hoc come esempio:
- contents
- Archive.zip
- Image.jpg
- Image-2.png
- Text.txt
- Video.mp4
Implementando il codice nell’esempio precedente, avremo:
<?php // Scorro i files nella cartella "contents" $directory = 'contents'; $rdi = new RecursiveDirectoryIterator( $directory ); $rii = new RecursiveIteratorIterator( $rdi ); foreach ( $rii as $file ) { echo '<p>' . $file->getFilename() . '</p>'; }
che restituisce a video:
.
..
Archive.zip
Image.jpg
Image-2.png
Text.txt
Video.mp4
I meno esperti avranno notato incuriositi le prime due righe, costituite da un punto (.) e da due punti (..). Nulla di grave, nei filesystem Unix-like, indicano, rispettivamente, la directory attuale e la directory genitore.
Non ti basta?
Files in sottocartelle
Come detto in precedenza, RecursiveDirectoryIterator legge ricorsivamente la directory, quindi anche le sottocartelle ed il loro contenuto. Infatti, rispetto all’esempio precedente, ho inserito anche qualche sottocartella e dei files al suo interno:
- contents
- Archive.zip
- Image.jpg
- Image-2.png
- Text.txt
- Video.mp4
- subfolder
- Doc.pdf
- Image-3.jpg
- Image-4.jpg
- Image-5.jpg
rilanciando lo script, otteniamo:
.
..
Archive.zip
Image.jpg
Image-2.png
Text.txt
Video.mp4
.
..
Doc.pdf
Image-3.jpg
Image-4.jpg
Image-5.jpg
Avrai notato che per ogni cartella, vengono generate le directory speciali (.) e (..). Per evitare che vengano utilizzate, puoi semplicemente aggiungere una condizione di controllo:
<?php // Scorro i files nella cartella "contents" $directory = 'contents'; $rdi = new RecursiveDirectoryIterator( $directory ); $rii = new RecursiveIteratorIterator( $rdi ); foreach ( $rii as $file ) { if ( $file->isDir() ) { continue; } echo '<p>' . $file->getFilename() . '</p>'; }
che salta direttamente al file successivo.
In alcuni casi però potresti avere bisogno del percorso completo del file e non solamente del nome. In questo caso, è sufficiente utilizzare la funzione getPathname() al posto della funzione getFilename(), ottenendo:
contents/Archive.zip
contents/Image.jpg
contents/Image-2.png
contents/Text.txt
contents/Video.mp4
contents/subfolder/Doc.pdf
contents/subfolder/Image-3.jpg
contents/subfolder/Image-4.jpg
contents/subfolder/Image-5.jpg
Ma aspetta un attimo! Lo scopo principale della guida era estrapolare le immagini…
Come leggere solo le immagini in una directory
Ricapitolando: abbiamo letto tutti i files presenti in una cartella e nelle sue sottocartelle, ma ora è necessario filtrare i risultati così da avere solamente le immagini. Semplice:
<?php // Scorro i files nella cartella "contents" $directory = 'contents'; $rdi = new RecursiveDirectoryIterator( $directory ); $rii = new RecursiveIteratorIterator( $rdi ); foreach ( $rii as $file ) { if ( $file->isDir() ) { continue; } if ( ! in_array( mime_content_type( $file->getPathname() ), array( 'png' => 'image/png', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'bmp' => 'image/bmp', 'ico' => 'image/vnd.microsoft.icon', 'tiff' => 'image/tiff', 'tif' => 'image/tiff', 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', ) ) ) { continue; } echo '<p>' . $file->getFilename() . '</p>'; }
Con l’utilizzo della funzione mime_content_type() di PHP, verifichiamo che il mime type di ogni file corrisponda ad una immagine ed in caso contrario, saltiamo al successivo.
Ovviamente, sostituendo i mime types puoi applicare questo script a qualsiasi tipo di file tu abbia bisogno di estrapolare. Non ti resta che mettere in pratica tutto questo nei tuoi prossimi progetti!
Ottimo. Ho scopiazzato e riadattato uno script per riuscire a cancellare le immagini vecchie create da una telecamera. La webcam salva le immagini in una questa struttura: webcam/immagini/anno/mese/giorno. Lo script mi identifica con precisione tutte le immagini "da cancellare" ma quando attivo il comando unlink (sulla variabile che identifica "i files vecchi", vengono cancellate tutte le immagini in tutte le directory. Come avrai capito sono un superdilettante e sbaglio certamente qualcosa. Grazie per il supporto.