Capitolo 18. Caricare file

Sommario
Metodo POST per caricamento di file
Common Pitfalls
Caricamento di più file
Supporto per metodo PUT

Metodo POST per caricamento di file

PHP è in grado di ricevere file caricati da qualsiasi browser compatibile con le specifiche RFC-1867 (che comprende Netscape Navigator 3 o successivo, Microsoft Internet Explorer 3 con una modifica di Microsoft, o versioni successive senza modifica). Questa caratteristica permette di caricare sia file di testo che binari. Utilizzando le funzioni di PHP per l'autenticazione e manipolazione dei file, è possibile avere pieno controllo su chi ha i permessi per caricare un file e su ciò che deve essere fatto una volta che il file è stato caricato.

Si noti che PHP permette l'upload di file con metodo PUT come utilizzato dai programmi Netscape Composer e W3C Amaya. Si veda Supporto per metodo PUT per maggiori dettagli.

La schermata di caricamento di un file può essere costruita con una form particolare, di questo tipo:

Esempio 18-1. Form di caricamento file

<form enctype="multipart/form-data" action="_URL_" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="1000">
Invia questo file: <input name="userfile" type="file">
<input type="submit" value="Invia File">
</form>
Il valore della action _URL_ dovrebbe puntare a un file PHP. Il campo nascosto MAX_FILE_SIZE deve precedere il campo di immisione del file e il suo valore è la dimensione massima accettata del file. Il valore è in byte.

Attenzione

Il valore MAX_FILE_SIZE è consigliato al browser. E' facile aggirare questo valore, quindi non fate affidamento sul fatto che il navigatore si comporti come desiderato! L'impostazione PHP lato server per la dimensione massima non può comunque essere aggirata.

In PHP, le seguenti variabili sono definite all'interno dello script di destinazione a seguito di un upload terminato con successo, nell'ipotesi che l'impostazione register_globals sia attiva nel file php.ini. Se l'impostazione track_vars è attiva, le variabili saranno attive in PHP nell'array globale $HTTP_POST_VARS. Notate che i nomi delle variabili seguenti si basano sull'ipotesi che abbiate chiamato il file di cui fare l'upload 'userfile' come nell'esempio precedente:

Si noti che la parte "$userfile" della variabile precedente è specificata nel campo INPUT TYPE=file nella form di upload. Nell'esempio precedente dell'upload, è stata chiamata "userfile"

In PHP 4 il comportamento è leggermente differente, perché è disponibile il nuovo array globale $HTTP_POST_FILES che contiene le informazioni sul file caricato. Questo è disponibile solo se la variabile track_vars è attiva, ma track_vars è sempre attiva dalle versioni successive alla PHP 4.0.2.

Il contentuto dell'array $HTTP_POST_FILES è riportato di seguito. Si noti che che questo ipotizza l'uso del nome del file caricato 'userfile', come nell'esempio precedente:

$HTTP_POST_FILES['userfile']['name']

Il nome originale del file sulla macchina dell'utente.

$HTTP_POST_FILES['userfile']['type']

Il mime-type del file, se il browser fornisce questa informazione. Un esempio potrebbe essere "image/gif".

$HTTP_POST_FILES['userfile']['size']

La dimensione, in bytes, del file caricato.

$HTTP_POST_FILES['userfile']['tmp_name']

Il nome del file temporaneo in cui il file caricato è salvato sul server.

I file sono, di default, salvati in una directory temporanea sul server, a meno che un diverso percorso sia specificato nella direttiva upload_tmp_dir nel file php.ini. La directory del server predefinita può essere cambiata impostando la variabile di ambiente TMPDIR in cui è in esecuzione PHP. Non è possibile impostare questa variabile utilizzando la funzione putenv() da uno script PHP. Questa variabile di ambiente può anche essere usata per assicurarsi che anche altre operazioni stiano lavorando sui file caricati.

Esempio 18-2. Verifica dell'upload di file

Gli esempi seguenti valgono per versioni di PHP 3 maggiori di 3.0.16, e versioni di PHP 4 maggiorni di 4.0.2. Si vedano le definizioni delle funzioni is_uploaded_file() e move_uploaded_file().

<?php 
if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "Possibile attacco nell'upload del file: filename '$userfile'.";
}
/* ...or... */
move_uploaded_file($userfile, "/posto/dove/mettere/file/caricato");
?>

Per le versioni precedenti di PHP è necessario fare come descritto in seguito.

Nota: Questo non funziona con le versioni di PHP 4 successive alla 4.0.2. Dipende da funzionalità interne del PHP cambiate dopo quella versione.

<?php
/* Userland test for uploaded file. */ 
function is_uploaded_file($filename) {
    if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
        $tmp_file = dirname(tempnam('', ''));
    }
    $tmp_file .= '/' . basename($filename);
    /* User might have trailing slash in php.ini... */
    return (ereg_replace('/+', '/', $tmp_file) == $filename);
}

if (is_uploaded_file($userfile)) {
    copy($userfile, "/posto/dove/mettere/file/caricato");
} else {
    echo "Possibile attacco nell'upload del file: filename '$userfile'.";
}
?>

Lo script PHP che riceve il file caricato dovrebbe implementare la logica necessaria per determinare cosa deve essere fatto con il file caricato. E' possibile, per esempio, utilizzare la variabile $file_size per eliminare file che siano troppo grandi o troppo piccoli. E' possibile utillizzare la variabile $file_type per eliminare tutti i file che nono sodisfano certi criteri. Quale che sia la logica, bisognerebbe comunque sempre cancellare il file dalla directory temporanea e spostarlo da qualche altra parte.

Il file sarà eliminato dalla directory temporanea al termine della richiesta se non è stato mosso e rinominato.