注意本例用的是tp3.2框架
数据表
1.access_token表
2.wechat_user表
配置
//微信公众号配置
'WX_TOKEN' =>'weixin',//Token(令牌)
'WX_APPID' =>'w**************6',//AppID(应用ID)
'WX_APPSECRET' =>'6*************************0',//AppSecret(应用密钥)
公用函数
/**
* 模拟请求
*/
function _curl($URL = '', $post_data = array(),$timeout=0){
$cu = curl_init();
if($post_data){
curl_setopt($cu, CURLOPT_POST, 1);//post提交方式
curl_setopt($cu, CURLOPT_POSTFIELDS, $post_data);//post提交的数据
}
curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($cu, CURLOPT_URL, $URL);
curl_setopt($cu, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
curl_setopt($cu, CURLOPT_CONNECTTIMEOUT, $timeout);//在发起连接前等待的时间,如果设置为0,则无限等待。
$response = curl_exec($cu);
curl_close($cu);
return $response;
}
接口代码
<?php
namespace Home\Controller;
use Think\Controller;
define("TOKEN", C('WX_TOKEN'));
class WeixinController extends Controller {
private $appId;
private $appSecret;
public function _initialize(){
$this->appId=C('WX_APPID');
$this->appSecret=C('WX_APPSECRET');
}
public function valid()
{
$echoStr = $_GET["echostr"];
if(empty($echoStr)){
$this->responseMsg();
}
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
/**
* 验证消息的真实性
* 加密/校验流程如下:
* 1. 将token、timestamp、nonce三个参数进行字典序排序
* 2. 将三个参数字符串拼接成一个字符串进行sha1加密
* 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
* @throws Exception
* @return boolean
*/
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
/**
* 响应用户操作的回调函数
*/
public function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)){
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
//关注
if($postObj->MsgType=="event" || $postObj->event=="subscribe"){
//获取access_token
$access_token=$this->getAccessToken();
//获取用户信息
$usertemp = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$access_token&openid=$fromUsername&lang=zh_CN";
$userinfo=_curl($usertemp,'5');
$userarr = json_decode($userinfo);
//信息入库
$res=$this->addUser($userarr);
if($res){
$text = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
$msgType = "text";
$tip="欢迎关注XXX公众号!";
$result = sprintf($text, $fromUsername, $toUsername, $time, $msgType,$tip);
echo $result;
}
}
}else {
echo " ";
exit;
}
}
/**
* 获取全局access_token,access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。
* @return string $rst
*/
private function getAccessToken(){
$rst = M('AccessToken')->field('access_token,expires_in')->where(array('appid'=>$this->appId))->find();
if(!$rst || $rst['expires_in'] < time()){ //本地缓存的access_token不存在或过期
$url_get='https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->appId.'&secret='.$this->appSecret;
$timeout = 5;
//发送请求
$file_contents=_curl($url_get,'',$timeout);
$tokenobj = json_decode($file_contents);
if( !$tokenobj->errcode){
if($rst){//如果过期,则更新access_token数据
M('AccessToken')->where(array('appid'=>$this->appId))->save(array('access_token'=>$tokenobj->access_token, 'expires_in'=>(time()+$tokenobj->expires_in-600)));
} else {//否则新增一条数据
M('AccessToken')->add(array('appid'=>$this->appId,'access_token'=>$tokenobj->access_token, 'expires_in'=>(time()+$tokenobj->expires_in-600)));
}
return $tokenobj->access_token;
}
} else {
return $rst['access_token'];
}
}
/**
* 用户信息写入数据库
* @param object $userarr
* @return boolean
*/
public function addUser($userarr){
$data['subscribe'] = $userarr->subscribe;
$data['openid'] = $userarr->openid;
$data['nickname'] = $userarr->nickname;
$data['sex']= $userarr->sex;
$data['language'] = $userarr->language;
$data['city'] = $userarr->city;
$data['province']= $userarr->province;
$data['country'] = $userarr->country;
$data['headimgurl']= $userarr->headimgurl;
$data['subscribe_time'] = $userarr->subscribe_time;
$wechat=M('WechatUser');
//如果用户之前有关注过就更新
$row=$wechat->where(array('openid'=>$data['openid']))->find();
if($row['openid'] == $data['openid']){
$res=$wechat->where(array('id'=>$row['id']))->save($data);
}else{
//没有关注过就增加
$res=$wechat->add($data);
}
return $res;
}
}
网页授权方法
<span style="color:#FFFFFF;"> <span style="color:#000000;"> /**
* 网页授权 - 页面跳转
*
* https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri=http://{domain}/index.php?m=base&a=redirect&token=xwxgsg1418012911&response_type=code&scope=snsapi_base&state=g4fs56gd#wechat_redirect
* 要点:
* 1. appid 即为服务号才可以
* 2. domain 绑定的网页授权域名
* 3. from_user_name 替换成用户的wecha_id
* 4. 使用urlencode对链接进行处理
*/
function redirect(){
if(!empty($_GET)){
// $token = I('get.token');
$code = I('get.code');
$url_code =I('get.state');
// 判断url_code是真实链接还是链接标识
if(stristr($url_code, 'http') != FALSE){
$redirect_url = $url_code;
} else {
$url = D('AuthUrl')->where(array('code'=>$url_code))->find();
if (empty($url)) {
exit('wrong redirect_url!');
}
$redirect_url = htmlspecialchars_decode($url['url']);
}
// 获取access_token
$api_url='https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->appId.'&secret='.$this->appSecret.'&code='.$code.'&grant_type=authorization_code';
$reponse = _curl($api_url);
$reponse_array = json_decode($reponse, TRUE);
if (isset($reponse_array['access_token'])) {
$access_token = $reponse_array['access_token'];
$wecha_id = $reponse_array['openid'];
$redirect_url = str_replace('from_user_name', $wecha_id, $redirect_url);
if (strstr($redirect_url, 'http') != FALSE) {
redirect($redirect_url);
}
} else {
exit('appid is not exist or wrong!');
}
}
}</span></span>