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 相关文章推荐
Smarty Foreach 使用说明
Mar 23 PHP
如何批量替换相对地址为绝对地址(利用bat批处理实现)
May 27 PHP
php生成数字字母的验证码图片
Jul 14 PHP
WordPress开发中的get_post_custom()函数使用解析
Jan 04 PHP
浅析Yii2缓存的使用
May 10 PHP
php+jquery+html实现点击不刷新加载更多的实例代码
Aug 12 PHP
PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
Sep 11 PHP
thinkphp查询,3.X 5.0方法(亲试可行)
Jun 17 PHP
Yii2框架实现登录、退出及自动登录功能的方法详解
Oct 24 PHP
Laravel多用户认证系统示例详解
Mar 13 PHP
PHP正则表达式笔记与实例详解
May 09 PHP
Laravel 创建指定表 migrate的例子
Oct 09 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
php获取CSS文件中图片地址并下载到本地的方法
2014/12/02 PHP
php实现简单的权限管理的示例代码
2017/08/25 PHP
setTimeout与setInterval在不同浏览器下的差异
2010/01/24 Javascript
分享精心挑选的23款美轮美奂的jQuery 图片特效插件
2012/08/14 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
2012/09/20 Javascript
JS判定是否原生方法
2013/07/22 Javascript
jquery中html、val与text三者属性取值的联系与区别介绍
2013/12/29 Javascript
js验证输入是否为手机号码或电话号码示例
2013/12/30 Javascript
jquery单行文字向上滚动效果示例
2014/03/06 Javascript
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
2014/07/15 NodeJs
浅谈JavaScript中的Math.atan()方法的使用
2015/06/14 Javascript
javascript中使用new与不使用实例化对象的区别
2015/06/22 Javascript
ECMA5数组的新增方法有哪些及forEach()模仿实现
2015/11/03 Javascript
AngularJS 面试题集锦
2016/09/06 Javascript
使用AngularJS2中的指令实现按钮的切换效果
2017/03/27 Javascript
Vue.js 动态为img的src赋值方法
2018/03/14 Javascript
使用Vue动态生成form表单的实例代码
2018/04/26 Javascript
vue和webpack打包项目相对路径修改的方法
2018/06/15 Javascript
node中的session的具体使用
2018/09/14 Javascript
Angular2 自定义表单验证器的实现方法
2018/12/14 Javascript
详解使用angular框架离线你的应用(pwa指南)
2019/01/31 Javascript
9102年webpack4搭建vue项目的方法步骤
2019/02/20 Javascript
Vue 2.0 中依赖注入 provide/inject组合实战
2019/06/20 Javascript
如何实现vue的tree组件
2020/12/03 Vue.js
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
python判断图片宽度和高度后删除图片的方法
2015/05/22 Python
Python实现单词翻译功能
2017/06/06 Python
python笔记:mysql、redis操作方法
2017/06/28 Python
Python3安装Scrapy的方法步骤
2017/11/23 Python
Python cookbook(数据结构与算法)从字典中提取子集的方法示例
2018/03/22 Python
python 寻找list中最大元素对应的索引方法
2018/06/28 Python
《夜晚的实验》教学反思
2014/02/19 职场文书
《陋室铭》教学反思
2014/02/26 职场文书
干部下基层实施方案
2014/03/14 职场文书
法人单位授权委托书范文
2014/10/06 职场文书
公务员个人考察材料
2014/12/23 职场文书