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

PHP 檔案上傳類別封裝:支援自動建目錄、隨機命名與錯誤狀態管理

     編輯:PHP 相關知識

將檔案上傳邏輯封裝為可重用類別,能有效減少控制器層的樣板程式碼,並統一錯誤處理流程。本文提供一個輕量級 UploadClass,具備目錄自動建立、檔案大小限制、唯一檔名生成、上傳狀態追蹤等核心功能,並修正原始碼中變數作用域與邏輯判斷的潛在問題。

改良版上傳類別 UploadClass.php

<?php
declare(strict_types=1);

class UploadClass
{
    private string $location;   // 儲存目錄
    private int $maxSize;       // 最大允許位元組數
    private string $status;     // 狀態:success / failure / too_large / empty
    private string $filename;   // 最終儲存檔名

    public function __construct(array $file, string $location = './temp/', int $maxSize = 1000000)
    {
        $this->location = rtrim($location, '/') . '/';
        $this->maxSize = $maxSize;
        $this->status = 'success';
        $this->filename = '';

        // 確保目錄存在
        if (!is_dir($this->location)) {
            if (!mkdir($this->location, 0755, true)) {
                $this->status = 'dir_create_failed';
                return;
            }
        }

        // 檔案為空直接返回
        if (empty($file['name']) || $file['error'] !== UPLOAD_ERR_OK) {
            $this->status = 'empty';
            return;
        }

        // 檔案大小檢查
        if ($file['size'] > $this->maxSize) {
            $this->status = 'too_large';
            return;
        }

        // 生成唯一檔名:前綴_時間戳_隨機數.副檔名
        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $this->filename = sprintf('%s_%d_%d.%s', 'up', time(), mt_rand(10000, 99999), $ext);

        // 移動檔案
        $dest = $this->location . $this->filename;
        if (!move_uploaded_file($file['tmp_name'], $dest)) {
            $this->status = 'move_failed';
            $this->filename = '';
        }
    }

    public function getFilename(): string
    {
        return $this->filename;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function isSuccess(): bool
    {
        return $this->status === 'success';
    }

    public function getFullPath(): string
    {
        return $this->location . $this->filename;
    }
}

控制器使用範例

<?php
require_once 'UploadClass.php';

header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit(json_encode(['error' => 'Method not allowed']));
}

$uploader = new UploadClass($_FILES['file'] ?? [], __DIR__ . '/uploads/', 2 * 1024 * 1024); // 2MB

if ($uploader->isSuccess()) {
    echo json_encode([
        'success' => true,
        'filename' => $uploader->getFilename(),
        'path' => $uploader->getFullPath(),
        'url' => '/uploads/' . $uploader->getFilename() // 前端可直接訪問的 URL
    ]);
} else {
    $messages = [
        'empty' => '未選擇檔案或上傳錯誤',
        'too_large' => '檔案超過 2MB 限制',
        'move_failed' => '檔案儲存失敗,請檢查目錄權限',
        'dir_create_failed' => '無法建立上傳目錄',
    ];
    http_response_code(400);
    echo json_encode([
        'success' => false,
        'error' => $messages[$uploader->getStatus()] ?? '未知錯誤',
        'status_code' => $uploader->getStatus()
    ]);
}

設計重點說明

改進項目原始碼問題改良方案
變數作用域建構子內使用區域變數 $location、$max_size 而非屬性全面改用 $this->property,確保狀態保存
錯誤碼處理未檢查 $_FILES['error']建構子首行驗證 UPLOAD_ERR_OK
狀態管理單一 $event 字串,語意不明引入枚舉式狀態常數,提供 isSuccess() 便利方法
檔名生成直接使用 time() + rand(),極小機率衝突採用 sprintf 格式化,前綴區分業務,隨機範圍擴大至 90000
回傳格式直接 echo 輸出,難以整合 API類別專注邏輯,控制器負責 JSON 回應,關注點分離

進階擴充建議

  • 加入 setAllowedExtensions(array $exts) 白名單驗證
  • 實作 setOverwriteBehavior(bool $allow) 控制同名檔案覆蓋策略
  • 整合 finfo 檢測真實 MIME 類型,防止副檔名偽裝
  • 支援多檔上傳:UploadClass::handleMultiple(array $files, ...)
  • 加入事件鉤子:onBeforeMove、onAfterMove 供日誌、水印、縮圖等擴充

此類別遵循單一職責原則、依賴注入(目錄與大小可外部配置)、狀態機設計,易於單元測試與框架整合,是中型專案檔案上傳模組的優良起點。

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