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

PHP $_FILES 超全域陣列完整指南:檔案上傳處理與錯誤代碼對照

     編輯:PHP 相關知識

$_FILES 是 PHP 處理 HTTP POST 檔案上傳的核心超全域陣列。本文詳細說明其結構、各欄位含義、錯誤代碼對照、表單必要屬性、安全處理流程與常見陷阱。

陣列結構

假設表單欄位名為 myFile:

鍵名說明範例
$_FILES['myFile']['name']用戶端原始檔名photo.jpg
$_FILES['myFile']['type']MIME 類型(瀏覽器提供,不可信)image/jpeg
$_FILES['myFile']['size']檔案大小(位元組)2048576
$_FILES['myFile']['tmp_name']伺服器暫存檔完整路徑/tmp/phpA1B2C3
$_FILES['myFile']['error']上傳錯誤代碼(PHP 4.2.0+)0 (UPLOAD_ERR_OK)

錯誤代碼完整對照表

常數值說明
UPLOAD_ERR_OK0上傳成功,無錯誤
UPLOAD_ERR_INI_SIZE1超過 php.ini upload_max_filesize 限制
UPLOAD_ERR_FORM_SIZE2超過表單 MAX_FILE_SIZE 隱藏欄位限制
UPLOAD_ERR_PARTIAL3檔案僅部分上傳(網路中斷)
UPLOAD_ERR_NO_FILE4沒有檔案被上傳
UPLOAD_ERR_NO_TMP_DIR6缺少暫存目錄(PHP 5.0.3+)
UPLOAD_ERR_CANT_WRITE7寫入磁碟失敗(權限、空間不足)(PHP 5.1.0+)
UPLOAD_ERR_EXTENSION8被 PHP 擴展中斷(PHP 5.2.0+)

表單必要條件

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152"> <!-- 2MB,客戶端檢查,可繞過 -->
    <input type="file" name="myFile" accept="image/*">
    <input type="submit" value="上傳">
</form>
  • enctype="multipart/form-data":必須,否則 $_FILES 為空。
  • method="post":檔案上傳僅支援 POST。
  • MAX_FILE_SIZE:瀏覽器端提示,不可作為伺服器驗證依據。

安全處理標準流程

<?php
// upload.php
$uploadDir = __DIR__ . '/uploads/';
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$maxSize = 2 * 1024 * 1024; // 2MB

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit('僅接受 POST 請求');
}

if (!isset($_FILES['myFile']) || $_FILES['myFile']['error'] !== UPLOAD_ERR_OK) {
    $errCode = $_FILES['myFile']['error'] ?? UPLOAD_ERR_NO_FILE;
    $errors = [
        UPLOAD_ERR_INI_SIZE => '檔案過大 (超過 php.ini 限制)',
        UPLOAD_ERR_FORM_SIZE => '檔案過大 (超過表單限制)',
        UPLOAD_ERR_PARTIAL => '上傳中斷',
        UPLOAD_ERR_NO_FILE => '未選擇檔案',
        UPLOAD_ERR_NO_TMP_DIR => '伺服器暫存目錄錯誤',
        UPLOAD_ERR_CANT_WRITE => '寫入失敗',
        UPLOAD_ERR_EXTENSION => '被擴展阻擋',
    ];
    exit('上傳失敗: ' . ($errors[$errCode] ?? '未知錯誤'));
}

$file = $_FILES['myFile'];

// 1. 驗證檔案大小
if ($file['size'] > $maxSize) {
    exit('檔案超過 2MB 限制');
}

// 2. 驗證真實 MIME 類型(不可信 $_FILES['type'])
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowedTypes, true)) {
    exit('不允許的檔案類型: ' . $mime);
}

// 3. 驗證圖片真實性(防偽裝腳本)
$imgInfo = getimagesize($file['tmp_name']);
if ($imgInfo === false) {
    exit('非有效圖片檔案');
}

// 4. 產生安全檔名(避免覆蓋、路徑遍歷、特殊字元)
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
if (!in_array($ext, $allowedExt)) {
    exit('不允許的副檔名');
}
$newName = bin2hex(random_bytes(16)) . '.' . $ext; // 隨機檔名
$destPath = $uploadDir . $newName;

// 5. 移動暫存檔到目標目錄
if (!move_uploaded_file($file['tmp_name'], $destPath)) {
    exit('檔案移動失敗,請檢查目錄權限');
}

// 6. 設定檔案權限(僅擁有者讀寫)
chmod($destPath, 0644);

echo "上傳成功!檔案: $newName, 大小: {$file['size']} bytes, 類型: $mime";
?>

關鍵安全提醒

  1. 永遠不要信任 $_FILES['type']、$_FILES['name'],必須伺服器端驗證 MIME 與副檔名。
  2. 使用 move_uploaded_file() 而非 copy() 或 rename(),它會驗證檔案確實為 HTTP 上傳。
  3. 上傳目錄不可執行腳本:Nginx/Apache 設定該目錄 php_flag engine off 或禁止 .php 執行。
  4. 檔名使用隨機雜湊,避免中文、空格、特殊字元、覆蓋、路徑遍歷(../../etc/passwd)。
  5. 限制上傳大小:php.ini 設定 upload_max_filesize、post_max_size,Nginx client_max_body_size。
  6. 掃描惡意內容:整合 ClamAV 或上傳後非同步掃描。

多檔案上傳

<input type="file" name="myFiles[]" multiple>

// PHP 處理
foreach ($_FILES['myFiles']['tmp_name'] as $index => $tmpName) {
    if ($_FILES['myFiles']['error'][$index] === UPLOAD_ERR_OK) {
        // 處理單檔...
    }
}
?>

臨時檔案生命週期

  • 腳本執行結束後,暫存檔會自動刪除。
  • 必須在腳本中使用 move_uploaded_file() 移動到永久位置,否則資料遺失。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved