laravel 使用队列进行微信模板消息的群发

前置准备工作

框架:laravel 5.5

公众号:我的是服务号(需要营业执照申请,300一年)

PHP版本:7.1

需要自己配置好php环境,安装好redis

直接进入代码主题

php artisan make:controller Weixin\IndexController

创建好控制器Index,以下是代码 

<?php

namespace App\Http\Controllers\Weixin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Weixin;
use App\Jobs\SendMessage;
// use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\DB;
class IndexController extends Controller
{
    //接通微信,这是填在微信管理那边的url地址
    // http://域名/weixin/index 
    public function index()
    {
    	file_put_contents('1.txt', json_encode($_GET));
    	$signature = $_GET["signature"];
	    $timestamp = $_GET["timestamp"];
	    $nonce = $_GET["nonce"];
	    $echostr= $_GET["echostr"];
		
	    $token = 'omJNpZEhZeHj1ZxFECKkP48B5VFbk1HP';
	    $tmpArr = array($token, $timestamp, $nonce);
	    sort($tmpArr, SORT_STRING);
	    $tmpStr = implode( $tmpArr );
	    $tmpStr = sha1( $tmpStr );
	    
	    if( $tmpStr == $signature ){
	        echo $echostr;exit;
	    }else{
	        return false;
	    }
    }

    	//获取accesstoken
    	public function getAccessToken()
    	{
    		$appid = '自行填写自己公众号的';
    		$secret = '自行填写自己公众号的';
    		$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$secret;
    		$data = json_decode(self::curl($url),true);
    		// dd($data);
    		// $weixin = new Weixin;
    		$weixin = Weixin::find(1);
    		$weixin->accesstoken = $data['access_token'];
    		$weixin->update_time = time();
    		$weixin->expire_in = $data['expires_in'];

    		$weixin->save();
    	}
    	//获取模板列表
    	public function getTpl()
    	{

               $data = Weixin::find(1);
    		// dd($data['accesstoken']);
    		$url = 'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token='.$data['accesstoken'];
    		// dd($url);
    		$data = json_decode(self::curl($url),true);
    		dd($data);
    	}

    	//发送模板消息
    	public function send()
    	{
    		//方案一,直接mysql,然后foreach 然后,windows.localtion,进行每次的跳转,优势
//会一直执行,因为是同一个进程执行完当前的循环完成之后,又会继续跳转进入当前循环,直到数据跑完//位置
    		//方案二加入redis使用队列(这里主要写方案二)
    	
    		$openids = [
					 	'ogNMW570di2Bwqt3qfvnVKUJP5as','ogNMW58zn4bUxfIv614JOyevOxqw','ogNMW58gifjHQK1E-zH04A8xHx-g','ogNMW57ggKwBLAhi5QU-YBxHzabs','ogNMW5w27TF8HndZ6-B20ItrAUfk','ogNMW5zfGuvnWyxJjc-BRqQbjhnc','ogNMW58zn4bUxfIv614JOyevOxqw'];
    		// $openids = DB::select('select * from wxuser');
    		// dd($openids);
    		$param =  array(
    			'template_id'=>'-2ZZou72HPq8KrhX6w0MmDT4NEhIDd-Q6zs38P1h94M',
    	  		'data'=>array(
					'first'=>array('value'=>'您已经成为会员(功能测试)','color'=>'#173177'),
					'cardNumber'=>array('value'=>'1113','color'=>'#173177'),
					'address'=>array('value'=>'湖南省','color'=>'#173177'),
					'VIPName'=>array('value'=>'海峡','color'=>'#173177'),
					'VIPPhone'=>array('value'=>'17680311673','color'=>'#173177'),
					'expDate'=>array('value'=>'2020年10月30日','color'=>'#173177'),
					'remark'=>array('value'=>'请及时到店里来体验,谢谢合作,测试消息,不要在意哦','color'=>'#173177')));

    		foreach ($openids as $key => $value) 
    		{
    			$openid = array('touser'=>$value);
    			$param_s = json_encode(array_merge($openid,$param));
    

    			$job = new SendMessage($param_s);
    			$job->dispatch($job)->onQueue('message')->delay(3);
    			
    		}
    		

    	}

  

}

