#!/bin/php -c..
= 0 )
return $m;
return PHP_INT_MAX;
}
/**
* Ritorna il path della directory temporanea dei file caricati.
* @return string Path della directory temporanea dei file caricati.
*/
public static function ini_get_upload_tmp_dir()
{
$d = trim( ini_get("upload_tmp_dir") );
if( $d !== "" )
return $d;
$e = getenv("TMPDIR");
if( $e !== FALSE )
return $e;
$e = getenv("TEMP");
if( $e !== FALSE )
return $e;
if( strtoupper(substr(PHP_OS, 0, 3)) === "WIN" )
return "C:\\TEMP";
else
return "/tmp";
}
}
/**
* Una instanza di questa classe rappresenta un file caricato.
*/
class UploadedFile {
/** Codice errore di caricamento. */
public $error = UPLOAD_ERR_OK;
/** Descrizione dell'errore di caricamento, o stringa vuota per successo. */
public $error_msg = "";
/**
* Nome del file caricato come suggerito dal browser. Non comprende il path.
* La codifica del nome e' la stessa del FORM, nel nostro caso UTF-8.
*/
public $name = "";
/** Tipo MIME del file. */
public $type = "";
/** Lunghezza del file (bytes). */
public $size = 0;
/** Path completo del file temporanea che contiene il file caricato. */
public $tmp_name = "";
}
/**
* Ritorna l'oggetto che descrive il file caricato. Se ritorna NULL, il file
* non e' stato caricato. Se ritorna un oggetto, la proprieta' error
* dell'oggetto vale UPLOAD_ERR_OK se il file caricato e' valido, altrimenti
* il campo error_msg
descrive l'errore.
* @param string $name Identificativo del control HTML del file.
* @param string[int] $accept_types Elenco dei tipi MIME consentiti. Se NULL o
* array vuoto, qualsiasi tipo MIME viene accettato.
* @return UploadedFile Oggetto che descrive il file caricato. Ritorna NULL se
* il file non e' stato caricato (per esempio, l'utente non ha selezionato un
* file, oppure il FORM non contiene il control specificato). Ritorna NULL
* anche su errore.
* @triggers E_USER_NOTICE Errore nei seguenti casi: lunghezza file eccedente il
* limite del php.ini; upload parziale; directory temporanea mancante o non
* configurata; manca permesso di scrittura nella directory temporanea;
* lunghezza file negativa;
* lunghezza file non corrisponde a quella del file temporaneo;
* errata codifica UTF-8 del nome del file;
* tipo MIME di sintassi errata;
* tipo MIME non accettato;
* altri errori non specificatamente previsti.
*/
function get_uploaded_file($name, $accept_types)
{
if( ! isset($_FILES) || ! isset($_FILES[$name]) )
return NULL;
$f = new UploadedFile();
$f->error = (int) $_FILES[$name]['error'];
$f->name = (string) $_FILES[$name]['name'];
$f->type = (string) $_FILES[$name]['type'];
$f->size = (int) $_FILES[$name]['size'];
$f->tmp_name = (string) $_FILES[$name]['tmp_name'];
switch( $f->error ){
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_INI_SIZE:
$f->error_msg = "File troppo grande.";
trigger_error("file too big (" . $f->size
. " B) -- check upload_max_filesize in php.ini");
return $f;
case UPLOAD_ERR_FORM_SIZE:
$f->error_msg = "File troppo grande.";
trigger_error("file too big (" . $f->size
. " B) -- check hidden field MAX_FILE_SIZE");
return $f;
case UPLOAD_ERR_PARTIAL:
$f->error_msg = "Problema di comunicazione; solo parte del file"
. " pervenuto.";
trigger_error("partial upload");
return $f;
case UPLOAD_ERR_NO_FILE:
# Nessun file caricato o nome di file mancante.
return NULL;
case UPLOAD_ERR_NO_TMP_DIR:
$f->error_msg = "Problema di configurazione sul server.";
trigger_error("file upload: missing tmp dir.");
return $f;
case UPLOAD_ERR_CANT_WRITE:
$f->error_msg = "Problema di configurazione sul server.";
trigger_error("file upload: can't write file " . $f->tmp_name);
return $f;
case UPLOAD_ERR_EXTENSION:
$f->error_msg = "Upload interrotto.";
trigger_error("file upload: interrupted by extension");
return $f;
/*
Meglio prevedere anche errori imprevisti realmente... imprevisti!
*/
default:
$f->error_msg =
"Errore non previsto durante il caricamento del file.";
trigger_error("file upload: unexpected error code " . $f->error);
return $f;
}
/*
Siccome siamo paranoici, controlliamo anche che il $size
sia positivo o nullo:
*/
if( $f->size < 0 ){
$f->error = 1111; # FIXME: codice errore non standard
trigger_error("file upload: size " . $f->size);
return NULL;
}
/*
...e che il campo $size corrisponda alla dimensione del file
temporaneo:
*/
$size = @filesize($f->tmp_name);
if( $size === FALSE ){
$f->error = 1111; # FIXME: codice errore non standard
trigger_error("accesso fallito al file " . $f->tmp_name);
return NULL;
}
if( $f->size != $size ){
$f->error = 1111; # FIXME: codice errore non standard
trigger_error("file upload: claimed length " . $f->size
. ", actual tmp file length $size");
return NULL;
}
/*
Controllo sanitario sul nome del file. Forziamo il rispetto
della codifica UTF-8 eseguendo una conversione da UTF-8 in
se' stesso, poi eliminiamo i codici di controllo da 0 a 31
e il 127 (DEL).
ATTENZIONE! il nome di file risultante potrebbe anche essere
la stringa vuota.
*/
$f->name = mb_convert_encoding($f->name, 'UTF-8', 'UTF-8');
$f->name = preg_replace("/[\\000-\\037\\177]/", "", $f->name);
/*
Sanifica il tipo MIME. Eliminiamo tutti i codici
ASCII eccetto quelli stampabili da 33 a 126.
Controlla se e' un tipo MIME consentito.
*/
$f->type = preg_replace("/[\\000-\\037\\177-\\377]/", "", $f->type);
if( count($accept_types) > 0 and ! in_array($f->type, $accept_types) ){
$f->error = 1111; # FIXME: codice errore non standard
$f->error_msg = "Il file di tipo " . $f->type
. " non è tra quelli ammessi: "
. implode(", ", $accept_types) . ".";
}
return $f;
}
# Elenco dei tipi MIME dei file che il programma accetta:
$accept_types = array(
"image/gif",
"image/png",
"image/jpeg",
"image/pjpeg"
);
# Controllo se i cookies (che individuano l'utente e quindi i permessi
# per accedere al download dei file) sono presenti anche nei casi di
# file/POST troppo grande, memoria esaurita, ecc.
setcookie("COOKIE_DI_TEST", "per_vedere_i_casi_estremi");
header("Content-Type: text/html; charset=UTF-8");
echo <<< EOT
\n"; # # Il FORM per l'upload. # echo "Questi sono i principali parametri di configurazione di php.ini che interessano l'upload dei file. Il programma può leggerne il valore corrente e verificare che siano coerenti e corrispondano alle necessità del programma stesso. Inoltre questi valori si possono mostrare all'utente come utile avviso sui limiti imposti ai file che può inviare.
EOT; if( ! Upload::ini_get_file_uploads() ){ echo "ERRORE: upload dei file non abilitato.
"; } else { echo "file_uploads = ", Upload::ini_get_file_uploads()? "On":"Off", "
"; echo "upload_max_filesize = ", Upload::ini_get_upload_max_filesize(), " B
"; echo "upload_tmp_dir = ", Upload::ini_get_upload_tmp_dir(), "
"; echo "post_max_size = ", Upload::ini_get_post_max_size(), " B
"; echo "max_input_time = ", Upload::ini_get_max_input_time(), " s
"; if( Upload::ini_get_post_max_size() <= Upload::ini_get_upload_max_filesize() ){ echo "ERRORE: post_max_size deve essere > di upload_max_filesize
"; } if( ! file_exists(Upload::ini_get_upload_tmp_dir()) ){ echo "ERRORE: manca dir. temporanea ", Upload::ini_get_upload_tmp_dir(), "
"; } } echo "
EOT; $f = get_uploaded_file('FOTO', $accept_types); if( $f === NULL ){ echo "Nessun file ricevuto."; } elseif( $f->error != 0 ){ echo "Errore di caricamento: ", $f->error_msg; } else { echo "Nome: ", htmlspecialchars($f->name), ""; } echo "\n"; # # Informazioni di debugging # ?>
", "Tipo: ", htmlspecialchars($f->type), "
", "Dimensione: ", $f->size, " B
"; echo "
In alcune situazioni particolari specificate nell'articolo, le strutture dati $_FILES, $_POST ecc. non vengono istanziate o risultano array vuoti. Il programma potrebbe sfruttare il verificarsi di queste condizioni per rilevare che una simile situazione particolare si è verificata.
File ricevuto (sanificato):$_COOKIES:= htmlspecialchars( var_export($f) ) ?>
$_POST:= htmlspecialchars( var_export($_COOKIE, TRUE) ) ?>
$_FILES:= htmlspecialchars( var_export($_POST, TRUE) ) ?>
= htmlspecialchars( var_export($_FILES, TRUE) ) ?>
Il sorgente di questo programma: ?SEESOURCE=">VEDI SORGENTE
Questo programma è parte integrante dell'articolo PHP File Upload (www.icosaedro.it/articoli/php-file-upload.html).