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

PHP 文件上傳完整實戰:類型白名單、大小限制、重命名存儲、資料庫記錄一站式示例

     編輯:PHP 綜合知識

前端表單(關鍵屬性)

<form action="upload.php" method="post" enctype="multipart/form-data">
  <input type="hidden" name="MAX_FILE_SIZE" value="1048576"> <!-- 客戶端提示,非強制 -->
  <input type="file" name="upfile" accept="image/*">
  <button type="submit">上傳</button>
</form>

後端 upload.php(完整防護)

<?php
// 配置
const UPLOAD_DIR = __DIR__ . '/uploads/';
const MAX_SIZE   = 1024 * 1024; // 1MB
const ALLOWED_EXT = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
const ALLOWED_MIME = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];

// 確保目錄存在且不可執行
if (!is_dir(UPLOAD_DIR)) mkdir(UPLOAD_DIR, 0755, true);
file_put_contents(UPLOAD_DIR . '.htaccess', 'SetHandler default-handler'); // Apache 禁用 PHP 解析

// 檢查錯誤碼
if (!isset($_FILES['upfile']) || $_FILES['upfile']['error'] !== UPLOAD_ERR_OK) {
    $msg = match ($_FILES['upfile']['error'] ?? UPLOAD_ERR_NO_FILE) {
        UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => '文件超過大小限制',
        UPLOAD_ERR_PARTIAL => '文件上傳不完整',
        UPLOAD_ERR_NO_FILE => '未選擇文件',
        default => '上傳失敗,錯誤碼: ' . $_FILES['upfile']['error'],
    };
    die(json_encode(['code'=>1, 'msg'=>$msg]));
}

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime  = finfo_file($finfo, $_FILES['upfile']['tmp_name']);
finfo_close($finfo);

if (!in_array($mime, ALLOWED_MIME, true)) {
    die(json_encode(['code'=>1, 'msg'=>'文件類型不允許: ' . $mime]));
}

$ext = strtolower(pathinfo($_FILES['upfile']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, ALLOWED_EXT, true)) {
    die(json_encode(['code'=>1, 'msg'=>'副檔名不允許']));
}

if ($_FILES['upfile']['size'] > MAX_SIZE) {
    die(json_encode(['code'=>1, 'msg'=>'文件體積超過 1MB']));
}

// 生成唯一文件名:時間戳 + 隨機字符 + 原副檔名
$newName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
$dest = UPLOAD_DIR . $newName;

if (!move_uploaded_file($_FILES['upfile']['tmp_name'], $dest)) {
    die(json_encode(['code'=>1, 'msg'=>'移動文件失敗,請檢查目錄權限']));
}

// 寫入數據庫記錄(PDO)
require_once 'db.php';
$stmt = $pdo->prepare('INSERT INTO uploads (original_name, stored_name, mime, size, created_at) VALUES (?, ?, ?, ?, NOW())');
$stmt->execute([$_FILES['upfile']['name'], $newName, $mime, $_FILES['upfile']['size']]);

echo json_encode(['code'=>0, 'msg'=>'上傳成功', 'url'=>'/uploads/' . $newName]);
?>

關鍵安全點

風險對策
偽裝腳本上傳雙重驗證:finfo_file 檢測真實 MIME + 副檔名白名單
文件名遍歷/覆蓋重命名存儲,不信任用戶文件名
上傳目錄執行腳本.htaccess / Nginx location ~ \.php$ { deny all; }
大文件撐爆磁碟MAX_FILE_SIZE + 服務端 $_FILES['size'] 雙重限制
併發衝突隨機文件名幾乎無衝突;極端情況可加 while(file_exists) rename

進階:分片上傳(大文件/斷點續傳)

前端使用 Plupload/Uppy 切片,後端臨時目錄收集分片,全部分片到齊後合併、驗證、入庫。超出本文範圍,另文詳述。

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