Upload con Php
Premessa
Come è noto a chiunque abbia un minimo di familiarità con il PHP, è estremamente
semplice gestire gli Uploads da un computer-client verso un computer-server. Lo
scopo di questo articolo è proprio dimostrarlo e realizzare, alla fine, un
semplice script che ci consenta di gestire agevolmente il "caricamento" dei file
in rete.
Piccola, ma doverosa, premessa: cosa significa Upload?
Letteralmente questa parola inglese significa "caricare" e si contrappone,
logicamente, a Download (termine probabilmente più familiare del primo), ossia
"scaricare".
In breve indica l'operazione di trasferimento di uno o più files da un client
verso un server, operazione che di norma viene svolta avvalendosi del protocollo
FTP (File Transfer Protocol) e di appositi programmi (detti appunto client FTP).
Ma il trasferimento può anche essere attuato, con PHP, tramite un form con
metodo POST; ed è proprio questo il caso che stiamo prendendo in considerazione.
PHP, si diceva, può ricevere files "uploadati" da qualunque browser che sia
compatibile con le direttive fissate nella RFC (Request For Comments) 1867 che,
nel lontano Novembre 1995 (preistoria per gli standard di Internet...),
introduceva un nuovo tipo di opzione per i campi di un modulo di tipo input:
l'opzione FILE. Inoltre veniva definito un nuovo MIME (Multipurpose Internet
Mail Extensions) media type, denominato multipart/form-data (per maggiori
informazioni in merito, si può leggere l'intera RFC a questo indirizzo
http://www.ietf.org/rfc/rfc1867.txt ).
Discutine sul ForumCostruzione del modulo html
Fatta questa premessa introduttiva, possiamo adesso cominciare a costruire il
nostro script per gli Uploads. Il primo passo non può che essere la
realizzazione del modulo HTML che ci servirà per inviare i nostri files al
server; ridotto al suo schema essenziale, il form può essere così concepito:
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="upfile">
<input type="hidden" name="MAX_FILE_SIZE" value="10000">
<input type="submit" value="Invia il file">
</form>
Salviamo queste righe in un file chiamato form.html (non è necessaria
l'estensione .php, dato che contiene solo istruzioni html).
Un prima considerazione si impone: oltre al campo di tipo FILE, abbiamo aggiunto
un campo nascosto (hidden) chiamato MAX_FILE_SIZE con value 10000. Esso indica
la 'grandezza' massima (espressa in bytes) del file da caricare e a questo
proposito va detto che, come avverte chiaramente anche il manuale ufficiale di
PHP, non si deve fare troppo affidamento su questo parametro per "garantirsi"
contro gli upload di files di dimensioni maggiori di quella desiderata, perchè
il limite è facilmente aggirabile.
Molto più sicuro, a questo fine, è il parametro upload_max_filesize nel file
php.ini (il file di configurazione di PHP) che di default è settato a 2
MegaBytes.
Seconda considerazione: adesso che abbiamo il nostro modulo per l'upload, una
cosa che balza subito all'occhio è il tasto "sfoglia" (browse) alla destra del
campo di tipo FILE; questo bottone serve proprio per selezionare il file
dall'hard disk del client che verrà visualizzato (il file, non l'Hard Disk...),
all'interno del campo, con il suo percorso assoluto.Le variabili da usare per l'upload
Prima di addentrarci nella realizzazione della pagina PHP che "raccoglierà" i
dati provenienti dal modulo, è necessario spiegare cosa accade quando lo script
riceve un Upload.
In questa situazione vengono automaticamente definite alcune variabili
particolari, caratterizzate anzitutto dal fatto che il loro nome consta di due
parti: la prima coincide con il nome del campo di tipo FILE (nel nostro caso
quindi upfile); la seconda invece indica un "attributo" del file.
Da notare altresì che queste variabili saranno disponibili all'interno dell'array
globale $HTTP_POST_FILES ($_FILES a partire da PHP 4.1.0), sempre che il
parametro track_vars, nel file php.ini, sia settato ad ON (il problema,
peraltro, si pone per le versioni di PHP precedenti alla 4.03, a partire dalla
quale track_vars è automaticamente abilitato).
Queste variabili sono:
$nomefile (il nome temporaneo del file che viene attribuito al file sul server)
$nomefile_name (il nome originario o il percorso del file sul client)
$nomefile_size (la grandezza, espressa in bytes, del file)
$nomefile_type (il MIME type del file, ad esempio application/x-zip-compressed)
Come detto $nomefile si riferisce al nome del campo FILE del form, quindi
$upfile nel nostro esempio.
A questo punto però, è doveroso accennare alla grande modifica introdotta dallo
staff di PHP a partire dalla versione 4.2.0 (al momento in cui scrivo siamo
arrivati alla 4.2.3), ossia il settaggio ad Off di default del parametro
register_globals nel file php.ini.
Senza approfondire troppo l'argomento, in quanto esulerebbe dagli scopi di
questo scritto, possiamo limitarci a dire che, a seguito di questa novità per
riferirsi alle variabili globali, occorre fare riferimento all'array cui esse
appartengono (a meno che non si modifichi php.ini, ovviamente). Nel nostro caso,
quindi, all'array $HTTP_POST_FILES sostituiamo l'array $_FILES (in seguito
vedremo come rendere comunque compatibili anche le versioni di PHP precedenti
alla 4.1.0).
Quindi le variabili si "traducono" in:
$_FILES["nomefile"]["tmp_name"] (il nome temporaneo del file che viene
attribuito al file sul server)
$_FILES["nomefile"]["name"] (il nome originario o il percorso del file sul
client)
$_FILES["nomefile"]["size"] (la grandezza, espressa in bytes, del file)
$_FILES["nomefile"]["type"] (il MIME type del file, ad esempio application/x-zip-compressed).Costruiamo
la pagina Php per l'upload
Cominciamo quindi a costruire la pagina .php che si occuperà di verificare l'upload
e di gestire il file come vogliamo. Per comodità, preferisco scrivere prima
tutto il codice e poi spiegarlo passo passo, con l'avvertenza che anche qui,
come nel form, lo script sarà semplice, senza troppe opzioni.
<?
// QUESTE RIGHE RENDONO LO SCRIPT COMPATIBILE CON LE VERSIONI
// DI PHP PRECEDENTI ALLA 4.1.0
if(!isset($_FILES)) $_FILES = $HTTP_POST_FILES;
if(!isset($_SERVER)) $_SERVER = $HTTP_SERVER_VARS;
/********************* VARIABILI DA SETTARE ********************/
// Directory dove salvare i files Uploadati ( chmod 777, percorso assoluto)
$upload_dir = $_SERVER["DOCUMENT_ROOT"] . "/upload";
// Eventuale nuovo nome da dare al file uploadato
$new_name = "";
// Se $new_name è vuota, il nome sarà lo stesso del file uploadato
$file_name = ($new_name) ? $new_name : $_FILES["upfile"]["name"];
if(trim($_FILES["upfile"]["name"]) == "") {
die("Non hai indicato il file da uploadare !");
}
if(@is_uploaded_file($_FILES["upfile"]["tmp_name"])) {
@move_uploaded_file($_FILES["upfile"]["tmp_name"], "$upload_dir/$file_name")
or die("Impossibile spostare il file, controlla l'esistenza o i permessi della
directory dove fare l'upload.");
} else {
die("Problemi nell'upload del file " . $_FILES["upfile"]["name"]);
}
echo "L'upload del file " . $_FILES["upfile"]["name"] . " è avvenuto
correttamente";
?>
Le prime righe, come chiarisce il commento, servono a rendere disponibile la
sintassi dei nuovi array introdotti con PHP 4.1.0 anche alle versioni
precedenti.
Le due variabili da settare sono rispettivamente:
la directory dove spostare i files uploadati ($upload_dir, da indicare con il
percorso assoluto sul server e i cui permessi vanno settati a 777)
l'eventuale nuovo nome da dare al file che viene caricato sul server ($new_name;
se non si vuole rinominare il file, questo avrà lo stesso nome che aveva sul
computer client.)
A questo punto effettuiamo un controllo per verificare se è stato selezionato un
file per l'Upload, e lo facciamo con riferimento alla proprietà "name" del file.
Andata a buon fine questa verifica, possiamo passare al cuore dello script, la
parte cioè che "sposta" il file caricato in rete dalla directory temporanea del
server (che si può settare in php.ini, nella variabile upload_tmp_dir) alla
directory da noi indicata, eventualmente rinominandolo.
Le funzioni usate a questo scopo, sono is_uploaded_file() (PHP 3>= 3.0.17, PHP 4
>= 4.0.3) e move_uploaded_file() (PHP 4 >= 4.0.3, eventualmente si può usare
copy() in sostituzione). La prima funzione prende come parametro la variabile
che contiene il nome temporaneo del file uploadato sul server ($_FILES["upfile"]["tmp_name"])
e verifica, appunto, se sia stato caricato; la seconda funzione prende due
parametri: il primo è il nome temporaneo ed il secondo è il percorso finale
(comprensivo del nome, nuovo o meno, del file) dove spostarlo.
A questo proposito vi segnalo che è possibile, nell'ipotesi in cui si disponga
di una versione di PHP in cui non sia presente la funzione is_uploaded_file(),
"costruirne" una che svolga lo stesso compito, come evidenziato dal manuale
ufficiale a questo link: http://www.php.net/manual/it/features.file-upload.php.
Se anche queste operazioni si svolgono senza problemi (nel caso di difficoltà,
lo script restituirà solo messaggi d'errore personalizzati), verrà stampata a
video la frase che ci conferma che l'upload è avvenuto correttamente.
Conclusioni
Tutto molto semplice come si vede. Ovviamente è possibile implementare ulteriori
controlli all'interno dello script; ad esempio, sfruttando la proprietà "type",
si può agevolmente limitare l'upload solo a determinati tipi di files
aggiungendo poche righe subito dopo il controllo sull'esistenza del file
uploadato:
$allowed_types = array("image/gif","image/x-png","image/pjpeg","image/jpeg");
if(!in_array($_FILES["upfile"]["type"],$allowed_types)) {
die("Il file non è di un tipo consentito, sono ammessi solo i seguenti: " .
implode(",", $allowed_types) . ".");
}
?>
Sulla base di questo esempio, sarebbe consentito solo l'upload di immagini .gif,
.png e .jpg (o .jpeg).