首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

CodeIgniter 4 圖片上傳完整實戰:從表單到驗證的避坑指南

     編輯:PHP 綜合知識

前言:上傳類庫的「坑」不少

CodeIgniter 內建的 Upload 類庫功能強大,但預設值多、慣例嚴格,稍有不慎就會遇到「路徑無效」、「檔案類型不允許」、「中文檔名失效」等問題。本文以 CI 3/4 通用的核心邏輯為基礎,梳理完整流程與避坑要點。

一、前端表單:兩個關鍵點

<?= form_open_multipart('picture/upload') ?>
<?= form_upload('userfile') ?>  <!-- 1. name 必須為 userfile,或與 do_upload() 參數一致 -->
<?= form_close() ?>
  • enctype="multipart/form-data":form_open_multipart() 自動加上,缺少它 $_FILES 會是空的
  • input name:預設 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]);
    }
}

三、必須知道的「隱形規則」與避坑指南

1. allowed_types 順序陷阱

CI 內部用 getimagesize() 檢測 MIME,但某些格式(如 zip、gz)無法透過影像函式判斷,僅靠副檔名。將無法判斷 MIME 的類型放在前面,否則會誤判為「無法移動檔案」:

// 錯誤順序:png|gif|jpg|zip|gz  → zip/gz 會被當圖片驗證失敗
// 正確順序:zip|gz|png|gif|jpg    → 先通過副檔名放行,圖片再驗證 MIME

2. 中文檔名與特殊字元

  • 預設不支援中文檔名,會導致「無法移動檔案」錯誤
  • 解決:設定 'file_name' => time() 或 'encrypt_name' => TRUE 重新命名
  • 若必須保留原始檔名,需自行實作 mb_convert_encoding 或使用 transliterate 轉 ASCII

3. 上傳目錄權限與路徑

  • upload_path 必須是 絕對路徑,推薦 FCPATH . 'uploads/'(CI 3)或 WRITEPATH . 'uploads/'(CI 4)
  • Linux 下確保目錄擁有者為 PHP-FPM 執行用戶(如 www-data),權限 755 或 775
  • 錯誤 The upload path does not appear to be valid 90% 是路徑寫錯或不可寫

4. 取得檔案資訊:$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)
  • ✅ 上傳目錄設為 不可執行(Nginx: location /uploads { php_flag engine off; })
  • ✅ 檔案型態二次驗證(getimagesize()、finfo_file())
  • ✅ 資料庫僅存相對路徑,不暴露絕對路徑
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved