W3docs

Caricamento di file in PHP

Scopri come gestire il caricamento di file in PHP con $_FILES e move_uploaded_file(), con validazione sicura e configurazione php.ini.

Il caricamento di file è un requisito comune nello sviluppo web. Che si tratti di un'immagine del profilo, di un documento PDF o di un'importazione CSV, consentire agli utenti di inviare file al server è una funzionalità fondamentale della maggior parte delle applicazioni. In PHP questo viene gestito dalla funzione move_uploaded_file() insieme all'array superglobale $_FILES.

Questo capitolo tratta l'intero flusso di caricamento: configurare il form HTML, leggere i metadati del file caricato da $_FILES, validarlo in modo sicuro e spostarlo nella destinazione finale. Vengono esaminati anche i codici di errore del caricamento e le impostazioni di configurazione PHP che controllano i limiti di upload.

Come funziona il caricamento di file in PHP

Il caricamento di un file avviene in tre fasi:

  1. Il browser invia il file in una richiesta POST multipart/form-data.
  2. PHP riceve il file, lo scrive in una posizione temporanea sul disco, quindi espone i dettagli nell'array $_FILES.
  3. Lo script valida il file e lo sposta dalla posizione temporanea a una permanente con move_uploaded_file().

Il file temporaneo viene eliminato automaticamente al termine della richiesta se non viene spostato, quindi è necessario elaborarlo durante la stessa richiesta.

Il superglobale $_FILES

Quando viene caricato un file, le informazioni su di esso vengono memorizzate nell'array superglobale $_FILES. Per un campo del form denominato userfile, l'array contiene le seguenti chiavi:

  • $_FILES['userfile']['name'] - Il nome originale del file caricato.
  • $_FILES['userfile']['type'] - Il tipo MIME del file caricato.
  • $_FILES['userfile']['size'] - La dimensione del file caricato in byte.
  • $_FILES['userfile']['tmp_name'] - La posizione temporanea del file caricato sul server.
  • $_FILES['userfile']['error'] - Un codice di errore che indica se si è verificato un problema durante il caricamento del file (vedi i codici di errore di seguito).

Passo 1: Il form HTML

L'attributo enctype del form deve essere impostato su multipart/form-data, e il metodo deve essere POST. Senza multipart/form-data, il browser invia solo il nome del file, non il suo contenuto, e $_FILES sarà vuoto.

<form action="upload.php" method="POST" enctype="multipart/form-data">
  <input type="file" name="userfile">
  <input type="submit" value="Upload">
</form>

Passo 2: Validare il caricamento

Non fidarsi mai di un file caricato. Prima di spostarlo, verificare tre cose: che il caricamento sia avvenuto con successo, che la dimensione rientri nel limite consentito e che il file sia davvero del tipo atteso.

Controllare il codice di errore

Ispezionare sempre prima $_FILES['userfile']['error']. PHP definisce costanti con nome per i valori possibili:

CostanteValoreSignificato
UPLOAD_ERR_OK0Nessun errore, il file è stato caricato correttamente.
UPLOAD_ERR_INI_SIZE1Il file supera upload_max_filesize in php.ini.
UPLOAD_ERR_FORM_SIZE2Il file supera il campo MAX_FILE_SIZE del form.
UPLOAD_ERR_PARTIAL3Il file è stato caricato solo parzialmente.
UPLOAD_ERR_NO_FILE4Nessun file è stato caricato.
UPLOAD_ERR_NO_TMP_DIR6Manca una cartella temporanea.
UPLOAD_ERR_CANT_WRITE7Impossibile scrivere il file su disco.

Validare tipo e dimensione in modo sicuro

Non affidarsi a $_FILES['userfile']['type']. Quel valore è fornito dal browser e può essere facilmente falsificato da un attaccante. Invece, rilevare il tipo MIME reale dal contenuto del file con l'estensione finfo, e imporre un limite di dimensione autonomamente:

$file = $_FILES['userfile'];

// 1. Did the upload succeed?
if ($file['error'] !== UPLOAD_ERR_OK) {
  exit("Upload failed with error code " . $file['error']);
}

// 2. Enforce a maximum size (2 MB here).
$maxBytes = 2 * 1024 * 1024;
if ($file['size'] > $maxBytes) {
  exit("File is too large.");
}

// 3. Detect the real MIME type, not the client-supplied one.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($file['tmp_name']);

$allowed = [
  'image/jpeg' => 'jpg',
  'image/png'  => 'png',
  'image/gif'  => 'gif',
];

if (!isset($allowed[$mime])) {
  exit("Only JPEG, PNG, and GIF images are allowed.");
}

Passo 3: Spostare il file nella destinazione finale

Una volta validato il file, spostarlo con move_uploaded_file(). Accetta due argomenti: il percorso temporaneo ($_FILES['userfile']['tmp_name']) e il percorso di destinazione. Usare questa funzione invece di copy() o rename() è importante — verifica che il file sia stato un autentico upload HTTP, il che impedisce a un attaccante di ingannare lo script facendogli spostare un file arbitrario del server.

Generare il nome del file finale autonomamente invece di fidarsi del nome originale. Questo evita attacchi di directory traversal (un nome come ../../config.php) e la sovrascrittura di file esistenti:

$targetDir = "uploads/";

// Build a safe, unique file name; never trust the client's name.
$extension  = $allowed[$mime];
$safeName   = bin2hex(random_bytes(8)) . "." . $extension;
$targetFile = $targetDir . $safeName;

if (move_uploaded_file($file['tmp_name'], $targetFile)) {
  echo "The file was uploaded as " . $safeName;
} else {
  echo "There was an error saving the file.";
}

Per maggiori dettagli su questa funzione e sulla sua funzione complementare is_uploaded_file(), consultare i capitoli di riferimento move_uploaded_file() e is_uploaded_file().

Configurazione che influisce sui caricamenti

Alcune direttive di php.ini limitano silenziosamente ciò che lo script può ricevere. Se i caricamenti di file di grandi dimensioni falliscono anche quando il codice è corretto, verificare queste impostazioni:

  • file_uploads — deve essere On affinché i caricamenti funzionino.
  • upload_max_filesize — la dimensione massima del singolo file che PHP accetta (default 2M).
  • post_max_size — la dimensione massima totale del corpo POST; deve essere maggiore di upload_max_filesize.
  • max_file_uploads — il numero massimo di file in una singola richiesta.

Conclusione

Il caricamento di file in PHP è una parte fondamentale dello sviluppo web. Con l'array superglobale $_FILES e la funzione move_uploaded_file(), è possibile gestire i caricamenti in poche righe. La parte difficile è farlo in modo sicuro: controllare sempre il codice di errore del caricamento, imporre un limite di dimensione, rilevare il tipo MIME reale con finfo invece di fidarsi di $_FILES[...]['type'], e generare un nome file proprio in modo che il client non possa mai controllare dove il file viene salvato. Per elaborare il file salvato in seguito, consultare gestione dei file PHP e validazione dei form.

Esercitazione

Pratica
Quali delle seguenti affermazioni riguardanti il caricamento di file in PHP sono corrette?
Quali delle seguenti affermazioni riguardanti il caricamento di file in PHP sono corrette?
Was this page helpful?