本文目录导读:

在PHP项目中发送短信验证码,通常需要借助第三方短信服务提供商(如阿里云、腾讯云、Twilio、七牛云等),因为自己搭建短信网关成本高且复杂。
以下是一套完整、安全的实现流程,以阿里云短信服务为例(其他平台原理类似)。
第一步:准备工作(以阿里云为例)
- 注册账号:在阿里云官网开通“短信服务”。
- 获取密钥:获取
AccessKey ID和AccessKey Secret。 - 申请签名与模板:
- 签名:XX科技”(需企业/个人认证)。
- 模板:您的验证码为:${code},5分钟内有效。”
- 模板ID:
SMS_123456789。
第二步:安装依赖
推荐使用阿里云官方SDK,通过Composer安装:
composer require alibabacloud/sdk
第三步:核心代码实现
以下是一个发送短信验证码的示例类:
<?php
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
class SmsService
{
private $accessKeyId;
private $accessKeySecret;
private $signName; // 短信签名
private $templateCode; // 短信模板ID
public function __construct($accessKeyId, $accessKeySecret, $signName, $templateCode)
{
$this->accessKeyId = $accessKeyId;
$this->accessKeySecret = $accessKeySecret;
$this->signName = $signName;
$this->templateCode = $templateCode;
// 初始化客户端(建议在框架启动时全局初始化一次)
AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessKeySecret)
->regionId('cn-hangzhou') // 根据实际区域调整
->asDefaultClient();
}
/**
* 发送验证码
* @param string $phone 手机号
* @param string $code 验证码(6位数字)
* @return array ['success' => true/false, 'message' => '...']
*/
public function sendCode($phone, $code)
{
try {
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
->version('2017-05-25')
->action('SendSms')
->method('POST')
->host('dysmsapi.aliyuncs.com')
->options([
'query' => [
'PhoneNumbers' => $phone,
'SignName' => $this->signName,
'TemplateCode' => $this->templateCode,
'TemplateParam' => json_encode(['code' => $code]), // 模板变量
],
])
->request();
$response = $result->toArray();
if ($response['Code'] === 'OK') {
return ['success' => true, 'message' => '发送成功'];
} else {
return ['success' => false, 'message' => $response['Message'] ?? '发送失败'];
}
} catch (ClientException $e) {
return ['success' => false, 'message' => $e->getErrorMessage()];
} catch (ServerException $e) {
return ['success' => false, 'message' => $e->getErrorMessage()];
}
}
}
第四步:调用示例
// 配置参数(建议从 .env 文件读取)
$sms = new SmsService(
'你的AccessKey ID',
'你的AccessKey Secret',
'XX科技', // 短信签名
'SMS_123456789' // 模板ID
);
// 生成6位随机验证码
$code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
// 发送
$result = $sms->sendCode('13800138000', $code);
if ($result['success']) {
// 保存验证码到Redis/数据库,设置有效期(如5分钟)
// Redis::setex('sms_code:13800138000', 300, $code);
} else {
// 处理发送失败
echo '发送失败:' . $result['message'];
}
第五步:安全性建议(重要)
- 验证码有效期:一般设为5分钟,过期删除。
- 频率限制:
- 同一手机号:
60秒内不能重复发送,每日不超过10次。 - 同一IP:
每小时不超过20次(防刷)。
- 同一手机号:
- 验证码存储:
- 使用Redis
SETEX或数据库加过期字段。 - 绝不要将验证码明文存储到日志或返回给前端。
- 使用Redis
- 前端限制:在前端也做60秒倒计时,但后端必须独立校验。
- 接口防刷:
- 使用验证码(图片验证码/captcha)防止机器调用。
- 对接口加签名或Token验证。
其他主流服务商参考
| 服务商 | SDK | 备注 |
|---|---|---|
| 腾讯云 | tencentcloud/sms |
需申请签名+模板 |
| Twilio | twilio/sdk |
国际常用,国内支持有限 |
| 七牛云 | qiniu/php-sdk |
安全高效 |
| 容联云 | rongcloud/rong-sms-sdk |
老牌短信服务商 |
常见错误排查
SignatureDoesNotMatch:检查AccessKey Secret是否配置正确。InvalidPhoneNumber:手机号格式错误,需+86开头(国内)或国际格式。TemplateParam缺失:检查模板变量是否与TemplateParam的JSON键名一致。签名或模板未审核:申请后需要等待审核通过(一般2~24小时)。