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

PHP 判斷文件上傳框是否選擇文件:前後端雙重驗證最佳實踐

     編輯:PHP 相關知識

文件上傳是 Web 表單的高頻功能,正確判斷用戶是否選擇了文件、文件是否合法,關係到業務流程順暢與服務器安全。本文梳理 PHP 後端判斷邏輯、前端預檢方案、多文件場景處理,並指出常見誤區。

後端核心判斷邏輯

PHP 通過 $_FILES 超全局陣列接收上傳信息。關鍵在於檢查 ['error'] 狀態碼與 ['tmp_name'] 是否存在。

<?php
/**
 * 判斷單文件上傳是否有效
 * @param string $fieldName 表單 input name 屬性值
 * @return array ['success'=bool, 'message'=string, 'file'=array|null]
 */
function validateSingleUpload(string $fieldName): array
{
    // 1. 檢查字段是否存在
    if (!isset($_FILES[$fieldName])) {
        return ['success' => false, 'message' => '表單缺少文件字段'];
    }

    $file = $_FILES[$fieldName];

    // 2. 檢查上傳錯誤碼(最關鍵!)
    // UPLOAD_ERR_OK (0) 表示成功
    if ($file['error'] !== UPLOAD_ERR_OK) {
        $errors = [
            UPLOAD_ERR_INI_SIZE   => '文件超過 php.ini upload_max_filesize 限制',
            UPLOAD_ERR_FORM_SIZE  => '文件超過表單 MAX_FILE_SIZE 限制',
            UPLOAD_ERR_PARTIAL    => '文件僅部分被上傳',
            UPLOAD_ERR_NO_FILE    => '未選擇文件',
            UPLOAD_ERR_NO_TMP_DIR => '臨時目錄缺失',
            UPLOAD_ERR_CANT_WRITE => '寫入磁盤失敗',
            UPLOAD_ERR_EXTENSION  => '被 PHP 擴展阻止',
        ];
        return ['success' => false, 'message' => $errors[$file['error']] ?? '未知上傳錯誤'];
    }

    // 3. 檢查臨時文件是否真實存在(防偽造)
    if (!is_uploaded_file($file['tmp_name'])) {
        return ['success' => false, 'message' => '非法上傳文件'];
    }

    // 4. 可選:檢查文件大小、MIME、擴展名等業務規則
    // if ($file['size'] > 2 * 1024 * 1024) return ['success' => false, 'message' => '文件超過 2MB'];

    return ['success' => true, 'message' => '驗證通過', 'file' => $file];
}

// 使用示例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $result = validateSingleUpload('file');
    if ($result['success']) {
        // 移動到永久存儲
        $dest = __DIR__ . '/uploads/' . basename($result['file']['name']);
        move_uploaded_file($result['file']['tmp_name'], $dest);
        echo "上傳成功:$dest";
    } else {
        echo "失敗:" . $result['message'];
    }
}
?>

常見誤區 ❌

  • if (!empty($_FILES['file']['tmp_name'])):不可靠。即使用戶未選文件,PHP 仍會創建 tmp_name 鍵(值為空字符串),且 error=UPLOAD_ERR_NO_FILE (4)。必須檢查 error 碼。
  • if ($_FILES['file']['size'] > 0):同理,無文件時 size 為 0,但無法區分「用戶未選」與「文件為空」。
  • 信任 $_FILES['file']['type']:瀏覽器根據擴展名猜測,極易偽造。務必使用 finfo_file() 或 mime_content_type() 解析實際內容。

前端預檢(用戶體驗優化)

<!-- HTML -->
<form id="uploadForm" enctype="multipart/form-data">
    <input type="file" id="fileInput" name="file" accept="image/*,.pdf" required>
    <button type="submit" id="submitBtn">上傳</button>
</form>

<script>
// 原生 JS 驗證
document.getElementById('uploadForm').addEventListener('submit', function(e) {
    const fileInput = document.getElementById('fileInput');
    if (fileInput.files.length === 0) {
        e.preventDefault();
        alert('請選擇文件');
        return;
    }
    // 可選:客戶端大小/類型預檢
    const file = fileInput.files[0];
    if (file.size > 2 * 1024 * 1024) {
        e.preventDefault();
        alert('文件不得超過 2MB');
    }
});

// 或使用 jQuery(若項目已引入)
$('#uploadForm').on('submit', function() {
    return $('#fileInput').val().length > 0 || (alert('請選擇文件'), false);
});
</script>

多文件上傳場景

HTML:<input type="file" name="files[]" multiple>

<?php
function validateMultipleUpload(string $fieldName): array
{
    if (!isset($_FILES[$fieldName])) {
        return ['success' => false, 'message' => '缺少字段'];
    }

    $files = $_FILES[$fieldName];
    $validFiles = [];
    $errors = [];

    // $_FILES 結構為:['name'=>[...], 'tmp_name'=>[...], 'error'=>[...], ...]
    // 需重組為逐文件結構
    $count = count($files['name']);
    for ($i = 0; $i < $count; $i++) {
        $file = [
            'name'     => $files['name'][$i],
            'tmp_name' => $files['tmp_name'][$i],
            'error'    => $files['error'][$i],
            'size'     => $files['size'][$i],
            'type'     => $files['type'][$i],
        ];

        if ($file['error'] === UPLOAD_ERR_OK && is_uploaded_file($file['tmp_name'])) {
            $validFiles[] = $file;
        } else {
            $errors[] = "文件 {$file['name']}: " . ($file['error'] === UPLOAD_ERR_NO_FILE ? '未選擇' : "錯誤碼 {$file['error']}");
        }
    }

    return [
        'success' => !empty($validFiles),
        'valid_files' => $validFiles,
        'errors' => $errors,
    ];
}

// 使用
$result = validateMultipleUpload('files');
if ($result['success']) {
    foreach ($result['valid_files'] as $file) {
        move_uploaded_file($file['tmp_name'], __DIR__ . '/uploads/' . $file['name']);
    }
    echo "成功上傳 " . count($result['valid_files']) . " 個文件";
}
if (!empty($result['errors'])) {
    echo "部分失敗:" . implode('; ', $result['errors']);
}
?>

jQuery 多文件預檢邏輯

<script>
$('#uploadForm').on('submit', function() {
    const files = $('input[name="files[]"]')[0].files;
    if (files.length === 0) {
        alert('至少選擇一個文件');
        return false;
    }
    let hasValid = false;
    for (let f of files) {
        if (f.size > 0) { hasValid = true; break; }
    }
    if (!hasValid) {
        alert('所選文件均為空');
        return false;
    }
    return true; // 允許提交
});
</script>

總結檢查清單

層面關鍵點
後端必檢$_FILES['xxx']['error'] === UPLOAD_ERR_OK + is_uploaded_file()
後端建議檢文件大小、MIME 類型、擴展名白名單、文件名安全化
前端預檢required 屬性 + JS 檢查 files.length / size
多文件重組 $_FILES 結構,逐個驗證,收集錯誤信息
存儲安全隨機文件名、存放於 Web 目錄外、執行權限禁止、病毒掃描
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved