469 lines
18 KiB
PHP
469 lines
18 KiB
PHP
<?php
|
||
// 微信公众号基础类 需要安装redis
|
||
//杨星宇 除微信登录 微信支付
|
||
define("TOKEN", "mytoken");
|
||
class Wechatpush{
|
||
|
||
public $appid;
|
||
public $secret;
|
||
public $access_token;
|
||
|
||
function __construct($appid,$secret){
|
||
$this->appid = $appid;
|
||
$this->secret = $secret;
|
||
$this->valid();
|
||
$this->getaccess_token();
|
||
}
|
||
|
||
public function valid(){ //验证token
|
||
$echoStr = input('echostr');
|
||
if($this->checkSignature()){
|
||
echo $echoStr;
|
||
//exit;
|
||
}
|
||
}
|
||
|
||
private function checkSignature(){ //验证token
|
||
$signature = input("signature");
|
||
$timestamp = input("timestamp");
|
||
$nonce = input("nonce");
|
||
$token = TOKEN;
|
||
$tmpArr = array($token, $timestamp, $nonce);
|
||
sort($tmpArr);
|
||
$tmpStr = implode( $tmpArr );
|
||
$tmpStr = sha1( $tmpStr );
|
||
|
||
if( $tmpStr == $signature ){
|
||
return true;
|
||
}else{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
public function getaccess_token(){ //获取access_token 用redis来做中间token存储
|
||
$redis = new \Redis();
|
||
$redis->connect('127.0.0.1',6379);
|
||
$token = $redis->get($this->appid);
|
||
if($token){
|
||
$this->access_token = $token;
|
||
}else{
|
||
$token_access_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $this->appid . "&secret=" . $this->secret;
|
||
$res = file_get_contents($token_access_url); //获取文件内容或获取网络请求的内容
|
||
$result = json_decode($res, true); //接受一个 JSON 格式的字符串并且把它转换为 PHP 变量
|
||
if(isset($result['access_token'])){
|
||
//把access_token存入redis用 access_token expires_in 过期时间 来做过期时间
|
||
$result['expires_in'] = 3600;
|
||
$redis->setex($this->appid,$result['expires_in'],$result['access_token']);
|
||
$this->access_token = $result['access_token'];
|
||
}else{
|
||
$this->access_token = '';
|
||
}
|
||
}
|
||
}
|
||
|
||
//获取粉丝openid 一次最多拉取 1万条
|
||
public function getopenid(){
|
||
$url ="https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->access_token;
|
||
$result = $this->https_request($url);
|
||
$info = json_decode($result,true);
|
||
if(isset($info['data'])){
|
||
$users = $info['data']['openid'];
|
||
}else{
|
||
$users = null;
|
||
}
|
||
return $users;
|
||
}
|
||
|
||
//获取所有全部粉丝openid 一次最多拉取 1万条 需要多次拉取 next_openid=列表最后一个openid
|
||
public function getopenidall($nextid=null){
|
||
$next_openid = empty($nextid)?null:"&next_openid=".$nextid;
|
||
$url ="https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$this->access_token.$next_openid;
|
||
$result = $this->https_request($url);
|
||
$info = json_decode($result,true);
|
||
if(isset($info['data'])){
|
||
$users = $info['data']['openid'];
|
||
$endid = $info['next_openid'];
|
||
}else{
|
||
$users = null;
|
||
$endid = null;
|
||
}
|
||
$openidArr = array(
|
||
'users'=>$users,
|
||
'endid'=>$endid
|
||
);
|
||
return $openidArr;
|
||
}
|
||
|
||
//创建底部菜单 注意菜单名称如果是数组转json 需要 urlencode() 汉字 打包后 在解码
|
||
public function wechatnav($arr){
|
||
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$this->access_token;
|
||
$jsondata = urldecode(json_encode($arr));
|
||
$ch = curl_init(); //创建一个请求
|
||
curl_setopt($ch,CURLOPT_URL,$url); //设置请求的url
|
||
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); // 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
|
||
curl_setopt($ch,CURLOPT_POST,1); //启用时会发送一个常规的POST请求,类型为:application/x-www-form-urlencoded,就像表单提交的一样
|
||
curl_setopt($ch,CURLOPT_POSTFIELDS,$jsondata); //全部数据使用HTTP协议中的"POST"操作来发送。要发送文件,在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似'para1=val1¶2=val2&...'或使用一个以字段名为键值,字段数据为值的数组。如果value是一个数组,Content-Type头将会被设置成multipart/form-data。
|
||
$output = curl_exec($ch); //执行请求
|
||
curl_close($ch); //关闭资源
|
||
return $output;
|
||
}
|
||
|
||
//查看底部菜单
|
||
public function getwechatnav(){
|
||
$url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=".$this->access_token;
|
||
$data = $this->getHttp($url);
|
||
return $data;
|
||
}
|
||
|
||
public function deletenav(){ //删除底部菜单
|
||
return file_get_contents("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=".$this->access_token);
|
||
}
|
||
|
||
//被动回复图文消息 注意:Xml里面不能有编辑器换行或者空格 严格要求官方数据格式
|
||
//只能关注回复才能使用高级素材模式 否则会自动转成客服消息图文模式
|
||
public function transmitNews($object,$newsArray){
|
||
if(!is_array($newsArray)){
|
||
return "";
|
||
}
|
||
$itemTpl = "<item>
|
||
<Title><![CDATA[%s]]></Title>
|
||
<Description><![CDATA[%s]]></Description>
|
||
<PicUrl><![CDATA[%s]]></PicUrl>
|
||
<Url><![CDATA[%s]]></Url>
|
||
</item>";
|
||
$item_str = "";
|
||
foreach ($newsArray as $item){
|
||
$item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
|
||
}
|
||
$xmlTpl = "<xml>
|
||
<ToUserName><![CDATA[%s]]></ToUserName>
|
||
<FromUserName><![CDATA[%s]]></FromUserName>
|
||
<CreateTime>%s</CreateTime>
|
||
<MsgType><![CDATA[news]]></MsgType>
|
||
<ArticleCount>%s</ArticleCount>
|
||
<Articles>
|
||
$item_str
|
||
</Articles>
|
||
</xml>";
|
||
|
||
$result = sprintf($xmlTpl, $object['FromUserName'], $object['ToUserName'], time(), count($newsArray));
|
||
echo $result;
|
||
}
|
||
|
||
//被动回复文本消息 注意:Xml里面不能有编辑器换行或者空格 严格要求官方数据格式
|
||
public function transmitText($object,$content){
|
||
if (!isset($content) || empty($content)){
|
||
return "";
|
||
}
|
||
$xmlTpl = "<xml>
|
||
<ToUserName><![CDATA[%s]]></ToUserName>
|
||
<FromUserName><![CDATA[%s]]></FromUserName>
|
||
<CreateTime>%s</CreateTime>
|
||
<MsgType><![CDATA[%s]]></MsgType>
|
||
<Content><![CDATA[%s]]></Content>
|
||
</xml>";
|
||
$result = sprintf($xmlTpl, $object['FromUserName'], $object['ToUserName'], time(),'text',$content);
|
||
echo $result;
|
||
}
|
||
|
||
|
||
//关注回复发送图片
|
||
public function transmitImage($object,$mediaId){
|
||
if (!isset($mediaId) || empty($mediaId)){
|
||
return "";
|
||
}
|
||
$xmlTpl = "<xml>
|
||
<ToUserName><![CDATA[%s]]></ToUserName>
|
||
<FromUserName><![CDATA[%s]]></FromUserName>
|
||
<CreateTime>%s</CreateTime>
|
||
<MsgType><![CDATA[%s]]></MsgType>
|
||
<Image>
|
||
<MediaId><![CDATA[%s]]></MediaId>
|
||
</Image>
|
||
</xml>";
|
||
$result = sprintf($xmlTpl, $object['FromUserName'], $object['ToUserName'], time(),'image',$mediaId);
|
||
echo $result;
|
||
}
|
||
|
||
//推送模板消息
|
||
public function pushTemplate($openids=array(),$data=array()){
|
||
$touser = $openids;
|
||
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $this->access_token;
|
||
foreach ($touser as $value) {
|
||
$datapush = $this->getDataTemplateArray($value,$data);
|
||
$json_data = json_encode($datapush);//转化成json数组让微信可以接收
|
||
$res = $this->https_request($url, urldecode($json_data));//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode'] == 0 && $res['errcode'] == "ok"){
|
||
return 1;
|
||
}else{
|
||
return $res['errcode'];
|
||
}
|
||
}
|
||
}
|
||
|
||
//获取发送模板消息数据数组
|
||
public function getDataTemplateArray($openid,$data){
|
||
$data = array(
|
||
'touser' => $openid, //单个openid
|
||
'template_id' => $data['template'],
|
||
'url' => $data['link'],
|
||
'data' => array(
|
||
'first' => array(
|
||
'value' => $data['title'],
|
||
'color' => "#000"
|
||
),
|
||
'keyword1' => array(
|
||
'value' => $data['keyword1'],
|
||
'color' => $data['color2']
|
||
),
|
||
'keyword2' => array(
|
||
'value' => $data['keyword2'],
|
||
'color' => "#000"
|
||
),
|
||
'remark' => array(
|
||
'value' => $data['remark'],
|
||
'color' => $data['color3']
|
||
),
|
||
)
|
||
);
|
||
return $data;
|
||
}
|
||
|
||
|
||
public function getDataArrayKefu($value,$link){ //获取发送数据数组 发送文本客服消息
|
||
$data = array(
|
||
'touser' => $value, //要发送给用户的openid
|
||
'msgtype'=>'text',
|
||
'text' => array(
|
||
'content' =>$link
|
||
)
|
||
);
|
||
return $data;
|
||
}
|
||
|
||
public function getDataArrayKefuImg($value,$title,$description,$url,$imgurl){ //获取发送数据数组 发送图文客服消息
|
||
$data = '{
|
||
"touser":"'.$value.'",
|
||
"msgtype":"news",
|
||
"news":{
|
||
"articles": [
|
||
{
|
||
"title":"'.$title.'",
|
||
"description":"'.$description.'",
|
||
"url":"'.$url.'",
|
||
"picurl":"'.$imgurl.'"
|
||
}
|
||
]
|
||
}
|
||
}';
|
||
return $data;
|
||
}
|
||
|
||
//发送文本客服消息 text 需要urlencode编码一下
|
||
public function kefu($openids=array(),$text){
|
||
$touser = $openids;
|
||
$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=". $this->access_token;
|
||
foreach ($touser as $value) {
|
||
$data = $this->getDataArrayKefu($value,$text);
|
||
$json_data = json_encode($data);//转化成json数组让微信可以接收
|
||
$res = $this->https_request($url, urldecode($json_data));//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode'] == 0 && $res['errcode'] == "ok"){
|
||
return '发送成功';
|
||
}else{
|
||
var_dump($res);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 发送图文客服消息 openid 标题 描述 外链地址 图片地址
|
||
public function kefuImg($openids=array(),$title,$description,$linkurl,$imgurl){
|
||
$touser = $openids;
|
||
$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=". $this->access_token;
|
||
foreach ($touser as $value) {
|
||
$data = $this->getDataArrayKefuImg($value,$title,$description,$linkurl,$imgurl);
|
||
$res = $this->https_request($url, $data);//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode'] == 0 && $res['errcode'] == "ok"){
|
||
return '发送成功';
|
||
}else{
|
||
var_dump($res);
|
||
}
|
||
}
|
||
}
|
||
|
||
//curl请求函数,微信都是通过该函数请求
|
||
public function https_request($url, $data = null){
|
||
$curl = curl_init(); //创建请求
|
||
curl_setopt($curl, CURLOPT_URL, $url); //设置请求的URL
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);//禁用后cURL将终止从服务端进行验证。使用CURLOPT_CAINFO选项设置证书使用CURLOPT_CAPATH选项设置证书目录 如果CURLOPT_SSL_VERIFYPEER(默认值为2)被启用,CURLOPT_SSL_VERIFYHOST需要被设置成TRUE否则设置为FALSE。
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);//1 检查服务器SSL证书中是否存在一个公用名(common name)。译者注:公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。2 检查公用名是否存在,并且是否与提供的主机名匹配
|
||
if (!empty($data)) {
|
||
curl_setopt($curl, CURLOPT_POST, 1); //设置为POST
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);//传递一个数组到CURLOPT_POSTFIELDS,cURL会把数据编码成 multipart/form-data,而然传递一个URL-encoded字符串时,数据会被编码成 application/x-www-form-urlencoded
|
||
}
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);//在启用CURLOPT_RETURNTRANSFER的时候,返回原生的(Raw)输出。
|
||
$output = curl_exec($curl);//设置OK
|
||
curl_close($curl);
|
||
return $output;
|
||
}
|
||
|
||
// get请求
|
||
public function getHttp($url,$post_data=array()) {
|
||
$ch = curl_init($url);
|
||
$timeout = 6000;
|
||
curl_setopt($ch, CURLOPT_POST, 1);
|
||
curl_setopt($ch, CURLOPT_HEADER,0 );
|
||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
|
||
$ret = curl_exec($ch);
|
||
curl_close($ch);
|
||
return $ret;
|
||
}
|
||
|
||
|
||
// 以下是高级群发 素材管理
|
||
|
||
// 上传图片 返回media_id
|
||
public function uploadImage($file,$type='image'){
|
||
$data = array('media' => new \CURLFile(realpath($file)));
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token='.$this->access_token.'&type='.$type;
|
||
$res = $this->https_request($url,$data);//请求开始
|
||
$res = json_decode($res, true);
|
||
if (isset($res['errcode'])){
|
||
return 0;
|
||
}else{
|
||
return $res['media_id'];
|
||
}
|
||
}
|
||
|
||
// 上传图文消息内的图片获取URL $file 必须服务器绝对路径
|
||
public function getimg($file){
|
||
$data = array('media' => new \CURLFile(realpath($file)));
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token='.$this->access_token;
|
||
$res = $this->https_request($url,$data);//请求开始
|
||
$res = json_decode($res, true);
|
||
if (isset($res['errcode'])){
|
||
return 0;
|
||
}else{
|
||
return $res['url'];
|
||
}
|
||
}
|
||
|
||
// 上传图文素材 返回素材的media_id
|
||
// 注意素材里的 文本需要 urlencode 编码 打包json后在 urldecode 数据才正确
|
||
// 编辑器里的文本需要 urlencode + htmlspecialchars(str_replace("\"", "'", $data['content'])) 然后 urldecode + htmlspecialchars_decode
|
||
// $data = 2维数组(必须)
|
||
public function upMaterial($data){
|
||
// $url = 'https://api.weixin.qq.com/cgi-bin/material/add_news?access_token='.$this->access_token;
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/draft/add?access_token='.$this->access_token;
|
||
$news = array();
|
||
$news['articles'] = $data;
|
||
$news = json_encode($news);
|
||
$news = urldecode($news);
|
||
$news = htmlspecialchars_decode($news);
|
||
$res = $this->https_request($url,$news);//请求开始
|
||
$res = json_decode($res, true);
|
||
if (isset($res['errcode'])){
|
||
return null;
|
||
}else{
|
||
return $res['media_id'];
|
||
}
|
||
|
||
}
|
||
|
||
// 修改已经上传的图文素材 当个栏目修改
|
||
// 注意素材里的 文本需要 urlencode 编码 打包json后在 urldecode 数据才正确
|
||
// 编辑器里的文本需要 urlencode + htmlspecialchars(str_replace("\"", "'", $data['content'])) 然后 urldecode + htmlspecialchars_decode
|
||
// 正确时errcode的值应为0 $data = 一维数组 $media_id = 素材ID $index = 栏目所在素材位置
|
||
public function renewNews($data,$media_id,$index){
|
||
// $url = 'https://api.weixin.qq.com/cgi-bin/material/update_news?access_token='.$this->access_token;
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/draft/update?access_token='.$this->access_token;
|
||
$news = array(
|
||
"media_id"=>$media_id,
|
||
"index"=>$index,
|
||
"articles"=>$data
|
||
);
|
||
$news = json_encode($news);
|
||
$news = urldecode($news);
|
||
$news = htmlspecialchars_decode($news);
|
||
$res = $this->https_request($url,urldecode($news));//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode']==0){
|
||
return 1;
|
||
}else{
|
||
return $res;
|
||
}
|
||
}
|
||
|
||
// 删除图文模板
|
||
public function delmd($media_id){
|
||
// $url = 'https://api.weixin.qq.com/cgi-bin/material/del_material?access_token='.$this->access_token;
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/draft/delete?access_token='.$this->access_token;
|
||
$data = array('media_id'=>$media_id);
|
||
$data = json_encode($data);
|
||
$res = $this->https_request($url,$data);//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode']==0){
|
||
return 1;
|
||
}else{
|
||
return $res;
|
||
}
|
||
}
|
||
|
||
// 测试高级群发
|
||
public function ceshiPush($openid,$media_id){
|
||
$this->valid();
|
||
$this->getaccess_token();
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token='.$this->access_token;
|
||
$data = '{
|
||
"touser":"'.$openid.'",
|
||
"mpnews":{
|
||
"media_id":"'.$media_id.'"
|
||
},
|
||
"msgtype":"mpnews"
|
||
}';
|
||
$res = $this->https_request($url,$data);//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode']==0){
|
||
return '发送成功';
|
||
}else{
|
||
return $res['errmsg'];
|
||
}
|
||
}
|
||
|
||
// 开始高级群发 $openids = 一维数组 $media_id = 素材ID
|
||
public function advancedPush($openids,$media_id){
|
||
$url = 'https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token='.$this->access_token;
|
||
$openid = json_encode($openids);
|
||
$news = '{
|
||
"touser":'.$openid.',
|
||
"mpnews":{
|
||
"media_id":"'.$media_id.'"
|
||
},
|
||
"msgtype":"mpnews",
|
||
"send_ignore_reprint":1,
|
||
"is_to_all":"true"
|
||
}';
|
||
$res = $this->https_request($url,$news);//请求开始
|
||
$res = json_decode($res, true);
|
||
if ($res['errcode']==0){
|
||
return 1;
|
||
}else{
|
||
return $res['errmsg'];
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
?>
|