最安全方式是先用 filter_input() 校验过滤,再用预处理语句入库;因 $_POST 未经校验易致 SQL 注入、XSS 等风险,且不处理未定义索引、类型错误等问题。

PHP 接收表单数据最常用也最安全的方式是用 $_POST 或 $_GET,但直接用它们就上线等于裸奔——必须校验、过滤、转义,否则 SQL 注入、XSS、空值崩溃全可能找上门。
为什么不能直接用 $_POST['username']?
因为用户能任意改请求体:删字段、填超长字符串、塞 HTML 标签、传数组冒充字符串……$_POST 是“原样照收”,不验证类型、不检查长度、不防恶意字符。
- 空提交时
$_POST['email']会触发Notice: Undefined index - 用户在输入框里贴一段
<script>alert(1)</script>,你 echo 出去就 XSS - 把
$_POST['id']直接拼进 SQL 查询,比如"SELECT * FROM user WHERE id = " . $_POST['id'],别人传1 OR 1=1 --就能拖库
filter_input() 是比 $_POST 更靠谱的起点
它内置类型转换和基础过滤,还能自动处理未设置字段(返回 null 而非报 Notice),比手写 isset() + is_numeric() + trim() 更简洁可靠。
- 接收整数 ID:
filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT)—— 非数字或空时返回false,不是字符串"0" - 接收邮箱:
filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL)—— 仅校验格式,不查域名是否存在 - 接收带空格的用户名并去首尾空格:
filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING)(PHP 8.1+ 已弃用,改用FILTER_SANITIZE_FULL_SPECIAL_CHARS+ 手动trim())
数据库入库前必须用预处理(PDO::prepare() 或 mysqli_prepare())
哪怕你用 filter_input() 过滤了邮箱,也不能跳过预处理。过滤解决的是“数据是否合规”,预处理解决的是“数据会不会被当 SQL 代码执行”——这是两层防御。
立即学习“PHP免费学习笔记(深入)”;
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$_POST['name'], $_POST['email']]);
- 别用
mysql_real_escape_string()(已废弃)或手动加引号拼 SQL - 如果字段要支持富文本,入库前仍需用
htmlspecialchars()存储(或至少明确区分“存储原始”和“输出渲染”两步) - 注意
$_POST值仍是字符串,filter_input()返回的整数/布尔等类型,在传给execute()时会被 PDO 自动转换,无需额外 cast
文件上传要用 $_FILES 单独处理,且绝不信任 $_FILES['file']['name']
浏览器传来的 name 字段完全可控,攻击者可改成 ../../etc/passwd 或 shell.php。真实文件名、类型、大小都得靠服务端重新判定。
- 用
is_uploaded_file($_FILES['avatar']['tmp_name'])确认是合法上传临时文件 - 用
pathinfo($_FILES['avatar']['name'], PATHINFO_EXTENSION)取扩展名不可信,应结合finfo_open()检查 MIME 类型 - 保存时用唯一文件名(如
uniqid() . '.jpg'),存到非 Web 可访问目录,或加 Nginx/ Apache 规则禁止执行
真正麻烦的从来不是“怎么拿到数据”,而是“怎么确认这数据可信、可用、不伤系统”。表单入口越简单,后端校验逻辑就越不能省——少一行 filter_input(),多一个被黑的可能。



















