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

PHP 文件上傳完整指南:從表單構建到安全驗證的最佳實踐

     編輯:PHP 相關知識

前端表單構建

文件上傳表單必須設置 enctype="multipart/form-data" 並使用 POST 方法:

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000">
    <input name="userfile" type="file">
    <input type="submit" value="上傳文件">
</form>
  • MAX_FILE_SIZE:客戶端提示上限 (字節),瀏覽器可能攔截超大文件,不可作為服務端唯一驗證依據。
  • name="userfile":對應 $_FILES['userfile'] 數組鍵名。

後端核心處理邏輯 (upload.php)

<?php
function uploadFile($type, $name, $ext, $size, $error, $tmp_name, $targetName, $uploadDir) {
    // 1. 基礎配置
    $maxSize = 2000000; // 2MB
    $allowedMimes = ['image/pjpeg', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png'];
    $allowedExts  = ['.jpg', '.gif', '.png', '.jpeg']; // 去重
    $filePath = $uploadDir . $targetName;

    // 2. 目錄準備 (遞歸創建 + 權限設置)
    if (!is_dir($uploadDir)) {
        if (!mkdir($uploadDir, 0755, true)) {
            die("無法創建上傳目錄: $uploadDir");
        }
    }

    // 3. 文件大小驗證
    if ($size > $maxSize) die("文件大小超過限制 ($maxSize 字節)");
    if ($size == 0) die("請選擇文件");

    // 4. 類型雙重驗證 (MIME + 擴展名)
    if (!in_array($type, $allowedMimes) || !in_array(strtolower($ext), $allowedExts)) {
        die("文件類型不允許,僅支持: " . implode(", ", $allowedExts));
    }

    // 5. 移動臨時文件
    if (!move_uploaded_file($tmp_name, $filePath)) {
        die("文件移動失敗,請檢查目錄寫入權限");
    }

    // 6. 錯誤碼處理 (作為最後防線)
    switch ($error) {
        case UPLOAD_ERR_OK: return true;
        case UPLOAD_ERR_INI_SIZE: die("超過 php.ini upload_max_filesize");
        case UPLOAD_ERR_FORM_SIZE: die("超過表單 MAX_FILE_SIZE");
        case UPLOAD_ERR_PARTIAL: die("文件僅部分上傳");
        case UPLOAD_ERR_NO_FILE: die("未選擇文件");
        default: die("未知上傳錯誤代碼: $error");
    }
}

// 調用示例
$f = $_FILES['userfile'];
uploadFile($f['type'], $f['name'], pathinfo($f['name'], PATHINFO_EXTENSION),
           $f['size'], $f['error'], $f['tmp_name'], time() . ".jpg", "./uploads/");
echo "上傳成功!";
?>

安全加固清單 (生產環境必讀)

進階優化方向

  • 分片/斷點續傳:前端 Plupload/WebUploader + 後端合並邏輯,支持大文件。
  • 異步處理:上傳即入隊列 (Redis/RabbitMQ),Worker 異步驗證、轉碼、存儲,秒級響應。
  • 雲存儲直傳:簽名直傳至 OSS/S3,服務端僅驗證回調,減輕帶寬壓力。
  • 圖片處理管道:集成 Intervention Image / Imagick,自動縮略圖、水印、WebP 轉換。

總結

文件上傳看似簡單,實則是安全攻擊面最集中的功能之一。核心原則:不信任任何客戶端數據,多層驗證,最小權限,隔離存儲。建議在成熟框架 (Laravel, Symfony) 中使用其內置上傳組件,或引入成熟庫 (如 league/flysystem) 而非手寫原生代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
風險點防範措施
MIME 偽造不可信任 $_FILES['type'],需使用 finfo_file() 檢測真實 MIME:
$finfo = finfo_open(FILEINFO_MIME_TYPE); $realMime = finfo_file($finfo, $tmp_name);
擴展名繞過白名單驗證擴展名;重命名文件 (時間戳+隨機數+白名單後綴);禁止解析上傳目錄腳本 (.php, .phtml 等)。
文件內容檢測圖片類用 getimagesize() 驗證真實性;掃描文件頭魔數;集成 ClamAV 病毒掃描。
目錄遍歷嚴格過濾文件名中的 ../、..\\;使用 basename() 獲取純文件名。
權限控制上傳目錄設置 不可執行 (Nginx/Apache 禁用腳本解析);文件權限 0644,目錄 0755。
DoS 攻擊限制單文件/總大小;限制并發上傳數;使用獨立存儲服務 (OSS/S3) 卸載主服務器。
臨時文件殘留異常分支確保 @unlink($tmp_name);定期清理 upload_tmp_dir。