上傳文件普遍的過程:
- 一個上傳文件用的表單,允許用戶選擇一個文件並上傳它。
- 當這個表單被提交,該文件被上傳到指定的目錄。
- 同時,該文件將被驗證是否符合您設定的要求。
- 一旦文件上傳成功,還要返回一個上傳成功的確認窗口。
public function __construct($props = array())
{
if (count($props) > 0)
{
$this->initialize($props);
}
log_message('debug', "Upload Class Initialized");
}
其中調用了成員方法initialize($config = array()):public function initialize($config = array())
{
$defaults = array(
'max_size' => 0,
'max_width' => 0,
'max_height' => 0,
'max_filename' => 0,
'allowed_types' => "",
'file_temp' => "",
'file_name' => "",
'orig_name' => "",
'file_type' => "",
'file_size' => "",
'file_ext' => "",
'upload_path' => "",
'overwrite' => FALSE,
'encrypt_name' => FALSE,
'is_image' => FALSE,
'image_width' => '',
'image_height' => '',
'image_type' => '',
'image_size_str' => '',
'error_msg' => array(),
'mimes' => array(),
'remove_spaces' => TRUE,
'xss_clean' => FALSE,
'temp_prefix' => "temp_file_",
'client_name' => ''
);
foreach ($defaults as $key => $val)
{
if (isset($config[$key]))
{
$method = 'set_'.$key;
if (method_exists($this, $method))
{
$this->$method($config[$key]);
}
else
{
$this->$key = $config[$key];
}
}
else
{
$this->$key = $val;
}
}
// if a file_name was provided in the config, use it instead of the user input
// supplied file name for all uploads until initialized again
$this->_file_name_override = $this->file_name;
}
該函數利用:if ( ! isset($_FILES[$field]))
{
$this->set_error('upload_no_file_selected');
return FALSE;
}
然後判斷上傳路徑,判上傳路徑是否爲一個有效的路徑且是否有寫的權限:if ( ! $this->validate_upload_path())
{
// errors will already be set by validate_upload_path() so just return FALSE
return FALSE;
}
validate_upload_path()函數代碼如下:public function validate_upload_path()
{
if ($this->upload_path == '')
{
$this->set_error('upload_no_filepath');
return FALSE;
}
if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE)
{
$this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
}
if ( ! @is_dir($this->upload_path))
{
$this->set_error('upload_no_filepath');
return FALSE;
}
if ( ! is_really_writable($this->upload_path))
{
$this->set_error('upload_not_writable');
return FALSE;
}
$this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/", $this->upload_path);
return TRUE;
}
接着判斷文件是否是通過 HTTP POST 上傳的,is_uploaded_file()if ( ! is_uploaded_file($_FILES[$field]['tmp_name']))
{
$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
switch($error)
{
case 1: // UPLOAD_ERR_INI_SIZE
$this->set_error('upload_file_exceeds_limit');
break;
case 2: // UPLOAD_ERR_FORM_SIZE
$this->set_error('upload_file_exceeds_form_limit');
break;
case 3: // UPLOAD_ERR_PARTIAL
$this->set_error('upload_file_partial');
break;
case 4: // UPLOAD_ERR_NO_FILE
$this->set_error('upload_no_file_selected');
break;
case 6: // UPLOAD_ERR_NO_TMP_DIR
$this->set_error('upload_no_temp_directory');
break;
case 7: // UPLOAD_ERR_CANT_WRITE
$this->set_error('upload_unable_to_write_file');
break;
case 8: // UPLOAD_ERR_EXTENSION
$this->set_error('upload_stopped_by_extension');
break;
default : $this->set_error('upload_no_file_selected');
break;
}
return FALSE;
}
如果文件是通過HTTP POST上傳,則設置上傳數據的類變量:$this->file_temp = $_FILES[$field]['tmp_name'];
$this->file_size = $_FILES[$field]['size'];
$this->_file_mime_type($_FILES[$field]);
$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
$this->file_ext = $this->get_extension($this->file_name);
$this->client_name = $this->file_name;
然後判斷文件是否是被允許上傳的類型:if ( ! $this->is_allowed_filetype())
{
$this->set_error('upload_invalid_filetype');
return FALSE;
}
is_allowed_filetype($ignore_mime = FALSE)public function is_allowed_filetype($ignore_mime = FALSE)
{
if ($this->allowed_types == '*')
{
return TRUE;
}
if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
{
$this->set_error('upload_no_file_types');
return FALSE;
}
$ext = strtolower(ltrim($this->file_ext, '.'));
if ( ! in_array($ext, $this->allowed_types))
{
return FALSE;
}
// Images get some additional checks
$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
if (in_array($ext, $image_types))
{
if (getimagesize($this->file_temp) === FALSE)
{
return FALSE;
}
}
if ($ignore_mime === TRUE)
{
return TRUE;
}
$mime = $this->mimes_types($ext);
if (is_array($mime))
{
if (in_array($this->file_type, $mime, TRUE))
{
return TRUE;
}
}
elseif ($mime == $this->file_type)
{
return TRUE;
}
return FALSE;
}
接着確定新名稱和類型是否允許:if ($this->_file_name_override != '')
{
$this->file_name = $this->_prep_filename($this->_file_name_override);
// If no extension was provided in the file_name config item, use the uploaded one
if (strpos($this->_file_name_override, '.') === FALSE)
{
$this->file_name .= $this->file_ext;
}
// An extension was provided, lets have it!
else
{
$this->file_ext = $this->get_extension($this->_file_name_override);
}
if ( ! $this->is_allowed_filetype(TRUE))
{
$this->set_error('upload_invalid_filetype');
return FALSE;
}
}
然後將文件大小轉換爲KB:if ($this->file_size > 0)
{
$this->file_size = round($this->file_size/1024, 2);
}
接着判斷文件大小是否被允許:
if ( ! $this->is_allowed_filesize())
{
$this->set_error('upload_invalid_filesize');
return FALSE;
}
如果文件是圖片還要判斷圖片的屬性是否被允許,寬度、高度
if ( ! $this->is_allowed_dimensions())
{
$this->set_error('upload_invalid_dimensions');
return FALSE;
}
接着清楚文件名中的一些特殊字符:<!--、-->、<、>、"、$、=、;、?、/
$this->file_name = $this->clean_file_name($this->file_name);
如果文件名太長,則截斷文件名:
if ($this->max_filename > 0)
{
$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
}
接着刪除空白的文件名
if ($this->remove_spaces == TRUE)
{
$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
}
接着驗證文件名稱:如果存在同名文件,$overwrite設置爲TRUE則覆蓋文件,如果爲FALSE,則在文件名後加數字,如filename1.jpg
$this->orig_name = $this->file_name;
if ($this->overwrite == FALSE)
{
$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
if ($this->file_name === FALSE)
{
return FALSE;
}
}
接着使用XSS filter過濾:
if ($this->xss_clean)
{
if ($this->do_xss_clean() === FALSE)
{
$this->set_error('upload_unable_to_write_file');
return FALSE;
}
}
最後把文件移動到上傳目錄:
if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
{
if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
{
$this->set_error('upload_destination_error');
return FALSE;
}
}
如果上傳的是圖片則設置文件的一些屬性:寬度、高度。