上次写了一篇微信模版消息推送,但是不知道怎么异步推送。导致要等它推送完几百条才能关闭网页。
然后请教了大神,和自己摸索,在此记录。
1、推送页,推送到另一个文件处理微信推送,使用fsockopen。一次性推送,不保存数据库,有需要自己改。
$data = input('post.');//前台传过来的值,组装模版使用。
$host = $_SERVER['HTTP_HOST'];//域名
$path = '/admin/send/index';//异步推送到这个文件,在这个文件里面处理推送。
$data = http_build_query($data);
//$data = json_encode($data,JSON_UNESCAPED_UNICODE);
$fp = fsockopen($host, 80, $error, $errstr, 1);
$http = "POST $path HTTP/1.1\r\nHost: $host\r\nContent-type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($data) . "\r\nConnection:close\r\n\r\n$data\r\n\r\n";
fwrite($fp, $http);
//实现异步把下面注释掉,意思是不处理返回
// $receive = '';
// while (!feof($fp)) {
// $receive .= fgets($fp, 128);
// }
// echo "<br />".$receive;
//连接主动断开时,线上proxy层没有及时把请求发给上游
fclose($fp);
return json(['code' => 1, 'msg' => '推送完成!', 'url' => url('notive/send')]);
2、异步处理页,实际上这里再一次使用fsockopen。
<?php
namespace app\admin\controller;
use think\facade\Request;
class Send
{
public function index()
{
$data = input('post.');//这个是fscokopen推送过来的data。
$value = db('wx_config')->where([ 'key' => 'SHOPWCHAT'])->value('value');
$value = json_decode($value,true);
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$value['appid']."&secret=".$value['appsecret'];
if (cookie('access_token')){
$access_token=cookie('access_token');
}else{
$cont = json_decode($this->getToken($url));
$access_token=$cont->access_token;
setcookie('access_token',$access_token,7200);
}//获取access_token
$all = $this->get_allopenid($access_token);//获取关注的用户,因为只能推送关注的用户。
$openids = $all['data']['openid'];//关注用户的openID
foreach ($openids as $key => $value) {
if (db('users')->where('openid',$value)->value('unsub') == '1'){
unset($openids[$key]);
}
}
$openids = array_values($openids);//这里是筛选没有退订的用户,并重新排序键值对。这些推送最好是可以退订的,不然用户举报可能会封号哦。我是根据用户回复“退订”关键词来标记的。这一步是有必要的。
foreach ($openids as $key => $value) {
$params = json_encode($this->json_tempalte($value,$data),JSON_UNESCAPED_UNICODE);
$fp = fsockopen('api.weixin.qq.com', 80, $error, $errstr, 1);
$http = "POST /cgi-bin/message/template/send?access_token={$access_token} HTTP/1.1\r\nHost: api.weixin.qq.com\r\nContent-type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($params) . "\r\nConnection:close\r\n\r\n$params\r\n\r\n";
fwrite($fp, $http);
fclose($fp);
sleep(1);
}//这里就是遍历推送到各个openID了、sleep(1)是为了防止推送过快出问题。
return ture;
}
function getToken($url) {//这个方法是获取access_token
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko)");
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
function get_allopenid($access_token,$next_openid = ''){//这个方法是获取所有关注的用户的
$url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={$access_token}&next_openid=".$next_openid;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
$data = curl_exec($ch);
$data = json_decode($data,true);
if ($data["count"] == 10000){
$newdata = $this->get_allopenid($access_token,$data["next_openid"]);
$data["data"]["openid"] = array_merge_recursive($date["data"]["openid"], $newdata["data"]["openid"]);
}
return $data;
}
function json_tempalte($openid,$data,$template_id = 'DtlkLjhNf5p5P7kYorbm-6kop3zlSyct1wL70fuJ8ME'){//这里是组装模版消息的方法
$template=array(
'touser'=>$openid,
'template_id'=>$template_id,//这个是模版ID,获取方法自己看文档很详细。
'url'=>$data['url'],
'topcolor'=>"#7B68EE",
'data'=>array(
'first'=>array('value'=>$data['first'],'color'=>"#000"),
'keyword1'=>array('value'=>$data['keyword1'],'color'=>'#F70997'),
'keyword2'=>array('value'=>$data['keyword2'],'color'=>'#248d24'),
'keyword3'=>array('value'=>date("Y-m-d H:i:s"),'color'=>'#000'),
'remark' =>array('value'=>$data['remark'],'color'=>'#1784e8'), )
);
return $template;
}
}