You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移动端相机拍摄图片无法通过联系表单上传的技术排查请求

移动端相机拍摄照片上传表单的异常问题

我是Web开发新手,现有一个联系表单:通过文件夹选择.jpg/.jpeg/.png等文件时可正常发送给接收方,但在移动端使用相机拍摄照片上传时,图片无法发送。JS验证会在发送前检查文件大小和类型,有问题则阻止提交。奇怪的是:部分新手机上,用户首次填写表单时拍摄的照片可发送,但同一用户用同一手机第二次填写时,图片无法发送。

相关代码

HTML代码

<div class="file-upload-container">
    <!-- File Upload 1 -->
    <label for="fileUpload1" data-lang="contact-form-11">Bestand 1:</label>
    <input type="file" id="fileUpload1" name="fileUpload1" capture="environment"
        accept=".jpg, .jpeg, .png, .pdf, .doc, .docx">
    <span id="fileUpload1Name"></span> <!-- Span to display the uploaded file name -->

    <!-- File Upload 2 -->
    <label for="fileUpload2" data-lang="contact-form-12">Bestand 2:</label>
    <input type="file" id="fileUpload2" name="fileUpload2" capture="environment"
        accept=".jpg, .jpeg, .png, .pdf, .doc, .docx">
    <span id="fileUpload2Name"></span> <!-- Span to display the uploaded file name -->
</div>

JS验证代码

function validateContactForm() {
    let naam = document.getElementById("name").value;
    let email = document.getElementById("email").value;
    let bericht = document.getElementById("message").value;
    let contactReasons = document.querySelectorAll('input[name="contact_reason"]');
    let isValid = true;
    let errorMessage = '';

    // Vorige foutmeldingen wissen
    document.getElementById("formInputErrorDisplay").innerHTML = '';

    // Naam validatie
    if (naam.trim() === "") {
        errorMessage += getErrorMessage("naamRequired") + "<br>";
        isValid = false;
    }

    // E-mail validatie
    let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
        errorMessage += getErrorMessage("invalidEmail") + "<br>";
        isValid = false;
    }

    // Bericht validatie
    if (bericht.trim().length < 100 || bericht.trim().length > 2500) {
        errorMessage += getErrorMessage("messageLength") + "<br>";
        isValid = false;
    }

    // Radio buttons validatie
    let isReasonSelected = Array.from(contactReasons).some(radio => radio.checked);
    if (!isReasonSelected) {
        errorMessage += getErrorMessage("reasonRequired") + "<br>";
        isValid = false;
    }

    // Bestanden validatie
    let bestandsGrootteLimiet = 5242880; // 5MB
    for (let i = 1; i <= 2; i++) {
        let fileUpload = document.getElementById(`fileUpload${i}`);
        if (fileUpload && fileUpload.files.length > 0) {
            let file = fileUpload.files[0];
            if (file.size > bestandsGrootteLimiet) {
                errorMessage += getErrorMessage("fileTooLarge", {i}) + "<br>";
                isValid = false;
            }
            if (!['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(file.type)) {
                errorMessage += getErrorMessage("invalidFileType", { i }) + "<br>";
                isValid = false;
            }
        }
    }

    // Foutmeldingen weergeven in het div-element
    if (!isValid) {
        document.getElementById("formInputErrorDisplay").innerHTML = errorMessage;
    }

    return isValid;
}

// Event listener toevoegen aan het formulier
document.getElementById("contact_form").addEventListener("submit", function(event) {
    if (!validateContactForm()) {
        event.preventDefault();
    }
});

PHP代码

