Nella lezione precedente di questa guida abbiamo visto il funzionamento delle due variabili superglobali $_GET e $_POST. In questa lezione vedremo, invece, come funziona la variabile superglobale $_FILES la quale viene utilizzata quale vettore per il trasferimento di file dal client verso il server. In altre parole, in questa lezione vedremo come gestire gli upload di files con PHP.
Configurare correttamente le opzioni relative agli upload
Prima di procedebe รจ bene ricordare al lettore che allโinterno del file php.ini sono presenti diverse opzioni che riguardano lโupload di file alle quali รจ bene prestare attenzione. Se non avete accesso diretto al file php.ini vi ricordo che potete visualizzare le varie impostazioni della vostra installazione di PHP utilizzando la funzione phpinfo().
Di seguito le opzioni interessate:
- file_uploads: se settata su 0 (o "off") lโupload di file รจ disabilitato (di default รจ settata su 1 o su "on");
- upload_tmp_dir: รจ la directory temporanea che PHP utilizzerร per far transitare i file durante lโupload; se non รจ specificata il sistema utilizzerร una cartella di default;
- upload_max_filesize: indica la dimensione massima di file che รจ possibile caricare (di default 2M);
- max_file_uploads: numero massimo di file che รจ possibile caricare simultaneamente.
Oltre a questi ci sono altri parametri che influenzano gli upload di file, cioรจ:
- post_max_size: indica la dimensione massima dei dati che รจ possibile inviare attraverso il metodo POST (il suo valore dovrebbe essere maggiore di upload_max_filesize);
- memory_limit: imposta la dimensione massima di memoria che puรฒ essere occupata dallโesecuzione di uno script (nelle versioni recenti di PHP รจ settato a 128M). Per non interferire con gli upload, questo parametro dovrebbe essere maggiore di post_max_size.
Come detto, รจ bene prestare attenzione a questi parametri in quanto, molto spesso, i problemi o gli errori nelle operazioni di upload mediante PHP sono dovuti ad una loro cattiva configurazione.
Creare il modulo di upload
Per effettuare lโupload di un file abbiamo bisogno, prima di tutto, di predisporre un form HTML che consenta allโutente di selezionare un file dal suo computer e di inviarcelo mediante il metodo POST. Di seguito il codice HTMl del nostro form di upload:
<form enctype="multipart/form-data" action="upload.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="30000">
Invia questo file: <input name="userfile" type="file"></br>
<input type="submit" value="Invia File">
</form>
In merito al codice proposto qui sopra sono necessarie alcune osservazioni:
- abbiamo aggiunto al tag <form> lโattributo enctype con valore "multipart/form-data": questa accortezza รจ essenziale in quanto una sua eventuale omissione comprometterebbe il funzionamento del sistema di upload!
- abbiamo previsto un campo nascosto MAX_FILE_SIZE: questo campo hidden deve precedere il campo di immissione del file ed รจ utilizzato per specificare la dimensione massima (espressa in byte) per il file. Eโbene precisare che questo campo รจ facoltativo ed un suo utilizzo, seppur consigliato, non รจ determinante. Altrettanto opportuno sottolineare come lโutilizzo di questo campo debba considerarsi "insicuro" in quanto il limite ivi espresso potrebbe essere facilmente aggirato (sempre meglio prevedere dei controlli lato server).
- la selezione del file รจ gestita medinate un input di tipo file il quale crea un pulsante che consente allโutente di selezionare un file locale navigando allโinterno del proprio computer.
Il codice PHP che realizza lโupload
Come detto allโinizio diq uesta lezione, PHP ci offre la variabile superglobale $_FILES la quale รจ un vettore (un array) contenente tutte le informazioni sul file che viene caricato. Facciamo un paio di esempi per capire meglio come funziona la variabile $_FILES:
Per conoscere il nome del file scaricato useremo:
$_FILES['userfile']['name']
Per vedere il mime-type:
$_FILES['userfile']['type']
Per vedere le sue dimensioni:
$_FILES['userfile']['size']
ecc.
Vediamo ora il codice dello script upload.php il quale recuperร il file per poi metterlo nella cartella che noi abbiamo predisposto per ospitare i file uploadati:
<?php
// per prima cosa verifico che il file sia stato effettivamente caricato
if (!isset($_FILES['userfile']) || !is_uploaded_file($_FILES['userfile']['tmp_name'])) {
echo 'Non hai inviato nessun file...';
exit;
}
//percorso della cartella dove mettere i file caricati dagli utenti
$uploaddir = '/var/www/myupload/';
//Recupero il percorso temporaneo del file
$userfile_tmp = $_FILES['userfile']['tmp_name'];
//recupero il nome originale del file caricato
$userfile_name = $_FILES['userfile']['name'];
//copio il file dalla sua posizione temporanea alla mia cartella upload
if (move_uploaded_file($userfile_tmp, $uploaddir . $userfile_name)) {
//Se l'operazione รจ andata a buon fine...
echo 'File inviato con successo.';
}else{
//Se l'operazione รจ fallta...
echo 'Upload NON valido!';
}
?>
Lo script come al solito รจ ampiamente commentato in ogni passaggio e pertanto dovreste aver compreso tutti i passaggi svolti, tuttavia ritengo opportuno alcune precisazioni in merito a due funzioni native di PHP che assumono un ruolo centrale nei processi di upload:
- nella prima linea di codice, dopo aver verificato se la variabile $_FILES รจ settata, ho utilizzato is_uploaded_file() per verificare se effettivamente รจ stato trasferito un file;
- con la funzione move_uploaded_file verifico se il file temporaneo รจ stato spostato correttamente nella cartella di destinazione: nel primo caso la funzione restituisce TRUE, in caso contrario FALSE.
Tecniche per la validazione degli upload
Il codice proposto qui sopra รจ davvero minimale e, prima di essere messo in produzione, necessiterebbe di alcune implementazioni ulteriori. Vediamo, di seguito, alcuni codici per implementare dei controlli di sicurezza circa i file caricati dagli utenti.
Verificare se il file รจ stato caricato
Si tratta di un controllo essenziale ed รจ lโunico che abbiamo introdotto nel nostro esempio:
if (!isset($_FILES['userfile']) || !is_uploaded_file($_FILES['userfile']['tmp_name'])) {
echo 'Non hai inviato nessun file...';
exit;
}
Verificare che il file non sia troppo grande
Un controllo piuttosto comune consiste nel verificare se il file caricato dallโutente non sia superiore ad una dimensione massima:
// limito la dimensione massima a 4MB
if ($_FILES['userfile']['size'] > 4194304) {
echo 'Il file รจ troppo grande!';
exit;
}
Verificare che lโupload non sovrascriva altro file
Talvalta puรฒ essere utile verificare se il file inviato dallโutente mediante il modulo di upload sia giร presente allโinterno della nostra cartella di destinazione:
$target_file = '/var/www/myupload/' . $_FILES['userfile']['name'];
if (file_exists($target_file)) {
echo 'Il file esiste giร ';
exit;
}
Verificare lโestensione del file caricato
Un modo semplice per controllare il tipo di file caricato dallโutente consiste nellโeffettuare una verifica sulla sua estensione:
$ext_ok = array('doc', 'docx', 'pdf');
$temp = explode('.', $_FILES['userfile']['name']);
$ext = end($temp);
if (!in_array($ext, $ext_ok)) {
echo 'Il file ha un estensione non ammessa!';
exit;
}
la verifica del tipo di file, รจ bene sottolinearlo, รจ molto impostante: senza un controllo del genere un attaccante potrebbe caricare sul nostro server dei codici malevoli che potrebbero compromettere la sicurezza del nostro sito web!
Verificare se il file รจ effettivamente un immagine
Un tipo di controllo molto comune consiste nel verificare se il tipo di file corrisponde a quello atteso. Se, ad esempio, abbiamo predisposto un modulo per il caricamento di immagini รจ buona norma verificare che il file inviato dallโutente sia effettivamente un file grafico:
$is_img = getimagesize($_FILES['userfile']['tmp_name']);
if (!$is_img) {
echo 'Puoi inviare solo immagini';
exit;
}