在PHP中限制短信发送频率是防止滥用的重要措施,以下是几种常见的实现方案和代码示例:

核心思路
- 频率限制:基于手机号/IP限制单位时间内的发送次数
- 验证码校验:增加图形验证码或滑块验证
- 冷却时间:发送后强制等待时间
方案1:基于Redis的计数器(推荐)
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$mobile = $_POST['mobile'];
$ip = $_SERVER['REMOTE_ADDR'];
// 设置频率限制(1分钟内同一手机最多1条)
$mobileKey = "sms_limit:{$mobile}";
if ($redis->exists($mobileKey)) {
die("操作过于频繁,请1分钟后再试");
}
// IP限制(1小时内最多发10条)
$ipKey = "sms_ip_limit:{$ip}";
$ipCount = $redis->incr($ipKey);
if ($ipCount > 10) {
die("今日发送次数已达上限");
}
$redis->expire($ipKey, 3600); // 1小时过期
// 发送短信(模拟)
if (sendSMS($mobile)) {
// 设置手机号冷却时间(60秒)
$redis->setex($mobileKey, 60, "1");
echo "短信发送成功";
}
function sendSMS($mobile) {
// 实际对接短信接口
return true;
}
?>
方案2:数据库记录法(MySQL)
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$mobile = $_POST['mobile'];
$ip = $_SERVER['REMOTE_ADDR'];
// 检查1分钟内是否已发送
$stmt = $pdo->prepare("SELECT COUNT(*) FROM sms_log
WHERE mobile = ? AND created_at > NOW() - INTERVAL 1 MINUTE");
$stmt->execute([$mobile]);
if ($stmt->fetchColumn() > 0) {
die("请等待60秒后重试");
}
// 检查IP当日发送量
$stmt = $pdo->prepare("SELECT COUNT(*) FROM sms_log
WHERE ip = ? AND created_at > CURDATE()");
$stmt->execute([$ip]);
if ($stmt->fetchColumn() >= 50) {
die("今日发送次数已达上限");
}
// 记录发送日志
$stmt = $pdo->prepare("INSERT INTO sms_log (mobile, ip, created_at) VALUES (?, ?, NOW())");
$stmt->execute([$mobile, $ip]);
// 发送短信...
echo "短信发送成功";
?>
表结构:

CREATE TABLE sms_log (
id INT AUTO_INCREMENT PRIMARY KEY,
mobile VARCHAR(20) NOT NULL,
ip VARCHAR(45) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
方案3:前端+后端双重验证
// 后端增加图形验证码验证
session_start();
if ($_POST['captcha'] !== $_SESSION['captcha']) {
die("验证码错误");
}
// 销毁已用验证码
unset($_SESSION['captcha']);
// 后续发送逻辑...
关键防护措施
| 防护层 | 实现方式 | 推荐值 |
|---|---|---|
| 手机号冷却期 | Redis SETEX | 60-120秒 |
| 单日手机号上限 | Redis INCR/Database COUNT | 5-10次/日 |
| IP频率限制 | Redis INCR/Database COUNT | 50次/小时 |
| 验证码防护 | GD库生成图形验证码 | 必选 |
最佳实践建议
- 多级限制:手机号+IP双重校验
- 错误模糊:不返回具体限制类型(如”操作频繁”替代”手机号超限”)
- 日志监控:记录异常请求用于分析攻击
- 动态调整:根据业务情况自动调整阈值
// 动态调整示例:繁忙时段放宽限制 $hour = date('H'); $maxLimit = ($hour >= 8 && $hour <= 20) ? 15 : 5;
重要提示:生产环境应结合WAF防火墙、Nginx限流模块等基础设施级防护,避免所有压力集中在应用代码层。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/289752.html

