天天看點

微信授權封裝+微信系統告警通知

簡要說明

本次主要說的是微信授權擷取使用者基本資訊,還有就是日志回報系統。利用微信自帶的消息及時通知開發人員程式的報錯。可達到快速收到問題解決問題,有助于建立一個可靠的風控體系

注意這裡代碼隻有隐性授權 顯性授權自己加上即可  原理一樣

系統告警通知是使用的微信模闆消息進行一個告警的通知

基本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');
           

繼續閱讀