天天看点

微信授权封装+微信系统告警通知

简要说明

本次主要说的是微信授权获取用户基本信息,还有就是日志反馈系统。利用微信自带的消息及时通知开发人员程序的报错。可达到快速收到问题解决问题,有助于建立一个可靠的风控体系

注意这里代码只有隐性授权 显性授权自己加上即可  原理一样

系统告警通知是使用的微信模板消息进行一个告警的通知

基本model   不同的框架稍微改改就可以直接用(如:缓存方法哪里需要自己根据自己框架特点进行改动)

<?php
/**
 *微信推送消息
 *by sqc 
 * 
 */
defined('InShopNC') or exit('Access Invalid!');

class wx_centerModel extends Model{

    protected $appid;  
    protected $secrect;  
    protected $accessToken;
    protected $redirect_uri;// 微信授权回调地址
    protected $code; // 微信授权code
    protected $o_access_token; // 微信授权access_token 注意:此access_token与基础支持的access_token不同
    protected $openid; // 微信授权openid
    protected $unionid; // 微信授权unionid
    //protected $GobackUrl; // 授权结束后返回用户界面的地址 弃
    protected $errors;

    function  __construct()  
    {  
        $this->appid = '********';  
        $this->secrect = '**************';
        
        // 测试 121科技号
        // $this->appid = '************';  
        // $this->secrect = '****************';
        // 第三个参数可用于多个公众号分别存储access_token使得与主号分离
        $this->accessToken = $this->getToken($this->appid, $this->secrect,'wx_access_token');  
    }

    /**
     * 设置参数
     *
     * @param mixed $key
     * @param mixed $value
     */
    public function set($key,$value){
        $this->$key = $value;
    }
    /**
     * 读取参数
     */
    public function get($key){
        return $this->$key;
    }

    /**
     * 隐性授权第一步:获取code
     * @return [type] [description]
     */
    public function silent_outh_step1(){
        var_dump($this->redirect_uri);
        if($this->redirect_uri){
            $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect_uri=".urlencode($this->redirect_uri)."&response_type=code&scope=snsapi_base&state=state#wechat_redirect";
            header('Location:'.$url);
        }else{
            return $this->error('微信授权回调地址参数丢失');
        }
        
    }

