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

PHP 檔案上傳完整指南:從基礎到進階實戰技巧

     編輯:PHP 相關知識

PHP 檔案上傳完整指南:從基礎到進階實戰技巧

檔案上傳是 Web 開發中最常見的功能之一,但也是安全漏洞高發區。本文系統整理 PHP 檔案上傳的核心知識點,涵蓋基礎實作、錯誤碼解析、MIME 類型驗證、重名處理、日期分目錄儲存、多檔案上傳、陣列結構轉換以及伺服器配置優化等實戰場景。

1. 最簡單的檔案上傳範例

首先建立一個基本的 HTML 表單,注意必須設定 enctype="multipart/form-data":

<form action="upload_file.php" method="post" enctype="multipart/form-data">
  <label for="file">選擇檔案:</label>
  <input type="file" name="file" id="file" />
  <br />
  <input type="submit" name="submit" value="上傳" />
</form>

對應的 PHP 處理邏輯(upload_file.php):

<?php
if ($_FILES["file"]["size"] < 20000) {
    if ($_FILES["file"]["error"] > 0) {
        echo "錯誤代碼: " . $_FILES["file"]["error"] . "<br />";
    } else {
        echo "檔案名: " . $_FILES["file"]["name"] . "<br />";
        echo "類型: " . $_FILES["file"]["type"] . "<br />";
        echo "大小: " . ($_FILES["file"]["size"] / 1024) . " KB<br />";
        echo "暫存路徑: " . $_FILES["file"]["tmp_name"] . "<br />";

        if (file_exists("upload/" . $_FILES["file"]["name"])) {
            echo $_FILES["file"]["name"] . " 已存在。";
        } else {
            move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
            echo "儲存於: upload/" . $_FILES["file"]["name"];
        }
    }
} else {
    echo "檔案過大";
}
?>

2. 深入理解 $_FILES 超全域變數

$_FILES 陣列包含五個關鍵鍵值:

  • name:用戶端原始檔名
  • type:瀏覽器提供的 MIME 類型(不可信)
  • size:檔案大小(位元組)
  • tmp_name:伺服器暫存路徑
  • error:錯誤代碼(見下表)
常數值說明
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找不到暫存目錄
UPLOAD_ERR_CANT_WRITE7寫入失敗

3. 安全驗證檔案類型:棄用 $_FILES['type'],改用 Fileinfo 擴展

$_FILES['type'] 仅依賴副檔名,極易偽造(如將 .mp3 改為 .jpg)。正確做法是啟用 php_fileinfo 擴展,使用 finfo_file() 讀取真實 MIME:

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);
$allowed = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowed)) {
    die('禁止的檔案類型');
}

4. 場景一:檔案重名自動重新命名

採用「原檔名 + 4 位隨機字元」策略,確保唯一性:

if (file_exists("./upload/" . $_FILES["file"]["name"])) {
    do {
        $suffix = '';
        $chars = '0123456789abcdefghijklmnopqrstuvwxyz';
        for ($i = 0; $i < 4; $i++) {
            $suffix .= $chars[rand(0, strlen($chars) - 1)];
        }
        $original = $_FILES['file']['name'];
        $ext = substr($original, strrpos($original, '.') + 1);
        $base = substr($original, 0, strrpos($original, '.'));
        $filename = $base . $suffix . '.' . $ext;
    } while (file_exists("./upload/" . $filename));
    move_uploaded_file($_FILES["file"]["tmp_name"], "./upload/" . $filename);
} else {
    move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
}

5. 場景二:按日期建立目錄結構

利用 date() 動態生成年/月/日路徑,避免單目錄檔案過多影響效能:

$structure = './' . date("Y") . '/' . date("m") . '/' . date("d") . '/';
if (!mkdir($structure, 0777, true)) {
    die('建立目錄失敗');
}
move_uploaded_file($_FILES["file"]["tmp_name"], $structure . $_FILES["file"]["name"]);

6. 場景三:多檔案上傳與陣列結構重組

HTML 表單使用 name="pictures[]":

<form method="post" enctype="multipart/form-data">
  <input type="file" name="pictures[]" />
  <input type="file" name="pictures[]" />
  <input type="file" name="pictures[]" />
  <input type="submit" value="送出" />
</form>

PHP 處理預設陣列結構較難操作(按屬性分組),建議重組為「每個檔案一個關聯陣列」:

function diverse_array($vector) {
    $result = [];
    foreach ($vector as $key1 => $value1) {
        foreach ($value1 as $key2 => $value2) {
            $result[$key2][$key1] = $value2;
        }
    }
    return $result;
}
$upload = diverse_array($_FILES["upload"]);
// 結果:$upload[0]['name'], $upload[0]['type']... 更直觀

7. 伺服器層面限制上傳大小完整配置

單靠前端 <input type="hidden" name="MAX_FILE_SIZE"> 可被繞過,必須在多層配置:

php.ini 關鍵參數

max_execution_time = 30      ; 腳本最大執行秒數
max_input_time = 60          ; 接收資料最大秒數
memory_limit = 128M          ; 記憶體上限
post_max_size = 8M           ; POST 總資料上限(含所有欄位)
upload_max_filesize = 2M     ; 單檔案上限

注意:post_max_size 必須 ≥ upload_max_filesize。

Nginx 配置

location / {
    root html;
    index index.html index.htm;
    client_max_body_size 1000m;  # 允許 1GB 請求體
}

掌握以上要點,即可構建安全、健壯、可擴展的 PHP 檔案上傳系統。實務上建議再搭配:檔案掃毒、儲存路徑非 Web 可訪問、資料庫記錄元資料等進階措施。

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