filter_input() 可一步完成取值、类型校验与过滤,替代直接访问 $_get/$_post,避免空值、类型错误及xss风险,是php 5.2+安全处理用户输入的推荐方式。

用 filter_input() 替代直接访问 $_GET 和 $_POST
直接读 $_GET['id'] 或 $_POST['email'] 是查找逻辑出问题的高发源头——类型不确定、空值没处理、XSS 风险裸奔。PHP 原生的 filter_input() 能一步完成「取值 + 类型校验 + 过滤」,比手写 isset() + is_numeric() + trim() 更可靠。
常见错误现象:$_GET['page'] 传了字符串 "abc",后续用在 SQL LIMIT 里直接报错或跳过校验;或者用户提交 <script>alert(1)</script> 到搜索关键词字段,前端没转义就渲染。
- 查数字 ID:用
filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT),返回false而非0或空字符串,避免把无效 ID 当成合法值 - 查搜索关键词:用
filter_input(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS),保留中文和空格,但转义<code>>等 HTML 元素 - 查邮箱:用
filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL),比正则更贴近 RFC 标准,且自动 trim
数据库查询必须用预处理语句(PDO::prepare() 或 mysqli_prepare())
拼接 SQL 字符串做查找(比如 "SELECT * FROM user WHERE name = '" . $_GET['name'] . "'")是注入漏洞的温床,哪怕加了 addslashes() 也防不住多字节编码绕过。预处理不是“可选优化”,是查找类代码的强制底线。
使用场景:所有带用户输入参数的 SELECT,尤其是 WHERE 条件含 =、LIKE、IN 的情况。
-
LIKE模糊查时,通配符%必须在 PHP 层拼进变量,再绑定,不能写进 SQL 模板里——例如$keyword = '%' . $keyword . '%'; $stmt->bindValue(':q', $keyword, PDO::PARAM_STR); - 查多个 ID(如
IN (1,2,3)),PDO 不支持直接绑定数组,得动态生成占位符:$placeholders = str_repeat('?,', count($ids) - 1) . '?';,再逐个绑定 - 不要为了省事用
PDO::query()执行带变量的 SELECT——它不走预处理,等同于裸拼
空结果和异常要显式处理,别依赖 if ($row) 这类模糊判断
很多查找代码只写 $row = $stmt->fetch(); if ($row) { ... },但没区分「没找到」和「数据库连不上」「SQL 语法错」「字段名写错导致 fetch 返回 false」这几种完全不同的情况。线上出问题时,日志里只剩一个空 $row,根本看不出是业务逻辑还是基础设施故障。
性能影响:提前退出能省掉后续无意义的处理,但更重要的是让错误可定位。
- 执行前检查语句是否准备成功:
if (!$stmt = $pdo->prepare($sql)) { throw new RuntimeException('SQL prepare failed'); } - 执行后检查是否出错:
if (!$stmt->execute($params)) { error_log('Query failed: ' . implode(', ', $stmt->errorInfo())); } - 查单条记录时,用
$row = $stmt->fetch(PDO::FETCH_ASSOC); if (!$row) { http_response_code(404); die('Not found'); },明确表达语义
分页参数必须校验范围,limit 和 offset 不能信用户传的任何值
用户改 URL 里的 page=9999999 或 limit=-1,后端不做限制就直接塞进 SQL,轻则查库超时,重则拖垮数据库连接池。这不是“用户恶意”,而是真实存在的爬虫试探和误操作。
容易踩的坑:只校验 page > 0,却忘了 limit 上限;或用 max(1, (int)$_GET['page']) 但没限制最大页码,导致 offset 算出来几千万,MySQL OFFSET 性能断崖下跌。
-
limit建议硬编码上限,比如$limit = min(100, (int)filter_input(INPUT_GET, 'limit', FILTER_VALIDATE_INT) ?: 20); -
page或offset应结合总记录数做二次校验:查总数后,若$offset >= $total,直接返回空数组,而不是让 MySQL 扫全表 - 避免用
OFFSET做深分页,超过 10 万行建议改用游标分页(WHERE id > ? ORDER BY id LIMIT ?),但这需要业务主键稳定递增
最常被忽略的一点:所有过滤、校验、预处理步骤,必须在数据库查询之前全部完成。顺序错了,比如先 bind 再 filter,或者先 fetch 再判断类型,就等于没做。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











