back to top

Upload con PHP: caricare un file sul server attraverso un form

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().

Pubblicitร 

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;    
}
Pubblicitร 
Massimiliano Bossi
Massimiliano Bossi
Stregato dalla rete sin dai tempi delle BBS e dei modem a 2.400 baud, ho avuto la fortuna di poter trasformare la mia passione in un lavoro (nonostante una Laurea in Giurisprudenza). Adoro scrivere codice e mi occupo quotidianamente di comunicazione, design e nuovi media digitali. Orgogliosamente "nerd" sono il fondatore di MRW.it (per il quale ho scritto centinaia di articoli) e di una nota Web-Agency (dove seguo in prima persona progetti digitali per numerosi clienti sia in Italia che all'estero).