微信 服务号开发

tp5.0  一个入口文件,一个wx类

//WxAction.php 入口
<?php
/**
 * Created by PhpStorm.
 * User: lxd
 * Date: 17/10/31
 * Time: 18:01
 * 微信请求统一入口,单独的类,无需基础其他类
 */
namespace app\index\controller;

use telerr\Chaoxin;
use think\Config;
use think\Request;
use wx\Wx;

class WxAction
{
    protected $request  = null;

    /**
     * 构造
     */
    public function __construct()
    {

        //绑定请求对象
        $this->request  = Request::instance();

        //接收参数, 验证来源
        $this->getParam();

    }

    /**
     * 验证请求来源
     */
    private function checkFrom()
    {
        if( !$this->request->wx_signature || !$this->request->wx_timestamp || !$this->request->wx_nonce ) {
            exit( ‘非法请求‘ );
        }
        $tmpArr         = [$this->request->wx_token, $this->request->wx_timestamp, $this->request->wx_nonce];
        sort( $tmpArr, SORT_STRING );

        if( $this->request->wx_signature != sha1( implode(  ‘‘, $tmpArr ) ) ) {
            exit( ‘请求非法‘ );
        }

        if( $this->request->has( ‘echostr‘ ) )
            exit( $this->request->param(‘echostr‘) );
    }

    /**
     * 接收参数
     */
    private function getParam()
    {
        $this->request->wx_signature      = $this->request->param( ‘signature‘, ‘‘, ‘trim‘ );
        $this->request->wx_timestamp      = $this->request->param( ‘timestamp‘, ‘‘, ‘trim‘ );
        $this->request->wx_nonce          = $this->request->param( ‘nonce‘, ‘‘, ‘trim‘ );
        $this->request->wx_openid         = $this->request->param( ‘openid‘, ‘‘, ‘trim‘ );
        $this->request->wx_token          = Config::get( ‘wx.appToken‘ );
        if( Config::get(‘app_debug‘ ) )
            $this->request->wx_token          = Config::get( ‘wx.appTokenlxdTest‘ );

        //验证请求来源
        $this->checkFrom();
    }

    /**
     * 默认访问方法
     */
    public function index()
    {
        //获取解析后的数据
        $this->request->wxRequest     = Wx::parseXml( $this->request->getInput() );

        $wxObj      = Wx::instance();
        register_shutdown_function( array($wxObj,‘eventDefault‘) ); //记日志

        //请求方法
        if( is_array( $this->request->wxRequest ) && !empty( $this->request->wxRequest ) ) {
            $tmpMsgType         = strtolower( $this->request->wxRequest[‘msgtype‘] );
            switch( $tmpMsgType ) {
                //事件
                case ‘event‘ :
                    $tmpEvent       = strtolower( $this->request->wxRequest[‘event‘] );
                    switch( $tmpEvent ) {
                        case ‘subscribe‘: //关注事件(直接关注|扫码关注)
                            $wxObj->eventSubscribe();
                            break;
                        case ‘unsubscribe‘: //取消关注事件
                            $wxObj->eventUnsubscribe();
                            break;
                        case ‘scan‘: //扫描二维码,已关注
                            $wxObj->eventScan();
                            break;
                        case ‘location‘: //上报地理位置
                        case ‘click‘: //点击自定义菜单事件
                            $wxObj->eventClick();
                            break;
                        case ‘view‘: //点击自定义链接菜单事件
                            $wxObj->viewClickEvn();
                            break;
                        default :
                            //默认动作
                    }
                    break;

                //文本消息
                case ‘text‘:
                    $wxObj->eventText();
                    break;

                default:
                    $wxObj->noSupprt(); //默认动作
                    break;
            }

            $wxObj      = null;
        }
    }

}
//wx类
<?php
/**
 * Created by PhpStorm.
 * User: lxd
 * Date: 17/11/1
 * Time: 13:33
 * 微信处理类
 */
namespace wx;

use app\bp\controller\User;
use app\common\controller\UserAgencyRalation;
use app\common\model\UserAgenceRelateion;
use Curl\Curl;
use redis\Redis;
use telerr\Chaoxin;
use think\Cache;
use think\Config;
use think\Loader;
use think\Log;
use think\Request;
use think\Session;

class Wx
{
    protected $request      = null;
    protected $cache               = null;
    protected $curl                = null;
    protected static $instance     = null;
    protected $accessTokenCt       = 7000; //微信官方7200,少200秒 jsapi_ticket 也采用该时间
    protected $ipListCt            = 2592000; //30天
    protected $redisKey            = ‘Wx::‘;

    /**
     * 构造方法
     */
    private function __construct()
    {
        if( !$this->request )
            $this->request  = Request::instance();

        //初始化缓存类
        if( !$this->cache ) {
            $this->cache        = Redis::getInstance();
        }

        //初始化缓存类
        if( !$this->curl ) {
            $this->curl     = new Curl();
            $this->curl->setJsonDecoder(false);
        }

    }

    public function __call($method, $args)
    {
        if( method_exists( $this, $method ) ) {
            return call_user_func( [$this,$method], $args );
        }

        $this->myLog( ‘ ?? 调用了不存在的方法‘ . $method . ‘; 参数  ‘ . json_encode( $args ) );

        return false;
    }

    /**
     * 初始化类
     */
    public static function instance()
    {
        if( is_null( self::$instance ) )
            self::$instance     = new static();

        return self::$instance;
    }

    /**
     * 解析xml
     *
     * @param string $xml 数据
     * @return array $return
     */
    public static function parseXml( $xml )
    {
        if( !is_string( $xml ) )
            return [];

        $domobj         = new \DOMDocument();
        if( !$domobj->loadXML( $xml ) ) {
            Log::error( ‘load error ‘. $xml );
            return [];
        }

        $return         = [];
        if( $tagname = $domobj->getElementsByTagName( ‘ToUserName‘ )->item( 0 ) ) {
            $return[‘tuser‘]        =  $tagname->nodeValue;
            $tagname             = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘FromUserName‘ )->item( 0 ) ) {
            $return[‘fuser‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘CreateTime‘ )->item( 0 ) ) {
            $return[‘ctime‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘MsgType‘ )->item( 0 ) ) {
            $return[‘msgtype‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Event‘ )->item( 0 ) ) {
            $return[‘event‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘EventKey‘ )->item( 0 ) ) {
            $return[‘eventkey‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Ticket‘ )->item( 0 ) ) {
            $return[‘ticket‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Latitude‘ )->item( 0 ) ) {
            $return[‘lat‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Longitude‘ )->item( 0 ) ) {
            $return[‘lon‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Precision‘ )->item( 0 ) ) {
            $return[‘precision‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘Content‘ )->item( 0 ) ) {
            $return[‘content‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘MsgId‘ )->item( 0 ) ) {
            $return[‘msgid‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        if( $tagname = $domobj->getElementsByTagName( ‘MenuId‘ )->item( 0 ) ) {
            $return[‘menuid‘]        =  $tagname->nodeValue;
            $tagname           = null;
        }

        $domobj         = null;
        return $return;
    }

    /**
     * 获取微信 access_token
     */
    public function getAccessToken()
    {
        $cachename      = ‘access_token_online‘;
        if( Config::get( ‘app_debug‘ ) )
            $cachename      = ‘access_token1‘;

        $accessToken    = $this->cache->get( $this->redisKey . $cachename );
        if( !$accessToken ) {
            if( Config::get(‘app_debug‘) )
                $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/token?grant_type=client_credential&appid=‘ . Config::get( ‘wx.appIDlxdTest‘ ) . ‘&secret=‘ . Config::get( ‘wx.appsecretlxdTest‘ );
            else
                $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/token?grant_type=client_credential&appid=‘ . Config::get( ‘wx.appID‘ ) . ‘&secret=‘ . Config::get( ‘wx.appsecret‘ );

            $info       = $this->sendCurl( $url );
            if( isset( $info[‘access_token‘] ) && $info[‘access_token‘] ) {
                $accessToken        = $info[‘access_token‘];
                if( !$this->cache->set( $this->redisKey . $cachename, $accessToken, $this->accessTokenCt ) ) {
                    $this->myLog( ‘access_token 写入缓存失败‘ );
                    return true;
                }
            }
        }

        return $accessToken;
    }

    /**
     * 关注事件(直接关注|扫码关注)
     *
     * @return bool
     */
    public function eventSubscribe()
    {
        $parentId   = 0;
        $eventKey   = isset( $this->request->wxRequest[‘eventkey‘] ) ? strtolower( $this->request->wxRequest[‘eventkey‘] ) : ‘‘;
        if( $eventKey ) {
            if( strpos( $eventKey, ‘qrscene_‘ ) !== 0 ) {
                $this->myLog( ‘用户关注获取 $eventKey 值不是qrscene_开头,请检查‘ . var_export( $this->request->wxRequest, true ) );
            }

            $parentId   = str_replace( ‘qrscene_‘, ‘‘, $eventKey );
        }

        $info       = $this->getUserinfoByOpenid( $this->request->wxRequest[‘fuser‘] );
        if( $info ) {
            //如果不存在,那么自己生产一个
            if( !isset( $info[‘unionid‘] ) ) {
                $info[‘unionid‘]      = ‘__‘ . md5( $this->request->wxRequest[‘fuser‘] . $this->request->wxRequest[‘tuser‘] );
                if( !Config::get(‘app_debug‘) )
                    $this->myLog( ‘未获取到unionid值,info‘ . var_export( $info, true ) );
            }

            $this->request->wxRegData       = [
                ‘user‘      => $info,
                ‘param‘     => $this->request->wxRequest,
                ‘openid‘    => isset( $this->request->wxRequest[‘fuser‘] ) ? $this->request->wxRequest[‘fuser‘] : $this->request->wx_openid,
            ];

            //判断数据库是否存在用户信息,存在添加日志;不存在 添加用户,添加日志
            $model      = Loader::controller( ‘app\common\controller\User‘ );
            $isExi      = $model->isExiByUnionid();

            if( $isExi === false ) {
                $this->myLog( ‘isExiByUnionid ‘ . var_export( $model->isExiByUnionid(), true ) . ‘wxdata ‘ . $this->request->wxRegData );
            }else if( !$isExi ) {
                $res        = $model->addOneUserByWx();

                if( !$res ) {
                    $this->myLog( ‘微信注册用户失败,‘ . $this->request->modelErr . ‘data == ‘ . json_encode( $this->request->getInput() ) );
                    return false;
                }

                $time       = time();
                //如果有父id 推荐人,给推荐人发送消息
                if( $parentId ) {
                    //写入 关系表
                    $relationModel      = Loader::model( ‘UserAgenceRelateion‘ );
                    $relationAdd        = [
                        ‘uid‘       => $parentId,
                        ‘cuid‘      => $res,
                        ‘sour‘      => UserAgenceRelateion::SOURWX,
                        ‘monrate‘   => \app\common\model\User::BMSSONNORMALAGENCYMONRATE,
                        ‘atm‘       => $time,
                        ‘montype‘   => UserAgenceRelateion::MONFROMBM
                    ];
                    if( !$relationModel->addOneData( $relationAdd ) ) {
                        $this->myLog( ‘代理二级关系入库失败‘ . json_encode( $relationAdd ) );
                    }

                    $template_id        = ‘‘;
                    if( Config::get( ‘app_debug‘ ) )
                        $template_id    = ‘lgR8cs4krnc0DRYYU0liwesaFbd2iWax-IJywTWqdAw‘;

                    $touser         = \app\common\controller\User::getOpenidByUid( $parentId );
                    $url            = ‘‘;
                    $nickName       = isset( $info[‘nickname‘] ) ? $info[‘nickname‘] : ‘该用户无昵称‘;
                    $data           = [
                        ‘first‘     => [‘value‘ => ‘你邀请的用户接受了你的邀请‘, ‘color‘ => ‘#337ab7‘],
                        ‘keyword1‘  => [‘value‘ => ‘微信昵称:‘ . $nickName, ‘color‘ => ‘#337ab7‘],
                        ‘keyword2‘  => [‘value‘ => date( ‘Y-m-d H:i‘, $time ), ‘color‘ => ‘#337ab7‘],
                        ‘remark‘    => [‘value‘ => ‘感谢您的关注‘, ‘color‘ => ‘#337ab7‘]
                    ];
                    $this->_sendWxTemplate( $template_id, $touser, $url, $data );
                }
            }

            $helpurl        = $this->makeUrlAndShort( ‘/index/user/applyAgency‘ );
            $content        = <<<EOF
亲,终于等到你~
轻松赚钱的秘诀在这里等待您的到来,海量优质商品超高的优惠力度

回复“找XX”系统会自动推送商品的优惠信息,如“找牙刷”

回复“签到”即可签到,签到成功近期会有神秘奖励,敬请期待

申请成为代理,分享商品轻松赚钱 $helpurl
EOF;

            $this->_sendWXText( $content );

            return true;
        }

        return $info;
    }

    /**
     * 取消关注事件
     *
     */
    public function eventUnsubscribe() {

    }

    /**
     * 获取用户基本资料,基于openid
     */
    public function getUserinfoByOpenid( $openid )
    {
        $rk         = ‘Wx:getUserinfoByOpenid:‘ . $openid;
        $info       = $this->cache->get( $rk );
        if( $info )
            return $info;

        //获取用户信息
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!eventSubscribe 方法执行异常‘ . json_encode( func_get_args() ) );
            return false;
        }

        if( Config::get(‘app_debug‘) )
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/user/info?access_token=‘.$accessToken.‘&openid=‘.$openid.‘&lang=zh_CN‘;
        else
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/user/info?access_token=‘.$accessToken.‘&openid=‘.$openid.‘&lang=zh_CN‘;

        $info       = $this->sendCurl( $url );
        if( !$info ) {
            $this->myLog( ‘获取用户基本资料失败, url = ‘ . $url . ‘, info = ‘. var_export( $url, true ) );
            return true;
        }

        $this->cache->set( $rk, $info, 86400 );
        return $info;
    }

    /**
     * 记录log到数据库
     */
    public function eventDefault()
    {
        if( !$this->request->wxRegData ) {
            $this->request->wxRegData       = [
                ‘param‘     => $this->request->wxRequest,
                ‘openid‘    => isset( $this->request->wxRequest[‘fuser‘] ) ? $this->request->wxRequest[‘fuser‘] : $this->request->wx_openid,
            ];
        }

        $model      = Loader::controller( ‘app\common\controller\Wxlog‘ );
        $res        = $model->addOne();
        if( !$res ) {
            $this->myLog( ‘微信log记录失败,‘ . $this->request->modelErr . ‘data == ‘ . json_encode( $this->request->wxRegData ) );
            return false;
        }
        return true;
    }

    /**
     * log
     */
    public function myLog( $msg, $isback = true )
    {
        Log::init( [
            ‘path‘  => \think\Config::get( ‘thirdlog‘ ) . ‘Wx‘ . DIRECTORY_SEPARATOR,
            ‘file_size‘     => ‘209715200‘ //200m
        ] );
        Log::write( $msg );
        Chaoxin::sendTextMsg( $msg, $isback );
    }

    /**
     * curl
     */
    public function sendCurl( $url, $type = ‘get‘, $data = [], $postJson = true )
    {

        if( $type == ‘get‘ )
            $this->curl->get( $url );
        else{
            if( $postJson )
                $this->curl->setHeader( ‘Content-Type‘, ‘application/json‘ );

            $this->curl->post( $url, $data );
        }
        if( $this->curl->error ) {
            $this->myLog(‘curl 请求异常, url ===‘ . $url . ‘; error = ‘ . $this->curl->errorCode . ‘|‘ . $this->curl->errorMessage);
            return false;
        } else {
            $info       =  json_decode( $this->curl->response, true );
            if( $info ) {
                if( isset( $info[‘errcode‘] ) && $info[‘errcode‘] != 0 ) {
                    if( $info[‘errcode‘] == ‘40001‘ ) { //获取access_token 失败

                        $cachename      = ‘access_token_online‘;
                        if( Config::get( ‘app_debug‘ ) )
                            $cachename      = ‘access_token1‘;
                        $this->cache->del( $this->redisKey . $cachename );

                        $this->getAccessToken();
                    }

                    if( $info[‘errcode‘] != ‘40163‘ && $info[‘errcode‘] != ‘40029‘ ) //code 失效,网页在微信外打开了
                        $this->myLog( ‘请求结果失败, url = ‘ . $url . ‘info == ‘ . var_export( $info, true ) );

                    return false;
                }
                return $info;
            }else {
                $this->myLog( ‘请求结果异常, url = ‘ . $url . ‘info == ‘ . var_export( $info, true ) );
                return false;
            }
        }
    }

    /**
     * 网页授权,获取用户信息
     */
    public function webScope()
    {
        $code       = $this->request->param( ‘code‘, ‘‘ );
        if( !$code ) {
            $this->myLog( ‘未获取到code,wx.php webScope 方法非法进入‘ );
            return false;
        }

        if( Config::get( ‘app_debug‘ ) )
            $url    = Config::get(‘wx.apiUrl‘) . "/sns/oauth2/access_token?appid=".Config::get(‘wx.appIDlxdTest‘)."&secret=".Config::get(‘wx.appsecretlxdTest‘)."&code=".$code."&grant_type=authorization_code";
        else
            $url    = Config::get(‘wx.apiUrl‘) . "/sns/oauth2/access_token?appid=".Config::get(‘wx.appID‘)."&secret=".Config::get(‘wx.appsecret‘)."&code=".$code."&grant_type=authorization_code";

        $info       = $this->sendCurl( $url );
        if( !$info || !isset( $info[‘openid‘] ) || empty( $info[‘openid‘] ) ) {
            if( isset($info[‘errcode‘]) ) { //40163 code been used;网页在浏览器上打开
                if( $info[‘errcode‘] != ‘40163‘ && $info[‘errcode‘] != ‘40029‘ )
                    $this->myLog( ‘网页授权url请求获取信息失败,info == ‘ . var_export( $info, true ) );
            }
            return false;
        }

        //获取用户资料
        $uinfo       = $this->getUserinfoByOpenid( $info[‘openid‘] );
        if( !$uinfo )
            return false;
        /**
        if( !Config::get( ‘app_debug‘ ) ) {
            if( !isset( $uinfo[‘unionid‘] ) || empty( $uinfo[‘unionid‘] ) ) {
                $this->myLog( ‘用户基本资料中没有得到unionid, info=== ‘ . var_export( $info, true ) );
                return false;
            }
        }else {
            //测试服,自己生成一个
            if( !isset( $uinfo[‘unionid‘] ) || empty( $uinfo[‘unionid‘] ) ) {
                $uinfo[‘unionid‘]       = ‘__‘ . md5( $info[‘openid‘] . Config::get(‘wx.fuwuhaoWxchatlxdTest‘) );
            }
        }
        */

        if( !isset( $uinfo[‘unionid‘] ) ) {
            $uinfo[‘unionid‘]       = ‘__‘ . md5( $info[‘openid‘] . Config::get(‘wx.fuwuhaoWxchatlxdTest‘) );
            if( !Config::get( ‘app_debug‘ ) ) {
                $uinfo[‘unionid‘]       = ‘__‘ . md5( $info[‘openid‘] . Config::get(‘wx.fuwuhaoWxchat‘) );
                $this->myLog( ‘用户基本资料中没有得到unionid, info=== ‘ . var_export( $info, true ) );
            }
        }

        $this->request->wxRegData       = [
            ‘user‘      => $uinfo,
            ‘param‘     => $this->request->wxRequest,
            ‘openid‘    => $info[‘openid‘],
        ];

        $model      = Loader::controller( ‘app\common\controller\User‘ );
        $info   = $model->getOneByUnionid();
        if( !$info ) {

            //注册一下。
            $res        = $model->addOneUserByWx();
            if( !$res ) {
                $this->myLog( ‘微信注册用户失败,‘ . $this->request->modelErr . ‘data == ‘ . json_encode( $this->request->wxRegData ) );
                return false;
            }

            $info   = $model->getOneByUnionid();
            if( !$info ) {
                $this->myLog( ‘通过unionid获取用户信息失败,info == ‘ . var_export( $info, true ) . ‘, wxrequest = ‘ . var_export( $this->request->wxRegData, true ) );
                return false;
            }
        }
        return $info;
    }

    /**
     * 验证访问来源是否来自于微信
     */
    public function checkWxIp()
    {
        $ip         = $this->request->ip(0, true);
        if( !$ip )
            return false;

        $ipList = $this->cache->get( $this->redisKey . ‘ip‘);
        if( !$ipList ) {
            $accessToken        = $this->getAccessToken();
            if( !$accessToken ) {
                $this->myLog( ‘获取微信token失败,请检查!!checkWxIp 方法执行异常‘ );
                return false;
            }

            $url    = Config::get(‘wx.apiUrl‘) . "/cgi-bin/getcallbackip?access_token=" . $accessToken;
            $info   = $this->sendCurl( $url );
            if( $info && isset( $info[‘ip_list‘] ) ) {
                $ipList         = $info[‘ip_list‘];
                if( !$this->cache->set( $this->redisKey . ‘ip‘, $info[‘ip_list‘], $this->ipListCt ) ){
                    $this->myLog( ‘缓存ip数据异常!‘ );
                    return false;
                }
            }
        }

        $this->myLog( ‘iplist ‘ . var_export( $ipList , true ) );
        if( !in_array( $ip, $ipList ) ) {
            $this->myLog( ‘非法访问,ip‘ . $ip . var_export( $_SERVER, true ) );
            return false;
        }
        return true;
    }

    /**
     * 菜单设置
     */
    public function setButton()
    {
        //获取用户信息
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!setButton 方法执行异常‘ );
            return false;
        }

        $state          = Config::get( ‘wx.state‘ );
        $appid          = Config::get(‘wx.appID‘);
        $url            = ‘bm.mmd360.com‘;
        if( Config::get( ‘app_debug‘ ) ) {
            $appid      = Config::get( ‘wx.appIDlxdTest‘ );
            $url            = ‘ypdev.bimai.top‘;
        }

        $arr    = [
            ‘button‘    => [
                [
                    ‘name‘  => ‘自服务‘,
                    ‘sub_button‘    => [
                        [
                            ‘name‘  => ‘代理申请‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fuser%2FapplyAgency&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘我的佣金‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fgain&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘我的收藏‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fuser_collect%2FgetList&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘使用帮助‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fuser%2Fhelp&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘个人中心‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fuser&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ]
                    ]
                ],
                [
                    ‘name‘  => ‘商品库‘,
                    ‘sub_button‘    => [
                        [
                            ‘name‘  => ‘实时新品‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fgoods%2FgetTodayGoods&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘必买推荐‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fgoods%2FhotCakeList&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘热卖活动‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fgoods_activity%2FgetActivityList&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ],
                        [
                            ‘name‘  => ‘全部商品‘,
                            ‘type‘  => ‘view‘,
                            ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2Findex%2Fgoods_cate%2FgetCate&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                        ]
                    ]
                ],
//                [
//                    ‘name‘  => ‘邀请海报‘,
//                    ‘type‘  => ‘click‘,
//                    ‘key‘   => ‘invite‘,
//                ]
                [
                    ‘name‘  => ‘优品商城‘,
                    ‘type‘  => ‘view‘,
                    ‘url‘   => ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=http%3A%2F%2F‘.$url.‘%2F__youzan__&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘
                ]
            ]
        ];

        if( Config::get(‘app_debug‘) )
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/menu/create?access_token=‘ . $accessToken;
        else
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/menu/create?access_token=‘ . $accessToken;

        $info       = $this->sendCurl( $url, ‘post‘, json_encode( $arr, JSON_UNESCAPED_UNICODE ) );
        if( !$info ) {
            $this->myLog( ‘设置自定义菜单失败, url = ‘ . $url . ‘, info = ‘. var_export( $info, true ) );
            return true;
        }

        return true;
    }

    /**
     * 文本消息回复
     */
    public function eventText()
    {
        $this->request->wxRegData       = [
            ‘param‘     => $this->request->wxRequest,
            ‘openid‘    => $this->request->wxRequest[‘fuser‘]
        ];

        //验证消息是否为重复的,存在让微信不要再发了
        $model      = Loader::controller( ‘app\common\controller\Wxlog‘ );
        $res        = $model->isExiMsg();
        if( $res === false ) {
            $this->myLog( ‘查询msgid唯一性失败,reqeust = ‘ . $this->request->wxRequest );
            return false;
        }
        if( $res ) {
            echo ‘success‘;die;
        }

        $content        = $this->request->wxRequest[‘content‘];
        if( !$content ) {
            $this->myLog( ‘未获取到文本消息,reqeust = ‘ . $this->request->wxRequest );
            return false;
        }

        //验证是否存在 "找" 字
        $content            = trim( $content );
        if( $content == ‘签到‘ )
            $this->setTextMsgQd();

        if( mb_strpos( $content, ‘找‘, 0, ‘utf-8‘ ) !== false )
            $this->setTextMsgFind( $content );

        echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], ‘该业务尚未开通,请稍后再试~‘ );
        die;
    }

    /**
     * 文本回复方法 - 找
     */
    private function setTextMsgFind( $content )
    {
        if( mb_strpos( $content, ‘找‘, 0, ‘utf-8‘ ) === 0 ) {
            if( mb_strlen( $content, ‘utf-8‘) == 1 ) {
                echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], ‘您的输入有误,请输入【找?】,其中?为要查找的关键字,比如 ‘.PHP_EOL.‘找苹果‘ );
            }else {
                $keyword        = mb_substr( $content, 1 );
                $model          = Loader::controller( ‘app\index\controller\Search‘ );
                $info           = $model->api( $keyword );
                $recontent      = ‘‘;
                if( !$info || !isset( $info[1] ) ) {
                    $recontent  = <<<EOF
[发呆] [发呆] [发呆]  您搜索的【{$keyword}】 今天没有参加优惠活动,再看看其他的优惠商品~\n
大波优惠券商品向您袭来,猛戳链接??: http://t.cn/RQXc6yz\n
买不到不罢休的小伙伴,扭头看这里:【http://t.cn/RQXVS2p】
EOF;
                }else {
                    $url            = $this->makeUrlAndShort( $info[1] );
                    $recontent  = <<<EOF
为您查到:【{$keyword}】 的相关产品优惠:{$url}
EOF;
                }

                echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], $recontent);
            }
            die;
        }
    }

    /**
     * 文本回复方法 - 签到
     */
    private function setTextMsgQd()
    {
        $wxUinfo        = $this->getUserinfoByOpenid( $this->request->wxRequest[‘fuser‘] );
        if( !$wxUinfo ){
            $this->myLog( $this->request->wxRequest[‘fuser‘] . ‘通过微信获取用户信息失败, info=== ‘ . var_export( $this->request->wxRequest, true ) );
            $content        = <<<EOF
未获取到您的任何信息,请稍后再试![微笑]
EOF;
            $this->_sendWXText( $content );
        }

        if( !isset( $wxUinfo[‘unionid‘] ) ) {
            $wxUinfo[‘unionid‘]       = ‘__‘ . md5( $this->request->wxRequest[‘fuser‘] . Config::get(‘wx.fuwuhaoWxchatlxdTest‘) );
            if( !Config::get( ‘app_debug‘ ) ) {
                $wxUinfo[‘unionid‘]       = ‘__‘ . md5( $this->request->wxRequest[‘fuser‘] . Config::get(‘wx.fuwuhaoWxchat‘) );
                $this->myLog( ‘用户基本资料中没有得到unionid, info=== ‘ . var_export( $this->request->wxRequest, true ) );
            }
        }

        $model          = Loader::controller( ‘app\common\controller\UserActivity‘ );
        $res            = $model->makeQD( $wxUinfo[‘unionid‘] );
        $str            = ‘签到成功‘;
        if( $res === false ) {
            $this->myLog( ‘签到方法失败,请检查 makeQD‘ . $this->request->modelErr );
            $content        = <<<EOF
服务器出错啦,请稍后再试![微笑]
EOF;
            $this->_sendWXText( $content );
        }

        if( $res == 1 )
            $str        = ‘您已经签到‘;
        else if( $res == 0 ) {
            $url            = $this->makeUrlAndShort( ‘/index/user/applyAgency‘ );
            $content        = <<<EOF
呀,您还不是代理!快点击进入传送门,成为代理,分享商品轻松赚钱
{$url}
EOF;
            $this->_sendWXText( $content );
        }

        $url            = $this->makeUrlAndShort( ‘/index/goods/hotCakeList‘ );
        $content        = <<<EOF
{$str},快去分享商品吧:
$url
EOF;
        $this->_sendWXText( $content );
    }

    /**
     * 返回短连接,并缓存
     */
    private function makeUrlAndShort( $url )
    {
        $cachename      = $this->redisKey . ‘makeUrlAndShort::‘ . $url;
        $info           = $this->cache->get( $cachename );
        if( $info )
            return $info;

        $state          = Config::get( ‘wx.state‘ );
        $appid          = Config::get(‘wx.appID‘);
        if( Config::get( ‘app_debug‘ ) )
            $appid      = Config::get( ‘wx.appIDlxdTest‘ );

        $uri            = urlencode( getHttpUrl() . $url );
        $longUrl        = ‘https://open.weixin.qq.com/connect/oauth2/authorize?appid=‘.$appid.‘&redirect_uri=‘.$uri.‘&response_type=code&scope=snsapi_base&state=‘.$state.‘#wechat_redirect‘;
        $info           = $this->long2short( $longUrl );
        if( $info ){
            $this->cache->set( $cachename, $info );
            return $info;
        }
        return $longUrl;
    }

    /**
     * 不支持的动作回复
     */
    public function noSupprt()
    {
        $content = <<<EOF
您好,相关业务暂无开通,请稍后再试~
EOF;

        echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], $content );
        die;
    }

    /**
     * 点击事件动作
     */
    public function eventClick()
    {
        $key        = isset( $this->request->wxRequest[‘eventkey‘] ) ? $this->request->wxRequest[‘eventkey‘] : ‘‘;
        if( !$key ) {
            $this->myLog( ‘微信:点击事件中未获取到key值!!‘ );
            $this->_sendWXText( ‘您好~‘ );
        }

        switch( $key ) {
            case ‘invite‘:
                $this->_clickInvite();
                break;
            default:
                $this->myLog( ‘微信:获取到未定义的key值,请检查!‘ );
                $content    = <<<EOF
哎呀~ 出故障啦,请稍后再试~ [微笑]
EOF;
                $this->_sendWXText( $content );
        }
    }

    /**
     * 邀请海报 按钮
     */
    protected function _clickInvite()
    {
        $fuser      = $this->request->wxRequest[‘fuser‘];
        register_shutdown_function( function() use ( $fuser ) {
            //获取用户信息
            $wxUinfo        = $this->getUserinfoByOpenid( $fuser );
            if( !$wxUinfo ){
                $this->myLog( $this->request->wxRequest[‘fuser‘] . ‘通过微信获取用户信息失败, info=== ‘ . var_export( $this->request->wxRequest, true ) );
                $this->kfResponseText( $fuser, ‘未获取到您的任何信息,请稍后再试![微笑] ‘ );
                return;
            }

            if( !isset( $wxUinfo[‘unionid‘] ) ) {
                $wxUinfo[‘unionid‘]       = ‘__‘ . md5( $this->request->wxRequest[‘fuser‘] . Config::get(‘wx.fuwuhaoWxchatlxdTest‘) );
                if( !Config::get( ‘app_debug‘ ) ) {
                    $wxUinfo[‘unionid‘]       = ‘__‘ . md5( $this->request->wxRequest[‘fuser‘] . Config::get(‘wx.fuwuhaoWxchat‘) );
                    $this->myLog( ‘用户基本资料中没有得到unionid, info=== ‘ . var_export( $this->request->wxRequest, true ) );
                }
            }

            $uid   = \app\common\controller\User::getUidByUninonid( $wxUinfo[‘unionid‘], true );
            if( $uid === 0 ) {
                $this->myLog( ‘通过微信获取必买用户信息失败, info=== ‘ . var_export( $this->request->wxRequest, true ) . ‘ resuid = ‘ . var_export( $uid, true ) );
                $helpurl        = $this->makeUrlAndShort( ‘/index/user/applyAgency‘ );
                $content    = <<<EOF
亲,先申请代理吧[微笑]
传送门:$helpurl
EOF;
                $this->kfResponseText( $fuser, $content );
                return;
            }
            if( !$uid ) {
                $this->myLog( ‘通过微信获取必买用户信息失败, info=== ‘ . var_export( $this->request->wxRequest, true ) . ‘ resuid = ‘ . var_export( $uid, true ) );
                $this->kfResponseText( $fuser, ‘未获取到您的任何信息,请稍后再试![微笑] ‘ );
                return;
            }

            $userModel      = Loader::model( ‘app\common\controller\User‘ );
            $userinfo       = $userModel->getInfoById( $uid );
            if( !isset( $userinfo[‘invite_img‘] ) || !$userinfo[‘invite_img‘] || !isset( $userinfo[‘head_pic‘]) )
                $userinfo   = $userModel->getInfoById( $uid, true );

            if( !$userinfo || !isset( $userinfo[‘invite_img‘] ) ) {
                $this->myLog( ‘通过用户id读取用户信息异常, $userinfo=== ‘ . var_export( $userinfo, true ) );
                $this->kfResponseText( $fuser, ‘未获取到您的任何信息,请稍后再试![微笑] ‘ );
                return;
            }

            if( $userinfo[‘invite_img‘] )
                $this->kfResponseImg( $fuser, Config::get( ‘upload.uploadpath‘ ) . $userinfo[‘invite_img‘], 100 );
            else {
                $res    = call_user_func(
                    [Loader::controller( ‘app\common\controller\User‘ ), ‘makeInvteImg‘],
                    [‘uid‘ => $uid, ‘pic‘ => $userinfo[‘head_pic‘] ]
                );
                if( isset( $res[‘error‘] ) ) {
                    $this->myLog( ‘生成用户海报失败‘ . $res[‘error‘] );
                    $content    = <<<EOF
很抱歉,生成海报失败,请稍后再试![微笑]
EOF;

                    $this->kfResponseText( $fuser, $content );
                    return;
                }

                $this->_reMakeCurl();
                $this->kfResponseImg( $fuser, $res[‘path‘], 100 );
            }
        } );

        $content    = <<<EOF
正在为您生成专属邀请海报
请稍等...
EOF;
        $this->_sendWXText( $content );
    }

    /**
     * 点击菜单事件
     */
    public function viewClickEvn()
    {

//        Chaoxin::sendTextMsg( ‘wx info ‘ . var_export($this->request->wxRequest, true ) );
//
//        echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], ‘你好!‘ );
//        die;
    }

    /**
     * 获取 jsapi_ticket
     */
    public function getJsapiTicket()
    {
        $cachename      = ‘js_access_token_online‘;
        if( Config::get( ‘app_debug‘ ) )
            $cachename      = ‘js_access_token‘;

        $jsaccessToken    = $this->cache->get( $this->redisKey . $cachename );
        if( !$jsaccessToken ) {
            //获取用户信息
            $accessToken        = $this->getAccessToken();
            if( !$accessToken ) {
                $this->myLog( ‘获取微信token失败,请检查!!getJsapiTicket 方法执行异常‘ . json_encode( func_get_args() ) );
                return false;
            }

            $url        = Config::get(‘wx.apiUrl‘) . "/cgi-bin/ticket/getticket?access_token={$accessToken}&type=jsapi";
            $res        = $this->sendCurl( $url );
            if( !isset( $res[‘ticket‘] ) || !$res[‘ticket‘] ) {
                $this->myLog( ‘获取 jstoken 失败,请检查‘ . var_export( $res, true ) );
                return false;
            }

            if( !$this->cache->set( $this->redisKey . $cachename, $res[‘ticket‘], $this->accessTokenCt ) ) {
                $this->myLog( ‘服务器缓存jstoken失败‘ );
                return false;
            }

            $jsaccessToken      = $res[‘ticket‘];
        }

        return $jsaccessToken;
    }

    /**
     * 获取 临时素材 图片
     */
    public function getMediaInfoPic( $media_id )
    {
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!getJsapiTicket 方法执行异常‘ . json_encode( func_get_args() ) );
            return false;
        }

        $url        = Config::get(‘wx.apiUrl‘) . "/cgi-bin/media/get?access_token={$accessToken}&media_id={$media_id}";
        $source     = file_get_contents( $url );
        $imageinfo  = getimagesizefromstring( $source );
        $path       = Config::get( ‘upload.idcardpath‘ );
        if( !is_dir( $path ) ) {
            if( !mkdir( $path, 0755, true ) ) {
                $this->myLog( ‘ getMediaInfoPic 创建目录失败,‘ . __FILE__ );
                return false;
            }
        }
        $filename   = ‘‘;
        if( is_array( $imageinfo ) && isset( $imageinfo[‘mime‘] ) ) {
            switch ( $imageinfo[‘mime‘] ) {
                case ‘image/gif‘:
                    $filename   = $media_id . ‘.gif‘;
                    break;
                case ‘image/jpeg‘:
                    $filename   = $media_id . ‘.jpg‘;
                    break;
                case ‘image/png‘ :
                    $filename   = $media_id . ‘.png‘;
                    break;
                default :
                    $filename   = $media_id . ‘.jpg‘;
                    break;
            }

            if( !file_put_contents( $path . $filename, $source ) ) {
                return false;
            }

            return str_replace( ROOT_PATH . ‘public‘, ‘‘, $path ) . $filename;
        }
        return false;
    }

    /**
     * 新增临时素材
     * @param string $type  /image/voice/video/thumb
     *
     * @return string
     */
    public function setMediaInfo( $file, $type = ‘image‘ )
    {
        if( !is_file( $file ) ) {
            $this->myLog( ‘图片消息回复异常,图片查找失败‘ . var_export( is_file( $file ), true ), false );
            return false;
        }

        $fileMd5    = md5_file( $file );

        $cacheName  = ‘Wx:setMediaInfo:‘ . $fileMd5;
        $cacheInfo  = $this->cache->get( $cacheName );
        if( $cacheInfo )
            return $cacheInfo;

        //获取用户信息
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!setButton 方法执行异常‘, false );
            return false;
        }

        $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/media/upload?access_token=‘.$accessToken.‘&type=‘ . $type;

        $fileData   = [
            ‘media‘     => "@{$file}"
        ];
        $info       = $this->sendCurl( $url, ‘post‘, $fileData, false );

        if( !$info ) {
            $this->myLog( ‘上传临时素材失败, url = ‘ . $url );
            return false;
        }

        if( isset( $info[‘media_id‘] ) && $info[‘media_id‘] ) {
            $this->cache->set( $cacheName, $info[‘media_id‘], 252000 ); //70小时
            return $info[‘media_id‘];
        }

        return false;
    }

    /**
     * 文本消息回复
     * @param $toUser
     * @param $fromUser
     * @param $content
     * @return string
     */
    public function responseText( $toUser, $fromUser, $content ){
        $textTpl = <<<EOF
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>
EOF;
        $resultStr = sprintf($textTpl, $toUser, $fromUser, time(), $content );
        return $resultStr;
    }

    /**
     * 图片消息回复
     * @param string $mediaid  绝对路径
     * @return string
     */
    public function responseImg( $toUser, $fromUser, $imgpath )
    {
        //上传临时素材
        $mediaid    = $this->setMediaInfo( $imgpath );
        if( !$mediaid ) {
            $this->myLog( ‘responseImg 上传临时素材失败,返回为空,imgpath ‘ . $imgpath );
            $this->_sendWXText( ‘很抱歉,服务器临时出现故障,请稍后再试...‘ );
        }

        $textTpl    = <<<EOF
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image><MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>
EOF;
        $resultStr = sprintf($textTpl, $toUser, $fromUser, time(), $mediaid );
        return $resultStr;
    }

    /**
     * 客服消息 图片消息
     * @param int $usleep 是否等待几毫秒,生成海报操作中避免比文字出现的时间早,
     *
     * @return boolean
     */
    public function kfResponseImg( $openid, $imgpath, $usleep = 0 )
    {
        if( $usleep )
            usleep( $usleep );

        //上传临时素材
        $mediaid    = $this->setMediaInfo( $imgpath );
        if( !$mediaid ) {
            $this->myLog( ‘responseImg 上传临时素材失败,返回为空,imgpath ‘ . $imgpath , false );
            return false;
        }

        $postData     = [
            ‘touser‘    => $openid,
            ‘msgtype‘   => ‘image‘,
            ‘image‘     => [
                ‘media_id‘  => $mediaid
            ],
        ];

        //获取用户信息
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!setButton 方法执行异常‘, false );
            return false;
        }

        $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/message/custom/send?access_token=‘.$accessToken;
        $info       = $this->sendCurl( $url, ‘post‘, $postData );
        if( !$info || $info[‘errcode‘] ) {
            $this->myLog( ‘发送客服图片消息失败, url = ‘ . $url . ‘ pd == ‘ . json_encode( $postData ), false );
            return true;
        }

        return true;
    }

    /**
     * 客服消息 文字消息
     *
     * @return boolean
     */
    public function kfResponseText( $openid, $content )
    {

        $postData     = [
            ‘touser‘    => $openid,
            ‘msgtype‘   => ‘text‘,
            ‘text‘     => [
                ‘content‘  => $content
            ],
        ];

        //获取用户信息
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!setButton 方法执行异常‘, false );
            return false;
        }

        $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/message/custom/send?access_token=‘.$accessToken;
        $info       = $this->sendCurl( $url, ‘post‘, json_encode( $postData, JSON_UNESCAPED_UNICODE) );
        if( !$info || $info[‘errcode‘] ) {
            $this->myLog( ‘发送客服文本消息失败, url = ‘ . $url . ‘ pd == ‘ . json_encode( $postData ), false );
            return true;
        }

        return true;
    }

    /**
     * 生成微信xml
     * @param string $encrypt 加密后的消息密文
     * @param string $signature 安全签名
     * @param string $timestamp 时间戳
     * @param string $nonce 随机字符串
     *
     * @return string
     */
    public static function createXml( $encrypt, $signature, $timestamp, $nonce )
    {
        $format = "<xml>
<Encrypt><![CDATA[%s]]></Encrypt>
<MsgSignature><![CDATA[%s]]></MsgSignature>
<TimeStamp>%s</TimeStamp>
<Nonce><![CDATA[%s]]></Nonce>
</xml>";
        return sprintf($format, $encrypt, $signature, $timestamp, $nonce);
    }

    /**
     * 日志
     */
    public function __destruct()
    {
    }

    /**
     * 发送模板消息
     */
    public function sendTemplateMsg( $data )
    {
        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!eventSubscribe 方法执行异常‘ . json_encode( func_get_args() ) );
            return false;
        }

        $url    = Config::get( ‘wx.apiUrl‘ ) . ‘/cgi-bin/message/template/send?access_token=‘. $accessToken;
        $this->sendCurl( $url, ‘post‘, $data );
    }

    /**
     * 微信服务号 长连接转短连接
     */
    public function long2short( $longurl )
    {
        if( !$longurl )
            return ‘‘;

        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!eventSubscribe 方法执行异常‘ . json_encode( func_get_args() ) );
            return false;
        }

        if( Config::get(‘app_debug‘) )
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/shorturl?access_token=‘ . $accessToken;
        else
            $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/shorturl?access_token=‘ . $accessToken;

        $res    =  $this->sendCurl( $url, ‘post‘, [
            ‘action‘        => ‘long2short‘,
            ‘long_url‘      => $longurl
        ] );

        if( !isset( $res[‘errcode‘] ) || $res[‘errcode‘] != 0 ){
            $this->myLog( ‘长连接转短连接失败‘ . json_encode( $res ) );
            return false;
        }

        return $res[‘short_url‘];
    }

    /**
     * 文本消息回复终端
     */
    private function _sendWXText( $content )
    {
        ob_start();
        echo $this->responseText( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], $content );
        ob_end_flush();
    }

    /**
     * 图片消息回复终端
     * @param string $file 绝对路径
     */
    private function _sendWXImg( $file )
    {
        ob_start();
        echo $this->responseImg( $this->request->wxRequest[‘fuser‘], $this->request->wxRequest[‘tuser‘], $file );
        ob_end_flush();
    }

    /**
     * 生成永久二维码的ticket
     * @param string $scene_str 最大64位
     */
    public function getQcodeTicket( $scene_str )
    {
        $len        = strlen( $scene_str );
        if( $len < 1 || $len > 64 ) {
            $this->myLog( ‘生成永久二维码的ticket scenstr 长度不合法,, len = ‘ . $len );
            return false;
        }

        $accessToken        = $this->getAccessToken();
        if( !$accessToken ) {
            $this->myLog( ‘获取微信token失败,请检查!!eventSubscribe 方法执行异常‘ . json_encode( func_get_args() ) );
            return false;
        }
        $url        = Config::get(‘wx.apiUrl‘) . ‘/cgi-bin/qrcode/create?access_token=‘ . $accessToken;
        $res    =  $this->sendCurl( $url, ‘post‘, [
            ‘action_name‘   => ‘QR_LIMIT_STR_SCENE‘,
            ‘action_info‘   => [
                ‘scene‘     => [
                    ‘scene_str‘     => $scene_str
                ]
            ],
        ] );
        if( !isset( $res[‘ticket‘] ) || !$res[‘ticket‘] ) {
            $this->myLog( ‘生成永久二维码的ticket 失败,res == ‘ . var_export( $res, true ) );
            return false;
        }

        return $res[‘ticket‘];
    }

    /**
     * 读取二维码图片
     * @param string $response 返回值
     *
     * @return string url
     */
    public function getQcodeImg( $ticket )
    {
        return ‘https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=‘ . $ticket;
    }

    /**
     * 已关注扫描二维码
     *
     */
    public function eventScan()
    {
        $content = <<<EOF
赶快分享吧~[奸笑][奸笑][奸笑]
EOF;
        $this->_sendWXText( $content );
    }

    public function _reMakeCurl()
    {
        $this->curl->close();
        $this->curl     = null;
        $this->curl     = new Curl();
    }

    /**
     * 发送模板消息
     */
    protected function _sendWxTemplate( $template_id, $touser, $url, $data )
    {
        $data[‘template_id‘]        = $template_id;
        if( !$data[‘template_id‘] )
            return ;

        $data[‘touser‘]         = $touser;
        if( !$data[‘touser‘] )
            return ;

        $http       = ‘http://‘;
        if( $_SERVER[‘SERVER_PORT‘] == 443 )
            $http   = ‘https://‘;

        $data[‘url‘]            = $http . $_SERVER[‘SERVER_NAME‘] . $url;
        $data[‘data‘]           = $data;

        register_shutdown_function( function() use ($data ) {
            $wx         = Wx::instance();
            return  $wx->sendTemplateMsg( $data );
        } );
    }
}

  

