CodeIgniter 內建的 Upload 類庫功能強大,但預設值多、慣例嚴格,稍有不慎就會遇到「路徑無效」、「檔案類型不允許」、「中文檔名失效」等問題。本文以 CI 3/4 通用的核心邏輯為基礎,梳理完整流程與避坑要點。
<?= form_open_multipart('picture/upload') ?>
<?= form_upload('userfile') ?> <!-- 1. name 必須為 userfile,或與 do_upload() 參數一致 -->
<?= form_close() ?>
form_open_multipart() 自動加上,缺少它 $_FILES 會是空的do_upload() 讀取 userfile,若表單用其他 name,必須傳參 do_upload('your_name')public function upload() {
$config = [
'upload_path' => FCPATH . 'uploads/', // 絕對路徑,相對 index.php;目錄需可寫
'allowed_types' => 'gif|jpg|png', // 擴展名順序影響驗證,見下文
'max_size' => 1024, // KB,預設 0 不限制
'max_width' => 1024,
'max_height' => 768,
'file_name' => time(), // 覆蓋原始檔名,避免中文/特殊字元問題
'encrypt_name' => TRUE, // 更推薦:自動生成隨機檔名
'remove_spaces' => TRUE, // 移除檔名空格
];
$this->load->library('upload', $config);
if (!$this->upload->do_upload()) { // 或 do_upload('custom_name')
$error = $this->upload->display_errors();
// 記錄日誌、回傳 JSON 錯誤等
log_message('error', 'Upload failed: ' . $error);
$this->output->set_status_header(400)->set_json_output(['error' => $error]);
} else {
$data = $this->upload->data(); // 取得完整檔案資訊陣列
$fileName = $data['file_name'];
// 入庫、生成縮圖、回傳成功資訊...
$this->output->set_json_output(['success' => true, 'file' => $data]);
}
}
allowed_types 順序陷阱CI 內部用 getimagesize() 檢測 MIME,但某些格式(如 zip、gz)無法透過影像函式判斷,僅靠副檔名。將無法判斷 MIME 的類型放在前面,否則會誤判為「無法移動檔案」:
// 錯誤順序:png|gif|jpg|zip|gz → zip/gz 會被當圖片驗證失敗
// 正確順序:zip|gz|png|gif|jpg → 先通過副檔名放行,圖片再驗證 MIME
'file_name' => time() 或 'encrypt_name' => TRUE 重新命名mb_convert_encoding 或使用 transliterate 轉 ASCIIupload_path 必須是 絕對路徑,推薦 FCPATH . 'uploads/'(CI 3)或 WRITEPATH . 'uploads/'(CI 4)755 或 775The upload path does not appear to be valid 90% 是路徑寫錯或不可寫$this->upload->data()回傳陣列包含:file_name、file_type、file_path、full_path、raw_name、orig_name、file_ext、file_size、is_image、image_width、image_height、image_type、image_size_str 等,足夠支援後續縮圖、水印、入庫等操作。
// CI 4 原生支援多檔:$this->request->getFiles()
$files = $this->request->getFileMultiple('userfile'); // name="userfile[]"
foreach ($files as $file) {
if ($file->isValid() && !$file->hasMoved()) {
$newName = $file->getRandomName();
$file->move(WRITEPATH . 'uploads', $newName);
// 入庫...
}
}
搭配 Validation 服務可集中管理規則:
$rules = [
'userfile' => 'uploaded[userfile]|max_size[userfile,2048]|mime_in[userfile,image/jpg,image/png,image/gif]',
];
if (!$this->validate($rules)) { /* 處理錯誤 */ }
allowed_types 為業務必要類型max_size 防止佔滿磁碟encrypt_name)location /uploads { php_flag engine off; })getimagesize()、finfo_file())