itjackjw/hyperf-sms

Hyperf SMS包。

dev-main 2023-12-12 03:17 UTC

This package is auto-updated.

Last update: 2024-09-12 04:55:33 UTC


README

简介

组件实现了一套干净、简洁的API,并为许多第三方短信发送服务提供了相应的驱动,让您可以快速、简单地从您的应用发送短信。驱动基本移植自overtrue/easy-sms,同时借鉴了其网关策略并进行了扩展。

安装

composer require hyperf-ext/sms

配置

发布配置

php bin/hyperf.php vendor:publish hyperf-ext/sms

发送器配置

配置文件中的senders节点配置的每个发送器配置都有自己的「驱动」和配置选项,这将允许您的应用程序使用不同的短信服务来发送特定的消息。例如,您的应用程序可能使用阿里云发送验证码类消息,而使用腾讯云发送通知类消息。或者为同类消息配置多个发送器来提高服务可用性。

阿里云

短信消息类可用配置内容方法:templatewithsignature

[
    'driver' => \HyperfExt\Sms\Drivers\AliyunDriver::class,
    'config' => [
        'access_key_id' => '',
        'access_key_secret' => '',
        'sign_name' => '',
    ],
]

百度智能云

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\BaiduCloudDriver::class,
    'config' => [
        'ak' => '',
        'sk' => '',
        'invoke_id' => '',
        'domain' => '',
    ],
]

华为云

短信消息类可用配置内容方法:templatewithfrom

[
    'driver' => \HyperfExt\Sms\Drivers\HuaweiCloudDriver::class,
    'config' => [
        'endpoint' => '', // 从管理控制台获取到的 App 接入地址
        'app_key' => '',
        'app_secret' => '',
        'from' => [
            'default' => '', // 默认签名通道号
            // 'another' => '', // 其他签名通道号
        ],
    ],
]

聚合数据

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\JuheDataDriver::class,
    'config' => [
       'app_key' => '',
    ],
]

螺丝帽

短信消息类可用配置内容方法:content

[
    'driver' => \HyperfExt\Sms\Drivers\LuosimaoDriver::class,
    'config' => [
       'app_key' => '',
    ],
]

七牛云

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\QiniuDriver::class,
    'config' => [
        'secret_key' => '',
        'access_key' => '',
    ],
]

融云

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\RongCloudDriver::class,
    'config' => [
        'app_key' => '',
        'app_secret' => '',
    ],
]

容联云通讯

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\RonglianDriver::class,
    'config' => [
        'app_id' => '',
        'account_sid' => '',
        'account_token' => '',
        'is_sub_account' => false,
    ],
]

SendCloud

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\SendCloudDriver::class,
    'config' => [
        'sms_user' => '',
        'sms_key' => '',
        'timestamp' => false, // 是否启用时间戳
    ],
]

短信宝

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\SmsBaoDriver::class,
    'config' => [
        'user' => '',
        'password' => '',
    ],
]

腾讯云

短信消息类可用配置内容方法:templatewithsignature

[
    'driver' => \HyperfExt\Sms\Drivers\TencentCloudDriver::class,
    'config' => [
        'sdk_app_id' => '',
        'secret_id' => '',
        'secret_key' => '',
        'sign' => null, // 短信签名
        'from' => [ // SenderId,中国大陆地区无需配置
            'default' => '', // 默认 SenderId
            // 'another' => '', // 其他 SenderId
        ],
    ],
]

Twillo

短信消息类可用配置内容方法:content

[
    'driver' => \HyperfExt\Sms\Drivers\TwilioDriver::class,
    'config' => [
        'account_sid' => '',
        'token' => '',
        'from' => [
            'default' => '',
            // 'another' => '',
        ],
    ],
]

UCloud

短信消息类可用配置内容方法:templatewithsignature

[
    'driver' => \HyperfExt\Sms\Drivers\UCloudDriver::class,
    'config' => [
        'private_key' => '',
        'public_key' => '',
        'sig_content' => '', // 短信签名
        'project_id' => '', // 项目ID,子账号才需要该参数
    ],
]

云片

短信消息类可用配置内容方法:contentsignature

[
    'driver' => \HyperfExt\Sms\Drivers\YunpianDriver::class,
    'config' => [
        'api_key' => '',
        'signature' => '', // 短信签名,内容中无签名时使用
    ],
]

网易云信

短信消息类可用配置内容方法:templatewith

[
    'driver' => \HyperfExt\Sms\Drivers\YunxinDriver::class,
    'config' => [
       'app_key' => '',
       'app_secret' => '',
       'code_length' => 4, // 随机验证码长度,范围 4~10,默认为 4
       'need_up' => false, // 是否需要支持短信上行
    ],
]

生成短信消息类

应用发送的每种消息都被表示为短信消息类。这些类存储于app/Sms目录中。如果您的应用中没有该目录,别慌,当您使用gen:sms命令生成您的首个短信消息类时,应用将会自动创建它:

php bin/hyperf.php gen:sms VerificationCode

编写短信消息类

所有的短信消息类的配置都在build方法中完成。您可以通过调用诸如contenttemplatesignaturefrom这样的各种各样的方法来配置消息的内容及其发送。

配置发送器

在发送消息前,您需要指定哪些发送器可被用于发送消息。有两种方式来指定可用发送器。

通过配置文件

您可以通过配置文件的default.senders节点来指定默认的被用于发送消息的发送器,值类型可以是arraystring

[
    'default' => [
        'senders' => ['aliyun', 'twillo'],
    ],
]

通过Smsable类属性

您也可以通过短信消息类的senders公开属性来指定可用发送器,如果您未在短信消息类中指定,那么在发送时会自动使用配置文件中指定的发送器。

use HyperfExt\Sms\Smsable;

class VerificationCode extends Smsable
{
    public $senders = ['aliyun', 'twillo'];
}

指定地区限定的发送器

由于短信服务提供商所服务的地区是有限的,亦或是因各地区价格因素的考量,您可能会为此使用多个提供商来让您的业务覆盖尽可能多的地区,此时您可为指定地区的号码配置指定的发送器。

[
    'aliyun' => ['cn', 'hk', 'mo', 'tw'], // 仅当手机号是大陆和港澳台地区时使用阿里云和腾讯云
    'tencent_cloud' => ['cn', 'hk', 'mo', 'tw'],
    'twillo', // 大陆和港澳台地区以外使用 Twillo
]

地区代码使用ISO 3166-1两位地区代码,不区分大小写。

发送器的筛选逻辑在内建的发送器策略中实现,您可以通过自定义发送器策略来根据自身需求实现自己的处理逻辑。

配置发送器策略

发送器策略是在使用多个发送器的情况下,用来确定发信程序以何种顺序来选择发送器的排序和筛选程序。当一个发送器发送失败后会根据顺序选择下一个发送器,直到发送成功。

组件内建OrderStrategyRandomStrategy两个默认的策略。OrderStrategy策略依照您指定发送器的顺序来选择发送器。RandomStrategy策略则将发送器列表打乱来随机排序。

就像配置发送器一样,发送器策略有着相同的两种配置方式。配置文件的default.strategy节点,或短信消息类的strategy公开属性。

自定义发送器策略

您也可以自定义发送器策略,只需实现StrategyInterface接口。该接口只有一个apply方法,接受两个参数。第一个参数接受您配置的可用发送器列表,第二个参数接受要收信的手机号码MobileNumber类。

配置内容

您可以在短信消息类的build方法中使用content方法指定短信内容,使用template方法来指定在短信模板,使用with方法来指定短信参数,使用signature方法来指定短信签名。

您需要根据您选择的短信服务的不同来选择使用哪些方法。

通过content方法

public function build(SenderInterface $sender): void
{
    return $this
        ->content('您的验证码是 123456')
        ->signature('【HyperfExt】');
}

通过template方法

public function build(SenderInterface $sender): void
{
    return $this
        ->template('SMS_001')
        ->signature('【HyperfExt】')
        ->with('code', '123456');
}

配置发件人ID

某些短信业务提供商可能会要求传递发件人ID(一般称为sender idfrom),您可以在对应发送器下的config.from节点内配置,并通过短信消息类的from方法使用。以Twillo为例:

// 在配置文件中指定
'twillo' => [
    'driver' => \HyperfExt\Sms\Drivers\TwilioDriver::class,
    'config' => [
        'account_sid' => '',
        'token' => '',
        'from' => [
            'default' => '123', // 当未在短信消息类中指定时使用 `default` 的值
            'another1' => '456',
            'another2' => '789',
        ],
    ],
],

// 在短信消息类中使用
public function build(SenderInterface $sender): void
{
    return $this
        ->from('another2');
}

发送短信

若要发送短信,使用Sms辅助类的to方法。to方法接受手机号码和实现了HasMobileNumber接口的实例。一旦指定了收信人,就可以将短信消息类实例传递给send方法:

<?php

namespace App\Controller;

use App\Sms\VerificationCode;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use HyperfExt\Sms\Sms;

class VerificationController
{
    public function send(RequestInterface $request): ResponseInterface
    {
        // 假定 $user 已经实现了 HasMobileNumber 接口
        $user = $request->user();
        // 发送
        Sms::to($user)->send(new VerificationCode());
    }
}

通过特定的发送器发送短信

默认情况下,组件将使用您配置的发送器来发送短信。但是,您可以使用sender方法通过特定的发送器发送:

Sms::sender('twillo')
    ->to($request->user())
    ->send(new VerificationCode());

短信队列

将短信消息加入队列

由于发送短信消息可能大幅度增加应用的响应时间,许多开发者选择将短信消息加入队列放在后台发送。组件使用hyperf/async-queue简化了这一工作,安装时已经自动依赖,请根据文档进行配置。

若要将短信消息加入队列,可以在指定消息的接收者后,使用Sms辅助类的queue方法:

Sms::to($request->user())
    ->queue(new VerificationCode());

此方法自动将作业推送到队列中以便消息在后台发送。使用此特性之前,需要配置队列

如果要将短信推送到指定队列,可以通过设置queue方法的第二个参数实现。

延迟消息队列

想要延迟发送队列化的短信消息,可以使用later方法。later方法的第二个参数是标示消息延后多少秒后发送:

Sms::to($request->user())
    ->later(new VerificationCode(), 300); //延后  5 分钟发送

如果要将短信推送到指定队列,可以通过设置queue方法的第二个参数实现。

默认使用队列

如果您希望您的短信类始终使用队列,您可以给短信消息类实现HyperfExt\Contract\ShouldQueue接口,现在即使您调用了send方法,短信依旧使用队列的方式发送。另外,如果需要将短信推送到指定队列,可以设置在短信消息类中设置queue属性。

use HyperfExt\Contract\ShouldQueue;
use HyperfExt\Sms\Smsable;

class VerificationCode extends Smsable implements ShouldQueue
{
    /**
     * 列队名称。
     *
     * @var string
     */
    public $queue = 'default';
}

本地开发

当您正在开发一个短信的应用程序时,您可能不想实际地向真实手机号码发送消息。组件提供了在本地开发过程中「禁用」实际发送短信的方法。

日志驱动

log发送器驱动不发送短信,而是将所有短信消息写入日志文件用来校验。有关为每个环境配置应用程序的更多信息,请参阅配置文档

事件

在发送短信消息的时候,组件会触发两个事件。SmsMessageSending事件在发送消息前触发,SmsMessageSent事件在消息发送完成后触发。记住,这些事件都是在短信被发送时触发,而不是在队列化的时候。

验证器规则

为了有限的减少发送短信到无效的手机号码的情况,组件提供了两个方便使用的验证规则来手机号码的有效性。

需要安装配置 hyperf/validation 组件。需要在验证消息的多语言文件中自行添加 mobile_numbermobile_number_format 两条翻译。

这些验证器验证的有效性是指验证手机号码规则的有效,而非验证其真实性。

mobile_number[:...regions]

mobile_number 验证规则用来验证手机号码字段值是否有效,可选验证号码所属国家或地区是否在 regions 列表中。regionsISO 3166-1 两位字母代码(下称「地区代码」)的地区代码列表。

regions 列表为空且配置文件中默认地区代码为 null 时,要验证的号码必须含有 ITU-T E.164 建议书规定的国家代码(下称「国码」),否则将视为无效号码。

regions 列表为空且配置文件中默认地区代码有值时,无论要验证的号码是否含有国码,都验证此号码是否属于默认地区,适合业务仅面向单一地区的场景。

regions 列表仅有一个地区代码时,无论要验证的号码是否含有国码、配置文件中默认地区代码是否有值,都验证此号码是否属于该地区。

regions 列表地区代码数量大于一个时,要验证的号码都必须含有国码,否则将视为无效号码。

注意,该验证规则接受任意电话号码格式。如果您需要同时验证地区和格式,请额外使用 mobile_number_format 规则。如果仅验证号码有效性和格式,可以只用 mobile_number_format 规则。

'phone' => mobile_number'
'phone' => mobile_number:cn,hk,mo,tw'

mobile_number_format:format

mobile_number_format 验证规则用来验证手机号码字段值是否有效,且号码格式是否符合 format 格式。

e164

验证号码格式是否符合 ITU-T E.164 建议书规定的格式。例如,+8618812345678

international

验证号码格式是否符合国际拨号格式。例如,+86 188 1234 5678

national[,region]

验证号码格式是否符合受话地号码格式,不能含有国际冠码和国码。例如,188 1234 5678。配置文件中默认地区代码为 null 时,必须提供 region 值。

rfc3966

验证号码格式是否符合 RFC3966。例如,tel:+86-188-1234-5678

digits

验证号码格式是否都是数字。例如,861881234567818812345678

自定义正则表达式

验证号码格式是否匹配此正则表达式。

e164digits 和自定义正则表达式外的验证格式均为 ITU-T E.123 建议书规定的格式。

'phone' => mobile_number_format:e164'

待办事项

  • 测试用例