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

PHP 檔案上傳判斷:前後端雙重驗證檔案是否已選擇

     編輯:PHP 綜合知識

檔案上傳驗證需「前端攔截、後端把關」雙重防護。前端提升使用者體驗,後端確保資料完整與安全。本文深入剖析判斷邏輯與常見誤區。

一、基礎表單結構

<form action="" method="post" enctype='multipart/form-data'>
檔案上傳:<input type="file" name="file" id="file"/>
<input type="submit" id="send" value="提交"/>
</form>

二、前端 JavaScript 判斷

簡易版(僅檢查是否有值)

<script>
document.getElementById("send").onclick = function() {
    var file = document.getElementById("file").value;
    if (file.length < 1) {
        alert('請選擇圖片');
        return false;
    }
};
</script>

缺點:使用者輸入任意文字也能通過,無法驗證真實檔案。

進階版(副檔名驗證)

function CheckWorkFile() {
    var obj = document.getElementById('fuMain');
    if (obj.value == '') {
        alert('請選擇要上傳的檔案');
        return false;
    }
    // 取得副檔名(最後一個 . 之後)
    var ext = obj.value.match(/^(.*)(\\.)(.{1,8})$/)[3].toLowerCase();
    if (ext != 'doc') {
        alert('檔案類型不正確,請選擇 .doc 檔案');
        return false;
    }
    return true;
}

三、後端 PHP 判斷

常見錯誤寫法

<?php
// 僅檢查 tmp_name 是否為空 — 不夠嚴謹
if (!empty($_FILES['file']['tmp_name'])) {
    echo '已選擇檔案';
} else {
    echo '請選擇檔案';
}
?>

問題:即使上傳失敗(錯誤代碼非 0),tmp_name 可能仍有值。

正確嚴謹判斷

<?php
function isFileUploaded($fileInputName) {
    if (!isset($_FILES[$fileInputName])) return false;
    $file = $_FILES[$fileInputName];
    // 單檔上傳
    if (is_string($file['name'])) {
        return $file['error'] === UPLOAD_ERR_OK 
            && is_uploaded_file($file['tmp_name'])
            && $file['size'] > 0;
    }
    // 多檔上傳(陣列)
    foreach ($file['name'] as $idx => $name) {
        if ($file['error'][$idx] === UPLOAD_ERR_OK
            && is_uploaded_file($file['tmp_name'][$idx])
            && $file['size'][$idx] > 0) {
            return true; // 至少有一個成功
        }
    }
    return false;
}

// 使用範例
if (isFileUploaded('file')) {
    echo '已選擇有效檔案';
} else {
    echo '請選擇檔案或上傳失敗';
}
?>

四、檔案類型深度驗證(防偽造)

僅檢查副檔名或 $_FILES['type'] 極不安全,需讀取檔案頭部 Magic Bytes:

<?php
function getRealFileType($filename) {
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); // 僅讀 2 位元組
    fclose($file);
    $info = @unpack("C2chars", $bin);
    $typeCode = intval($info['chars1'] . $info['chars2']);
    
    $map = [
        7790 => 'exe', 8297 => 'rar', 8075 => 'zip',
        255216 => 'jpg', 7173 => 'gif', 6677 => 'bmp', 13780 => 'png'
    ];
    
    // 修正負數情況(PHP unpack 有號數問題)
    if ($info['chars1'] == -1 && $info['chars2'] == -40) return 'jpg';
    if ($info['chars1'] == -119 && $info['chars2'] == 80) return 'png';
    
    return $map[$typeCode] ?? 'unknown: ' . $typeCode;
}

// 使用範例
$allowed = ['jpg', 'png', 'gif'];
$realType = getRealFileType($_FILES['file']['tmp_name']);
if (!in_array($realType, $allowed)) {
    die('禁止的檔案類型: ' . $realType);
}
?>

五、完整驗證流程建議

  1. 前端:HTML5 accept 屬性限制選擇框 + JS 檢查副檔名 + 檔案大小預估
  2. 後端:UPLOAD_ERR_OK → is_uploaded_file() → 檔案大小 → Magic Bytes 類型 → 檔名重命名 → 移動至安全目錄
  3. 資料庫:記錄原始檔名、儲存路徑、MIME、大小、上傳者、時間

「信任前端,驗證後端」是檔案上傳安全的鐵律。Magic Bytes 檢測雖非絕對(可偽造頭部),但能擋絕大多數偽裝檔案,配合副檔名白名單與儲存目錄執行權限控制,構建多層防護。

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