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

CodeIgniter 4 文件上傳類完整實戰指南:從基礎到生產級最佳實踐

     編輯:PHP 相關知識

前言

CodeIgniter 4 (CI4) 重寫了文件上傳類,提供流暢接口、強類型驗證、多存儲適配器支持。本文基於 CI4 最新版,覆蓋表單構建、控制器邏輯、配置詳解、安全加固及雲存儲擴展。

目錄結構規劃

app/
├── Config/
│   └── Upload.php          # 上傳配置文件(推薦)
├── Controllers/
│   └── Upload.php          # 控制器
├── Views/
│   ├── upload_form.php     # 上傳表單
│   └── upload_success.php  # 成功頁面
└── Helpers/
    └── form_helper.php     # 可選:自定義表單助手

1. 視圖層:構建上傳表單

app/Views/upload_form.php

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>文件上傳</title>
    <style>
        .error {color: #e74c3c; margin: 1rem 0;}
        .success {color: #27ae60; margin: 1rem 0;}
        form {max-width: 500px; margin: 2rem auto; padding: 1.5rem; border: 1px solid #ddd; border-radius: 8px;}
        .form-group {margin-bottom: 1rem;}
        label {display: block; margin-bottom: .5rem; font-weight: 600;}
        input[type="file"] {display: block; width: 100%;}
        button {background: #3498db; color: white; border: none; padding: .75rem 1.5rem; border-radius: 4px; cursor: pointer;}
        button:hover {background: #2980b9;}
    </style>
</head>
<body>
    <h1 style="text-align:center;">文件上傳演示</h1>
    
    <?php if (session()->getFlashdata('error')): ?>
        <div class="error"><?= session()->getFlashdata('error') ?></div>
    <?php endif; ?>
    
    <?php if (session()->getFlashdata('success')): ?>
        <div class="success"><?= session()->getFlashdata('success') ?></div>
    <?php endif; ?>

    <form action="<?= site_url('upload/doUpload') ?>" method="post" enctype="multipart/form-data">
        <?= csrf_field() ?>
        <div class="form-group">
            <label for="userfile">選擇圖片 (JPG/PNG/GIF, ≤2MB)</label>
            <input type="file" name="userfile" id="userfile" accept="image/jpeg,image/png,image/gif" required>
        </div>
        <button type="submit">上傳</button>
    </form>
</body>
</html>

app/Views/upload_success.php

<?php $data = $upload_data ?? []; ?>
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>上傳成功</title></head>
<body style="text-align:center; padding:2rem;">
    <h1>🎉 文件上傳成功!</h1>
    <div style="max-width:500px; margin:2rem auto; text-align:left;">
        <p><strong>文件名:</strong> <?= esc($data['client_name'] ?? '') ?></p>
        <p><strong>存儲名:</strong> <?= esc($data['name'] ?? '') ?></p>
        <p><strong>類型:</strong> <?= esc($data['type'] ?? '') ?></p>
        <p><strong>大小:</strong> <?= number_format(($data['size'] ?? 0)/1024, 2) ?> KB</p>
        <p><strong>路徑:</strong> <?= esc($data['full_path'] ?? '') ?></p>
        <?php if (($data['is_image'] ?? 0) === 1): ?>
            <p><strong>尺寸:</strong> <?= $data['image_width'] ?> × <?= $data['image_height'] ?></p>
            <img src="<?= base_url('uploads/' . $data['name']) ?>" alt="預覽" style="max-width:100%; border:1px solid #ddd;">
        <?php endif; ?>
    </div>
    <p><a href="<?= site_url('upload') ?>">繼續上傳</a></p>
</body>
</html>

2. 配置文件:集中管理上傳策略

app/Config/Upload.php

<?php namespace Config;

use CodeIgniter\Config\BaseConfig;

class Upload extends BaseConfig
{
    // 默認配置(可被控制器覆蓋)
    public $default = [
        'upload_path'      => FCPATH . 'uploads/',   // 絕對路徑,需可寫
        'allowed_types'    => 'jpg|jpeg|png|gif|webp',
        'max_size'         => 2048,                  // KB
        'max_width'        => 1920,
        'max_height'       => 1080,
        'encrypt_name'     => true,                  // 防衝突、防猜測
        'remove_spaces'    => true,                  // 文件名空格→下劃線
        'overwrite'        => false,                 // 不覆蓋,自動重命名
        'file_name'        => '',                    // 為空則用 encrypt_name
    ];

    // 業務場景差異化配置
    public $avatar = [
        'max_size'    => 512,
        'max_width'   => 400,
        'max_height'  => 400,
        'allowed_types' => 'jpg|png',
    ];

    public $document = [
        'allowed_types' => 'pdf|doc|docx|xls|xlsx|txt',
        'max_size'      => 10240,  // 10MB
    ];
}

3. 控制器:業務邏輯與異常處理

app/Controllers/Upload.php

<?php namespace App\Controllers;

use CodeIgniter\Controller;
use CodeIgniter\Files\File;
use Config\Services;

class Upload extends Controller
{
    public function index()
    {
        return view('upload_form');
    }

    public function doUpload()
    {
        // 1. 獲取配置(合併默認 + 場景配置)
        $config = config('Upload')->default;
        if ($this->request->getPost('type')) {
            $type = $this->request->getPost('type');
            $config = array_merge($config, config('Upload')->{$type} ?? []);
        }

        // 2. 初始化上傳庫
        $upload = Services::upload($config);
        
        // 3. 執行上傳(字段名默認 userfile)
        if (!$upload->doUpload('userfile')) {
            // 失敗:返回錯誤信息
            return redirect()->back()
                ->withInput()
                ->with('error', $upload->displayErrors());
        }

        // 4. 成功:獲取文件元數據
        $fileData = $upload->getData();
        
        // 5. 業務擴展點:保存到數據庫、生成縮略圖、推送隊列等
        $this->postProcess($fileData);

        // 6. 返回成功頁面
        return view('upload_success', ['upload_data' => $fileData]);
    }

    /**
     * 上傳後處理(可提取到 Service/Listener)
     */
    protected function postProcess(array $data): void
    {
        // 示例:記錄日誌
        log_message('info', '文件上傳: ' . json_encode([
            'name' => $data['name'],
            'size' => $data['size'],
            'type' => $data['type'],
            'user_id' => auth()->id() ?? 'guest',
        ]));

        // 示例:生成縮略圖(需安裝 intervention/image)
        // if ($data['is_image']) { ... }
    }
}

4. 路由配置

app/Config/Routes.php

$routes->get('upload', 'Upload::index');
$routes->post('upload/doUpload', 'Upload::doUpload');

5. 安全加固清單(生產環境必做)

風險對策代碼位置
惡意腳本上傳1. allowed_types 嚴格白名單 2. encrypt_name=true 3. 存儲目錄禁用 PHP 執行Config/Upload.php + Nginx/Apache 配置
文件名注入/路徑遍歷remove_spaces=true、encrypt_name=true、CI4 內置路徑安全檢查配置自動生效
大文件 DoSmax_size + PHP upload_max_filesize + Nginx client_max_body_size 三層限制php.ini / nginx.conf / Config
MIME 偽裝CI4 使用 finfo 檢測真實類型,非僅信任瀏覽器傳來的 type核心庫自動處理
CSRF表單包含 ,控制器啟用 $this->request->getPost('csrf_token') 驗證View + Controller

6. 進階:雲存儲適配

CI4 支持自定義存儲處理器,實現 CodeIgniter\Files\FileInterface 即可對接 S3、OSS、COS、七牛等:

<?php namespace App\Libraries\Storage;

use CodeIgniter\Files\File;
use Aws\S3\S3Client;

class S3Handler implements \CodeIgniter\Files\FileInterface
{
    private S3Client $client;
    private string $bucket;
    
    public function __construct(string $key, string $secret, string $region, string $bucket)
    {
        $this->client = new S3Client(['version'=>'latest','region'=>$region,'credentials'=>compact('key','secret')]);
        $this->bucket = $bucket;
    }
    
    // 實現 move(), delete(), getPath(), getURL() 等方法...
}

// 使用:在控制器中
$upload = Services::upload($config);
$upload->setFileHandler(new S3Handler(...));

7. 常見問題排查

  • 上傳目錄不可寫:chmod 775 uploads/、確保 PHP-FPM 用戶(www-data)有權限
  • 大文件上傳失敗:檢查 php.ini post_max_size、upload_max_filesize、max_execution_time;Nginx client_max_body_size 20M;
  • 圖片不顯示:確認 base_url 配置正確、Nginx 靜態資源 location 配置、文件實際存在

最佳實踐總結:配置集中化 → 控制器薄化 → 業務服務化 → 安全分層 → 存儲抽象化。CI4 上傳類已足夠強大,善用配置文件與服務層,避免控制器膨脹。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved