簡要說明
本次主要說的是微信授權擷取使用者基本資訊,還有就是日志回報系統。利用微信自帶的消息及時通知開發人員程式的報錯。可達到快速收到問題解決問題,有助于建立一個可靠的風控體系
注意這裡代碼隻有隐性授權 顯性授權自己加上即可 原理一樣
系統告警通知是使用的微信模闆消息進行一個告警的通知
基本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');