PHP表单验证必须在后端实现,因前端限制可被绕过;需用trim()预处理、filter_var()做基础校验、preg_match()处理业务规则,并统一收集错误、分离验证与渲染逻辑。

PHP表单验证不是靠背函数列表学会的,而是从「绕过前端提交的脏数据」开始真正理解的——你必须亲手用 curl 或浏览器开发者工具发一次空邮箱、带 script 标签的名字、超长用户名,再看后端怎么崩,才能记住为什么 filter_var() 不能代替 trim(),为什么 empty() 会把 "0" 当空字符串。
先搞清哪些验证必须在 PHP 做,哪些只是锦上添花
前端 required、type="email"、pattern 全部可被禁用或绕过,浏览器控制台一行 document.querySelector("form").submit() 就能跳过所有限制。所以:
- 非空判断、长度截断、类型校验(如邮箱格式)、数值范围检查——这些必须在 PHP 层做,且不能只依赖前端传来的值
-
htmlspecialchars()要在输出到 HTML 前调用,不是验证环节,但不加它,验证通过的数据照样触发 XSS - 数据库写入前必须用 PDO 预处理,哪怕字段已“验证合格”,因为验证和防注入是两件事
从 filter_var() 开始,但别只用它
filter_var() 快、轻、不用装扩展,适合基础类型:邮箱、URL、IP、整数。但它有硬伤:
-
filter_var($email, FILTER_VALIDATE_EMAIL)会放行test@localhost这类明显无效的地址 -
filter_var($url, FILTER_VALIDATE_URL)接受http://a这种非法 URL - 对中文姓名、手机号、密码强度等业务规则完全无能为力
- 它不自动去空格,
" user@example.com "会被判失败,得先trim()
正确用法示例:
立即学习“PHP免费学习笔记(深入)”;
$email = trim($_POST['email'] ?? '');
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = '邮箱格式不正确';
}
正则 preg_match() 是补位主力,但别写“全能正则”
中国大陆手机号用 /^1[3-9]\d{9}$/ 没问题;但想用一个正则覆盖全球手机号?别试。实际项目中更常见的是:
- 密码强度分拆验证:
preg_match('/[a-z]/', $pwd)+preg_match('/[A-Z]/', $pwd)+preg_match('/\d/', $pwd) - 中文姓名用
/^[\x{4e00}-\x{9fa5}]{2,10}$/u,注意末尾u修饰符,否则 Unicode 匹配失效 - 用户名允许字母、数字、下划线,但不能以数字开头:
/^[a-zA-Z_][a-zA-Z0-9_]*$/ - 所有
preg_match()前必须trim(),否则前后空格会导致匹配失败
错误收集要按字段组织,别用 die() 或 echo 堆提示
用户填了 5 个错字段,你只报第一个,他改完再提交,又报第二个……体验极差。应该:
- 定义空数组
$errors = [] - 每个字段单独验证,失败就往
$errors['field_name']里塞字符串或字符串数组 - HTML 表单里用
value="= htmlspecialchars($_POST['name'] ?? '') ?>"保留已输内容 - 对应字段下方加
<?php if (isset($errors['name'])): ?><span class="error">= htmlspecialchars($errors['name']) ?></span><?php endif; ?>
最容易被忽略的一点:验证逻辑和渲染逻辑必须分离。把 if (!filter_var(...)) { echo "xxx"; } 散落在 HTML 里,后期加新字段或改提示语时,你会重写三遍。



