    /**
     * 隐性授权第2步:获取openid等信息  注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
     * @return 对象
     */
    public function silent_outh_step2(){
        $this->code = $this->code?$this->code:$_GET['code'];
        if($this->code){
            //第二步:通过code换取网页授权access_token
            $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->secrect}&code={$this->code}&grant_type=authorization_code";
            $res_json = $this->request_get($url);
            $res_arrone = json_decode($res_json, true); //转换为数组
            if($res_arrone['openid']){
                $this->openid = $res_arrone['openid'];
                $this->o_access_token = $res_arrone['access_token'];
                $this->unionid = $res_arrone['unionid'];// 这一步会有unionid 这是手册中没有的(2017.4.6)
            }else{
                $this->error($res_arrone);
            }
        }else{
            $this->error('没有获取到微信授权code');
        }
        return $this;
        
    }


    /**
     * 授权第3步:获取用户基本信息的  注意:这个是基于(这2个字省略了很多哦 可以到我博客上看)显性授权的
     * 需scope为 snsapi_userinfo
     * 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了
     * @return [type] [description]
     */
    public function outh_step3(){
        if($this->openid && $this->o_access_token){
            $get_userinfo_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$this->o_access_token}&openid={$this->openid}&;
            $userinfo_json = $this->request_get($get_userinfo_url);
            $userinfo = json_decode($userinfo_json, true); //转换为数组
            //判断授权是否成功
           if(empty($userinfo) || isset($userinfo['errcode'])){
                if(!$this->unionid){
                    return $this->error($userinfo);
                }
                $userinfo['unionid']=$this->unionid;
                $userinfo['openid']=$this->openid;
            }
            return $userinfo;
        }else{
            return $this->error('获取用户信息参数不全');
        }
        
    }

    /**
     * 获取用户基本信息(UnionID机制)  基于openid
     */
    public function get_user_info(){
        if($this->accessToken && $this->openid){
            $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$this->accessToken}&openid={$this->openid}&;
            $userinfo_json = $this->request_get($url);
            $userinfo = json_decode($userinfo_json, true); //转换为数组
            if(empty($userinfo) || isset($userinfo['errcode'])){
                if(!$this->unionid){
                    $userinfo['get_user_info'] =1;// 与outh_step3做区分
                    return $this->error($userinfo);
                }
                $userinfo['unionid']=$this->unionid;
                $userinfo['openid']=$this->openid;
            }
            return $userinfo;
        }else{
            return $this->error('accessToken或openid无法获取到');
        }
    }

    /** 
     * 发送post请求 
     * @param string $url 
     * @param string $param 
     * @return bool|mixed 
     */  
    protected function request_post($url = '', $param = '')  
    {  
        if (empty($url) || empty($param)) {  
            return false;  
        }  
        $postUrl = $url;  
        $curlPost = $param;  
        $ch = curl_init(); //初始化curl  
        curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定网页  
        curl_setopt($ch, CURLOPT_HEADER, 0); //设置header  
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上  
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);  
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
        curl_setopt($ch, CURLOPT_POST, 1); //post提交方式  
        curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);  
        $data = curl_exec($ch); //运行curl  
        curl_close($ch);  
        return $data;  
    }  
    /** 
     * 发送get请求 
     * @param string $url 
     * @return bool|mixed 
     */  
    protected function request_get($url = '')  
    {  
        if (empty($url)) {  
            return false;  
        }  
        $ch = curl_init();  
        curl_setopt($ch, CURLOPT_URL, $url);  
        curl_setopt($ch, CURLOPT_TIMEOUT, 500);  
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);  
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);  
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
        $data = curl_exec($ch);  
        curl_close($ch);  
        return $data;  
    }  
    /** 
     * @param $appid 
     * @param $appsecret 
     * @return mixed 
     * 获取token 
     */  
    public function getToken($appid, $appsecret,$name)
    {   
        $key =  $name?$name:$appid;
        $access_token_info = rkcache($key);
        $access_token_info = unserialize($access_token_info);
        if ($access_token_info['time']>TIMESTAMP) {  
            $access_token = $access_token_info['token'];  
        } else {  
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $appid . "&secret=" . $appsecret;  
            $token = $this->request_get($url);  
            $token = json_decode(stripslashes($token));  
            $arr = json_decode(json_encode($token), true);
            $access_token = $arr['access_token'];
            $cache_arr['token'] = $arr['access_token'];
            $cache_arr['time'] = TIMESTAMP + 7200;
            wkcache($key, serialize($cache_arr));  
        }  
        return $access_token;  
    }

    /**
     * 制作一个日志
     * @param  string $name 错误标题
     * @param  mid  $msg  错误描述 可以字符串 或 数组 数组只支持到2维
     * @param  string $type 错误级别
     *
     */
    public function make_log($name,$msg,$type='notice',$openid=''){
        $template_id ='DjyGuUbytYLKvEyQUxRRffsHIWYuErqrijovg6LZVd8';
        
        if(is_array($msg)){
            $tmp_msg = '';
            foreach ($msg as $k => $v) {
                $tmp_msg .=$k.':'.$v;
                if(is_array($v)){
                    $tmp_msg .=' ( ';
                    foreach ($v as $k2 => $v2) {
                        $tmp_msg .=$k2.'->'.$v2;
                    }
                    $tmp_msg .=' ) ';
                }
                $tmp_msg .='|||';
            }
            $msg = $tmp_msg;
        }
        $data=array(  
           'first'=>array('value'=>urlencode("商城组错误通知"),'color'=>"#00CD00"),  
           'keyword1'=>array('value'=>urlencode($name),'color'=>'#EE5C42'),  
           'keyword2'=>array('value'=>urlencode(date('Y-m-d H:i:s',TIMESTAMP)),'color'=>'#030303'),  
           'keyword3'=>array('value'=>urlencode($type),'color'=>'#EE9A00'),  
           'keyword4'=>array('value'=>urlencode($this->getClientIP()),'color'=>'#030303'),
           'keyword5'=>array('value'=>urlencode($msg),'color'=>'#EE4000'),
           'remark'=>array('value'=>urlencode('121商城组'),'color'=>'#030303'),  
        );
        if(!$openid){
            $log_m = Model('wx_log');
            $openids = $log_m->select();
            foreach ($openids as $ky => $ve) {
                if($ve['openid']){
                    $this->doSend_logInfo($ve['openid'],$template_id,'',$data);
                }
            }
            return true;
        }
       $wxmsgs = $this->doSend_logInfo($openid,$template_id,'',$data); 
    }
    /** 
     * 发送自定义的模板消息 
     * @param $touser 
     * @param $template_id 
     * @param $url 
     * @param $data 
     * @param string $topcolor 
     * @return bool 
     */  
    public function doSend_logInfo($touser, $template_id, $url, $data, $topcolor = '#7B68EE')  
    {  
        $template = array(  
            'touser' => $touser,  
            'template_id' => $template_id,  
            'url' => $url,  
            'topcolor' => $topcolor,  
            'data' => $data  
        );  
        $json_template = json_encode($template);  
        $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $this->accessToken;  
        $dataRes = $this->request_post($url, urldecode($json_template));
        $dataRes = json_decode(stripslashes($dataRes));  
        $dataRes = json_decode(json_encode($dataRes), true);
        if ($dataRes['errcode'] == 0) {  
            return true;  
        } else {  
            return false;  
        }  
    }

    private function getClientIP(){   
        if (getenv("HTTP_CLIENT_IP"))  
            $ip = getenv("HTTP_CLIENT_IP");  
        else if(getenv("HTTP_X_FORWARDED_FOR"))  
            $ip = getenv("HTTP_X_FORWARDED_FOR");  
        else if(getenv("REMOTE_ADDR"))  
            $ip = getenv("REMOTE_ADDR");  
        else $ip = "Unknow";  
        return $ip;  
    }
    /**
     * 返回用户错误信息
     * @return 返回值可以是josn或者是array
     */
    private function error($msg,$type = 'array'){
        switch ($type) {
            case 'array':
                $this->errors['error'][] = $msg;
                $this->make_log('微信授权系统',$msg,'notice');
                return $this->errors;
                break;
            
            default:
                # code...
                break;
        }
    }     
}
           

