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

PHP 文件上傳入庫:從表單到 BLOB 的完整最佳實踐

     編輯:程式設計綜合問答

原始代碼存在的問題

提交的代碼片段暴露了多個典型錯誤:

  • 表單缺少 enctype="multipart/form-data":導致 $_FILES 為空,文件無法上傳。
  • 直接使用 $_POST['pic'] 獲取文件信息:文件上傳數據只存在 $_FILES 超全局變量中。
  • 硬編碼絕對路徑:'./Users/e-bag4/Desktop' 在生產環境必定失效,且存在目錄遍歷風險。
  • SQL 拼接未防注入:values('$path') 直接拼接變量,極易遭受 SQL 注入攻擊。
  • 將文件路徑而非二進制內容存入 BLOB:題目要求存入 BLOB 類型,卻存了字符串路徑。

正確流程:上傳 → 驗證 → 讀取二進制 → 預處理語句入庫

1. 修正 HTML 表單

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="pic" accept="image/*" required>
    <input type="submit" value="上傳">
</form>

2. PHP 處理腳本(PDO + Prepared Statement)

<?php
require_once 'db.php'; // 返回 PDO 實例 $pdo

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['pic'])) {
    $file = $_FILES['pic'];
    
    // 基礎驗證
    if ($file['error'] !== UPLOAD_ERR_OK) {
        die('上傳錯誤代碼:' . $file['error']);
    }
    $allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime = finfo_file($finfo, $file['tmp_name']);
    if (!in_array($mime, $allowedMimes)) {
        die('只允許上傳 JPG/PNG/GIF/WebP 圖片');
    }
    if ($file['size'] > 5 * 1024 * 1024) { // 5MB
        die('文件大小超過 5MB 限制');
    }

    // 讀取二進制內容
    $blobData = file_get_contents($file['tmp_name']);
    if ($blobData === false) {
        die('讀取臨時文件失敗');
    }

    // 入庫:使用預處理語句綁定 BLOB
    try {
        $sql = "INSERT INTO e_user (pic, mime_type, original_name, upload_time) VALUES (?, ?, ?, NOW())";
        $stmt = $pdo->prepare($sql);
        // PDO::PARAM_LOB 告訴驅動這是大對象
        $stmt->bindValue(1, $blobData, PDO::PARAM_LOB);
        $stmt->bindValue(2, $mime);
        $stmt->bindValue(3, basename($file['name']));
        $stmt->execute();
        echo "上傳成功!ID: " . $pdo->lastInsertId();
    } catch (PDOException $e) {
        error_log($e->getMessage());
        echo "數據庫寫入失敗,請稍後重試";
    }
}
?>

3. 數據庫表結構建議

CREATE TABLE e_user (
    id INT AUTO_INCREMENT PRIMARY KEY,
    pic LONGBLOB NOT NULL,          -- 存儲二進制,LONGBLOB 支持 4GB
    mime_type VARCHAR(50) NOT NULL, -- 圖片 MIME 類型,用於輸出時設置 Content-Type
    original_name VARCHAR(255),     -- 原始文件名
    upload_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

進階優化:大文件分塊讀取與異步處理

若文件超過 PHP memory_limit,直接 file_get_contents 會 OOM。可採用流式寫入:

$stmt->bindParam(1, $fp, PDO::PARAM_LOB);
$fp = fopen($file['tmp_name'], 'rb');
$stmt->execute();
fclose($fp);

生產環境建議:文件落地磁盤/對象存儲,數據庫僅存儲元數據(路徑、Hash、大小),通過 CDN 分發,極大降低 DB 壓力。

總結

文件上傳入 BLOB 的核心要點:表單 enctype、$_FILES 使用、MIME/大小驗證、PDO::PARAM_LOB 綁定、預處理語句防注入。切勿存絕對路徑,切勿拼接 SQL。

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