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 相关文章推荐
如何使用PHP中的字符串函数
Oct 09 PHP
防止本地用户用fsockopen DDOS攻击对策
Nov 02 PHP
PHP对表单提交特殊字符的过滤和处理方法汇总
Feb 18 PHP
PHP实现把MySQL数据库导出为.sql文件实例(仿PHPMyadmin导出功能)
May 10 PHP
PHP获取当前页面URL函数实例
Oct 22 PHP
ioncube_loader_win_5.2.dll的错误解决方法
Jan 04 PHP
Docker 如何布置PHP开发环境
Jun 21 PHP
yii2缓存Caching基本用法示例
Jul 18 PHP
PHP 芝麻信用接入的注意事项
Dec 01 PHP
Zend Framework入门应用实例详解
Dec 11 PHP
php实现基于pdo的事务处理方法示例
Jul 21 PHP
PHP简单实现二维数组的矩阵转置操作示例
Nov 24 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使用curl存储cookie的示例
2014/03/31 PHP
Linux系统下php获得系统分区信息的方法
2015/03/30 PHP
分享3个php获取日历的函数
2015/09/25 PHP
PHP函数超时处理方法
2016/02/14 PHP
PHP+JS实现的商品秒杀倒计时用法示例
2016/11/15 PHP
php变量与数组相互转换的方法(extract与compact)
2016/12/02 PHP
ThinkPHP5.0多个文件上传后找不到临时文件的修改方法
2018/07/30 PHP
对laravel in 查询的使用方法详解
2019/10/09 PHP
javascript 触发事件列表 比较不错
2009/09/03 Javascript
禁止JQuery中的load方法装载IE缓存中文件的方法
2009/09/11 Javascript
dreamweaver 安装Jquery智能提示
2011/04/02 Javascript
ASP.NET jQuery 实例16 通过控件CustomValidator验证RadioButtonList
2012/02/03 Javascript
js判断生效时间不得大于失效时间的思路及代码
2013/04/23 Javascript
jQuery当鼠标悬停时放大图片的效果实例
2013/07/03 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
javascript将url中的参数加密解密代码
2014/11/17 Javascript
jQuery Chart图表制作组件Highcharts用法详解
2016/06/01 Javascript
jQuery实现每隔几条元素增加1条线的方法
2016/06/27 Javascript
强大Vue.js组件浅析
2016/09/12 Javascript
node.js学习之断言assert的使用示例
2017/09/28 Javascript
Vue.js中的computed工作原理
2018/03/22 Javascript
获取layer.open弹出层的返回值方法
2018/08/20 Javascript
教你使用vue-cli快速构建的小说阅读器
2019/05/13 Javascript
判断js数据类型的函数实例详解
2019/05/23 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
[04:16]DOTA2全国高校联赛16强抽签
2018/05/02 DOTA
python 上下文管理器使用方法小结
2017/10/10 Python
pygame实现飞机大战
2020/03/11 Python
Python爬虫爬取新闻资讯案例详解
2020/07/14 Python
迷你唐卡软皮鞋:Minnetonka Moccasin
2018/05/01 全球购物
总经理秘书岗位职责
2014/03/17 职场文书
出生公证书样本
2014/04/04 职场文书
2014年党务工作总结
2014/11/25 职场文书
毕业设计致谢词
2015/05/14 职场文书
创业计划书之个人工作室
2019/08/22 职场文书
python单向链表实例详解
2022/05/25 Python