#!/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 PHP File Upload - Test Program

PHP File Upload - Test Program

EOT; # # Verifica della configurazione del php.ini # echo <<< EOT

Verifica configurazione php.ini

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 "
\n"; # # Il FORM per l'upload. # echo "

Form per upload file

\n"; echo "
0 ) echo "accept='", implode(",", $accept_types), "'\n"; echo "action='", $_SERVER["PHP_SELF"], "' >\n"; echo "
\n"; echo "Scegli una immagine tra uno dei seguenti tipi:\n"; if( count($accept_types) == 0 ) echo "qualsiasi tipo.\n"; else echo implode(", ", $accept_types), ".\n"; $max_size = min(Upload::ini_get_upload_max_filesize(), Upload::ini_get_post_max_size()); echo "La dimensione del file non deve superare $max_size B.

\n"; # ATTENZIONE! questo limite non comprende l'eventuale LimitRequestBody # impostato nel WEB server. Il suo valore, tuttavia, non si puo' # determinarlo a runtime. echo <<< EOT Titolo della immagine:

Seleziona un file o trascina sul bottone l'icona del file:

EOT; echo <<< EOT

File ricevuto

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), "
", "Tipo: ", htmlspecialchars($f->type), "
", "Dimensione: ", $f->size, " B
"; echo "
"; } echo "\n"; # # Informazioni di debugging # ?>

Debug

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:


$_POST:


$_FILES:



Note

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