Le basi dell’upload di files
In questa serie di articoli tratteremo un aspetto particolare della programmazione per il web, ovvero il processo di upload di files. Si tratta di un’operazione non esente da insidie e che va quindi gestita con cura.
Questa serie è composta da cinque tutorial:
- Le basi dell’upload di file: dove vedremo come viene gestito il processo e quali funzioni utilizzare.
- Una classe avanzata per gestire gli upload: dove svilupperemo una classe robusta per la gestione dell’upload di file.
- Utilizzare la classe upload: dove vedremo come utilizzare la classe sviluppata nell’articolo precedente.
- Introduzione alla libreria GD: siccome il più delle volte utilizziamo il processo di upload per caricare immagini, introdurremo la libreria GD con la quale è possibile creare e manipolare immagini.
- Applicazioni della libreria GD: dove vedremo l’utilità di questa libreria per gestire le immagini caricate. Ad esempio la creazione “al volo” di thumbnail, o la posa di un watermark.
Il tutto ci porterà a sviluppare una semplice gallery. Pronto per iniziare?
Come avviene il processo di upload di un file?
Il processo di upload è rappresentato nel seguente schema:
- Il file viene scelto dall’utente tramite un form che deve avere delle caratteristiche precise, il file può essere indifferentemente un file di testo o un file binario.
- Il file viene caricato nella cartella temporanea del webserver.
- A questo punto possiamo svolgere tutti i controlli necessari.
- Se questo controlli non saranno superati il file sarà eliminato (i file scritti nella cartella temporanea al termine dell’operazione vengono cancellati automaticamente dello script).
- Se i controlli daranno esito positivo, il file sarà spostato nella cartella di destinazione e rinominato.
- E’ possibile infine salvare nel database le informazioni del file che abbiamo caricato. L’idea di inserire direttamente il file binario nel database è da scartare. Si andrebbe infatti ad incidere notevolmente sulle prestazioni.
A questo punto possiamo iniziare dal form.
Come creare un form di upload?
Crea un nuovo file e salvalo come upload.php
Le principali ed indispensabili caratteristiche di un form di upload sono:
- l’attributo enctype deve essere multipart/form-data
- il metodo deve essere POST (ovviamente è impossibile passare un file con il metodo GET)
Dunque iniziamo a dichiarare il nostro form
<form enctype="multipart/form-data" action="upload_process.php" method="post">
A questo punto potremmo inserire un campo hidden specifico dei form di upload che serve (o servirebbe) a limitare la dimensione dei file caricati.
<input type="hidden" name="MAX_FILE_SIZE" value="1048576" />
Con questo campo indichiamo che la dimensione massima del file caricato non deve superare i 1048576 bytes, ovvero 1MB.
Personalmente ritengo questo passaggio superfluo ed addirittura fuorviante. Tutto quello che viene dichiarato lato client è facilmente aggirabile. Disponiamo di diversi metodi sicuri lato server, quindi utilizzeremo quelli.
Passiamo dunque al campo che ci permetterà di scegliere il file da caricare. E’ un campo di input con type = “file”.
<input name="upload_name" type="file" />
È chiaramente possibile inserire anche tutti gli altri tipi di campo disponibili per i form. Il loro contenuto lo troveremo poi nell’array $_POST, mentre le informazioni sul file caricato le troveremo nell’array $_FILES. Ma questo lo vedremo più avanti.
Non ci resta che dichiarare il pulsante di submit ed il form sarà pronto per l’uso.
<form enctype="multipart/form-data" action="upload_process.php" method="post"> <input name="upload_name" type="file" /> <input type="submit" value="upload" /> </form>
Ottenendo questo risultato
Gli amanti dell’estetica si mettano il cuore in pace. Per un motivo a me ignoto, non è possibile gestire tramite CSS il pulsante “sfoglia”.
Come gestire il processo
Ora ci sposteremo nel vero cuore del processo di upload. Il form punta al file upload_process.php; crealo.
Come accennato precedentemente, nella pagina di destinazione disporremo di alcune informazioni sul file caricato all’interno dell’array $_FILES, vediamo quali sono queste informazioni:
- $_FILES[‘upload_name’][‘name’] contiene il nome originale del file caricato;
- $_FILES[‘upload_name’][‘tmp_name’] contiene il nome assegnato al file nella cartella temporanea;
- $_FILES[upload_name’][‘size’] contiene la dimensione in bytes del file caricato;
- $_FILES[‘upload_name’][‘type’] contiene il mime del file (ad esempio image/png);
- $_FILES[‘upload_name’][‘error’] contiene informazioni su eventuali errori del processo (vedremo nel prossimo tutorial);
In questo primo tutorial non faremo nessun tipo di controllo, ci limiteremo a spostare il file dalla cartella temporanea alla cartella di destinazione. Lo faremo con l’apposita funzione move_uploaded_file che passa due parametri:
- il nome del file temporaneo
- il percorso/nome del file di destinazione
Quindi il nostro upload_process.php potrebbe essere così
move_uploaded_file($_FILES['upload_name']['tmp_name'],'img/' . $_FILES['upload_name']['name']);
Scritto in questo modo, il file verrà prelevato dalla cartella temporanea e salvato nella cartella img con lo stesso nome che aveva sul computer che lo ha inviato.
Il nostro sistema di upload ora funziona, ma ad un livello estremamente basilare per non dire rudimentale. Per rendere questo sistema robusto, dobbiamo tenere conto di alcuni aspetti:
- Limitazione delle estensioni: E’ meglio limitare le possibili estensioni dei file allo stretto necessario. Non procedendo a questa limitazione è possibile ad esempio caricare dei file PHP maligni e, conoscendo la cartella di destinazione, eseguirli con tutte le conseguenze del caso. E mi fermo qui.
- Limitazione della dimensione: Come abbiamo visto è inutile farlo dal form. Nel nostro script lato server abbiamo a disposizione il valore $_FILES[‘upload_name’][‘size’] grazie al quale potremmo fare la nostra verifica. E’ possibile, come misura aggiuntiva, modificare i valori upload_max_filesize e/o post_max_size nel php.ini.
- Verificare la legittimità del file: Prima di spostare il file dalla cartella temporanea a quella di destinazione, é fortemente consigliato l’utilizzo della funzione is_uploaded_file alla quale passeremo il nome del file. Questa funzione verifica che il file sia stato caricato tramite il protocollo HTTP POST e non magari grazie a qualche astuta peripezia. L’utilizzo di questa funzione ci mette al riparo da tutta una serie di scherzetti che possono costare caro.
- Rinominare il file: Non esiste nessun motivo per il quale si debba salvare il file con lo stesso nome che aveva sul computer client. L’operazione di rinomina del file con una stringa casuale è una procedura diffusissima (guarda ad esempio il nome delle tue immagini caricate su facebook) ed ha due ragioni principali:
- Otterremo un nome normalizzato, quindi senza spazi o caratteri speciali che possono creare problemi nel salvataggio.
- Se non usiamo questo metodo, dovremo controllare se il nome del file che abbiamo caricato non esista già nella cartella di destinazione. E’ un’operazione che, se abbiamo molti file, può diventare molto onerosa.
Conclusione
In questo primo tutorial abbiamo visto le basi dell’upload di file. Abbiamo sviluppato un sistema molto rudimentale e piuttosto lacunoso, anche se funziona perfettamente.
Alla fine abbiamo visto quali aspetti bisognerebbe tenere conto per migliorare la sicurezza e la stabilità dell’applicazione.
Nel prossimo tutorial svilupperemo una classe robusta ed altamente configurabile che terrà conto di questi, ma anche di altri aspetti e che potrai utilizzare nei tuoi lavori.
21 commenti
Trackback e pingback
-
Una classe per gestire l’upload | Your Inspiration Web
[...] precedente articolo, abbiamo visto le basi della procedura di upload di un file. Oggi svilupperemo una classe robusta e…
Grazie per questo tutorial! Davvero molto interessante e ben scritto.
Grazie Davide
molto interessante!!!
Grazie
Interessante buon inizio! Aspetterò con ansia il prosieguo.
Grazie dell’apprezzamento Giacinto!
Davvero un ottimo articolo, complimenti. Non è che integrate pure il modo di trasformare quell’orrendo pulsante “Sfoglia” in qualche altra cosa?
Ciao Giuliano.
Come detto, tramite css non vi é nessuna possibilità.
E’ possibile tramite javascript. Ad esempio svovrappnonendo un immagine al bottone esistente.
Oppure esistono dei plugin jQuery che gestiscono il layout dei campi form. Come sai, anche altri campi non sono molto o per niente personalizzabili (select, radio, checkbox). Grazie a questi plugin lo diventano.
ritorno in grande stile anche per il nostro maurizio! bentornato ubriacone :)
Nando, non fare lo spiritoso e goditi gli ultimi mesi nei quali potrai lavorare :-)
maurì, ma quali ultimi mesi… già qui è un gran casino. quanto ti capisco adesso.
Ottimo articolo, devo dire che avendo già affrontato questa tematica ero ben informato sull’argomento.
Seguirò accuratamente i prossimi capitoli inquanto a breve ne avrò bisogno.
Bel tutorial complimenti!
Grazie anche a te Gianfranco
Ottimo articolo Maurizio, da un po di tempo volevo sviluppare un’ applicazione partendo proprio dall’upload, ma volevo chiederti (magari sarà argomento nelle prossime lezioni) qual’e il modo per selezionare più file?
grazie
Ciao Michelangelo e grazie.
Puoi inserire più campi “file” ed utilizzare come nome campo un array (ad esempio: upload_file[]).
La classe che svilupperemo nel prossimo tutorial non é pensata per questa eventualità in quanto poi, anche lato server, l’array $_FILES avrà tre dimensioni ($_FILES[‘upload_name’][‘name’][2])
http://www.php.net/manual/en/features.file-upload.post-method.php (esempio #3)
P.S puoi comunque utilizzare degli uploader tipo plupload (http://www.plupload.com/).
In questi tutorial, siccome ci interessa la tecnica, facciamo tutto “a mano”
Grazie per la risp. e per la segnalazione di plupload.com!
se utilizzassi l’attributo – multiple=”multiple” – dentro “input file” posso selezionare più file, ottenebdo il risultato da me cercato, ma devo anche dare al nome campo un array come suggerito da te? e lato server avrò l’array globale a tre dimensioni?
Grazie ancora e scusami se approfitto della tua gentilezza!
multiple é una caratteristica di html5 supportata unicamente dai browser di ultimissima generazione, e nemmeno tutti (ie ad esempio non lo supporta). Di solito sconsiglio vivamente l’utilizzo di una caratteristica almeno fino a quando non é supportata dall’ultima versione di tutti i browser. E da li via, comunque con cautela
non conoscevo la limitazione… grazie mille per avermi messo in guardia!
Ottimo articolo… a quando la prossima parte? ;-)