原文地址:https://www.cnblogs.com/lxdd/p/9142480.html

时间: 2024-11-10 15:38:03

微信 服务号开发的相关文章

微信服务号开发-获取用户位置信息

微信服务号开发-获取用户位置信息 在微信公众号开发的中,获取用户位置信息是非常常见的功能需求,通过用户的位置信息,可以做一些地图导航,以及基于LBS的营销活动.下面将介绍微信服务号获取用户位置信息的原理与步骤. 原理 1. 位置信息获取流程 2. 位置信息报文 <xml><ToUserName><![CDATA[gh_public_member_account]]></ToUserName> <FromUserName><![CDATA[o

微信服务号开发笔记

原理 微信服务号的原理比较简单.从请求响应角度来看,逻辑是: 用户微信客户端 <—> 微信服务器 <—> 微信服务号后台程序 <—> 数据库或Web Service 也就是,用户的各种请求先经过微信的服务器,微信服务器将请求转发给微信服务号后台程序. 既然是微信服务器把用户请求数据转发给我们开发的微信服务号后台程序,那么在启用服务号的开发模式时就需要提供一个URL.另外为了安全 考虑,还需要提供一个token,用来校验请求是否来自微信服务器.校验的方法见微信开发者文档.

微信服务号开发-商城微信登录

最近帮朋友写了个微信服务号,服务号名字叫做十四行诗.没错是卖月饼的商城. 简单介绍下微信登录,与官方文档不同,简单画了一下UML图 简单的说就是先建立了一个index.php(直接拍域名就过去了.),然后传一个appid,微信公众号后台能拿到 <?php $appid = ''; header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri=http://w

JAVA微信服务号开发简记

现在微信公众平台的开发已经越来越普遍,这次开发需要用到微信公众平台.所以这边做一个简单的记录,也算是给那些没踩过坑的童鞋一些启示吧.我将分几块来简单的描述一下,之后会做详细的说明. 基本认证信息说明 首先.微信分为了几个不同的号.有订阅号.服务号.企业号. 其中订阅号是免费的.其他都是要钱的.免费的基本上只能发发信息. 要钱的功能比较全面.基本上微信的接口都能调用了.这里我也主要开发的是服务号. 如果要申请服务号微信也是明码标价,300块一次,一年一次.(收钱真狠) 简单的说,如果你没有交钱那么

微信服务号开发 上传多媒体文件:图片

/**     * 通过文件上传得到文件media_id,文件名     *      * @param file     * @return     */    public static Map<String, String> getIdByUploadFile(File file) {        Map<String, String> map = new HashMap<String, String>();        // 返回文件上传成功的media_i

微信服务号 redirect_uri域名与后台配置不一致,错误代码10003

微信服务号开发获取用户openid时一直提示 redirect_uri域名与后台配置不一致,错误代码10003:后台也配置了域名 原因: 结果:获取到了openid 原文地址:https://www.cnblogs.com/yangzailu/p/8983837.html

利用OpenShift托管Node.js Web服务进行微信公众号开发

最近写了一个微信的翻译机器人.用户只要关注该微信号,发送英文的消息,就能收到中文翻译的回复.后台是用Node.js写的,托管在OpenShift的Paas平台上.翻译过程实际上是调用微软的Bing translation API做的,代码中用到了alexu84的bing-translate和JacksonTian的wechat这两个npm模块.下面把做的过程详细说一下. 1. 微信公众号开发 首先是要到https://mp.weixin.qq.com 申请一个公众号,并申请成为开发者.目前个人只

微信公众服务号开发

1 公司提供接口,微信平台可以通过访问我们的接口,进行数据交互,通过xml. 2 http://mp.weixin.qq.com/ 微信服务号平台,输入用户名密码进入高级功能-开发者模式, 3 申请服务号之后,微信会提供appid和AppSecret两个参数,根据这两个参数可以获取token,token作为你服务号和微信交互的证明. 4 接下里就是完成自己的接口部分的开发,然后接口的服务器配置地址输入微信服务号的服务器配置url,本地的项目地址是不行的,得是能访问的地址 5 接口的开发,接受xm

微信服务号、订阅号和企业号的差别(运营和开发两个角度)

一.运营的角度 1.1.概括 订阅号: 微信最初的形态是一个纯粹的社交工具,也就是人与人之间的联系工具,当中又分熟人之间的联系和陌生人之间的联系.于是就诞生了朋友圈和订阅号. 而订阅号的作用就是媒体社交.订阅号最主要是自媒体或媒体为读者用户提供优质的对他们感兴趣或有价值的内容.从而与关注者建立关系或使用户对自身品牌的认可. 服务号: 相比于订阅号.服务号要复杂的多,当微信有了朋友圈能够卖商品,订阅号能够做营销. 那么当出现人与商业之间的联系需求时.服务号便诞生了,它不仅要要做一个服务者还要做一个