diff --git a/e107_handlers/upload_handler.php b/e107_handlers/upload_handler.php index 3abed11a4..2db9111fc 100644 --- a/e107_handlers/upload_handler.php +++ b/e107_handlers/upload_handler.php @@ -1,811 +1,843 @@ -e_log_event(10,debug_backtrace(),"DEBUG","Upload Handler test","Process uploads to {$uploaddir}, fileinfo ".$fileinfo,FALSE,LOG_TO_ROLLING); -// $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Intermediate directory: {$ul_temp_dir} ",FALSE,LOG_TO_ROLLING); - - $overwrite = varset($options['overwrite'],FALSE); - $save_to_db = varset($options['save_to_db'],FALSE); - - - $uploaddir = realpath($uploaddir); // Mostly to get rid of the grot that might be passed in from legacy code. Also strips any trailing '/' + if (UH_DEBUG) + $admin_log-> + e_log_event(10, debug_backtrace(), "DEBUG", "Upload Handler test", "Process uploads to {$uploaddir}, fileinfo ".$fileinfo, FALSE, LOG_TO_ROLLING); + // $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Intermediate directory: {$ul_temp_dir} ",FALSE,LOG_TO_ROLLING); + + $overwrite = varset($options['overwrite'], FALSE); + $save_to_db = varset($options['save_to_db'], FALSE); + + $uploaddir = realpath($uploaddir); // Mostly to get rid of the grot that might be passed in from legacy code. Also strips any trailing '/' if (!is_dir($uploaddir)) { - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Invalid directory: ".$uploaddir,FALSE,FALSE); - return FALSE; // Need a valid directory + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Invalid directory: ".$uploaddir, FALSE, FALSE); + return FALSE; // Need a valid directory } - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Destination directory: ".$uploaddir,FALSE,FALSE); - - - - $final_chmod = varset($options['final_chmod'],0644); - - + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Destination directory: ".$uploaddir, FALSE, FALSE); + + $final_chmod = varset($options['final_chmod'], 0644); + if (isset($options['file_array_name'])) { - $files = $_FILES[$options['file_array_name']]; + $files = $_FILES[$options['file_array_name']]; } else { - $files = $_FILES['file_userfile']; + $files = $_FILES['file_userfile']; } - - - $max_file_count = varset($options['max_file_count'],0); - - + + $max_file_count = varset($options['max_file_count'], 0); + if (!is_array($files)) { - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","No files uploaded",FALSE,FALSE); - return FALSE; + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "No files uploaded", FALSE, FALSE); + return FALSE; } - - - $uploaded = array(); - - $max_upload_size = calc_max_upload_size(varset($options['max_upload_size'],-1)); // Find overriding maximum upload size - $allowed_filetypes = get_filetypes(varset($options['file_mask'],''), varset($options['filetypes'],'')); + $uploaded = array( + ); + + $max_upload_size = calc_max_upload_size(varset($options['max_upload_size'], -1)); // Find overriding maximum upload size + $allowed_filetypes = get_filetypes(varset($options['file_mask'], ''), varset($options['filetypes'], '')); $max_upload_size = set_max_size($allowed_filetypes, $max_upload_size); - - -// That's the basics set up - we can start processing files now - - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Start individual files: ".count($files['name'])." Max upload: ".$max_upload_size,FALSE,FALSE); - - - $c = 0; - foreach ($files['name'] as $key => $name) - { - $first_error = FALSE; // Clear error flag - if (($name != '') || $files['size'][$key]) // Need this check for things like file manager which allow multiple possible uploads - { - $name = preg_replace("/[^a-z0-9._-]/", "", str_replace(" ", "_", str_replace("%20", "_", strtolower($name)))); - $raw_name = $name; // Save 'proper' file name - useful for display - $file_ext = trim(strtolower(substr(strrchr($name, "."), 1))); // File extension - - if (!trim($files['type'][$key])) $files['type'][$key] = 'Unknowm mime-type'; - - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Process file {$name}, size ".$files['size'][$key],FALSE,FALSE); - - if ($max_file_count && ($c > $max_file_count)) - { - $first_error = 249; // 'Too many files uploaded' error - } - else - { - $first_error = $files['error'][$key]; // Start with whatever error PHP gives us for the file - } - - if (!$first_error) - { // Check file size early on - if ($files['size'][$key] == 0) - { - $first_error = 4; // Standard error code for zero size file - } - elseif ($files['size'][$key] > $max_upload_size) - { - $first_error = 254; - } - elseif (isset($allowed_filetypes[$file_ext]) && ($allowed_filetypes[$file_ext] > 0) && ($files['size'][$key] > $allowed_filetypes[$file_ext])) - { // XML file set limits per extension - $first_error = 254; - } - } - - if (!$first_error) - { - $uploadfile = $files['tmp_name'][$key]; // Name in temporary directory - if (!$uploadfile) $first_error = 253; - } - - if (!$first_error) - { - // Need to support multiple files with the same 'real' name in some cases - if (strpos($fileinfo,"attachment") === 0) - { // For attachments, add in a prefix plus time and date to give a unique file name - $addbit = explode('+',$fileinfo,2); - $name = time()."_".USERID."_".trim($addbit[1]).$name; - } - elseif (strpos($fileinfo,"prefix") === 0) - { // For attachments, avatars, photos etc alternatively just add a prefix we've been passed - $addbit = explode('+',$fileinfo,2); - $name = trim($addbit[1]).$name; - } + + // That's the basics set up - we can start processing files now + + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Start individual files: ".count($files['name'])." Max upload: ".$max_upload_size, FALSE, FALSE); - $destination_file = $uploaddir."/".$name; - - if ($fileinfo == "unique" && file_exists($destination_file)) - { // Modify destination name to make it unique - but only if target file name exists - $name = time()."_".$name; - $destination_file = $uploaddir."/".$name; - } - - if (file_exists($destination_file) && !$overwrite) $first_error = 250; // Invent our own error number - duplicate file - } - - if (!$first_error) + $c = 0; + foreach ($files['name'] as $key=>$name) + { + $first_error = FALSE; // Clear error flag + if (($name != '') || $files['size'][$key]) // Need this check for things like file manager which allow multiple possible uploads { - $tpos = FALSE; - if ($file_ext != '') // Require any uploaded file to have an extension - { - if ($ul_temp_dir) - { // Need to move file to our own temporary directory - $tempfilename = $uploadfile; - $uploadfile = $ul_temp_dir.basename($uploadfile); - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Move {$tempfilename} to {$uploadfile} ",FALSE,LOG_TO_ROLLING); - @move_uploaded_file($tempfilename,$uploadfile); // This should work on all hosts - } - $tpos = (($file_status = vet_file($uploadfile, $name, $allowed_filetypes, varset($options['extra_file_types'],FALSE))) === TRUE); - } - if ($tpos === FALSE) - { - // File type upload not permitted - error message and abort - $first_error = 251; // Invent our own error number - file type not permitted - } - } - - - if (!$first_error) - { // All tests passed - can store it somewhere - $uploaded[$c]['name'] = $name; - $uploaded[$c]['rawname'] = $raw_name; - $uploaded[$c]['type'] = $files['type'][$key]; - $uploaded[$c]['size'] = 0; - $uploaded[$c]['index'] = $key; // Store the actual index from the file_userfile array - - - if ($save_to_db) - { // Store binary files in the database if selected. Maximum two files this way - // This is really legacy stuff - not seriously changed from the original apart from using the newer file vetting routines - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Save to DB {$c}: ".$uploaded[$c]['name'],FALSE,LOG_TO_ROLLING); - set_magic_quotes_runtime(0); - $data = mysql_real_escape_string(fread(fopen($files['tmp_name'][$c], "rb"), filesize($uploadfile))); - set_magic_quotes_runtime(get_magic_quotes_gpc()); - if ($sql->db_Insert("rbinary", "0, '".$tp -> toDB($name, true)."', '".$tp -> toDB($files['type'][$c], true)."', '{$data}' ")) + $name = preg_replace("/[^a-z0-9._-]/", "", str_replace(" ", "_", str_replace("%20", "_", strtolower($name)))); + $raw_name = $name; // Save 'proper' file name - useful for display + $file_ext = trim(strtolower(substr(strrchr($name, "."), 1))); // File extension + + if (!trim($files['type'][$key])) + $files['type'][$key] = 'Unknowm mime-type'; + + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Process file {$name}, size ".$files['size'][$key], FALSE, FALSE); + + if ($max_file_count && ($c > $max_file_count)) { - $uploaded[$c]['name'] = "Binary ".mysql_insert_id()."/".$name; - $uploaded[$c]['size'] = $files['size'][$c]; + $first_error = 249; // 'Too many files uploaded' error } else { - $first_error = 252; // "Could not save file" + $first_error = $files['error'][$key]; // Start with whatever error PHP gives us for the file } - } - else - { // Store as flat file -// $method = (OPEN_BASEDIR == FALSE ? "copy" : "move_uploaded_file"); -// if (@$method($uploadfile, $destination_file)) - if ((!$ul_temp_dir && @move_uploaded_file($uploadfile, $destination_file)) || ($ul_temp_dir && @rename($uploadfile, $destination_file))) // This should work on all hosts - { - @chmod($destination_file, $final_chmod); - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Final chmod() file {$destination_file} to {$final_chmod} ",FALSE,FALSE); - $uploaded[$c]['size'] = $files['size'][$key]; - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Saved file {$c} OK: ".$uploaded[$c]['name'],FALSE,FALSE); - } - else - { - $first_error = 252; // Error - "couldn't save destination" - } + if (!$first_error) + { // Check file size early on + if ($files['size'][$key] == 0) + { + $first_error = 4; // Standard error code for zero size file + } + elseif ($files['size'][$key] > $max_upload_size) + { + $first_error = 254; + } + elseif (isset($allowed_filetypes[$file_ext]) && ($allowed_filetypes[$file_ext] > 0) && ($files['size'][$key] > $allowed_filetypes[$file_ext])) + { // XML file set limits per extension + $first_error = 254; + } + } + + if (!$first_error) + { + $uploadfile = $files['tmp_name'][$key]; // Name in temporary directory + if (!$uploadfile) + $first_error = 253; + } + + if (!$first_error) + { + // Need to support multiple files with the same 'real' name in some cases + if (strpos($fileinfo, "attachment") === 0) + { // For attachments, add in a prefix plus time and date to give a unique file name + $addbit = explode('+', $fileinfo, 2); + $name = time()."_".USERID."_".trim($addbit[1]).$name; + } + elseif (strpos($fileinfo, "prefix") === 0) + { // For attachments, avatars, photos etc alternatively just add a prefix we've been passed + $addbit = explode('+', $fileinfo, 2); + $name = trim($addbit[1]).$name; + } + + $destination_file = $uploaddir."/".$name; + + if ($fileinfo == "unique" && file_exists($destination_file)) + { // Modify destination name to make it unique - but only if target file name exists + $name = time()."_".$name; + $destination_file = $uploaddir."/".$name; + } + + if (file_exists($destination_file) && !$overwrite) + $first_error = 250; // Invent our own error number - duplicate file + } + + if (!$first_error) + { + $tpos = FALSE; + if ($file_ext != '') // Require any uploaded file to have an extension + { + if ($ul_temp_dir) + { // Need to move file to our own temporary directory + $tempfilename = $uploadfile; + $uploadfile = $ul_temp_dir.basename($uploadfile); + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Move {$tempfilename} to {$uploadfile} ", FALSE, LOG_TO_ROLLING); + @move_uploaded_file($tempfilename, $uploadfile); // This should work on all hosts + } + $tpos = (($file_status = vet_file($uploadfile, $name, $allowed_filetypes, varset($options['extra_file_types'], FALSE))) === TRUE); + } + if ($tpos === FALSE) + { + // File type upload not permitted - error message and abort + $first_error = 251; // Invent our own error number - file type not permitted + } + } + + if (!$first_error) + { // All tests passed - can store it somewhere + $uploaded[$c]['name'] = $name; + $uploaded[$c]['rawname'] = $raw_name; + $uploaded[$c]['type'] = $files['type'][$key]; + $uploaded[$c]['size'] = 0; + $uploaded[$c]['index'] = $key; // Store the actual index from the file_userfile array + + if ($save_to_db) + { // Store binary files in the database if selected. Maximum two files this way + // This is really legacy stuff - not seriously changed from the original apart from using the newer file vetting routines + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Save to DB {$c}: ".$uploaded[$c]['name'], FALSE, LOG_TO_ROLLING); + set_magic_quotes_runtime(0); + $data = mysql_real_escape_string(fread(fopen($files['tmp_name'][$c], "rb"), filesize($uploadfile))); + set_magic_quotes_runtime(get_magic_quotes_gpc()); + if ($sql-> + db_Insert("rbinary", "0, '".$tp->toDB($name, true)."', '".$tp->toDB($files['type'][$c], true)."', '{$data}' ")) + { + $uploaded[$c]['name'] = "Binary ".mysql_insert_id()."/".$name; + $uploaded[$c]['size'] = $files['size'][$c]; + } + else + { + $first_error = 252; // "Could not save file" + } + } + else + { // Store as flat file + // $method = (OPEN_BASEDIR == FALSE ? "copy" : "move_uploaded_file"); + // if (@$method($uploadfile, $destination_file)) + if ((!$ul_temp_dir && @move_uploaded_file($uploadfile, $destination_file)) || ($ul_temp_dir && @rename($uploadfile, $destination_file))) // This should work on all hosts + { + @chmod($destination_file, $final_chmod); + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Final chmod() file {$destination_file} to {$final_chmod} ", FALSE, FALSE); + + $uploaded[$c]['size'] = $files['size'][$key]; + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Saved file {$c} OK: ".$uploaded[$c]['name'], FALSE, FALSE); + } + else + { + $first_error = 252; // Error - "couldn't save destination" + } + } + } + + if (!$first_error) + { // This file succeeded + $uploaded[$c]['message'] = LANUPLOAD_3." '".$raw_name."'"; + $uploaded[$c]['error'] = 0; + } + else + { + $uploaded[$c]['error'] = $first_error; + $uploaded[$c]['size'] = 0; + switch ($first_error) + { + case 1: // Exceeds upload_max_filesize in php.ini + $error = LANUPLOAD_5; + break; + case 2: // Exceeds MAX_FILE_SIZE in form + $error = LANUPLOAD_6; + break; + case 3: // Partial upload + $error = LANUPLOAD_7; + break; + case 4: // No file uploaded + $error = LANUPLOAD_8; + break; + case 5: // Undocumented code (zero file size) + $error = LANUPLOAD_9; + break; + case 6: // Missing temporary folder + $error = LANUPLOAD_13; + break; + case 7: // File write failed + $error = LANUPLOAD_14; + break; + case 8: // Upload stopped by extension + $error = LANUPLOAD_15; + break; + case 249: // Too many files (our error code) + $error = LANUPLOAD_19; + break; + case 250: // Duplicate File (our error code) + $error = LANUPLOAD_10; + break; + case 251: // File type not allowed (our error code) + $error = LANUPLOAD_1." ".$files['type'][$key]." ".LANUPLOAD_2." ({$file_status})"; + break; + case 252: // File uploaded OK, but couldn't save it + $error = LANUPLOAD_4." [".str_replace("../", "", $uploaddir)."]"; + break; + case 253: // Bad name for uploaded file (our error code) + $error = LANUPLOAD_17; + break; + case 254: // file size exceeds allowable limits (our error code) + $error = LANUPLOAD_18; + break; + default: // Shouldn't happen - but at least try and make it obvious if it does! + $error = LANUPLOAD_16; + } + + $uploaded[$c]['message'] = LANUPLOAD_11." '".$name."'
".LANUPLOAD_12.": ".$error; + $uploaded[$c]['line'] = __LINE__; + $uploaded[$c]['file'] = __FILE__; + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Main routine error {$first_error} file {$c}: ".$uploaded[$c]['message'], FALSE, FALSE); + // If we need to abort on first error, do so here - could check for specific error codes + } + if (is_file($uploadfile)) + @unlink($uploadfile); // Don't leave the file on the server if error (although should be auto-deleted) + $c++; } - } - - if(!$first_error) - { // This file succeeded - $uploaded[$c]['message'] = LANUPLOAD_3." '".$raw_name."'"; - $uploaded[$c]['error'] = 0; - } - else - { - $uploaded[$c]['error'] = $first_error; - $uploaded[$c]['size'] = 0; - switch ($first_error) - { - case 1: // Exceeds upload_max_filesize in php.ini - $error = LANUPLOAD_5; - break; - case 2: // Exceeds MAX_FILE_SIZE in form - $error = LANUPLOAD_6; - break; - case 3: // Partial upload - $error = LANUPLOAD_7; - break; - case 4: // No file uploaded - $error = LANUPLOAD_8; - break; - case 5: // Undocumented code (zero file size) - $error = LANUPLOAD_9; - break; - case 6: // Missing temporary folder - $error = LANUPLOAD_13; - break; - case 7: // File write failed - $error = LANUPLOAD_14; - break; - case 8: // Upload stopped by extension - $error = LANUPLOAD_15; - break; - case 249: // Too many files (our error code) - $error = LANUPLOAD_19; - break; - case 250: // Duplicate File (our error code) - $error = LANUPLOAD_10; - break; - case 251: // File type not allowed (our error code) - $error = LANUPLOAD_1." ".$files['type'][$key]." ".LANUPLOAD_2." ({$file_status})"; - break; - case 252 : // File uploaded OK, but couldn't save it - $error = LANUPLOAD_4." [".str_replace("../", "", $uploaddir)."]"; - break; - case 253: // Bad name for uploaded file (our error code) - $error = LANUPLOAD_17; - break; - case 254: // file size exceeds allowable limits (our error code) - $error = LANUPLOAD_18; - break; - default : // Shouldn't happen - but at least try and make it obvious if it does! - $error = LANUPLOAD_16; - } - - $uploaded[$c]['message'] = LANUPLOAD_11." '".$name."'
".LANUPLOAD_12.": ".$error; - $uploaded[$c]['line'] = __LINE__ ; - $uploaded[$c]['file'] = __FILE__; - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Main routine error {$first_error} file {$c}: ".$uploaded[$c]['message'],FALSE,FALSE); - // If we need to abort on first error, do so here - could check for specific error codes - } - if (is_file($uploadfile)) @unlink($uploadfile); // Don't leave the file on the server if error (although should be auto-deleted) - $c++; - } } return $uploaded; } - - /* -Utility routine to handle the messages returned by process_uploaded_files(). -$upload_array is the list of uploaded files -$errors_only - if TRUE, no message is shown for a successful upload. -$use_handler - if TRUE, message_handler is used to display the message. + Utility routine to handle the messages returned by process_uploaded_files(). + $upload_array is the list of uploaded files + $errors_only - if TRUE, no message is shown for a successful upload. + $use_handler - if TRUE, message_handler is used to display the message. + Returns - a list of all accumulated messages. (Non-destructive call, so can be called several times with different options). + */ -Returns - a list of all accumulated messages. (Non-destructive call, so can be called several times with different options). -*/ function handle_upload_messages(&$upload_array, $errors_only = TRUE, $use_handler = FALSE) { -// Display error messages, accumulate FMESSAGE -// Write as a separate routine - returns all messages displayed. Option to only display failures. + // Display error messages, accumulate FMESSAGE + // Write as a separate routine - returns all messages displayed. Option to only display failures. $f_message = ''; - foreach($upload_array as $k => $r) + foreach ($upload_array as $k=>$r) { - if (!$errors_only || $r['error']) - { - if ($use_handler) + if (!$errors_only || $r['error']) { - require_once(e_HANDLER."message_handler.php"); - message_handler("MESSAGE",$r['message'], $r['line'], $r['file']); + if ($use_handler) + { + require_once (e_HANDLER."message_handler.php"); + message_handler("MESSAGE", $r['message'], $r['line'], $r['file']); + } + $f_message[] = $r['message']; } - $f_message[] = $r['message']; - } } - return implode("
",$f_message); + return implode("
", $f_message); } - - - /* -==================================================================== - LEGACY FILE UPLOAD HANDLER -==================================================================== -This is the 'legacy' interface, which handles various special cases etc. -It was the only option in E107 0.7.8 and earlier, and is still used in some places in core. -It also attempts to return in the same way as the original, especially when any errors occur - -Parameters for file_upload(): -$uploaddir - target directory for file. Defaults to e_FILE/public - -$avatar - sets the 'type' or destination of the file: - FALSE - its a 'general' file - 'attachment' - indicates an attachment (related to forum post or PM) - 'unique' - indicates that file name must be unique - new name given (prefixed with time()_ ) - 'avatar' - indicates an avatar is being uploaded - -$fileinfo - included within the name of the saved file with attachments - can be an identifier of some sort - (Forum adds 'FT{$tid}_' - where $tid is the thread ID. - -$overwrite - if true, an uploaded file can overwrite an existing file of the same name (not used in 0.7 core) - -Preference used: - $pref['upload_storagetype'] = 1 for files, 2 for database - -On exit, F_MESSAGE is defined with the success/failure message(s) that have been displayed - one file per line - -For backward compatibility, returns FALSE if only one file uploaded and an error; otherwise returns an array with per-file error codes as appropriate. -*/ - + ==================================================================== + LEGACY FILE UPLOAD HANDLER + ==================================================================== + This is the 'legacy' interface, which handles various special cases etc. + It was the only option in E107 0.7.8 and earlier, and is still used in some places in core. + It also attempts to return in the same way as the original, especially when any errors occur + Parameters for file_upload(): + $uploaddir - target directory for file. Defaults to e_FILE/public + $avatar - sets the 'type' or destination of the file: + FALSE - its a 'general' file + 'attachment' - indicates an attachment (related to forum post or PM) + 'unique' - indicates that file name must be unique - new name given (prefixed with time()_ ) + 'avatar' - indicates an avatar is being uploaded + $fileinfo - included within the name of the saved file with attachments - can be an identifier of some sort + (Forum adds 'FT{$tid}_' - where $tid is the thread ID. + $overwrite - if true, an uploaded file can overwrite an existing file of the same name (not used in 0.7 core) + Preference used: + $pref['upload_storagetype'] = 1 for files, 2 for database + On exit, F_MESSAGE is defined with the success/failure message(s) that have been displayed - one file per line + For backward compatibility, returns FALSE if only one file uploaded and an error; otherwise returns an array with per-file error codes as appropriate. + */ function file_upload($uploaddir, $avatar = FALSE, $fileinfo = "", $overwrite = "") { global $admin_log; - $options = array('extra_file_types' => TRUE); // As default, allow any filetype enabled in filetypes.php - - - if (!$uploaddir) {$uploaddir = e_FILE."public/";} - -// Compute storage type - 1 is file, 2 is DB - $upload_storagetype = varset($pref['upload_storagetype'],1); - if($uploaddir == e_THEME) {$upload_storagetype = 1;} - $options['save_to_db'] = ($upload_storagetype == "2" && $avatar == FALSE); - - if (strpos($avatar,'=') !== FALSE) + $options = array( + 'extra_file_types'=>TRUE + ); // As default, allow any filetype enabled in filetypes.php + + if (!$uploaddir) { - list($avatar,$param) = explode('=',$avatar,2); + $uploaddir = e_FILE."public/"; + } + + // Compute storage type - 1 is file, 2 is DB + $upload_storagetype = varset($pref['upload_storagetype'], 1); + if ($uploaddir == e_THEME) + { + $upload_storagetype = 1; + } + $options['save_to_db'] = ($upload_storagetype == "2" && $avatar == FALSE); + + if (strpos($avatar, '=') !== FALSE) + { + list($avatar, $param) = explode('=', $avatar, 2); } else { - $param = USERID; + $param = USERID; } switch ($avatar) { - case 'attachment' : - $avatar = "attachment+".$fileinfo; + case 'attachment': + $avatar = "attachment+".$fileinfo; break; - case 'avatar' : - $avatar = 'prefix+ap_'.$param.'_'; // Prefix unique to user - $options['overwrite'] = TRUE; // Allow update of avatar with same file name + case 'avatar': + $avatar = 'prefix+ap_'.$param.'_'; // Prefix unique to user + $options['overwrite'] = TRUE; // Allow update of avatar with same file name break; } - - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Legacy call, directory ".$uploaddir,FALSE,FALSE); - $ret = process_uploaded_files(getcwd()."/".$uploaddir, // Well, that's the way it was done before - $avatar,$options); - if ($ret === FALSE) + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Legacy call, directory ".$uploaddir, FALSE, FALSE); + + $ret = process_uploaded_files(getcwd()."/".$uploaddir, $avatar, $options); // Well, that's the way it was done before + + if ($ret === FALSE) { - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Legacy return FALSE",FALSE,FALSE); - return FALSE; + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Legacy return FALSE", FALSE, FALSE); + return FALSE; } - - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Legacy return with ".count($ret)." files",FALSE,FALSE); - $messages = handle_upload_messages($ret, FALSE, TRUE); // Show all the error and acknowledgment messages + + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Legacy return with ".count($ret)." files", FALSE, FALSE); + $messages = handle_upload_messages($ret, FALSE, TRUE); // Show all the error and acknowledgment messages define(F_MESSAGE, $messages); if (count($ret) == 1) { - if ($ret[0]['error'] != 0) return FALSE; // Special case if errors + if ($ret[0]['error'] != 0) + return FALSE; // Special case if errors } return $ret; } - - - - /* -==================================================================== - VETTING AND UTILITY ROUTINES -==================================================================== + ==================================================================== + VETTING AND UTILITY ROUTINES + ==================================================================== + // Check uploaded file to try and identify dodgy content. + // Return TRUE if appears OK. + // Return a numeric reason code 1..9 if unacceptable + // $filename is the full path+name to the uploaded file on the server + // $target_name is the intended name of the file once transferred + // $allowed_filetypes is an array of permitted file extensions, in lower case, no leading '.' + // (usually generated from filetypes.php) + // if $unknown is FALSE, rejects totally unknown file extensions (even if in $allowed_filetypes). + // if $unknown is TRUE, accepts totally unknown file extensions. + // otherwise $unknown is a comma-separated list of additional permitted file extensions + */ -// Check uploaded file to try and identify dodgy content. -// Return TRUE if appears OK. -// Return a numeric reason code 1..9 if unacceptable - -// $filename is the full path+name to the uploaded file on the server -// $target_name is the intended name of the file once transferred -// $allowed_filetypes is an array of permitted file extensions, in lower case, no leading '.' -// (usually generated from filetypes.php) -// if $unknown is FALSE, rejects totally unknown file extensions (even if in $allowed_filetypes). -// if $unknown is TRUE, accepts totally unknown file extensions. -// otherwise $unknown is a comma-separated list of additional permitted file extensions -*/ function vet_file($filename, $target_name, $allowed_filetypes = '', $unknown = FALSE) { -// 1. Start by checking against filetypes - that's the easy one! - $file_ext = strtolower(substr(strrchr($target_name, "."), 1)); - if (!isset($allowed_filetypes[$file_ext])) - { - if (is_bool($unknown)) return 1; // Reject out of hand if no possible alternative extensions - // Otherwise, it could be in the supplementary list - $tmp = explode(',', $unknown); - for ($i = 0; $i < count($tmp); $i++) { $tmp[$i] = strtolower(trim(str_replace('.', '', $tmp[$i]))); } - if (!in_array($file_ext, $tmp)) return 6; - } - - -// 2. For all files, read the first little bit to check for any flags etc - $res = fopen($filename, 'rb'); - $tstr = fread($res,100); - fclose($res); - if ($tstr === FALSE) return 2; // If can't read file, not much use carrying on! - if (stristr($tstr,' $f) + // 1. Start by checking against filetypes - that's the easy one! + $file_ext = strtolower(substr(strrchr($target_name, "."), 1)); + if (!isset($allowed_filetypes[$file_ext])) { - $file_array[$k] = trim($f); + if (is_bool($unknown)) + return 1; // Reject out of hand if no possible alternative extensions + // Otherwise, it could be in the supplementary list + $tmp = explode(',', $unknown); + for ($i = 0; $i < count($tmp); $i++) + { + $tmp[$i] = strtolower(trim(str_replace('.', '', $tmp[$i]))); + } + if (!in_array($file_ext, $tmp)) + return 6; } - } - - if ($def_file && is_readable(e_ADMIN.$def_file)) - { - $a_filetypes = trim(file_get_contents(e_ADMIN.$def_file)); - $a_filetypes = explode(',', $a_filetypes); - } - else - { // Its an 'override' array - $a_filetypes = explode(',', $def_file); - } - foreach ($a_filetypes as $ftype) - { - $ftype = strtolower(trim(str_replace('.', '', $ftype))); - if (!$file_mask || in_array($ftype, $file_array)) + + // 2. For all files, read the first little bit to check for any flags etc + $res = fopen($filename, 'rb'); + $tstr = fread($res, 100); + fclose($res); + if ($tstr === FALSE) + return 2; // If can't read file, not much use carrying on! + if (stristr($tstr, ' $f) + + // Get array of file types (file extensions) which are permitted - reads a definition file. + // Key is the file type. + // If $file_mask is a comma-separated list of file types, only those types which are in both the definition file and in $file_mask are added + function get_allowed_filetypes($def_file = FALSE, $file_mask = '') { - $file_array[$k] = trim($f); - } - } - - if ($def_file && is_readable(e_ADMIN.$def_file)) - { - require_once(e_HANDLER.'xml_class.php'); - $xml = new xmlClass; - $temp_vars = $xml->loadXMLfile(e_ADMIN.$def_file, true, false); - if ($temp_vars === FALSE) - { - echo "Error reading XML file: {$def_file}
"; + $ret = array( + ); + if ($def_file === FALSE) + return $ret; + + if ($file_mask) + { + $file_array = explode(',', $file_mask); + foreach ($file_array as $k=>$f) + { + $file_array[$k] = trim($f); + } + } + + if ($def_file && is_readable(e_ADMIN.$def_file)) + { + $a_filetypes = trim(file_get_contents(e_ADMIN.$def_file)); + $a_filetypes = explode(',', $a_filetypes); + } + else + { // Its an 'override' array + $a_filetypes = explode(',', $def_file); + } + foreach ($a_filetypes as $ftype) + { + $ftype = strtolower(trim(str_replace('.', '', $ftype))); + if (!$file_mask || in_array($ftype, $file_array)) + { + $ret[$ftype] = -1; + } + } return $ret; } - if (count($temp_vars['class']) == 1) + + // Parse a file size string (e.g. 16M) and compute the simple numeric value. + // If $action is empty, return this value. + // If $source evaluates to zero, return the compare value instead + // If $action == 'gt', return the larger of this value and $compare + // If $action == 'lt', return the smaller of this value and $compare + function file_size_decode($source, $compare = 0, $action = '') { - $temp_vars['class'] = array($temp_vars['class']); - } - foreach ($temp_vars['class'] as $v1) - { - $v = $v1['@attributes']; - if (check_class($v['name'])) - { - $current_perms[$v['name']] = array('type' => $v['type'],'maxupload' => $v['maxupload']); - $a_filetypes = explode(',', $v['type']); - foreach ($a_filetypes as $ftype) + $source = trim($source); + if (strtolower(substr($source, -1, 1)) == 'b') + $source = substr($source, 0, -1); // Trim a trailing byte indicator + $mult = 1; + if (strlen($source) && (strtoupper(substr($source, -1, 1)) == 'B')) + $source = substr($source, 0, -1); + if (!$source || is_numeric($source)) { - $ftype = strtolower(trim(str_replace('.', '', $ftype))); // File extension - if (!$file_mask || in_array($ftype, $file_array)) - { // We can load this extension - if (isset($ret[$ftype])) - { - $ret[$ftype] = file_size_decode($v['maxupload'],$ret[$ftype], 'gt'); // Use largest value - } - else - { - $ret[$ftype] = file_size_decode($v['maxupload']); - } - } + $val = $source; } - } + else + { + $val = substr($source, 0, -1); + switch (substr($source, -1, 1)) + { + case 'T': + $val = $val * 1024; + case 'G': + $val = $val * 1024; + case 'M': + $val = $val * 1024; + case 'K': + case 'k': + $val = $val * 1024; + break; + } + } + if ($val == 0) + return $compare; + switch ($action) + { + case 'lt': + return min($val, $compare); + case 'gt': + return max($val, $compare); + default: + return $val; + } + return 0; } - } -// echo '
';
-//  var_dump($ret);
-//  echo '
'; - return $ret; -} - - -// Calculate 'global' maximum upload size - the maximum before extension-specific restrictions taken into account -function calc_max_upload_size($max_up = -1) -{ - global $pref, $admin_log; - // Work out maximum allowable file size - if (UH_DEBUG) - { - $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test", - "File size limits - user set: ".$pref['upload_maxfilesize']." Post_max_size: ".ini_get('post_max_size')." upload_max_size: ".ini_get('upload_max_size'),FALSE,FALSE); - } - $max_upload_size = file_size_decode(ini_get('post_max_size')); - $max_upload_size = file_size_decode(ini_get('upload_max_filesize'), $max_upload_size, 'lt'); - if ($max_up > 0) - { - $max_upload_size = file_size_decode($max_up, $max_upload_size, 'lt'); - } - else - { - if (varset($pref['upload_maxfilesize'],0) > 0) $max_upload_size = file_size_decode($pref['upload_maxfilesize'], $max_upload_size, 'lt'); - } - if ($save_to_db) $max_upload_size = min($max_upload_size, 512000); // Approx 500k limit for database saves - if (UH_DEBUG) $admin_log->e_log_event(10,__FILE__."|".__FUNCTION__."@".__LINE__,"DEBUG","Upload Handler test","Final max upload size: {$max_upload_size}",FALSE,FALSE); - return $max_upload_size; -} - - - - -// Get an array of permitted filetypes according to a set hierarchy. -function get_filetypes($file_mask = FALSE, $filename = '') -{ - if ($filename != '') - { - if (strtolower(substr($filename,-4) == '.xml')) + + // Similar to get_allowed_filetypes(), but expects an XML file + // Returns an array where key is the file extension; value is max upload size + function get_XML_filetypes($def_file = FALSE, $file_mask = '') { - return get_XML_filetypes($filename, $file_mask); + $ret = array( + ); + if ($def_file === FALSE) + return $ret; + + if ($file_mask) + { + $file_array = explode(',', $file_mask); + foreach ($file_array as $k=>$f) + { + $file_array[$k] = trim($f); + } + } + + if ($def_file && is_readable(e_ADMIN.$def_file)) + { + require_once (e_HANDLER.'xml_class.php'); + $xml = new xmlClass; + $temp_vars = $xml->loadXMLfile(e_ADMIN.$def_file, true, false); + if ($temp_vars === FALSE) + { + echo "Error reading XML file: {$def_file}
"; + return $ret; + } + if (count($temp_vars['class']) == 1) + { + $temp_vars['class'] = array( + $temp_vars['class'] + ); + } + foreach ($temp_vars['class'] as $v1) + { + $v = $v1['@attributes']; + if (check_class($v['name'])) + { + $current_perms[$v['name']] = array( + 'type'=>$v['type'], 'maxupload'=>$v['maxupload'] + ); + $a_filetypes = explode(',', $v['type']); + foreach ($a_filetypes as $ftype) + { + $ftype = strtolower(trim(str_replace('.', '', $ftype))); // File extension + if (!$file_mask || in_array($ftype, $file_array)) + { // We can load this extension + if (isset($ret[$ftype])) + { + $ret[$ftype] = file_size_decode($v['maxupload'], $ret[$ftype], 'gt'); // Use largest value + } + else + { + $ret[$ftype] = file_size_decode($v['maxupload']); + } + } + } + } + } + } + // echo '
';
+		//  var_dump($ret);
+		//  echo '
'; + return $ret; } - return get_allowed_filetypes($filename, $file_mask); - } - - if (is_readable(e_ADMIN.e_READ_FILETYPES)) - { - return get_XML_filetypes(e_READ_FILETYPES, $file_mask); - } - - if (ADMIN && is_readable(e_ADMIN.'admin_filetypes.php')) - { - return get_allowed_filetypes('admin_filetypes.php', $file_mask); - } - - if (is_readable(e_ADMIN.'filetypes.php')) - { - return get_allowed_filetypes('filetypes.php', $file_mask); - } - return array(); // Just an empty array -} - - -// Scans the array of allowed file types, updates allowed max size as appropriate. -// Returns largest allowed file size -function set_max_size(&$allowed_filetypes, $max_upload_size) -{ - $new_max = 0; - foreach ($allowed_filetypes as $t => $s) - { - if ($s < 0) - { // Unspecified max - use the global value - $allowed_filetypes[$t] = $max_upload_size; + + // Calculate 'global' maximum upload size - the maximum before extension-specific restrictions taken into account + function calc_max_upload_size($max_up = -1) + { + global $pref,$admin_log; + // Work out maximum allowable file size + if (UH_DEBUG) + { + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "File size limits - user set: ".$pref['upload_maxfilesize']." Post_max_size: ".ini_get('post_max_size')." upload_max_size: ".ini_get('upload_max_size'), FALSE, FALSE); + } + $max_upload_size = file_size_decode(ini_get('post_max_size')); + $max_upload_size = file_size_decode(ini_get('upload_max_filesize'), $max_upload_size, 'lt'); + if ($max_up > 0) + { + $max_upload_size = file_size_decode($max_up, $max_upload_size, 'lt'); + } + else + { + if (varset($pref['upload_maxfilesize'], 0) > 0) + $max_upload_size = file_size_decode($pref['upload_maxfilesize'], $max_upload_size, 'lt'); + } + if ($save_to_db) + $max_upload_size = min($max_upload_size, 512000); // Approx 500k limit for database saves + if (UH_DEBUG) + $admin_log-> + e_log_event(10, __FILE__."|".__FUNCTION__."@".__LINE__, "DEBUG", "Upload Handler test", "Final max upload size: {$max_upload_size}", FALSE, FALSE); + return $max_upload_size; } - elseif ($allowed_filetypes[$t] > $max_upload_size) $allowed_filetypes[$t] = $max_upload_size; - if ($allowed_filetypes[$t] > $new_max) $new_max = $allowed_filetypes[$t]; - } - return $new_max; -} - - - -// Quick routine if all we want is the size of the largest file the current user can upload -function get_user_max_upload() -{ - $a_filetypes = get_filetypes(); - if (count($a_filetypes) == 0) return 0; // Return if no upload allowed - $max_upload_size = calc_max_upload_size(-1); // Find overriding maximum upload size - $max_upload_size = set_max_size($a_filetypes, $max_upload_size); - return $max_upload_size; -} - -?> \ No newline at end of file + + // Get an array of permitted filetypes according to a set hierarchy. + function get_filetypes($file_mask = FALSE, $filename = '') + { + if ($filename != '') + { + if (strtolower(substr($filename, -4) == '.xml')) + { + return get_XML_filetypes($filename, $file_mask); + } + return get_allowed_filetypes($filename, $file_mask); + } + + if (is_readable(e_ADMIN.e_READ_FILETYPES)) + { + return get_XML_filetypes(e_READ_FILETYPES, $file_mask); + } + + if (ADMIN && is_readable(e_ADMIN.'admin_filetypes.php')) + { + return get_allowed_filetypes('admin_filetypes.php', $file_mask); + } + + if (is_readable(e_ADMIN.'filetypes.php')) + { + return get_allowed_filetypes('filetypes.php', $file_mask); + } + return array( + ); // Just an empty array + } + + // Scans the array of allowed file types, updates allowed max size as appropriate. + // Returns largest allowed file size + function set_max_size(&$allowed_filetypes, $max_upload_size) + { + $new_max = 0; + foreach ($allowed_filetypes as $t=>$s) + { + if ($s < 0) + { // Unspecified max - use the global value + $allowed_filetypes[$t] = $max_upload_size; + } + elseif ($allowed_filetypes[$t] > $max_upload_size) + $allowed_filetypes[$t] = $max_upload_size; + if ($allowed_filetypes[$t] > $new_max) + $new_max = $allowed_filetypes[$t]; + } + return $new_max; + } + + // Quick routine if all we want is the size of the largest file the current user can upload + function get_user_max_upload() + { + $a_filetypes = get_filetypes(); + if (count($a_filetypes) == 0) + return 0; // Return if no upload allowed + $max_upload_size = calc_max_upload_size(-1); // Find overriding maximum upload size + $max_upload_size = set_max_size($a_filetypes, $max_upload_size); + return $max_upload_size; + } + +?>