// Bestandsverwerking en -upload
for ($i = 1; $i <= 2; $i++) {
    $fileInputName = "fileUpload" . $i;
    if (isset($_FILES[$fileInputName]) && $_FILES[$fileInputName]['error'] == UPLOAD_ERR_OK) {
        // Bestandstype en -grootte validatie
        $allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
        $maxSize = 5 * 1024 * 1024; // 5 MB
        $fileType = $_FILES[$fileInputName]['type'];
        $fileSize = $_FILES[$fileInputName]['size'];

        if (!in_array($fileType, $allowedTypes) || $fileSize > $maxSize) {
            echo "Ongeldig bestandstype of bestandsgrootte voor bestand $i.<br>";
            continue;
        }

        // Generate unique file name to prevent duplicates
        $fileExt = pathinfo($_FILES[$fileInputName]['name'], PATHINFO_EXTENSION);
        $newFileName = uniqid("upload_", true) . '.' . $fileExt;
        $target_dir = "../../../back-end/uploads/";
        $target_file = $target_dir . $newFileName;

        // Bestandsupload
        if (move_uploaded_file($_FILES[$fileInputName]["tmp_name"], $target_file)) {
            $bestanden[] = $target_file;
            // Logboekbericht
            $logMessage = "[" . date("d-m-Y H:i:s") . "] Bestand geüpload: " . $newFileName .
                          " door " . $email . 
                          ", Grootte: " . filesize($target_file) . " bytes\n";
            writeToLog($logMessage, $email);
        } else {
            echo "Er was een probleem met het uploaden van bestand $i.<br>";
        }
    }
}

邮件发送使用最新版本的PHPMailer,请问我遗漏了什么?不知道下一步该如何排查。


排查方向与修复方案

1. 移动端相机照片的MIME类型不匹配

部分新手机拍摄的照片会使用image/heic、image/heif等非标准MIME类型,或者客户端传递的file.type不准确,导致JS和PHP的类型验证失败。

  • JS端修复:同时校验文件后缀和MIME类型,做兜底判断:
// 替换原有文件类型验证逻辑
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.pdf', '.doc', '.docx'];
const fileExt = '.' + file.name.split('.').pop().toLowerCase();
if (!allowedTypes.includes(file.type) && !allowedExtensions.includes(fileExt)) {
    errorMessage += getErrorMessage("invalidFileType", { i }) + "<br>";
    isValid = false;
}
  • PHP端修复:用服务器端获取的真实MIME类型替代客户端传递的值,同时校验后缀:
// 替换原有的类型判断逻辑
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx'];
$fileExt = strtolower(pathinfo($_FILES[$fileInputName]['name'], PATHINFO_EXTENSION));
// 服务器端获取真实MIME类型
$fileType = mime_content_type($_FILES[$fileInputName]['tmp_name']);

if (!in_array($fileType, $allowedTypes) || !in_array($fileExt, $allowedExtensions) || $fileSize > $maxSize) {
    echo "Ongeldig bestandstype of bestandsgrootte voor bestand $i.<br>";
    continue;
}

2. 表单未重置导致的文件输入缓存

用户第二次提交时,浏览器可能缓存了第一次的文件输入状态,导致fileUpload.files获取异常。

  • 提交后重置表单:在表单提交成功后重置控件:
document.getElementById("contact_form").addEventListener("submit", function(event) {
    const formValid = validateContactForm();
    if (!formValid) {
        event.preventDefault();
    } else {
        // 提交成功后延迟重置,避免影响提交流程
        setTimeout(() => {
            this.reset();
            // 清空文件名显示
            document.getElementById("fileUpload1Name").textContent = "";
            document.getElementById("fileUpload2Name").textContent = "";
        }, 1000);
    }
});

3. PHP服务器上传配置限制

服务器的PHP配置可能限制了上传文件大小,比如upload_max_filesize、post_max_size设置过小,导致第二次上传(可能文件更大)失败。

  • 检查配置:创建phpinfo.php查看以下参数,确保值大于5MB(建议设为10MB):
    • upload_max_filesize
    • post_max_size
    • max_execution_time

4. 捕获完整的上传错误日志

在PHP中增加错误码处理,明确失败原因:

if (isset($_FILES[$fileInputName])) {
    switch ($_FILES[$fileInputName]['error']) {
        case UPLOAD_ERR_OK:
            // 原有处理逻辑
            break;
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            echo "Bestand $i is te groot (overschrijft serverlimiet).<br>";
            break;
        case UPLOAD_ERR_PARTIAL:
            echo "Bestand $i werd alleen gedeeltelijk geüpload.<br>";
            break;
        case UPLOAD_ERR_NO_FILE:
            // 无文件上传,跳过
            break;
        default:
            echo "Onbekende fout bij upload van bestand $i (foutcode: " . $_FILES[$fileInputName]['error'] . ")<br>";
    }
}

内容的提问来源于stack exchange,提问作者Timotheus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:44:55