主页

PHP公众号客服发送消息

梦冥光   IP属地: 青海
0 点赞 0阅读 2001

前一段时间项目中遇到一个稍微麻烦一点的问题。

即客户要求,他在后台编辑好文章后要主动给每个用户都发送消息,并可以让用户点击直接进入文章页面。

于是乎,当时脑子一热,想着没什么大的问题,so easy。模板消息不就得了。

后来在写代码的过程中却发现,并不行。

微信公众号中模板消息有很严格的限制。

1.必须有用户主动触发事件方可发送模板消息

2.模板消息一分钟只能发送六十条,超过六十条,不好意思。你懂。

于是乎,就想到了另一种方法:群发消息

但是一看文档中群发消息的限制,发现悲催了

群发消息服务号每个月最多只能发送4条。

而客户要求的是随时随地就能发送.这个4条明显不符合要求的。

怎么办呢?一度陷入困难之中。只好继续查看开发文档。

当看到客服功能时,突然想到,能不能用客服主动给用户发送消息呢?

于是乎,想到就去试验下。

首先,先在公众号后台功能模块中-》添加功能模块  添加   客服功能   模块

如图所示:

然后就进入代码环节了。

先添加客服。也可以公众号后台添加

添加客服(可以通过)

//先添加客服
function addkf()
{
 $token = getToken();
 $url = 'https://api.weixin.qq.com/customservice/kfaccount/add?access_token='.$token;
 $data = '{
   "kf_account" : "system@system",
   "nickname" : "客服1",
   "password" : "admin",
 }';
 echo https_request($url,$data);
}

主动发送消息,直接调用sendmsg()方法使用

//获取access_token的方法。
function getToken()
{
 $appid = 'appid';
 $appsecret = 'appsecret';
 $token_file = dirname(dirname(__FILE__)).'/data/token.txt';
 if(!file_exists($token_file) || ((time() - filemtime($token_file)) > 7000)){
  $TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret;
  $json=file_get_contents($TOKEN_URL);
  $result=json_decode($json);
  $ACC_TOKEN=$result->access_token;
  file_put_contents($token_file,$ACC_TOKEN);
 }else{
  $ACC_TOKEN = file_get_contents($token_file);
 }
 return $ACC_TOKEN;
}
//调用发送方法
function sendmsg($content,$openid)
{
 $token = getToken();
 $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$token;
 $content = '感谢你的关注\n回复你厉害 \n例如<a href=\"http://www.baidu.com\">回复123456</a>';
 $data = '{
  "touser":"'.$openid.'",
  "msgtype":"text",
  "text":
  {
    "content":"'.$content.'"
  }
 }';
 https_request($url,$data);
 return true;
}
/**
 * request 请求
 */
function https_request($url, $data = null){
 $curl = curl_init();
 curl_setopt($curl, CURLOPT_URL, $url);
 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
 if (!empty($data)){
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
 }
 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 $output = curl_exec($curl);
 curl_close($curl);
 return $output;
}


效果如上图所示

公众号可以给用户发送消息,而且发送的内容你可以使用html 标签哦

虽然这样感觉很方便,但是同样,微信公众平台对此也有限制。

1.用户必须关注公众号,方可收到信息。

2.用户只能连续收到   20   条客服消息。超过后用户就收不到消息,

超过后,用户必须   主动给公众号发送消息  。或者  点击菜单栏,这样20条消息的限制就会重置

下面是我使用了三种主动推送的方法,第一种无效,请直接使用方法三(推荐使用方法三),方法二是必须用户在48小时内有与公众号有互动行为(用户有主动发送消息给公众号)才能发送成功,方法三则不需要


<?php
header("Content-type: text/html; charset=utf-8");
/*
调用方式简单说明:
 $arr = array(
    'account' => '公众平台帐号',
    'password' => '密码'
);
$w = new Weixin($arr);
$w->getAllUserInfo();//获取所有用户信息
$w->getUserInfo($groupid, $fakeid);//获取所有用户信息,如果默认分组,则$groupid传0
$w->sendMessage('群发内容'); //群发给所有用户
$w->sendMessage('群发内容',$userId); //群发给特定用户,这里的$userId就是用户的fakeid,数组方式传递
*/
class Weixin {
    public $userFakeid;//所有粉丝的fakeid
    private $_account='sm_i@163.com';//用户名
    private $_password='youxiuwxxxxxxxxx';//密码
    private $url;//请求的网址
    private $send_data;//提交的数据
    private $getHeader = 0;//是否显示Header信息
    private $token;//公共帐号TOKEN
    private $host = 'mp.weixin.qq.com';//主机
    private $origin = 'https://mp.weixin.qq.com';
    private $referer;//引用地址
    private $cookie;
    private $pageSize = 100000;//每页用户数(用于读取所有用户)
    private $userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0';
      //方法一
      //--------------------------下面代码无效了----------------------//
    public function __construct($options){
        $this->_account = isset($options['account'])?$options['account']:'';
        $this->_password = isset($options['password'])?$options['password']:'';
        $this->login();
    }
      