上面控制器的send方法是群发方法

我用的是redis驱动

.env文件的

QUEUE_DRIVER=redis 要写成redis 如果这里的QUEUE_DRIVER=sync 表示同步执行的代码,不会执行队列

QUEUE_DRIVER=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

开始队列的操作

我用的是redis,所以要安装扩展,直接项目根目录下执行就可以了,完事之后可以尝试用一下,如果报错就要自行找问题了

我报错是找不到这个扩展,我重启了一下服务器就好了

composer require predis/predis ~1.0

创建队列

php artisan make:job SendMessage

 会看到生成文件

SendMessage.php

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Weixin;

class SendMessage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public $param_s;
    // public $tries; //最大尝试次数默认无限制
    // public $timeout;//超时时间

   
    public function __construct($param_s)
    {
        
       
         $this->param_s = $param_s;
 
    }

    /**
     * Execute the job.1
     *
     * @return void
     */
    public function handle()
    {
        
        $params = $this->param_s->param_s;
        $res = $this->curl($url,$params,true);
        $res = json_decode($res,true);
        if($res['errcode']==0)
        {
            var_dump("发送成功");
        }
        else
        {
            var_dump("发送失败");
        }
       

    }
 /**
     * 任务失败的处理过程
     *
     * @param  Exception  $exception
     * @return void
     */


    /**
     * 处理一个失败的任务
     *
     * @return void
     */
    public function failed(Exception $exception)
    {
        \Log::error('队列任务执行失败'."\n".date('Y-m-d H:i:s'));
    }


      /**
     * @param $url 请求网址
     * @param bool $params 请求参数
     * @param int $ispost 请求方式
     * @param int $https https协议
     * @return bool|mixed
     */
    public static function curl($url, $params = false, $ispost = 0, $https = 0)
    {
        $httpInfo = array();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($https) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
        }
        if ($ispost) {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
            curl_setopt($ch, CURLOPT_URL, $url);
        } else {
            if ($params) {
                if (is_array($params)) {
                    $params = http_build_query($params);
                }
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }

        $response = curl_exec($ch);

        if ($response === FALSE) {
            //echo "cURL Error: " . curl_error($ch);
            return false;
        }
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
        curl_close($ch);
        return $response;
    }
}

 使用方法:先添加route  

Route::group(['prefix'=>'weixin','namespace'=>'Weixin'],function()
{
	Route::get('index','IndexController@index');
	Route::get('gettoken','IndexController@getAccessToken');
	Route::get('gettpl','IndexController@getTpl');
	Route::get('send','IndexController@send');

});

访问send http://域名/weixin/send 

返回添加成功。

然后在服务器终端项目目录输入

php artisan queue:work redis --queue=message

因为我用的是redis所以在执行队列的时候加入了redis 参数,然后 --queue=message 是我队列的名字,如果有多个对列,就能进行区分进行队列的优先级先用谁。

                $job->dispatch($job)->onQueue('message')->delay(3);
在之前我写了这个onQueue这里,delay是说队列延时多久,单位是秒

然后队列会了就可以做很多东西,这里只是抛砖引玉。

防踩坑指南!防踩坑指南!防踩坑指南!

注意看我的参数 

这是我传参数进队列的地方  $job = new SendMessage($param_s);

队列那边首先在上面定义,然后在构造方法写好,然后获取参数是

$params = $this->param_s;这样写获取的值会把 param_s作为一个键名

所以获取是  $params = $this->param_s->param_s;这样才能获取到想要的值

然后:代码只要有修改,先停止服务器队列crtl+c就行,一定要先停止,改完代码,添加队列,再开始执行队列。流程就是 生产队列,消费队列。然后redis队列就是先进先出。

测试了一下数据,我有个表是35000的id 跑完花了大概1分58秒左右。但是微信那边的推送不是百分之百的,这个和微信有关系,或多或少会有偏差,比如有的用户长期不和公众号活跃,收不到推送消息,但是当取关再次关注之后就会收到消息

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值