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

PHP 規範化檔案上傳類:支援圖片/影音/文件、自動分目錄、安全驗證

     編輯:PHP 相關知識

專案中處理檔案上傳若散落在各控制器,難以維護且易留下安全漏洞。本文提供一個結構清晰、參數可配置的 Files::upload() 靜態類,涵蓋副檔名白名單、大小限制、目錄自動建立(按日期分層)、隨機重命名、權限設定、資料庫路徑回傳等完整流程,適合直接納入專案共用庫。

類別完整程式碼

<?php
class Files {
    /**
     * 檔案上傳統一入口
     * @param string $basePath  儲存根目錄絕對路徑(如 /var/www/uploads)
     * @param array  $file      $_FILES['fieldName'] 陣列
     * @param string $type      類型鍵名:image, flash, media, file(對應下方 $extArr)
     * @return array  ['error'=>msg] 或 ['file_url'=>url, 'file_size'=>size, 'db_path'=>relativePath]
     */
    public static function upload($basePath, $file, $type = 'image') {
        $msg = [];

        // 1. 基礎路徑正規化
        $savePath = rtrim(realpath($basePath), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
        $saveUrl  = rtrim($basePath, '/') . '/'; // 假設 Web 可存取路徑同根目錄

        // 2. 允許的副檔名對照表
        $extArr = [
            'image' => ['gif','jpg','jpeg','png','bmp','webp'],
            'flash' => ['swf','flv'],
            'media' => ['swf','flv','mp3','wav','wma','wmv','mid','avi','mpg','asf','rm','rmvb','mp4'],
            'file'  => ['doc','docx','xls','xlsx','ppt','htm','html','txt','zip','rar','gz','bz2','pdf'],
        ];

        // 3. 最大檔案大小(位元組,預設 1MB)
        $maxSize = 1000000; // 可改為配置參數

        // 4. 基礎驗證
        if (empty($file) || $file['error'] !== UPLOAD_ERR_OK) {
            $msg['error'] = '請選擇有效檔案。';
            return $msg;
        }
        if (!is_dir($savePath) || !is_writable($savePath)) {
            $msg['error'] = '上傳目錄不存在或不可寫入。';
            return $msg;
        }
        if (!isset($extArr[$type])) {
            $msg['error'] = "不支援的類型:$type";
            return $msg;
        }
        if ($file['size'] > $maxSize) {
            $msg['error'] = '檔案大小超過限制(' . self::formatSize($maxSize) . ')。';
            return $msg;
        }

        // 5. 副檔名驗證
        $origName = $file['name'];
        $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
        if (!in_array($ext, $extArr[$type])) {
            $msg['error'] = '不允許的副檔名。僅支援:' . implode(', ', $extArr[$type]);
            return $msg;
        }

        // 6. 建立日期分層目錄:/type/Y/m/d/
        $dateDir = $type . '/' . date('Y/m/d/');
        $fullDir = $savePath . $dateDir;
        $fullUrl = $saveUrl . $dateDir;
        if (!is_dir($fullDir)) {
            mkdir($fullDir, 0755, true);
        }

        // 7. 產生唯一檔名:YmdHis_隨機數.副檔名
        $newName = date('YmdHis') . '_' . mt_rand(10000, 99999) . '.' . $ext;
        $destPath = $fullDir . $newName;
        $destUrl  = $fullUrl . $newName;
        $dbPath   = $dateDir . $newName; // 存入資料庫的相對路徑

        // 8. 移動檔案
        if (!move_uploaded_file($file['tmp_name'], $destPath)) {
            $msg['error'] = '檔案移動失敗(權限或磁碟空間不足)。';
            return $msg;
        }

        // 9. 設定權限並回傳結果
        @chmod($destPath, 0644);
        $msg['file_url']  = $destUrl;
        $msg['file_size'] = $file['size'];
        $msg['db_path']   = $dbPath;
        return $msg;
    }

    private static function formatSize($bytes) {
        $units = ['B','KB','MB','GB','TB'];
        $i = 0;
        while ($bytes >= 1024 && $i < count($units)-1) {
            $bytes /= 1024; $i++;
        }
        return round($bytes, 2) . ' ' . $units[$i];
    }
}

控制器調用範例

<?php
// 接收前端 
$result = Files::upload('/var/www/html/uploads', $_FILES['avatar'], 'image');

if (isset($result['error'])) {
    // 失敗處理
    echo json_encode(['success' => false, 'msg' => $result['error']]);
} else {
    // 成功:儲存 $result['db_path'] 到資料庫,前端用 $result['file_url'] 顯示
    echo json_encode([
        'success' => true,
        'url'     => $result['file_url'],
        'path'    => $result['db_path'],
        'size'    => $result['file_size'],
    ]);
}

關鍵設計亮點

特性說明
類型白名單依業務區分 image/flash/media/file,防止上傳可執行腳本
日期分層目錄避免單一目錄檔案過多導致 inode 耗盡、列目錄緩慢
隨機重命名防止檔名衝突、路徑遍歷、覆蓋敏感檔案
不依賴 php.ini大小、副檔名、路徑全在類別內配置,部署更彈性
回傳結構統一成功含 url/size/db_path,失敗含 error,前後端介面穩定

安全補充建議

  • 上傳目錄設定 php_flag engine off (Apache) 或 location ~ \.php$ { deny all; } (Nginx) 禁止腳本執行。
  • 圖片類型建議用 getimagesize() 或 imagecreatefromstring() 二次驗證真偽。
  • 大型專案建議引入 league/flysystem 抽象儲存層,支援 S3、雲端儲存無縫遷移。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved