laravel框架使用阿里云短信发送消息操作示例


Posted in PHP onFebruary 15, 2020

本文实例讲述了laravel框架使用阿里云短信发送消息操作。分享给大家供大家参考,具体如下:

最新需要用到发送短信的功能,所以就在网上搜索一些写好的扩展。

扩展地址:

https://github.com/MissMyCat/aliyun-sms

通过composer安装:

composer require mrgoon/aliyun-sms dev-master

在 config/app.php 中 providers 加入:

Mrgoon\AliSms\ServiceProvider::class,

有需求的可以自行添加 aliases。

然后在控制台运行 :

php artisan vendor:publish

默认会在 config 目录下创建一个 aliyunsms.php 文件:

<?php
return [
  'access_key' => env('ALIYUN_SMS_AK'), // accessKey
  'access_secret' => env('ALIYUN_SMS_AS'), // accessSecret
  'sign_name' => env('ALIYUN_SMS_SIGN_NAME'), // 签名
];

然后在 .env 中配置相应参数:

ALIYUN_SMS_AK=
ALIYUN_SMS_AS=
ALIYUN_SMS_SIGN_NAME=

为了能够方便的发送短信,我们可以在 app 目录下,创建一个Services目录,并添加 AliyunSms.php 文件。

<?php
namespace App\Services;
use Mrgoon\AliSms\AliSms;
/**
 * 阿里云短信类
 */
class AliyunSms
{
  //验证码
  const VERIFICATION_CODE = 'verification_code';
  //模板CODE
  public static $templateCodes = [
    self::VERIFICATION_CODE => 'SMS_XXXXXXXXXX',
  ];
  /**
   * 发送短信
   */
  public static function sendSms($mobile, $scene, $params = [])
  {
    if (empty($mobile)) {
      throw new \Exception('手机号不能为空');
    }
    if (empty($scene)) {
      throw new \Exception('场景不能为空');
    }
    if (!isset(self::$templateCodes[$scene])) {
      throw new \Exception('请配置场景的模板CODE');
    }
    $template_code = self::$templateCodes[$scene];
    try {
      $ali_sms = new AliSms();
      $response = $ali_sms->sendSms($mobile, $template_code, $params);
      if ($response->Code == 'OK') {
        return true;
      }
      throw new \Exception($response->Message);
    } catch (\Throwable $e) {
      throw new \Exception($e->getMessage());
    }
  }
}

为了能够记录每次短信发送的状态,我们可以创建一个 sms_logs 表。

CREATE TABLE `sms_logs` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '类型(0:短信验证码,1:语音验证码,2:短信消息通知)',
 `mobile` varchar(16) NOT NULL DEFAULT '' COMMENT '手机号',
 `code` varchar(12) NOT NULL DEFAULT '' COMMENT '验证码',
 `checked` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否验证(0:未验证,1:已验证)',
 `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(0:未发送,1:已发送,2:发送失败)',
 `reason` varchar(255) NOT NULL DEFAULT '' COMMENT '失败原因',
 `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
 `operator_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作人ID',
 `ip` varchar(16) NOT NULL DEFAULT '' COMMENT '操作IP',
 `created` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
 `updated` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='短信表';

然后针对该表,我们创建一个 SmsLog 模型来管理。

<?php
namespace App\Models;
use App\Services\AliyunSms;
class SmsLog extends Model
{
  protected $fillable = [
    'type',
    'mobile',
    'code',
    'checked',
    'status',
    'reason',
    'remark',
    'operator_id',
    'ip',
  ];
  //类型(0:短信验证码,1:语音验证码,2:短信消息通知)
  const TYPE_CODE = 0;
  const TYPE_VOICE = 1;
  const TYPE_MESSAGE = 2;
  //是否验证(0:未验证,1:已验证)
  const CHECKED_UNVERIFIED = 0;
  const CHECKED_VERIFIED = 1;
  //状态(0:未发送,1:已发送,2:发送失败)
  const STATUS_NO_SEND = 0;
  const STATUS_SEND = 1;
  const STATUS_FAIL = 2;
  //短信发送间隔时间,默认60秒
  const SEND_INTERVAL_TIME = 60;
  /**
   * 检测短信验证码
   */
  protected function checkCode($mobile, $code)
  {
    if (!$mobile) {
      throw new \Exception('手机号不能为空');
    }
    if (!checkMobile($mobile)) {
      throw new \Exception('手机号不正确');
    }
    if (!$code) {
      throw new \Exception('验证码不能为空');
    }
    $sms_log = $this->where([
      ['type', self::TYPE_CODE],
      ['mobile', $mobile],
      ['status', self::STATUS_SEND],
      ['checked', self::CHECKED_UNVERIFIED],
    ])->orderBy('created', 'desc')->first();
    if (!$sms_log) {
      throw new \Exception('验证码不存在,请重新获取');
    }
    if ($code != $sms_log->code) {
      throw new \Exception('验证码错误');
    }
    $sms_log->checked = self::CHECKED_VERIFIED;
    $sms_log->save();
    return true;
  }
  /**
   * 检测短信频率
   */
  protected function checkRate($mobile)
  {
    if (!$mobile) {
      throw new \Exception('手机号不能为空');
    }
    $sms_log = $this->where([
      ['mobile', $mobile],
      ['status', self::STATUS_SEND],
    ])->orderBy('created', 'desc')->first();
    $now = time();
    if ($sms_log) {
      if (($now - strtotime($sms_log->created)) < self::SEND_INTERVAL_TIME) {
        throw new \Exception('短信发送太频繁,请稍后再试');
      }
    }
    return true;
  }
  /**
   * 发送短信验证码
   */
  protected function sendVerifyCode($mobile)
  {
    self::checkRate($mobile);
    $code = mt_rand(1000, 9999);
    $sms_log = $this->create([
      'type' => self::TYPE_CODE,
      'mobile' => $mobile,
      'code' => $code,
      'checked' => self::CHECKED_UNVERIFIED,
      'status' => self::STATUS_NO_SEND,
      'ip' => getRealIp(),
    ]);
    try {
      AliyunSms::sendSms($mobile, AliyunSms::VERIFICATION_CODE, ['code' => $code]);
      $sms_log->status = self::STATUS_SEND;
      $sms_log->save();
      return true;
    } catch (\Exception $e) {
      $sms_log->status = self::STATUS_FAIL;
      $sms_log->reason = $e->getMessage();
      $sms_log->save();
      throw new \Exception($e->getMessage());
    }
  }
}

这样,我们就可以在项目中通过 SmsLog::sendVerifyCode() 发送短信了。

getRealIp() 和 checkMobile() 方法为公共方法,存放在 app/Helpers 的 functions.php 中。

/**
 * 获取真实IP地址
 */
function getRealIp()
{
  $ip = false;
  if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) {
    $ip = getenv("HTTP_CLIENT_IP");
  } else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) {
    $ips = explode(", ", getenv("HTTP_X_FORWARDED_FOR"));
    if ($ip) {
      array_unshift($ips, $ip);
      $ip = false;
    }
    $ipscount = count($ips);
    for ($i = 0; $i < $ipscount; $i++) {
      if (!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i])) {
        $ip = $ips[$i];
        break;
      }
    }
  } else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) {
    $ip = getenv("REMOTE_ADDR");
  } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) {
    $ip = $_SERVER['REMOTE_ADDR'];
  } else {
    $ip = "unknown";
  }
  return isIp($ip) ? $ip : "unknown";
}
/**
 * 检查是否是合法的IP
 */
function isIp($ip)
{
  if (preg_match('/^((\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)(?:\.(\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)){3})$/', $ip)) {
    return true;
  } else {
    return false;
  }
}
/**
 * 验证手机号
 */
function checkMobile($mobile)
{
  return preg_match('/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$/i', $mobile);
}

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

PHP 相关文章推荐
拼音码表的生成
Oct 09 PHP
php中的一个中文字符串截取函数
Feb 14 PHP
轻松修复Discuz!数据库
May 03 PHP
php下保存远程图片到本地的办法
Aug 08 PHP
献给php初学者(入门学习经验谈)
Oct 12 PHP
PHP fopen()和 file_get_contents()应用与差异介绍
Mar 19 PHP
PHP数据库操作之基于Mysqli的数据库操作类库
Apr 19 PHP
php输出xml必须header的解决方法
Oct 17 PHP
php操作redis缓存方法分享
Jun 03 PHP
php递归实现无限分类的方法
Jul 28 PHP
PHP实现的下载远程文件类定义与用法示例
Jul 05 PHP
PHP 的Opcache加速的使用方法
Dec 29 PHP
laravel框架实现敏感词汇过滤功能示例
Feb 15 #PHP
PHP 枚举类型的管理与设计知识点总结
Feb 13 #PHP
PHP+ajax实现上传、删除、修改单张图片及后台处理逻辑操作详解
Feb 12 #PHP
分享8个Laravel模型时间戳使用技巧小结
Feb 12 #PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
Feb 11 #PHP
thinkphp5框架路由原理与用法详解
Feb 11 #PHP
php数组指针函数功能及用法示例
Feb 11 #PHP
You might like
Adodb的十个实例(清晰版)
2006/12/31 PHP
PHP中将数组转成XML格式的实现代码
2011/08/08 PHP
PHP中文竖排转换实现方法
2015/10/23 PHP
PHP数据库操作Helper类完整实例
2016/05/11 PHP
PHP实现创建微信自定义菜单的方法示例
2017/07/14 PHP
jQuery中使用了document和window哪些属性和方法小结
2011/09/13 Javascript
seajs1.3.0源码解析之module依赖有序加载
2012/11/07 Javascript
JS嵌套函数调用上下文的问题解决
2014/03/26 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
JavaScript sup方法入门实例(把字符串显示为上标)
2014/10/20 Javascript
JavaScript实现带箭头标识的多级下拉菜单效果
2015/08/27 Javascript
Javascript中call,apply,bind方法的详解与总结
2016/12/12 Javascript
js前端日历控件(悬浮、拖拽、自由变形)
2017/03/02 Javascript
利用jquery正则表达式在页面验证url网址输入是否正确
2017/04/04 jQuery
微信小程序 slider的简单实例
2017/04/19 Javascript
ES5 ES6中Array对象去除重复项的方法总结
2017/04/27 Javascript
微信小程序自定义导航隐藏和显示功能
2017/06/13 Javascript
jQuery使用ajax_动力节点Java学院整理
2017/07/05 jQuery
vue中echarts3.0自适应的方法
2018/02/26 Javascript
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
python发送邮件的实例代码(支持html、图片、附件)
2013/03/04 Python
CentOS中使用virtualenv搭建python3环境
2015/06/08 Python
Python xlwt设置excel单元格字体及格式
2020/04/18 Python
python实现多线程行情抓取工具的方法
2018/02/28 Python
使用pandas对矢量化数据进行替换处理的方法
2018/04/11 Python
如何在Django中设置定时任务的方法示例
2019/01/18 Python
详解Python sys.argv使用方法
2019/05/10 Python
Python中模块(Module)和包(Package)的区别详解
2019/08/07 Python
Python爬虫如何应对Cloudflare邮箱加密
2020/06/24 Python
美国办公用品折扣网站:Shoplet.com
2019/11/24 全球购物
软件专业毕业生个人自我鉴定
2014/04/17 职场文书
幼儿老师求职信
2014/06/30 职场文书
2014物价局群众路线对照检查材料思想汇报
2014/09/21 职场文书
2014年法务工作总结
2014/12/11 职场文书
酒店总经理岗位职责
2015/04/01 职场文书
阿里云ECS云服务器快照的概念以及如何使用
2022/04/21 Servers