php 安全获取参数应优先用 filter_input() 过滤并校验,禁用 $_request;发邮件推荐 phpmailer 并严格过滤邮箱、转义内容;mail() 需手动处理 mime 编码防乱码;务必添加日志与限流。

PHP 怎么安全地获取 URL 或表单传来的参数
直接用 $_GET 或 $_POST 读参数是常见做法,但不校验类型和内容会埋雷——比如邮箱字段传个 <script>alert(1)</script>,后续拼进邮件内容就可能触发 XSS;或者传空字符串、SQL 注入字符,影响后续逻辑或数据库操作。
推荐用 filter_input() 做带类型和规则的过滤:
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING); $subject = filter_input(INPUT_POST, 'subject', FILTER_SANITIZE_SPECIAL_CHARS);
- 必须检查返回值是否为
null(参数不存在)或false(过滤失败),不能直接当字符串用 -
FILTER_SANITIZE_EMAIL会删掉非法字符,但不验证邮箱格式是否真实有效;如需强校验,再补filter_var($email, FILTER_VALIDATE_EMAIL) - 别用
$_REQUEST—— 它混了 GET/POST/COOKIE,来源不可控,容易被绕过
用 PHPMailer 发送带参数内容的邮件最简路径
原生 mail() 函数配置麻烦、编码易出错、没错误反馈,现在基本都用 PHPMailer。它支持 UTF-8、附件、SMTP 认证,且参数注入风险可控。
安装后核心发送逻辑示例:
立即学习“PHP免费学习笔记(深入)”;
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com';
$mail->Password = 'app-password'; // 不是登录密码
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->setFrom('your@gmail.com', $name ?? 'Sender');
$mail->addAddress($email); // 已经过滤过的邮箱
$mail->Subject = $subject ?: 'No subject';
$mail->Body = "Hi {$name},\n\n" . htmlspecialchars($_POST['message'] ?? '', ENT_QUOTES, 'UTF-8');
$mail->send();
} catch (Exception $e) {
error_log("Mail failed: {$mail->ErrorInfo}");
}
-
$mail->Body中拼接用户输入前,务必用htmlspecialchars()转义,防止 HTML/JS 注入到邮件正文(尤其发 HTML 邮件时) - Gmail 等平台要求用「应用专用密码」而非账户密码,且需开启两步验证才能生成
- 别把
$email直接塞进addAddress()前不做filter_var(..., FILTER_VALIDATE_EMAIL)校验,否则 PHPMailer 会抛异常中断
为什么 mail() 函数发中文标题/内容总乱码
根本原因是没声明字符集和编码方式。原生 mail() 是裸协议调用,所有头信息(包括 Subject、Content-Type)都要手动构造 MIME 格式。
如果非要用 mail(),至少保证这三处一致:
$headers = "From: sender@example.com\r\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
$subject = "=?UTF-8?B?" . base64_encode("你好,这是标题") . "?=";
mail($email, $subject, "正文也是 UTF-8", $headers);
-
Subject必须用 MIME encoded-word 格式(=?UTF-8?B?...?=),否则 Outlook、Apple Mail 会显示问号或乱码 -
Content-Type头缺不得,且charset要和实际字符串编码一致(PHP 文件本身也得存成 UTF-8 无 BOM) - 换行符必须是
\r\n,Linux 下用\n会导致部分邮件服务器拒收
参数校验和邮件发送之间要不要加日志或限流
要,而且非常必要。线上环境没人会只靠「发成功了」判断业务正常——用户填错邮箱、SMTP 临时故障、同一 IP 短时间发 100 封,这些都得有应对。
- 记录关键参数(脱敏后的邮箱前缀、IP、时间戳)到文件或日志系统,方便排查“谁没收到邮件”
- 对高频请求做简单限流:比如用
apcu_store()缓存 IP + 时间戳,5 分钟内超过 5 次就拒绝,防恶意刷 - 邮件发送结果不要直接返回给前端提示“已发送”,而应统一返回“已提交,稍后查收”,避免暴露后端是否真的发出
真正难的不是怎么发邮件,是怎么让每次发送都可追溯、可防御、可降级。参数进来时多判一次,比事后查三天日志强得多。











