应使用filter_input()过滤输入、PDO预处理防SQL注入、htmlspecialchars()输出转义、禁用危险惯用法并实施CSRF防护。

如果您在PHP中接收HTML表单提交的数据,但未做安全处理,可能导致XSS、SQL注入或路径遍历等严重风险。以下是多种安全获取与处理表单数据的方法:
一、使用 filter_input() 替代直接访问 $_POST 或 $_GET
filter_input() 提供类型感知的输入过滤机制,能自动校验数据格式并清理恶意字符,避免依赖手动 trim() 和 htmlspecialchars() 的拼凑式防护。
1、调用 filter_input() 获取 POST 字段,指定过滤器类型,例如:filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) 仅当输入符合邮箱格式时返回值,否则返回 false。
2、对字符串类字段使用 FILTER_SANITIZE_STRING(注意:PHP 8.1+ 已废弃,应改用 FILTER_SANITIZE_FULL_SPECIAL_CHARS)。
立即学习“PHP免费学习笔记(深入)”;
3、获取整数时启用范围限制:filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]])。
4、对所有关键字段执行非空判断,若返回 false 或 null,则拒绝后续处理流程。
二、强制使用 PDO 预处理语句处理数据库写入
即使已用 filter_input() 过滤输入,任何将用户数据拼入 SQL 查询的行为仍存在注入风险;预处理语句通过参数绑定实现数据与指令分离,是防御 SQL 注入的根本手段。
1、初始化 PDO 实例时显式设置错误模式为异常:$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)。
2、编写带占位符的 SQL 语句,例如:"INSERT INTO users (name, email) VALUES (?, ?)"。
3、调用 prepare() 创建语句对象,再使用 execute() 绑定数组参数:$stmt->execute([$name, $email])。
4、禁止在查询中拼接任何来自 $_POST、$_GET 或 filter_input() 的原始值,包括字段名和表名——这些必须来自白名单配置。
三、输出用户数据前必须执行全参数 htmlspecialchars()
未经转义的用户输入直接嵌入 HTML 上下文,会触发反射型或存储型 XSS;htmlspecialchars() 必须显式声明全部三个参数,以杜绝编码歧义与浏览器自动识别漏洞。
1、对每个待输出变量调用:htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8')。
2、禁止省略第三个参数,避免因 default_charset 设置不一致导致 UTF-7 解码绕过。
3、在属性值上下文中(如 )尤其需启用 ENT_QUOTES,确保单引号也被转义,防止属性闭合攻击。
4、不得将 htmlspecialchars() 应用于已由数据库读取的富文本内容;此类内容应使用专用 HTML 清洗库(如 HTMLPurifier),而非简单转义。
四、禁用危险的表单处理惯用法
部分传统写法看似便捷,实则埋藏深层安全隐患,必须从代码规范层面禁止使用。
1、彻底删除形如 $_POST['username'] 或 $_GET['id'] 的裸引用,所有输入必须经 filter_input() 或封装函数统一入口。
2、禁止使用 mysqli_real_escape_string() 防御 SQL 注入——它无法应对宽字节、多语句或预处理未启用场景下的绕过。
3、禁用已废弃的 filter_sanitize_* 系列过滤器(如 FILTER_SANITIZE_STRING),改用 FILTER_SANITIZE_FULL_SPECIAL_CHARS 或更细粒度验证器。
4、拒绝在 form action 中使用 $_SERVER["PHP_SELF"],该变量可被 URL 片段注入恶意脚本;应硬编码目标路径或使用白名单路由映射。
五、实施 CSRF 防护与请求方法校验
仅验证数据内容不足以阻止伪造请求;攻击者可诱导用户点击恶意链接或提交跨域表单,从而在用户身份下执行非预期操作。
1、在表单中嵌入一次性 token:。
2、服务端接收后立即比对 session 中存储的 token 值,并在验证成功后销毁该 token。
3、在处理脚本开头强制校验请求方法:if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); exit; }。
4、对所有修改性操作(如删除、状态变更、密码重置)禁用 GET 请求,防止被搜索引擎缓存或日志泄露关键参数。



















