一.入口文件  用于验证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;
    }
}