本文目录导读:

- 清洗用户输入(通用)
- 防止 XSS 攻击(输出时清洗)
- 防止 SQL 注入(数据库交互)
- 去除多余字符(Trim / Strip)
- 综合示例:一个安全的处理函数
- 现代最佳实践(PHP 8+)
- 重要提醒
- 你的数据流应该长这样
在 PHP 中清洗数据是一个非常重要的安全实践,清洗数据的主要目的是防止 XSS 攻击、SQL 注入,并确保数据的格式正确。
注意:PHP 8.1+ 中 filter_var() 仍是首选,但需要根据使用场景选择正确的过滤器。
以下是 PHP 清洗数据的最佳实践,按使用场景分类:
清洗用户输入(通用)
这是最基础的一步,通常使用 filter_input() 或 filter_var()。
a. 清洗 Email 地址
$email = $_POST['email']; $clean_email = filter_var($email, FILTER_VALIDATE_EMAIL); // $clean_email 是 false,说明格式错误;否则返回清洗后的 email。
b. 清洗 URL
$url = $_POST['url']; $clean_url = filter_var($url, FILTER_SANITIZE_URL); // 注意:SANITIZE_URL 会移除非法字符,但不会验证 URL 是否有效。 // 若需验证,使用 FILTER_VALIDATE_URL。
c. 清洗整数
$age = $_POST['age']; $clean_age = filter_var($age, FILTER_SANITIZE_NUMBER_INT); // 结果是只包含数字和正负号的字符串,如 "25" 或 "-5"
防止 XSS 攻击(输出时清洗)
关键点:不要用 htmlspecialchars() 清洗输入数据后存入数据库(会导致数据被双重转义),而是只在输出到 HTML 时进行转义。
function escape_html($data) {
return htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
// 使用时:
echo escape_html($user_input);
// <script>alert('x')</script> 变成 <script>
补充:如果要在 HTML 属性中使用,确保使用 ENT_QUOTES(转义单引号和双引号)。
防止 SQL 注入(数据库交互)
不要使用 mysqli_real_escape_string 或 addslashes 来拼接 SQL。应该使用 Prepared Statements(预处理语句)。
// 使用 PDO(推荐)
$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $clean_email]); // 这里传原始数据即可,PDO 会自动处理转义
// 使用 MySQLi
$mysqli = new mysqli('localhost', $user, $pass, 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $id); // 'i' 表示整数
$stmt->execute();
去除多余字符(Trim / Strip)
处理表单数据时,通常需要去除首尾空格和反斜杠。
$name = trim($_POST['name']); // 去除首尾空格 $comment = strip_tags($_POST['comment']); // 去除所有 HTML 和 PHP 标签 // 或者用 htmlspecialchars 代替 strip_tags,以保留部分安全标签。
综合示例:一个安全的处理函数
以下是一个轻量级的通用清洗函数,适用于大多数 Web 请求:
<?php
function clean_input($data, $type = 'string') {
$data = trim($data);
$data = stripslashes($data);
switch ($type) {
case 'email':
return filter_var($data, FILTER_VALIDATE_EMAIL);
case 'url':
return filter_var($data, FILTER_SANITIZE_URL);
case 'int':
return filter_var($data, FILTER_SANITIZE_NUMBER_INT);
case 'string':
default:
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
}
// 使用
$clean_email = clean_input($_POST['email'], 'email');
$clean_message = clean_input($_POST['message'], 'string');
?>
现代最佳实践(PHP 8+)
a. 使用 filter_input_array()
一次性清洗整个 $_POST 数组,减少代码冗余。
$filters = [
'name' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
'email' => FILTER_VALIDATE_EMAIL,
'age' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 18]]
];
$clean_data = filter_input_array(INPUT_POST, $filters);
// $clean_data['name'] 清洗后名字
// $clean_data['email'] 如果无效则为 null 或 false
b. 不要依赖 $_GET / $_POST
尽量使用框架提供的请求对象(如 Laravel 的 $request->validate()),它们内置了更强大的验证与安全机制。
重要提醒
-
不要过度清洗:
htmlspecialchars只适用于 HTML 输出,不要用它清洗数据库查询参数(数据库用预处理语句)。 -
区分验证与清洗:
- 清洗:移除非法字符(如
FILTER_SANITIZE_*)。 - 验证:确保数据格式正确(如
FILTER_VALIDATE_*)。 - 推荐先验证,通过后再存储。
- 清洗:移除非法字符(如
-
对于 JSON 输出:使用
json_encode(),它会自动处理引号转义,无需手动清洗。
你的数据流应该长这样
用户输入 → (验证 + 清洗) → 存入数据库 (Prepared Statement)
↓
最终用户浏览器 ← HTML转义 ← (从数据库取出) 输出到页面
按照这个流程,你就能有效阻止常见的 Web 安全威胁。