萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 檔案上傳完整實作指南:$_FILES 處理、安全驗證、多檔上傳與大檔設定

前置環境準備

php.ini 關鍵設定

file_uploads = On
upload_tmp_dir = /tmp/php_uploads  ; 必須存在且 PHP 進程可寫
upload_max_filesize = 10M          ; 單檔上限
post_max_size = 12M                ; 必須 > upload_max_filesize
max_execution_time = 300           ; 大檔需增加執行時間
max_input_time = 300               ; 解析輸入時間

注意:修改後必須重啟 PHP 服務。

HTML 表單規範

<form action="upload.php" method="POST" enctype="multipart/form-data">
    <input type="file" name="userfile" />
    <input type="submit" value="上傳" />
</form>

關鍵點:enctype="multipart/form-data"、method="POST"。

單檔上傳核心邏輯

<?php
function uploadFile($inputName, $destDir = '../uploads/', $allowedTypes = [], $maxSize = 0)
{
    // 1. 檢查是否有檔案上傳
    if (empty($_FILES[$inputName]['name']) || $_FILES[$inputName]['error'] !== UPLOAD_ERR_OK) {
        return ['success' => false, 'msg' => '無檔案或上傳錯誤'];
    }

    $file = $_FILES[$inputName];
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

    // 2. 類型驗證
    if (!empty($allowedTypes) && !in_array($ext, $allowedTypes)) {
        return ['success' => false, 'msg' => '檔案類型不允許'];
    }

    // 3. 大小驗證
    if ($maxSize > 0 && $file['size'] > $maxSize) {
        return ['success' => false, 'msg' => '檔案大小超過限制'];
    }

    // 4. 目錄檢查
    $destDir = rtrim($destDir, '/') . '/';
    if (!is_dir($destDir) || !is_writable($destDir)) {
        return ['success' => false, 'msg' => '上傳目錄不存在或不可寫'];
    }

    // 5. 產生唯一檔名 (避免覆蓋)
    $fileName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
    $destPath = $destDir . $fileName;

    // 6. 移動暫存檔 (安全: 驗證是真正上傳檔案)
    if (!move_uploaded_file($file['tmp_name'], $destPath)) {
        return ['success' => false, 'msg' => '檔案移動失敗'];
    }

    // 7. 設定權限 (視需求)
    @chmod($destPath, 0644);

    return ['success' => true, 'filename' => $fileName, 'path' => $destPath];
}

// 使用範例
$result = uploadFile('userfile', '../data/agency/', ['jpg','png','gif','pdf'], 2*1024*1024);
if ($result['success']) {
    echo "上傳成功:" . $result['filename'];
} else {
    echo "失敗:" . $result['msg'];
}
?>

多檔案上傳

HTML 修改

<input type="file" name="userfile[]" multiple />

<input type="file" name="userfile[]" />
<input type="file" name="userfile[]" />
<input type="file" name="userfile[]" />

PHP 處理陣列結構

<?php
// $_FILES['userfile']['name'] 變成陣列
$fileCount = count($_FILES['userfile']['name']);
for ($i = 0; $i < $fileCount; $i++) {
    $singleFile = [
        'name'     => $_FILES['userfile']['name'][$i],
        'type'     => $_FILES['userfile']['type'][$i],
        'tmp_name' => $_FILES['userfile']['tmp_name'][$i],
        'error'    => $_FILES['userfile']['error'][$i],
        'size'     => $_FILES['userfile']['size'][$i],
    ];
    // 呼叫單檔處理邏輯...
}
?>

$_FILES 錯誤代碼對照表

代碼常數說明
0UPLOAD_ERR_OK成功
1UPLOAD_ERR_INI_SIZE超過 php.ini upload_max_filesize
2UPLOAD_ERR_FORM_SIZE超過表單 MAX_FILE_SIZE
3UPLOAD_ERR_PARTIAL部分上傳
4UPLOAD_ERR_NO_FILE未選擇檔案
6UPLOAD_ERR_NO_TMP_DIR缺少暫存目錄
7UPLOAD_ERR_CANT_WRITE寫入磁碟失敗
8UPLOAD_ERR_EXTENSIONPHP 擴充模組中斷上傳

安全性加強建議

  1. 檔案類型二次驗證:勿信任 $_FILES['type'],使用 finfo_file() 檢測真實 MIME。
  2. 儲存路徑不可直接存取:上傳目錄設定在 Web Root 外,或透過 PHP 讀取輸出。
  3. 檔名隨機化:避免覆蓋、路徑遍歷攻擊。
  4. 掃描惡意內容:整合 ClamAV 或上傳後異步掃描。
  5. 限制副檔名:禁止 .php, .phtml, .php5, .phar, .htaccess 等可執行副檔名。

大檔上傳優化

  • 前端分片上傳 (Plupload, Uppy, WebUploader)。
  • 後端支援斷點續傳 (合併分片)。
  • 調大 memory_limit、max_execution_time、nginx client_max_body_size。

結語

檔案上傳看似簡單,實則涉及環境設定、輸入驗證、安全防護、錯誤處理多個層面。建立可復用的上傳元件,並嚴格遵循「不信任客戶端資料」原則,是打造穩健系統的關鍵。

copyright © 萬盛學電腦網 all rights reserved