微信 服务号开发
Posted 栋的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信 服务号开发相关的知识,希望对你有一定的参考价值。
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 ); } ); } }
以上是关于微信 服务号开发的主要内容,如果未能解决你的问题,请参考以下文章