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

PHP 檔案上傳完整教學:表單建立、驗證限制、儲存與安全防護

     編輯:PHP 入門

PHP 檔案上傳完整教學

檔案上傳是 Web 應用常見功能,但也是高風險操作面。本文從表單建立、PHP 處理、驗證限制、安全儲存到防護措施,建構完整上傳解決方案。

目錄結構規劃

project/
├── upload/          # 上傳儲存目錄(權限 755 或 777)
├── form.html        # 上傳表單
└── upload.php       # 處理邏輯

建立上傳表單

關鍵屬性:enctype="multipart/form-data"、method="post"、input type="file"

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>檔案上傳</title>
</head>
<body>
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <label for="file">選擇檔案:</label>
        <input type="file" name="file" id="file" required><br><br>
        <input type="submit" name="submit" value="上傳">
    </form>
</body>
</html>

基礎上傳處理:$_FILES 陣列解析

<?php
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>";
}
?>
鍵名說明
name原始檔案名稱
typeMIME 類型(瀏覽器提供,不可全信)
size檔案大小(位元組)
tmp_name伺服器暫存路徑
error錯誤代碼(0 為成功)

上傳驗證與限制

錯誤代碼對照表

代碼常數說明
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_EXTENSION擴展阻止上傳

完整驗證範例:限制圖片類型與大小

<?php
// 設定
$allowedExts = ['gif', 'jpeg', 'jpg', 'png'];
$allowedMimes = [
    'image/gif', 'image/jpeg', 'image/pjpeg', 
    'image/x-png', 'image/png'
];
$maxSize = 200 * 1024; // 200 KB
$uploadDir = __DIR__ . '/upload/';

// 確保目錄存在
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    $file = $_FILES['file'];
    
    // 1. 檢查上傳錯誤
    if ($file['error'] !== UPLOAD_ERR_OK) {
        die("上傳錯誤: {$file['error']}");
    }
    
    // 2. 驗證副檔名
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (!in_array($ext, $allowedExts)) {
        die("不允許的副檔名: $ext");
    }
    
    // 3. 驗證 MIME 類型(需配合 finfo 實際檢測)
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    if (!in_array($mime, $allowedMimes)) {
        die("不允許的檔案類型: $mime");
    }
    
    // 4. 驗證大小
    if ($file['size'] > $maxSize) {
        die("檔案過大,限制 {$maxSize} 位元組");
    }
    
    // 5. 防止檔名衝突:生成唯一檔名
    $newName = bin2hex(random_bytes(16)) . '.' . $ext;
    $destPath = $uploadDir . $newName;
    
    // 6. 移動檔案
    if (move_uploaded_file($file['tmp_name'], $destPath)) {
        echo "上傳成功!儲存為: $newName";
        echo "<br>原始檔名: " . htmlspecialchars($file['name']);
        echo "<br>檔案大小: " . number_format($file['size'] / 1024, 2) . " KB";
    } else {
        die("檔案移動失敗,請檢查目錄權限");
    }
}
?>

關鍵安全防護措施

  1. 使用 move_uploaded_file():確認檔案確實經由 HTTP POST 上傳,防止路徑遍歷攻擊
  2. 不信任 $_FILES['type']:必須使用 finfo 或 getimagesize() 實際檢測檔案內容
  3. 重新命名檔案:避免覆蓋、特殊字元、執行腳本風險
  4. 儲存於 Web 根目錄外:或設定上傳目錄禁止腳本執行(Nginx/Apache 配置)
  5. 限制上傳大小:php.ini 設定 upload_max_filesize、post_max_size;表單隱藏欄位 MAX_FILE_SIZE(僅客戶端提示)
  6. 掃描惡意內容:整合 ClamAV 等防毒掃描
  7. 驗證圖片真實性:getimagesize() 回傳 false 即非有效圖片

Nginx/Apache 上傳目錄防護配置

Nginx

location /upload/ {
    # 禁止執行 PHP 等腳本
    location ~ \.php$ {
        deny all;
        return 403;
    }
    # 可選:僅允許圖片直接訪問
    # location ~* \.(jpg|jpeg|png|gif)$ { allow all; }
    # location / { deny all; }
}

Apache (.htaccess)

# 禁止腳本執行
SetHandler default-handler
Options -ExecCGI
RemoveHandler .php .phtml .php3 .php4 .php5 .php7 .php8 .phar
php_flag engine off

# 或僅允許圖片
# <FilesMatch "\.(?i:jpg|jpeg|png|gif)$">
#     Allow from all
# </FilesMatch>
# <FilesMatch ".*">
#     Deny from all
# </FilesMatch>

進階:分塊上傳大檔案

超過 PHP 限制的大檔案需前端分片(如 Plupload、Uppy、Dropzone),後端合併:

<?php
// 合併分片範例
$chunkDir = __DIR__ . '/chunks/' . $fileId . '/';
$finalPath = __DIR__ . '/upload/' . $fileName;

$chunks = glob($chunkDir . '*.part');
sort($chunks, SORT_NATURAL);

$fp = fopen($finalPath, 'wb');
foreach ($chunks as $chunk) {
    fwrite($fp, file_get_contents($chunk));
}
fclose($fp);

// 清理分片
array_map('unlink', $chunks);
rmdir($chunkDir);
?>

php.ini 關鍵設定

設定建議說明
file_uploadsOn啟用上傳功能
upload_max_filesize10M單檔最大值
post_max_size12MPOST 總大小,需 > upload_max_filesize
max_file_uploads20單次請求最大檔案數
upload_tmp_dir/tmp/upload指定暫存目錄(需可寫)
max_input_time300大檔上傳需較長解析時間

檔案上傳看似簡單,實則涉及驗證、儲存、權限、效能多重考量。遵循「不信任輸入、最小權限、纵深防禦」原則,才能構建安全可靠的上傳功能。

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