前置准备工作
框架: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秒左右。但是微信那边的推送不是百分之百的,这个和微信有关系,或多或少会有偏差,比如有的用户长期不和公众号活跃,收不到推送消息,但是当取关再次关注之后就会收到消息