    //登录
    private function login(){
        $url = 'https://mp.weixin.qq.com/cgi-bin/bizlogin?lang=zh_CN&ajax=1&action=startlogin';
        $this->send_data = array(
            'username' => $this->_account,
            'pwd' => md5($this->_password),
            'f' => 'json'
        );
        $this->referer = "https://mp.weixin.qq.com/";
        $this->getHeader = 1;
        $result = explode("\n",$this->curlPost($url));
        foreach ($result as $key => $value) {
            $value = trim($value);
  
            if (preg_match('/Token=(\d+)/i', $value,$match))
            {
                //获取token
                $this->token = trim($match[1]);
            }
  
            if (preg_match('/"ret":(.*)/i', $value,$match)){//获取token
                switch ($match[1]) {
                    case -1:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"系统错误")));
                    case -2:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"帐号或密码错误")));
                    case -3:
                        die(urldecode(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>urlencode("密码错误")))));
                    case -4:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"不存在该帐户")));
                    case -5:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"访问受限")));
                    case -6:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"需要输入验证码")));
                    case -7:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"此帐号已绑定私人微信号,不可用于公众平台登录")));
                    case -8:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"邮箱已存在")));
                    case -32:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"验证码输入错误")));
                    case -200:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"因频繁提交虚假资料,该帐号被拒绝登录")));
                    case -94:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"请使用邮箱登陆")));
                    case 10:
                        die(json_encode(array('status'=>1,'errCode'=>$match[1],'msg'=>"该公众会议号已经过期,无法再登录使用")));
                    case 0:
                        $this->userFakeid = $this->getUserFakeid();
                        break;
                }
            }
            if(preg_match('/^Set-Cookie:[\s]+([^=]+)=([^;]+)/i', $value,$match)){//获取cookie
                $this->cookie .=$match[1].'='.$match[2].'; ';
            }
              
        }
    }
      
    //单发消息
    private function send($fakeid,$content){
        $url = 'https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response&lang=zh_CN';
        $this->send_data = array(
                'type' => 1,
                'f' => 'json',
                'action' => 'sync',
                'content' => $content,
                'tofakeid' => $fakeid,
                'token' => $this->token,
                'ajax' => 1,
            );
        $this->referer = 'https://mp.weixin.qq.com/cgi-bin/singlemsgpage?token='.$this->token.'&fromfakeid='.$fakeid.'&msgid=&source=&count=20&t=wxm-singlechat&lang=zh_CN';
        return $this->curlPost($url);
    }
      
    //群发消息
    public function sendMessage($content='',$userId='') {
        if(is_array($userId) && !empty($userId)){
            foreach($userId as $v){
                $json = json_decode($this->send($v,$content));
                if($json->ret!=0){
                    $errUser[] = $v;
                }
            }
        }else{
            foreach($this->userFakeid as $v){
                $json = json_decode($this->send($v['fakeid'],$content));
                if($json->ret!=0){
                    $errUser[] = $v['fakeid'];
                }
            }
        }
          
        //共发送用户数
        $count = count($this->userFakeid);
        //发送失败用户数
        $errCount = count($errUser);
        //发送成功用户数
        $succeCount = $count-$errCount;
          
        $data = array(
            'status'=>0,
            'count'=>$count,
            'succeCount'=>$succeCount,
            'errCount'=>$errCount,
            'errUser'=>$errUser
        );
          
        return json_encode($data);
    }
    //获取所有用户信息
    public function getAllUserInfo(){
        foreach($this->userFakeid as $v){
            $info[] = $this->getUserInfo($v['groupid'],$v['fakeid']);
        }
          
        return $info;
    }
      
      
      
    //获取用户信息
    public function getUserInfo($groupId,$fakeId){
        $url = "https://mp.weixin.qq.com/cgi-bin/getcontactinfo?t=ajax-getcontactinfo&lang=zh_CN&fakeid={$fakeId}";
        $this->getHeader = 0;
        $this->referer = 'https://mp.weixin.qq.com/cgi-bin/contactmanagepage?token='.$this->token.'&t=wxm-friend&lang=zh_CN&pagesize='.$this->pageSize.'&pageidx=0&type=0&groupid='.$groupId;
        $this->send_data = array(
            'token'=>$this->token,
            'ajax'=>1
        );
        $message_opt = $this->curlPost($url);
        return $message_opt;
    }
      
    //获取所有用户fakeid
    private function getUserFakeid(){
        ini_set('max_execution_time',600);
        $pageSize = 1000000;
        $this->referer = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token={$this->token}";
        $url = "https://mp.weixin.qq.com/cgi-bin/contactmanage?t=user/index&pagesize={$pageSize}&pageidx=0&type=0&groupid=0&token={$this->token}&lang=zh_CN";
        $user = $this->vget($url);
        $preg = "/\"id\":(\d+),\"nick_name\"/";
        preg_match_all($preg,$user,$b);
        $i = 0;
        foreach($b[1] as $v)
        {
            $arr[$i]['fakeid'] = $v;
            $arr[$i]['groupid'] = 0;
            $i++;
        }
        return $arr;
    }
  
    /**
     * curl模拟登录的post方法
     * @param $url request地址
     * @param $header 模拟headre头信息
     * @return json
     */
    private function curlPost($url) {
        $header = array(
            'Accept:*/*',
            'Accept-Charset:GBK,utf-8;q=0.7,*;q=0.3',
            'Accept-Encoding:gzip,deflate,sdch',
            'Accept-Language:zh-CN,zh;q=0.8',
            'Connection:keep-alive',
            'Host:'.$this->host,
            'Origin:'.$this->origin,
            'Referer:'.$this->referer,
            'X-Requested-With:XMLHttpRequest'
        );
        $curl = curl_init(); //启动一个curl会话
        curl_setopt($curl, CURLOPT_URL, $url); //要访问的地址
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header); //设置HTTP头字段的数组
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); //对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); //从证书中检查SSL加密算法是否存在
        curl_setopt($curl, CURLOPT_USERAGENT, $this->useragent); //模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); //使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); //自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); //发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $this->send_data); //Post提交的数据包
        curl_setopt($curl, CURLOPT_COOKIE, $this->cookie); //读取储存的Cookie信息
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); //设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, $this->getHeader); //显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //获取的信息以文件流的形式返回
        $result = curl_exec($curl); //执行一个curl会话
        curl_close($curl); //关闭curl
        return $result;
    }
      
    private function vget($url){ // 模拟获取内容函数
        $header = array(
                'Accept: */*',
                'Connection: keep-alive',
                'Host: mp.weixin.qq.com',
                'Referer: '.$this->referer,
                'X-Requested-With: XMLHttpRequest'
        );
          
        $useragent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0';
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header); //设置HTTP头字段的数组
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
        curl_setopt($curl, CURLOPT_USERAGENT, $useragent); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_HTTPGET, 1); // 发送一个常规的GET请求
        curl_setopt($curl, CURLOPT_COOKIE, $this->cookie); // 读取上面所储存的Cookie信息
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, $this->getHeader); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            // echo 'Errno'.curl_error($curl);
        }
        curl_close($curl); // 关闭CURL会话
        return $tmpInfo; // 返回数据

    }

