CodeIgniter 3 內建 CI_Upload 僅支援單檔上傳。實務上常需一次上傳多檔(如圖片庫、附件),本文提供一個繼承 CI_Upload 的 MY_Upload 擴充庫,實作 do_multi_upload() 方法,完整支援多檔驗證、重命名、XSS 過濾、圖片處理、錯誤收集等功能,並相容單檔上傳回退。
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Upload extends CI_Upload {
protected $_multi_upload_data = [];
protected $_multi_file_name_override = '';
public function initialize($config = []) {
parent::initialize($config);
// 支援 file_name 為陣列:多檔指定檔名
if (!empty($this->file_name)) {
if (is_array($this->file_name)) {
$this->_file_name_override = '';
$this->_multi_file_name_override = $this->file_name;
} else {
$this->_file_name_override = $this->file_name;
$this->_multi_file_name_override = '';
}
}
}
// 覆寫 MIME 偵測以支援多檔索引
protected function _file_mime_type($file, $index = 0) {
$tmp_name = is_array($file['tmp_name']) ? $file['tmp_name'][$index] : $file['tmp_name'];
$type = is_array($file['type']) ? $file['type'][$index] : $file['type'];
// ... 保留父類別完整 MIME 偵測邏輯(finfo、file 指令、mime_content_type 回退) ...
// 為節省篇幅略過,實際使用請完整複製父類別 _file_mime_type 並修改上兩行取值邏輯
$this->file_type = $type; // 簡化示意
}
protected function set_multi_upload_data() {
$this->_multi_upload_data[] = [
'file_name' => $this->file_name,
'file_type' => $this->file_type,
'file_path' => $this->upload_path,
'full_path' => $this->upload_path . $this->file_name,
'raw_name' => str_replace($this->file_ext, '', $this->file_name),
'orig_name' => $this->orig_name,
'client_name' => $this->client_name,
'file_ext' => $this->file_ext,
'file_size' => $this->file_size,
'is_image' => $this->is_image(),
'image_width' => $this->image_width,
'image_height' => $this->image_height,
'image_type' => $this->image_type,
'image_size_str' => $this->image_size_str,
];
}
public function get_multi_upload_data() {
return $this->_multi_upload_data;
}
public function do_multi_upload($field) {
if (!isset($_FILES[$field])) return false;
// 單檔回退
if (!is_array($_FILES[$field]['name'])) {
return $this->do_upload($field);
}
if (!$this->validate_upload_path()) return false;
$total = count($_FILES[$field]['name']);
for ($i = 0; $i < $total; $i++) {
// 檢查是否為有效上傳檔案
if (!is_uploaded_file($_FILES[$field]['tmp_name'][$i])) {
$error = $_FILES[$field]['error'][$i] ?? 4;
$this->_set_upload_error($error);
return false;
}
// 設定當前檔案屬性
$this->file_temp = $_FILES[$field]['tmp_name'][$i];
$this->file_size = $_FILES[$field]['size'][$i];
$this->_file_mime_type($_FILES[$field], $i);
$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'][$i]);
$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;
}
// 多檔檔名覆寫
if (!empty($this->_multi_file_name_override[$i])) {
$this->file_name = $this->_prep_filename($this->_multi_file_name_override[$i]);
if (strpos($this->_multi_file_name_override[$i], '.') === false) {
$this->file_name .= $this->file_ext;
} else {
$this->file_ext = $this->get_extension($this->_multi_file_name_override[$i]);
}
if (!$this->is_allowed_filetype(true)) {
$this->set_error('upload_invalid_filetype');
return false;
}
}
// 檔案大小、圖片尺寸、檔名長度、空白移除、覆寫保護、XSS 清理、移動檔案、記錄資訊
// ... 完整邏輯請參考父類別 do_upload() 對應段落,此處略過重複程式碼 ...
// 關鍵差異:每輪迴圈結束呼叫 $this->set_multi_upload_data();
}
return true;
}
// 協助方法:統一錯誤代碼對應
protected function _set_upload_error($errorCode) {
$messages = [
1 => 'upload_file_exceeds_limit',
2 => 'upload_file_exceeds_form_limit',
3 => 'upload_file_partial',
4 => 'upload_no_file_selected',
6 => 'upload_no_temp_directory',
7 => 'upload_unable_to_write_file',
8 => 'upload_stopped_by_extension',
];
$this->set_error($messages[$errorCode] ?? 'upload_no_file_selected');
}
}
public function upload_gallery() {
$config = [
'upload_path' => FCPATH . 'uploads/gallery/',
'allowed_types' => 'jpg|jpeg|png|gif',
'max_size' => 2048, // 2MB
'max_width' => 1920,
'max_height' => 1080,
'encrypt_name' => true, // 自動加密檔名避免衝突
'remove_spaces' => true,
];
$this->load->library('upload', $config);
if (!$this->upload->do_multi_upload('gallery_images')) {
// 失敗:顯示錯誤
$error = $this->upload->display_errors();
$this->load->view('upload_form', ['error' => $error]);
} else {
// 成功:取得所有檔案資訊
$files = $this->upload->get_multi_upload_data();
// 寫入資料庫、產生縮圖等後續處理...
$this->load->view('upload_success', ['files' => $files]);
}
}
<form method="post" action="= site_url('gallery/upload_gallery') ?>" enctype="multipart/form-data">
<input type="file" name="gallery_images[]" multiple>
<button type="submit">上傳</button>
</form>
application/libraries/MY_Upload.php,CodeIgniter 自動載入覆寫。$_FILES[$field]['name'] 是否為陣列,自動回退 do_upload()。$config['file_name'] = ['custom_1.jpg', 'custom_2.jpg'] 可指定每檔檔名。display_errors() 正常運作。get_multi_upload_data() 回傳結構化陣列,含路徑、尺寸、型別等完整資訊。CI4 內建 CodeIgniter\Files\File 與 FileCollection 原生支援多檔上傳,無需自訂庫。升級時請改用 $this->request->getFiles() 並搭配 Validation 規則處理。
透過繼承 CI_Upload 實作 do_multi_upload(),即可在 CodeIgniter 3 專案中輕鬆實現企業級多檔上傳功能,完整保留驗證、安全、圖片處理等核心特性,程式碼可維護性極高。