Source for file Upload.php
Documentation is available at Upload.php
// ********************************************** //
// This software is licensed by the LGPL
// -> http://www.gnu.org/copyleft/lesser.txt
// (c) 2001- 2004 by Tomas Von Veschler Cox //
// ********************************************** //
// $Id: Upload.php 287177 2009-08-12 20:03:01Z cweiske $
* Pear File Uploader class. Easy and secure managment of files
* submitted via HTML Forms.
* - you can add error msgs in your language in the HTTP_Upload_Error class
* - try to think a way of having all the Error system in other
* file and only include it when an error ocurrs
* -- Notes for users HTTP_Upload >= 0.9.0 --
* Error detection was enhanced, so you no longer need to
* check for PEAR::isError() in $upload->getFiles() or call
* $upload->isMissing(). Instead you'll
* get the error when do a check for $file->isError().
* $upload = new HTTP_Upload('en');
* $file = $upload->getFiles('i_dont_exist_in_form_definition');
* if ($file->isError()) {
* die($file->getMessage());
define('HTTP_UPLOAD_DEFAULT_CHMOD', 0660 );
* Error Class for HTTP_Upload
* @author Tomas V.V.Cox <cox@idecnet.com>
* @see http://vulcanonet.com/soft/index.php?pack=uploader
* Selected language for error messages
* Whether HTML entities shall be encoded automatically
* Creates a new PEAR_Error
* @param string $lang The language selected for error code messages
$this->lang = ($lang !== null ) ? $lang : $this->lang;
$this->html = ($html !== false ) ? $html : $this->html;
$raw_size = ini_get('upload_max_filesize');
$ini_size = intval($raw_size);
case 'G': $ini_size *= 1024;
case 'M': $ini_size *= 1024;
case 'K': $ini_size *= 1024;
$maxsize = (isset ($_POST['MAX_FILE_SIZE'])) ?
$_POST['MAX_FILE_SIZE'] : null;
$maxsize = (isset ($HTTP_POST_VARS['MAX_FILE_SIZE'])) ?
$HTTP_POST_VARS['MAX_FILE_SIZE'] : null;
if (empty ($maxsize) || ($maxsize > $ini_size)) {
// XXXXX Add here error messages in your language
$this->error_codes = array (
'es' => " Fichero demasiado largo. El maximo permitido es: $maxsize bytes." ,
'en' => " File size too large. The maximum permitted size is: $maxsize bytes." ,
'et' => " Fail on liiga suur. Maksimaalne lubatud suurus on $maxsize baiti." ,
'de' => " Datei zu groß. Die zulässige Maximalgröße ist: $maxsize Bytes." ,
'nl' => " Het bestand is te groot, de maximale grootte is: $maxsize bytes." ,
'fr' => " Le fichier est trop gros. La taille maximum autorisée est: $maxsize bytes." ,
'it' => " Il file é troppo grande. Il massimo permesso é: $maxsize bytes." ,
'pt_BR' => " Arquivo muito grande. O tamanho máximo permitido é $maxsize bytes." ,
'ru' => " Файл слишком велик. Максимальный разрешённый объём: $maxsize байт." ,
'sv' => " Filen är för stor. Största tillåtna filstorlek är: $maxsize bytes." ,
'da' => " Filen er for stor. Største tilladte filstørrelse er : $maxsize bytes."
'es' => 'Falta directorio destino.',
'en' => 'Missing destination directory.',
'et' => 'Puudub sihtkataloog.',
'de' => 'Kein Zielverzeichnis definiert.',
'nl' => 'Geen bestemmings directory.',
'fr' => 'Le répertoire de destination n\'est pas défini.',
'it' => 'Manca la directory di destinazione.',
'pt_BR' => 'Ausência de diretório de destino.',
'ru' => 'Не указан целевой каталог.',
'sv' => 'Saknar destinationskatalog.',
'da' => 'Mangler destinationskatalog.'
'es' => 'El directorio destino no existe o es un fichero regular.',
'en' => 'The destination directory doesn\'t exist or is a regular file.',
'et' => 'Sihtkataloogi pole olemas või ta on tavaline fail.',
'de' => 'Das angebene Zielverzeichnis existiert nicht oder ist eine Datei.',
'nl' => 'De doeldirectory bestaat niet, of is een gewoon bestand.',
'fr' => 'Le répertoire de destination n\'existe pas ou il s\'agit d\'un fichier régulier.',
'it' => 'La directory di destinazione non esiste o é un file.',
'pt_BR' => 'O diretório de destino não existe ou é um arquivo.',
'ru' => 'Целевой каталог не существует или является обычным файлом.',
'sv' => 'Destinationskatalogen existerar inte, eller är en vanlig fil.',
'da' => 'Destinationskatalogen eksisterer ikke, eller er en almindelig fil.'
'NO_WRITE_PERMS' => array (
'es' => 'El directorio destino no tiene permisos de escritura.',
'en' => 'The destination directory doesn\'t have write perms.',
'et' => 'Valitud kataloogi ei saa kirjutada.',
'de' => 'Fehlende Schreibrechte für das Zielverzeichnis.',
'nl' => 'Geen toestemming om te schrijven in de doeldirectory.',
'fr' => 'Le répertoire de destination n\'a pas les droits en écriture.',
'it' => 'Non si hanno i permessi di scrittura sulla directory di destinazione.',
'pt_BR' => 'O diretório de destino não possui permissão para escrita.',
'ru' => 'Нет прав на запись в целевой каталог.',
'sv' => 'Destinationskatalogen har inte skrivrättigheter.',
'da' => 'Destinationskatalogen har ikke skrivrettigheder.'
'es' => 'No se ha escogido fichero para el upload.',
'en' => 'You haven\'t selected any file for uploading.',
'et' => 'Üleslaetav fail jäi valimata.',
'de' => 'Es wurde keine Datei für den Upload ausgewählt.',
'nl' => 'Er is geen bestand opgegeven om te uploaden.',
'fr' => 'Vous n\'avez pas sélectionné de fichier à envoyer.',
'it' => 'Nessun file selezionato per l\'upload.',
'pt_BR' => 'Nenhum arquivo selecionado para upload.',
'ru' => 'Вы не выбрали файл для загрузки.',
'sv' => 'Du har inte valt någon fil att ladda upp.',
'da' => 'Du har ikke valgt nogen fil at uploade.'
'es' => 'El formulario no contiene method="post" enctype="multipart/form-data" requerido.',
'en' => 'The html form doesn\'t contain the required method="post" enctype="multipart/form-data".',
'et' => 'Html-vorm ei sisalda nõutud method="post" enctype="multipart/form-data".',
'de' => 'Das HTML-Formular enthält nicht die Angabe method="post" enctype="multipart/form-data" '.
'nl' => 'Het HTML-formulier bevat niet de volgende benodigde '.
'eigenschappen: method="post" enctype="multipart/form-data".',
'fr' => 'Le formulaire HTML ne contient pas les attributs requis : '.
' method="post" enctype="multipart/form-data".',
'it' => 'Il modulo HTML non contiene gli attributi richiesti: "'.
' method="post" enctype="multipart/form-data".',
'pt_BR' => 'O formulário HTML não possui o method="post" enctype="multipart/form-data" requerido.',
'ru' => 'В форме HTML не указаны необходимые атрибуты: method="post" enctype="multipart/form-data".',
'sv' => 'HTML-formuläret innehåller inte de attribut som krävs: '.
' method="post" enctype="multipart/form-data"',
'da' => 'HTML-formularen mangler disse indstillinger: '.
' method="post" enctype="multipart/form-data"'
'es' => 'Fallo al copiar el fichero temporal.',
'en' => 'Failed to copy the temporary file.',
'de' => 'Temporäre Datei konnte nicht kopiert werden.',
'et' => 'Ajutise faili kopeerimine ebaõnnestus.',
'nl' => 'Het tijdelijke bestand kon niet gekopieerd worden.',
'fr' => 'L\'enregistrement du fichier temporaire a échoué.',
'it' => 'Copia del file temporaneo fallita.',
'pt_BR' => 'Falha ao copiar o arquivo temporário.',
'ru' => 'Не удалось скопировать временный файл.',
'sv' => 'Misslyckades med att kopiera den temporära filen.',
'da' => 'Det lykkedes ikke at kopiere den temporære fil.'
'es' => 'No puedo mover el fichero.',
'en' => 'Impossible to move the file.',
'et' => 'Faili asukohta ei saa muuta.',
'de' => 'Datei kann nicht verschoben werden.',
'nl' => 'Het bestand kon niet verplaatst worden.',
'fr' => 'Impossible de déplacer le fichier.',
'pt_BR' => 'Não foi possível mover o arquivo.',
'ru' => 'Не удалось переместить файл',
'sv' => 'Misslyckades med att flytta den temporära filen.',
'da' => 'Det lykkedes ikke at flytta den temporære fil.'
'es' => 'El fichero destino ya existe.',
'en' => 'The destination file already exists.',
'et' => 'Sihtfail on juba olemas.',
'de' => 'Die zu erzeugende Datei existiert bereits.',
'nl' => 'Het doelbestand bestaat al.',
'fr' => 'Le fichier de destination existe déjà.',
'it' => 'File destinazione già esistente.',
'pt_BR' => 'O arquivo de destino já existe.',
'ru' => 'Целевой файл уже существует.',
'sv' => 'Destinationsfilen existerar redan.',
'da' => 'Destinationsfilen findes allerede.'
'CANNOT_OVERWRITE' => array (
'es' => 'El fichero destino ya existe y no se puede sobreescribir.',
'en' => 'The destination file already exists and could not be overwritten.',
'de' => 'Die zu erzeugende Datei existiert bereits und konnte nicht überschrieben werden.',
'et' => 'Sihtfail on juba olemas. Seda ei saa üle kirjutada.',
'nl' => 'Het doelbestand bestaat al, en kon niet worden overschreven.',
'fr' => 'Le fichier de destination existe déjà et ne peux pas être remplacé.',
'it' => 'File destinazione già esistente e non si può sovrascrivere.',
'pt_BR' => 'O arquivo de destino já existe e não pôde ser sobrescrito.',
'ru' => 'Целевой файл уже существует и не может быть перезаписан.',
'sv' => 'Destinationsfilen existerar redan och kunde inte skrivas över.',
'da' => 'Destinationsfilen findes allerede og kunne ikke overskrives.'
'NOT_ALLOWED_EXTENSION' => array (
'es' => 'Extension de fichero no permitida.',
'en' => 'File extension not permitted.',
'et' => 'Faili laiend pole lubatud.',
'de' => 'Unerlaubte Dateiendung.',
'nl' => 'Niet toegestane bestands-extensie.',
'fr' => 'Le fichier a une extension non autorisée.',
'it' => 'Estensione del File non permessa.',
'pt_BR' => 'Extensão de arquivo não permitida.',
'ru' => 'Недопустимое расширение файла.',
'sv' => 'Ej tillåten filändelse.',
'da' => 'Ikke tilladt filformat.'
'es' => 'El fichero fue parcialmente subido',
'en' => 'The file was only partially uploaded.',
'et' => 'Faili üleslaadimine oli poolik.',
'de' => 'Die Datei wurde unvollständig übertragen.',
'nl' => 'Het bestand is slechts gedeeltelijk geupload.',
'pt_BR' => 'O arquivo não foi enviado por completo.',
'ru' => 'Файл был загружен лишь частично.',
'sv' => 'Filen blev endast delvis uppladdad.',
'da' => 'Filen blev kun delvis uploadet.'
'es' => 'Error en subida:',
'et' => 'Viga üleslaadimisel:',
'de' => 'Fehler beim Upload:',
'pt_BR' => 'Erro de upload:',
'ru' => 'Ошибка загрузки:',
'sv' => 'Fel vid upladdning:',
'da' => 'Fejl ved upload:'
'DEV_NO_DEF_FILE' => array (
'es' => 'No está definido en el formulario este nombre de fichero como <input type="file" name=?>.',
'en' => 'This filename is not defined in the form as <input type="file" name=?>.',
'et' => 'Failinimi ei olnud vormistatud htmlis <input type="file" name=?>.',
'de' => 'Dieser Dateiname ist im Formular nicht als <input type="file" name=?> definiert.',
'nl' => 'Deze bestandsnaam is niett gedefineerd in het formulier als <input type="file" name=?>.',
'pt_BR' => 'Este arquivo não foi definido no formulário como <input type="file" name=?>.',
'ru' => 'Это имя файла отсутствовало в форме как поле <input type="file" name=?>.',
'sv' => 'Detta filnamn är inte definierat i formuläret som <input type="file" name=?>.',
'da' => 'Dette filnavn er ikke definieret i formularen som <input type="file" name=?>.'
* @param string $e_code type of error
* @return string Error message
if (!empty ($this->error_codes[$e_code][$this->lang])) {
$this->error_codes[$e_code][$this->lang];
if (!empty ($this->error_codes['ERROR'][$this->lang])) {
$error = $this->error_codes['ERROR'][$this->lang];
$error = $this->error_codes['ERROR']['en'];
* Overwrites the PEAR::raiseError method
* @param string $e_code type of error
* @return object PEAR_Error a PEAR-Error object
return PEAR ::raiseError ($this->errorCode($e_code), $e_code);
* This class provides an advanced file uploader system
* for file uploads made from html forms
* @author Tomas V.V.Cox <cox@idecnet.com>
* @see http://vulcanonet.com/soft/index.php?pack=uploader
* Contains an array of "uploaded files" objects
* Whether the files array has already been built or not
* Contains the desired chmod for uploaded files
var $_chmod = HTTP_UPLOAD_DEFAULT_CHMOD;
* Specially used if the naming mode is 'seq'
* Contains file naming information
var $_modeNameSeq = array (
* @param string $lang Language to use for reporting errors
* @see Upload_Error::error_codes
$this->post_files = $_FILES;
if (isset ($_SERVER['CONTENT_TYPE'])) {
$this->content_type = $_SERVER['CONTENT_TYPE'];
global $HTTP_POST_FILES, $HTTP_SERVER_VARS;
$this->post_files = $HTTP_POST_FILES;
if (isset ($HTTP_SERVER_VARS['CONTENT_TYPE'])) {
$this->content_type = $HTTP_SERVER_VARS['CONTENT_TYPE'];
* - not given, function will return array of upload_file objects
* - is int, will return the $file position in upload_file objects array
* - is string, will return the upload_file object corresponding
* to $file name of the form. For ex:
* if form is <input type="file" name="userfile">
* to get this file use: $upload->getFiles('userfile')
* @return mixed array or object (see @param $file above) or Pear_Error
//build only once for multiple calls
$files = &$this->_buildFiles ();
if (PEAR ::isError ($files)) {
// there was an error with the form.
// Create a faked upload embedding the error
$files_code = $files->getCode ();
$this->lang, $this->_chmod);
foreach ($this->files as $obj) {
return $this->files[$file];
if (isset ($this->files['_error'])) {
return $this->files['_error'];
// developer didn't specify this name in the form
// warn him about it with a faked upload
* Creates the list of the uploaded file
* @return array of HTTP_Upload_File objects for every file
if (!isset ($this->content_type) ||
strpos($this->content_type, 'multipart/form-data') !== 0 )
// In 4.1 $_FILES isn't initialized when no uploads
// XXX (cox) afaik, in >= 4.1 and < 4.3 only
if (PEAR ::isError ($error)) {
// map error codes from 4.2.0 $_FILES['userfile']['error']
// Parse $_FILES (or $HTTP_POST_FILES)
foreach ($this->post_files as $userfile => $value) {
foreach ($value['name'] as $key => $val) {
$err = $value['error'][$key];
if (isset ($err) && $err !== 0 && isset ($uploadError[$err])) {
$error = $uploadError[$err];
$tmp_name = $value['tmp_name'][$key];
$size = $value['size'][$key];
$type = $value['type'][$key];
$formname = $userfile . " [$key]";
$formname, $type, $size, $error, $this->lang, $this->_chmod);
if (isset ($err) && $err !== 0 && isset ($uploadError[$err])) {
$error = $uploadError[$err];
$tmp_name = $value['tmp_name'];
$formname, $type, $size, $error, $this->lang, $this->_chmod);
* Checks if the user submited or not some file
* @return mixed False when are files or PEAR_Error when no files
* @see Read the note in the source code about this function
if (count($this->post_files) < 1 ) {
//we also check if at least one file has more than 0 bytes :)
foreach ($this->post_files as $userfile => $value) {
foreach ($value['name'] as $key => $val) {
$size += $value['size'][$key];
} elseif (!empty ($value['name'])) { //one file
$error = $value['error'];
if ($error !== null && $error != 2 && $size == 0 ) {
* Sets the chmod to be used for uploaded files
* @param int Desired mode
* This class provides functions to work with the uploaded file
* @author Tomas V.V.Cox <cox@idecnet.com>
* @see http://vulcanonet.com/soft/index.php?pack=uploader
* Assoc array with file properties
* If user haven't selected a mode, by default 'safe' will be used
* It's a common security risk in pages who has the upload dir
* under the document root (remember the hack of the Apache web?)
* @see HTTP_Upload_File::setValidExtensions()
var $_extensionsCheck = array ('php', 'phtm', 'phtml', 'php3', 'inc');
* @see HTTP_Upload_File::setValidExtensions()
var $_extensionsMode = 'deny';
* Whether to use case-sensitive extension checks or not
* @see HTTP_Upload_File::setValidExtensions()
var $_extensionsCaseSensitive = true;
* Contains the desired chmod for uploaded files
var $_chmod = HTTP_UPLOAD_DEFAULT_CHMOD;
* @param string $name destination file name
* @param string $tmp temp file name
* @param string $formname name of the form
* @param string $type Mime type of the file
* @param string $size size of the file
* @param string $error error on upload
* @param string $lang used language for errormessages
$type = null , $size = null , $error = null ,
$lang = null , $chmod = HTTP_UPLOAD_DEFAULT_CHMOD )
if (empty ($name) || ($error != 'TOO_LARGE' && $size == 0 )) {
} elseif ($tmp == 'none') {
// strpos needed to detect files without extension
if (($pos = strrpos($name, '.')) !== false ) {
$ext = substr($name, $pos + 1 );
if (isset ($_POST['MAX_FILE_SIZE']) &&
$size > $_POST['MAX_FILE_SIZE']) {
if (isset ($HTTP_POST_VARS['MAX_FILE_SIZE']) &&
$size > $HTTP_POST_VARS['MAX_FILE_SIZE']) {
'form_name' => $formname,
* Sets the name of the destination file
* @param string $mode A valid mode: 'uniq', 'seq', 'safe' or 'real' or a file name
* @param string $prepend A string to prepend to the name
* @param string $append A string to append to the name
* @return string The modified name of the destination file
function setName($mode, $prepend = null , $append = null )
$name .= '.' . $this->upload['ext'];
if (($pos = strrpos($name, '.')) !== false ) {
$name = $this->upload['real'];
$this->_modeNameSeq['flag'] = true;
$this->_modeNameSeq['prepend'] = $prepend;
$this->_modeNameSeq['append'] = $append;
$this->upload['name'] = $prepend . $name . $append;
* Sequence file names in the form: userGuide[1].pdf, userGuide[2].pdf ...
* @param string $dir Destination directory
//Check if a file with the same name already exists
$name = $dir . DIRECTORY_SEPARATOR . $this->upload['real'];
//we need to strip out the extension and the '.' of the file
//e.g 'userGuide.pdf' becomes 'userGuide'
//here's the pattern we're looking for
$pattern = '(\[)([[:digit:]]+)(\])$';
//just incase the original filename had a sequence, we take it out
// e.g: 'userGuide[3]' should become 'userGuide'
* attempt to find a unique sequence file name
$filename = $basename . '[' . $i . '].' . $this->upload['ext'];
$check = $dir . DIRECTORY_SEPARATOR . $filename;
* Unique file names in the form: 9022210413b75410c28bef.html
* @see HTTP_Upload_File::setName()
* Format a file name to be safe
* @param string $file The string file name
* @param int $maxlen Maximun permited string lenght
* @return string Formatted file name
* @see HTTP_Upload_File::setName()
$alpha = 'AEIOUYaeiouyAEIOUaeiouAEIOUaeiouAEIOUaeiouyAaOoAaNnCcaooaTtAa';
$name = substr($name, 0 , $maxlen);
$name = strtr($name, $noalpha, $alpha);
// not permitted chars are replaced with "_"
return preg_replace('/[^a-zA-Z0-9,._\+\()\-]/', '_', $name);
* @return bool If the file was submitted correctly
if ($this->upload['error'] === null ) {
* User haven't submit a file
* @return bool If the user submitted a file or not
if ($this->upload['error'] == 'NO_USER_FILE') {
* Some error occured during upload (most common due a file size problem,
* like max size exceeded or 0 bytes long).
* @return bool If there were errors submitting the file (probably
* because the file excess the max permitted file size)
if (in_array($this->upload['error'], array ('TOO_LARGE', 'BAD_FORM','DEV_NO_DEF_FILE'))) {
* Moves the uploaded file to its destination directory.
* @param string $dir Destination directory
* @param bool $overwrite Overwrite if destination file exists?
* @return mixed True on success or PEAR_Error object on error
function moveTo($dir, $overwrite = true )
if (!$this->_evalValidExtensions ()) {
$error = & $this->raiseError('NOT_ALLOWED_EXTENSION');
$err_code = $this->_chkDirDest ($dir);
if ($err_code !== false ) {
// Use 'safe' mode by default if no other was selected
//test to see if we're working with sequence naming mode
if (isset ($this->_modeNameSeq) && isset ($this->_modeNameSeq['flag']) && $this->_modeNameSeq['flag'] === true ) {
$this->upload['name'] = $this->_modeNameSeq['prepend'] . $this->nameToSeq($dir) . $this->_modeNameSeq['append'];
$name = $dir . DIRECTORY_SEPARATOR . $this->upload['name'];
if ($overwrite !== true ) {
// copy the file and let php clean the tmp
@chmod($name, $this->_chmod);
* Check for a valid destination dir
* @param string $dir_dest Destination dir
* @return mixed False on no errors or error code on error
function _chkDirDest ($dir_dest)
* Retrive properties of the uploaded file
* @param string $name The property name. When null an assoc array with
* all the properties will be returned
* @return mixed A string or array
* @see HTTP_Upload_File::HTTP_Upload_File()
* Returns a error message, if a error occured
* (deprecated) Use getMessage() instead
* @return string a Error message
* Returns a error message, if a error occured
* @return string a Error message
* Function to restrict the valid extensions on file uploads
* @param array $exts File extensions to validate
* @param string $mode The type of validation:
* 1) 'deny' Will deny only the supplied extensions
* 2) 'accept' Will accept only the supplied extensions
* @param bool $case_sensitive whether extension check is case sensitive.
$this->_extensionsCheck = $exts;
$this->_extensionsMode = $mode;
if ($case_sensitive != null ) {
$this->_extensionsCaseSensitive = $case_sensitive;
* Evaluates the validity of the extensions set by setValidExtensions
* @return bool False on non valid extension, true if they are valid
function _evalValidExtensions ()
$exts = $this->_extensionsCheck;
if (!$this->_extensionsCaseSensitive) {
if ($this->_extensionsMode == 'deny') {
Documentation generated on Mon, 11 Mar 2019 15:32:50 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|