//方法二

    //-----------------------以下代码是微信公众号主动发送消息给用户(必须48小时与公众号互动才可以)-----------------//
    public function httpRequest($url, $method="GET", $postfields = null, $headers = array(), $debug = false) {
        $method = strtoupper($method);
        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
        curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
        switch ($method) {
            case "POST":
                curl_setopt($ci, CURLOPT_POST, true);
                if (!empty($postfields)) {
                    $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
                }
                break;
            default:
                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
                break;
        }
        $ssl = preg_match('/^https:\/\//i',$url) ? TRUE : FALSE;
        curl_setopt($ci, CURLOPT_URL, $url);
        if($ssl){
            curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
            curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
        }
        //curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
        curl_setopt($ci, CURLOPT_FOLLOWLOCATION, FALSE);
        curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ci, CURLINFO_HEADER_OUT, true);
        /*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
        $response = curl_exec($ci);
        $requestinfo = curl_getinfo($ci);
        $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        if ($debug) {
            echo "=====post data======\r\n";
            var_dump($postfields);
            echo "=====info===== \r\n";
            print_r($requestinfo);
            echo "=====response=====\r\n";
            print_r($response);
        }
        curl_close($ci);
        return $response;
        //return array($http_code, $response,$requestinfo);
    }
    
     private function requestAndCheck($url, $method = 'GET', $fields = [])
 {
     $return = $this->httpRequest($url, $method, $fields);
     if ($return === false) {
        $this->error('http请求出错!');
         return false;
     }
     $wxdata = json_decode($return, true);
    //  $this->debug && $this->logDebugFile(['url' => $url,'fields' => $fields,'wxdata' => $wxdata]);
     if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
         if ($wxdata['errcode'] == 40001) {
             \think\Db::name('wx_user')->where('id', 1)->update(['web_expires' => 0]);//token错误
         }
         //$this->error('错误码'.$wxdata['errcode']);
         print_r('错误码'.$wxdata['errcode']);
         return false;
     }
 
     if (strtoupper($method) === 'GET' && empty($wxdata)) {
       $this->error('微信http请求返回为空!');
 
         return false;
     }
 
     return $wxdata;
 }
 
    public function nihao(){
     
     //  \think\Cache::connect($options);
     //  $jsapi = \think\Cache::get('acc');
     //  echo $jsapi;exit;
       
     
     
       $appid = 'wx474d0c9b54aab6a0';
       $appsecret = 'eb844c522a7d7054db97d1a4ffb392ce';
       $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret;
     
       $return = $this->requestAndCheck($url, 'GET');
       if ($return === false) {
           return false;
       }
       $web_expires = time() + 7000; // 提前200秒过期
       
       return $return['access_token'];
     
    }
    /*
     * 向用户推送消息
     */
    public function push_msg($openid='o-mmd6ojaoNYKWA8PzOJXSHvdWfc',$content='您好,这是标信后台发送'){
        $access_token = $this->nihao();
     
        $url ="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;
     
        $post_arr = array(
                        'touser'=>$openid,
                        'msgtype'=>'text',
                        'text'=>array(
                        'content'=>$content,
                            )
                        );
        $post_str = json_encode($post_arr,JSON_UNESCAPED_UNICODE);
        $return =  $this->requestAndCheck($url,'POST',$post_str);
        $return = json_decode($return,true);
     

    }

