
本文讲解如何通过 php 服务端验证与 html 结构配合,在表单提交失败时将各字段的错误消息精准渲染在其下方,避免页面跳转丢失用户输入,并确保用户体验连贯、反馈明确。
本文讲解如何通过 php 服务端验证与 html 结构配合,在表单提交失败时将各字段的错误消息精准渲染在其下方,避免页面跳转丢失用户输入,并确保用户体验连贯、反馈明确。
在 Web 表单开发中,仅靠客户端 required 或 type="email" 属性无法保证数据合法性——它们可被绕过,且不提供定制化提示。真正的健壮验证需结合服务端逻辑(如 PHP)与合理的 HTML 渲染结构。你当前的问题核心在于:PHP 验证失败后,错误变量(如 $nameErr)虽已生成,但原始 HTML 表单未在 else 分支中重新输出,导致错误消息无法与对应 关联展示。
✅ 正确做法:服务端验证 + 条件化表单重渲染
关键原则是:表单 HTML 必须与 PHP 验证逻辑处于同一响应流中。当验证失败时,不应仅 echo 错误文本,而应重新输出整个表单,并在对应位置插入已计算好的错误消息。
以下是重构后的完整 send-email.php 核心逻辑(精简关键部分,含安全增强):
<?php
require "vendor/autoload.php";
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
// 初始化错误变量(防止未定义警告)
$nameErr = $emailErr = $messErr = "";
$valid = true;
// 仅在 POST 提交时执行验证
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 安全过滤输入(注意:FILTER_SANITIZE_* 已被弃用,推荐使用更严格的清洗或白名单校验)
$nameSanitized = filter_var(trim($_POST['name'] ?? ''), FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$emailSanitized = filter_var($_POST['email'] ?? '', FILTER_SANITIZE_EMAIL);
$messageSanitized = filter_var(trim($_POST['message'] ?? ''), FILTER_SANITIZE_FULL_SPECIAL_CHARS);
// 自定义验证规则
if (!preg_match('/^[\p{Latin}\p{Cyrillic}\s]+$/u', $nameSanitized)) {
$nameErr = "仅允许拉丁字母、西里尔字母及空格。";
$valid = false;
}
if (empty($nameSanitized) || empty($messageSanitized)) {
$messErr = "姓名和留言为必填项。";
$valid = false;
}
// 改进邮箱正则:使用 FILTER_VALIDATE_EMAIL 更可靠
if (!filter_var($emailSanitized, FILTER_VALIDATE_EMAIL)) {
$emailErr = "请输入有效的邮箱地址。";
$valid = false;
}
// 验证通过则发送邮件
if ($valid) {
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = SMTP_USERNAME;
$mail->Password = SMTP_PASSWORD;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom($emailSanitized, $nameSanitized);
$mail->addAddress('your-recipient@example.com', 'Your Site');
$mail->Subject = '新留言:' . htmlspecialchars($nameSanitized);
$mail->Body = "姓名: $nameSanitized\n邮箱: $emailSanitized\n留言:\n$messageSanitized";
$mail->send();
header('Location: sent.html');
exit;
} catch (Exception $e) {
$messErr = "邮件发送失败:" . htmlspecialchars($mail->ErrorInfo);
$valid = false;
}
}
}
?>
<!DOCTYPE html>
<html>
<head><title>联系表单</title></head>
<body>
<form method="POST" action="send-email.php">
<label for="name">姓名 *</label>
<input type="text" name="name" id="name" placeholder="姓名*" required
value="<?= htmlspecialchars($nameSanitized ?? '') ?>">
<div class="error"><?= $nameErr ?></div>
<label for="email">邮箱 *</label>
<input type="email" name="email" id="email" placeholder="邮箱*" required
value="<?= htmlspecialchars($emailSanitized ?? '') ?>">
<div class="error"><?= $emailErr ?></div>
<label for="message">留言 *</label>
<textarea name="message" id="message" placeholder="您的留言*" required><?= htmlspecialchars($messageSanitized ?? '') ?></textarea>
<div class="error"><?= $messErr ?></div>
<button type="submit" class="button">提交</button>
</form>
</body>
</html>? 关键改进说明
- 表单始终渲染:无论是否提交,HTML 表单都存在;PHP 变量(如 $nameSanitized)在验证失败后保留用户原始输入(经 htmlspecialchars() 转义防 XSS),实现「错误提示 + 输入保留」双重体验。
- 语义化标签:添加
-
安全强化:
- 使用 htmlspecialchars() 输出所有用户数据,防止 XSS;
- 替换过时的邮箱正则为 FILTER_VALIDATE_EMAIL,更符合 RFC 标准;
- 对 $_POST 键使用空合并操作符 ?? '' 避免未定义索引警告。
-
错误定位精准:每个 紧邻其目标 或










