一.入口文件 用于验证token (对应微信公众号服务器配置)
<?php
traceHttp();
//1、将token、timestamp、nonce三个参数进行字典序排序
$token = 'yangzhenhua';
$timestamp = $_GET['timestamp'];
$nonce = $_GET['nonce'];
$signature = $_GET['signature'];
$echostr = $_GET['echostr'];
$array = array($token, $timestamp, $nonce);
sort($array);
//2、将三个参数字符串拼接成一个字符串进行sha1加密
$tmp_str = implode('', $array);
$tmp_str = sha1($tmp_str);
//3、开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if($tmp_str == $signature && $echostr)
{
echo $echostr;
exit();
}
else
{
//调用微信事件类
$jjb_wx_script_class = new JJbWxScriptClass();
echo $jjb_wx_script_class->responseScript();
}
function traceHttp()
{
logger("\n\nREMOTE_ADDR:".$_SERVER["REMOTE_ADDR"].(strstr($_SERVER["REMOTE_ADDR"],'101.226')? " FROM WeiXin": "Unknown IP"));
logger("QUERY_STRING:".$_SERVER["QUERY_STRING"]);
}
function logger($log_content)
{
if(isset($_SERVER['HTTP_APPNAME'])){ //SAE
sae_set_display_errors(false);
sae_debug($log_content);
sae_set_display_errors(true);
}else{ //LOCAL
$max_size = 500000;
$log_filename = "log.xml";
if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
file_put_contents($log_filename, date('Y-m-d H:i:s').$log_content."\r\n", FILE_APPEND);
}
}
二.token验证成功后调用微信的事件(关注,取消关注,自动回复等)
<?php
require_once dirname(__FILE__) . '/JJbWxClass.php';
require_once dirname(__FILE__) . '/../action/JJbWxUserAction.php';
require_once dirname(__FILE__) . '/../public/content_text.php';
class JJbWxScriptClass extends JJbWxClass
{
private $ToUserName;
private $FromUserName;
private $CreateTime;
private $jjb_wx_user_action;
public function __construct()
{
parent::__construct();
$this->jjb_wx_user_action = new JJbWxUserAction();
}
/**
* 接收事件推送
* @return string
*/
public function responseScript()
{
//接受xml数据
//$postXml = $GLOBALS['HTTP_RAW_POST_DATA'];//这个地方不能用全局,这个在开发环境和测试环境都是可以正常使用,但是在线上的话会接受不到数据,造成在公众号中回复消息时提示-----服务器故障,稍后再试
$postXml = file_get_contents("php://input");//在线上接受xml数据用这个方法能够正常显示!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if(empty($postXml))
{
return '';
}
//xml数据转数组
$postArr = $this->xmlToArray($postXml);
$MsgType = strtolower($postArr['MsgType']);
$this->ToUserName = $postArr['ToUserName'];
$this->FromUserName = $postArr['FromUserName'];
$this->CreateTime = time();
//判断事件类型
switch($MsgType)
{
case 'text':
$return_str = $this->textScript($postArr);
break;
case 'event':
$return_str = $this->eventScript($postArr);
break;
default:
$return_str = 'Unknow msg type: ' . $MsgType;
break;
}
return $return_str;
}
/**
* 事件推送(event)
* @param $postArr
* @return string
*/
private function eventScript($postArr)
{
$content = '';
if($postArr['Event'] == 'subscribe')
{
//用户关注事件
$array = $this->jjb_wx_user_action->userExist($this->FromUserName);
if($array)
{
//用户信息存入超过一个月之后或用户关注状态为取消关注,则替换数据库中旧数据
if($array['updatetime'] < time() || $array['subscribe'] == '0')
{
$user_array = $this->getWxUserAttention($this->FromUserName);
$this->jjb_wx_user_action->editWxUserInfo($user_array, $this->FromUserName);
}
}
else
{
//如果用户不存在数据库中,则存入用户信息
//$this->eventKeyScript($postArr['EventKey'], 'subscribe');
$father_id=$this->EventKey;
//把它变为整型
$aa= strlen($father_id);
$father=substr($father_id,8,($aa-8));
//echo'第一次id'.$father_id.'第一次id结束';
$user_array = $this->getWxUserAttention($this->FromUserName);
$arr_test['userinfo']=$user_array;
$arr_test['userlookbefore']=$father_id;
$arr_test['userlookafter']=$father;
comm_log('jjb_wx_guanzhu_', json_encode($arr_test));//把测试相关信息写入日志
$this->jjb_wx_user_action->setWxUserInfo($user_array,$father);
}
//扫描场景二维码登录事件,用户关注时的事件操作
if(isset($postArr['EventKey']) && !empty($postArr['EventKey']))
{
$this->eventKeyScript($postArr['EventKey'], 'subscribe');
}
$content = $GLOBALS['default_text'];
}
elseif($postArr['Event'] == 'unsubscribe')
{
//用户取消关注事件,修改用户关注状态
$this->jjb_wx_user_action->editWxUserState($this->FromUserName);
}
elseif($postArr['Event'] == 'SCAN')
{
//用户已关注微信公众账号,场景二维码事件
if($this->eventKeyScript($postArr['EventKey']))
{
//$content = '登录家教帮网站成功!';
$content = '您已经关注了家教帮';
}
else
{
$content = $GLOBALS['default_text'];
}
}
//else
//{
//$content = 'Unknow Event: ' . $postArr['Event'];
//$content = '';
//}
return $this->responseText($content);
}
/**
* 文本消息(text)
* @param $postArr
* @return string
*/
private function textScript($postArr)
{
if ($postArr['Content'] == '安全测试') {
$return_str = $this->responseText($GLOBALS['exam_text']);
} elseif (in_array($postArr['Content'], ['合作', '商务合作']) === true) {
$return_str = $this->responseText($GLOBALS['cooperation_text']);
} elseif (in_array($postArr['Content'], ['商务', '广告合作', '投稿', '转载', '转载授权']) === true) {
$return_str = $this->responseText($GLOBALS['reprint_text']);
} else {
$return_str = $this->responseText($GLOBALS['default_text']);
}
return $return_str;
}
/**
* 被动回复用户信息
* @param $content 回复消息
* @return string
*/
private function responseText($content)
{
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$resultStr = sprintf($template, $this->FromUserName, $this->ToUserName, $this->CreateTime, $content);
return $resultStr;
}
/**
* 扫描带参数二维码事件
* @param $event_key 二维码参数scene_id
* @param bool $type 是否未关注
* @return mixed
*/
private function eventKeyScript($event_key, $type = false)
{
if($type == 'subscribe')
{
$event_key = trim($event_key);
$event_key = str_replace('qrscene_', '', $event_key);
}
return $this->mem->set($event_key, $this->FromUserName, 0, 90);
}
/**
* xml转数组
* @param $xml xml数据
* @return mixed
*/
private function xmlToArray($xml)
{
//禁止引用外部xml实体
$disableLibxmlEntityLoader = libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
libxml_disable_entity_loader($disableLibxmlEntityLoader);
comm_log('jjb_wx_script_', json_encode($values));
return $values;
}
}
三.这个地方需要写入微信公众号相对应的appid 及 appsecret
<?php
date_default_timezone_set('PRC');
header('Content-Type:text/html;charset=utf-8');
class JJbWxClass
{
public $appid = '';//这是测试号appid
public $appsecret = '';
public $mem;
public function __construct()
{
global $mem;
$this->mem = $mem;
}
/**
* 获取微信access_token
* @return array|mixed|string
*/
public function getAccessToken()
{
$key = '';//这里是缓存时的键
$array_token = $this->mem->get($key);
if(!$array_token)
{
//从微信获取存入cache中 MEMCACHE_LONG
$array_token = $this->getWxToken();
$this->mem->set($key, json_encode($array_token), 0, 7200);
}
else
{
$array_token = json_decode($array_token, true);
if(!is_array($array_token) || !isset($array_token['get_token_time']))
{
//从微信获取存入cache中
$array_token = $this->getWxToken();
$this->mem->set($key, json_encode($array_token), 0, 7200);
}
else
{
//cache中存在,超时刷新token
if(time() - $array_token['get_token_time'] > 7200)
{
$array_token = $this->getWxToken();
$this->mem->set($key, json_encode($array_token), 0, 7200);
}
}
}
comm_log('jjb_toekn_', json_encode($array_token));
return $array_token['access_token'];
}
/**
* 模拟get请求
* @param $url
* @param null $data
* @return mixed
*/
public function https_request_get($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_PORT, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
/**
* 模拟post请求
* @param $url
* @param null $data
* @return mixed
*/
public function https_request_post($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;
}
/**
* 根据普通token和openid获取用户基本信息(关注后才可以获取全部信息,否则只能获取openid)
* @param $openid openid
* @return mixed
*/
public function getWxUserAttention($openid)
{
$token = $this->getAccessToken();
$get_user_info_url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $token . '&openid=' . $openid . '&lang=zh_CN';
$user_result = $this->https_request_get($get_user_info_url);
$user_array = json_decode($user_result, true);
return $user_array;
}
/**
* 返回用户access_token
* @return mixed
*/
private function getWxToken()
{
//获取token
$token_access_url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $this->appid . '&secret=' . $this->appsecret;
$res = file_get_contents($token_access_url);
$get_access_token = json_decode($res, true);
//存入获取token时间
$get_access_token['get_token_time'] = time();
return $get_access_token;
}
}