//方法三

    //-----------------------------------以下代码是公众号客服主动向用户发送消息-----------------------------//
    //先添加客服
    public function addkf()
    {
     $token = $this->getToken();
     $url = 'https://api.weixin.qq.com/customservice/kfaccount/add?access_token='.$token;
     print_r($url);
     $data = '{
       "kf_account" : "lbkj2017@gh_0f39f3ca77ac",
       "nickname" : "客服1",
     }';
     echo $this->https_request($url,$data);
    }
    //获取access_token的方法。
    public function getToken()
    {
        
        $appid = 'wx474d0c9b54aab6a0';
       $appsecret = 'eb844c522a7d7054db97d1a4ffb392ce';
     $token_file = dirname(dirname(__FILE__)).'/mobile/token.txt';
      
     if(!file_exists($token_file) || ((time() - filemtime($token_file)) > 7000)){
      $TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret;
      
      $json=file_get_contents($TOKEN_URL);
      $result=json_decode($json);
      $ACC_TOKEN=$result->access_token;
      file_put_contents($token_file,$ACC_TOKEN);
     }else{
      $ACC_TOKEN = file_get_contents($token_file);
     }
     
     return $ACC_TOKEN;
    }
    //调用发送方法
    public function sendmsg($content,$openid)
    {
     $token = $this->getToken();
     $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.$token;
     $content = '感谢你的关注\n回复你厉害 \n例如<a href=\"http://www.baidu.com\">回复123456</a>';
     $data = '{
      "touser":"'.$openid.'",
      "msgtype":"text",
      "text":
      {
        "content":"'.$content.'"
      }
     }';
     $this->https_request($url,$data);
     return true;
    }
    /**
     * request 请求
     */
    public function https_request($url, $data = null){
     $curl = curl_init();
     curl_setopt($curl, CURLOPT_URL, $url);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
     if (!empty($data)){
      curl_setopt($curl, CURLOPT_POST, 1);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
     }
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
     $output = curl_exec($curl);
     curl_close($curl);
     return $output;
    }
}

$arr = array( 'account' => 'sm_i@163.com', 'password' => 'youxiuwen198626' );
$w = new Weixin($arr);
//$sds=$w->getAllUserInfo();//获取所有用户信息
$openid = $_GET['openid'];
//$w->push_msg($openid)//主动发送消息
//$w->addkf($openid)//绑定客服
print_r($w->sendmsg('您好呀',$openid));
//$w->getUserInfo($groupid, $fakeid);//获取单个用户的信息,如果是默认组,则$groupid传0
?>
© 著作权归作者所有,转载或内容合作请联系作者