控制器总的授权调用

第一步

public function indexOp() {
        if(empty($_COOKIE['unionid'])){
            // 授权获取用户的unionid
            $this->check_back_url();
            // 开始调用授权
            $wx_model = Model('wx_center');
            $wx_model->set('redirect_uri',BASE_SITE_URL."/mobile/index.php?act=goods_wx&op=get_unionid");
            $wx_model->silent_outh_step1();
        }else{

            // 直接返回
            header('Location: '.$this->check_back_url());
            
        }
	}
           

第二步  $re = $wx_model->silent_outh_step2()->get_user_info(); 就是返回用户的基本信息

/**
     * 微信获取用户的信息
     */
    public function get_unionidOp() {
        $wx_model = Model('wx_center');
        $wx_model->set('code',$_GET['code']);
        $re = $wx_model->silent_outh_step2()->get_user_info();
        if(empty($re)||!$re['unionid']){
            echo '<meta charset="utf-8">';
            die('<center><h1>抱歉,您的网络超时,请稍后重试</h1></center>');
        }
        $_SESSION['my_userinfo'] = $re;
        setcookie("unionid",$re['unionid'],time()+365*3600*12,'/');
        header('Location: '.htmlspecialchars_decode(urldecode($_COOKIE['GobackUrl'])));die;
        
    }
           

告警消息的发送demo

$join_ceshi['商城告警测试'] = '成功成功';
 $join_ceshi['登陆错误'] = '10分钟多个注册导致系统故障';
$join_ceshi['订单告警'] = '10分钟内10000个下单';
$join_ceshi['下单错误'] = '参数错误';
$wx_model->make_log('这是一条测试数据',$join_ceshi,'notice',$re['openid']);
           

这个是我自己框架中model的调用 (逻辑处理model 类似于ThinkPHP中的大D方法)

$wx_model = Model('wx_center');
           

继续阅读