下面给你一份 “PHP 短信发送功能的实现与优化指南”,适合用于你的网站项目或 API 后端,包含完整架构、代码示例、优化策略与常见问题排查。
📱 PHP 短信发送功能的实现与优化指南
(适用于验证码短信、通知短信、营销短信)
1. 📌 短信发送整体架构
大多数 PHP 项目会采用下图的架构:
Your PHP App → SMS Service Layer → SMS Provider API (阿里云/腾讯云/容联云/国内短信平台)
核心包含 3 步:
- 创建 SMS 服务类(发送、日志、限流)
- 调用第三方短信服务商 API
- 处理返回值 + 存储发送记录 + 做限流
2. 🚀 第一步:选择短信服务商
常见高可用短信网关:
| 服务商 | 特点 | 适用场景 |
|---|---|---|
| 阿里云短信 | 稳定、国内最常用、价格适中 | 网站验证码、通知 |
| 腾讯云短信 | 稳定性强、API 简单 | 小程序、公众号、电商 |
| 容联云通讯 | 支持语音验证码 | 呼叫中心类 |
| Twilio(海外) | 国际短信 | 海外业务 |
建议:国内用阿里云;国际用 Twilio。
3. 🧩 第二步:创建一个通用短信发送类(PHP)
下面以阿里云为例(最常用):
📌 SmsService.php
<?php
class SmsService
{
private $accessKeyId;
private $accessKeySecret;
private $signName;
public function __construct($accessKeyId, $accessKeySecret, $signName)
{
$this->accessKeyId = $accessKeyId;
$this->accessKeySecret = $accessKeySecret;
$this->signName = $signName;
}
public function send($phoneNumber, $templateCode, $templateParams = [])
{
$params = [
"PhoneNumbers" => $phoneNumber,
"SignName" => $this->signName,
"TemplateCode" => $templateCode,
"TemplateParam" => json_encode($templateParams, JSON_UNESCAPED_UNICODE)
];
$content = $this->request("dysmsapi.aliyuncs.com", $params);
return json_decode($content, true);
}
private function request($domain, $params)
{
$apiParams = array_merge([
"RegionId" => "cn-hangzhou",
"Action" => "SendSms",
"Version" => "2017-05-25"
], $params);
$url = "https://{$domain}/?";
return file_get_contents($url . http_build_query($apiParams));
}
}
4. 🎯 第三步:调用示例(如发送验证码)
$sms = new SmsService("yourKeyId", "yourSecret", "签名名称");
$response = $sms->send(
"13888888888",
"SMS_12345678",
["code" => rand(100000, 999999)]
);
print_r($response);
5. 🔐 第四步:加入验证码缓存(Redis)
验证码必须加 时间限制 & 限流:
5.1 保存验证码
$redis->setex("sms:code:$phone", 300, $code); // 5分钟
5.2 限制每个手机号 60 秒发送一次
if ($redis->exists("sms:limit:$phone")) {
return "发送太频繁,请稍后再试";
}
$redis->setex("sms:limit:$phone", 60, 1);
6. ⚙️ 优化策略(必须做)
6.1 ✨ 幂等性:防止短时间重复发送
使用 Redis 控制:
一手机号 60 秒只能发送一次
同一 IP 1 小时最多 20 条
6.2 ✨ 短信发送记录
表结构(MySQL):
CREATE TABLE sms_log (
id INT AUTO_INCREMENT PRIMARY KEY,
phone VARCHAR(20),
template VARCHAR(50),
params VARCHAR(255),
status TINYINT COMMENT '0=失败 1=成功',
response TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
6.3 ✨ 自动切换短信服务商(可选)
防止某一平台故障,可以做:
try {
$response = $aliyun->send(...);
} catch (Exception $e) {
$response = $tencent->send(...); // fallback
}
7. 🛠️ 常见错误排查与解决
| 错误提示 | 原因 | 解决方案 |
|---|---|---|
| InvalidSignName | 签名未审核通过 | 去短信平台审核 |
| TemplateCode error | 模板未审核 | 提交审核 |
| PhoneNumber illegal | 手机号格式错 | 用正则校正 |
| RequestLimitExceeded | 超出频率 | 添加 Redis 限流 |
| 触发黑名单 | 同一手机号发送过多 | 控制发送次数 |
8. 🔒 推荐添加的安全保护
- 使用图形验证码防止机器刷短信
- 限流(手机号、IP、设备号)
- 短信验证码只允许使用一次
- 密码找回场景必须严格控频
9. 📦 开源可直接使用的 PHP 短信 SDK
| 服务商 | SDK |
|---|---|
| 阿里云 | composer require alibabacloud/client |
| 腾讯云 | composer require tencentcloud/tencentcloud-sdk-php |
| Twilio | composer require twilio/sdk |