完美利用Yii2微信后台开发的系列总结
网上有很多关于YII2.0微信开发教程,但是太过复杂凌乱,所以今天在这里给大家整理总结利用Yii2微信后台开发的系列了,给需要的小伙伴们参考。
一:接入微信
Yii2后台配置
1.在app/config/params.php中配置token参数
return[ //微信接入 'wechat'=>[ 'token'=>'yourtoken', ], ];
2.在app/config/main.php中配置路由
因为接口模块使用的RESTfulAPI,所以需要定义路由规则。
'urlManager'=>[ 'enablePrettyUrl'=>true, 'enableStrictParsing'=>true, 'showScriptName'=>false, 'rules'=>[ [ 'class'=>'yii\rest\UrlRule', 'controller'=>'wechat', 'extraPatterns'=>[ 'GETvalid'=>'valid', ], ], ], ],
3.在app/controllers中新建WechatController
<?php namespaceapi\controllers; useYii; useyii\rest\ActiveController; classWechatControllerextendsActiveController { public$modelClass=''; publicfunctionactionValid() { $echoStr=$_GET["echostr"]; $signature=$_GET["signature"]; $timestamp=$_GET["timestamp"]; $nonce=$_GET["nonce"]; //validsignature,option if($this->checkSignature($signature,$timestamp,$nonce)){ echo$echoStr; } } privatefunctioncheckSignature($signature,$timestamp,$nonce) { //youmustdefineTOKENbyyourself $token=Yii::$app->params['wechat']['token']; if(!$token){ echo'TOKENisnotdefined!'; }else{ $tmpArr=array($token,$timestamp,$nonce); //useSORT_STRINGrule sort($tmpArr,SORT_STRING); $tmpStr=implode($tmpArr); $tmpStr=sha1($tmpStr); if($tmpStr==$signature){ returntrue; }else{ returnfalse; } } } }
微信公众号后台配置
在微信公众号后台配置URL和Token,然后提交验证即可。
URL:http://app.demo.com/wechats/valid Token:yourtoken
二:获取用户信息
用户表设计
CREATETABLE`wechat_user`( `id`int(11)NOTNULL, `openid`varchar(255)COLLATEutf8_unicode_ciNOTNULL, `nickname`varchar(50)COLLATEutf8_unicode_ciNOTNULLCOMMENT'微信昵称', `sex`tinyint(4)NOTNULLCOMMENT'性别', `headimgurl`varchar(255)COLLATEutf8_unicode_ciNOTNULLCOMMENT'头像', `country`varchar(50)COLLATEutf8_unicode_ciNOTNULLCOMMENT'国家', `province`varchar(50)COLLATEutf8_unicode_ciNOTNULLCOMMENT'省份', `city`varchar(50)COLLATEutf8_unicode_ciNOTNULLCOMMENT'城市', `access_token`varchar(255)COLLATEutf8_unicode_ciNOTNULL, `refresh_token`varchar(255)COLLATEutf8_unicode_ciNOTNULL, `created_at`timestampNULLDEFAULTCURRENT_TIMESTAMP )ENGINE=InnoDBAUTO_INCREMENT=4DEFAULTCHARSET=utf8COLLATE=utf8_unicode_ci; ALTERTABLE`wechat_user` ADDPRIMARYKEY(`id`);
获取用户信息的相关接口
1.用户授权接口:获取access_token、openId等;获取并保存用户资料到数据库
publicfunctionactionAccesstoken() { $code=$_GET["code"]; $state=$_GET["state"]; $appid=Yii::$app->params['wechat']['appid']; $appsecret=Yii::$app->params['wechat']['appsecret']; $request_url='https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code'; //初始化一个curl会话 $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$request_url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); $result=curl_exec($ch); curl_close($ch); $result=$this->response($result); //获取token和openid成功,数据解析 $access_token=$result['access_token']; $refresh_token=$result['refresh_token']; $openid=$result['openid']; //请求微信接口,获取用户信息 $userInfo=$this->getUserInfo($access_token,$openid); $user_check=WechatUser::find()->where(['openid'=>$openid])->one(); if($user_check){ //更新用户资料 }else{ //保存用户资料 } //前端网页的重定向 if($openid){ return$this->redirect($state.$openid); }else{ return$this->redirect($state); } }
2.从微信获取用户资料
publicfunctiongetUserInfo($access_token,$openid) { $request_url='https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN'; //初始化一个curl会话 $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$request_url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); $result=curl_exec($ch); curl_close($ch); $result=$this->response($result); return$result; }
3.获取用户资料接口
publicfunctionactionUserinfo() { if(isset($_REQUEST["openid"])){ $openid=$_REQUEST["openid"]; $user=WechatUser::find()->where(['openid'=>$openid])->one(); if($user){ $result['error']=0; $result['msg']='获取成功'; $result['user']=$user; }else{ $result['error']=1; $result['msg']='没有该用户'; } }else{ $result['error']=1; $result['msg']='openid为空'; } return$result; }
三:微信支付
1.微信支付接口:打包支付数据
publicfunctionactionPay(){ if(isset($_REQUEST["uid"])&&isset($_REQUEST["oid"])&&isset($_REQUEST["totalFee"])){ //uid、oid、totalFee $uid=$_REQUEST["uid"]; $oid=$_REQUEST["oid"]; $totalFee=$_REQUEST["totalFee"]; $timestamp=time(); //微信支付参数 $appid=Yii::$app->params['wechat']['appid']; $mchid=Yii::$app->params['wechat']['mchid']; $key=Yii::$app->params['wechat']['key']; $notifyUrl=Yii::$app->params['wechat']['notifyUrl']; //支付打包 $wx_pay=newWechatPay($mchid,$appid,$key); $package=$wx_pay->createJsBizPackage($uid,$totalFee,$oid,$notifyUrl,$timestamp); $result['error']=0; $result['msg']='支付打包成功'; $result['package']=$package; return$result; }else{ $result['error']=1; $result['msg']='请求参数错误'; } return$result; }
2.接收微信发送的异步支付结果通知
publicfunctionactionNotify(){ $postStr=$GLOBALS["HTTP_RAW_POST_DATA"]; $postObj=simplexml_load_string($postStr,'SimpleXMLElement',LIBXML_NOCDATA); // if($postObj===false){ die('parsexmlerror'); } if($postObj->return_code!='SUCCESS'){ die($postObj->return_msg); } if($postObj->result_code!='SUCCESS'){ die($postObj->err_code); } //微信支付参数 $appid=Yii::$app->params['wechat']['appid']; $mchid=Yii::$app->params['wechat']['mchid']; $key=Yii::$app->params['wechat']['key']; $wx_pay=newWechatPay($mchid,$appid,$key); //验证签名 $arr=(array)$postObj; unset($arr['sign']); if($wx_pay->getSign($arr,$key)!=$postObj->sign){ die("签名错误"); } //支付处理正确-判断是否已处理过支付状态 $orders=Order::find()->where(['uid'=>$postObj->openid,'oid'=>$postObj->out_trade_no,'status'=>0])->all(); if(count($orders)>0){ //更新订单状态 foreach($ordersas$order){ //更新订单 $order['status']=1; $order->update(); } return'<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ //订单状态已更新,直接返回 return'<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } }
3.微信支付类WechatPay.php
<?php namespaceapi\sdk; useYii; classWechatPay { protected$mchid; protected$appid; protected$key; publicfunction__construct($mchid,$appid,$key){ $this->mchid=$mchid; $this->appid=$appid; $this->key=$key; } publicfunctioncreateJsBizPackage($openid,$totalFee,$outTradeNo,$orderName,$notifyUrl,$timestamp){ $config=array( 'mch_id'=>$this->mchid, 'appid'=>$this->appid, 'key'=>$this->key, ); $unified=array( 'appid'=>$config['appid'], 'attach'=>'支付', 'body'=>$orderName, 'mch_id'=>$config['mch_id'], 'nonce_str'=>self::createNonceStr(), 'notify_url'=>$notifyUrl, 'openid'=>$openid, 'out_trade_no'=>$outTradeNo, 'spbill_create_ip'=>'127.0.0.1', 'total_fee'=>intval($totalFee*100), 'trade_type'=>'JSAPI', ); $unified['sign']=self::getSign($unified,$config['key']); $responseXml=self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder',self::arrayToXml($unified)); $unifiedOrder=simplexml_load_string($responseXml,'SimpleXMLElement',LIBXML_NOCDATA); if($unifiedOrder===false){ die('parsexmlerror'); } if($unifiedOrder->return_code!='SUCCESS'){ die($unifiedOrder->return_msg); } if($unifiedOrder->result_code!='SUCCESS'){ die($unifiedOrder->err_code); } $arr=array( "appId"=>$config['appid'], "timeStamp"=>$timestamp, "nonceStr"=>self::createNonceStr(), "package"=>"prepay_id=".$unifiedOrder->prepay_id, "signType"=>'MD5', ); $arr['paySign']=self::getSign($arr,$config['key']); return$arr; } publicstaticfunctioncurlGet($url='',$options=array()){ $ch=curl_init($url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_TIMEOUT,30); if(!empty($options)){ curl_setopt_array($ch,$options); } //https请求不验证证书和host curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); $data=curl_exec($ch); curl_close($ch); return$data; } publicstaticfunctioncurlPost($url='',$postData='',$options=array()){ if(is_array($postData)){ $postData=http_build_query($postData); } $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_POST,1); curl_setopt($ch,CURLOPT_POSTFIELDS,$postData); curl_setopt($ch,CURLOPT_TIMEOUT,30);//设置cURL允许执行的最长秒数 if(!empty($options)){ curl_setopt_array($ch,$options); } //https请求不验证证书和host curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); $data=curl_exec($ch); curl_close($ch); return$data; } publicstaticfunctioncreateNonceStr($length=16){ $chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str=''; for($i=0;$i<$length;$i++){ $str.=substr($chars,mt_rand(0,strlen($chars)-1),1); } return$str; } publicstaticfunctionarrayToXml($arr){ $xml="<xml>"; foreach($arras$key=>$val){ if(is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return$xml; } publicstaticfunctiongetSign($params,$key){ ksort($params,SORT_STRING); $unSignParaString=self::formatQueryParaMap($params,false); $signStr=strtoupper(md5($unSignParaString."&key=".$key)); return$signStr; } protectedstaticfunctionformatQueryParaMap($paraMap,$urlEncode=false){ $buff=""; ksort($paraMap); foreach($paraMapas$k=>$v){ if(null!=$v&&"null"!=$v){ if($urlEncode){ $v=urlencode($v); } $buff.=$k."=".$v."&"; } } $reqPar=''; if(strlen($buff)>0){ $reqPar=substr($buff,0,strlen($buff)-1); } return$reqPar; } }
四:获取JS-SDK的config参数
根据微信公众平台开发者文档:
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的webapp可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现webapp的页面会导致签名失败,此问题会在Android6.2中修复)。
即:
wx.config({ debug:true,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:'',//必填,公众号的唯一标识 timestamp:,//必填,生成签名的时间戳 nonceStr:'',//必填,生成签名的随机串 signature:'',//必填,签名,见附录1 jsApiList:[]//必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
1.微信支付类WechatPay.php
<?php namespaceapi\sdk; useYii; classWechatPay { publicfunctiongetSignPackage($url){ $jsapiTicket=self::getJsApiTicket(); $timestamp=time(); $nonceStr=self::createNonceStr(); //这里参数的顺序要按照key值ASCII码升序排序 $string="jsapi_ticket=".$jsapiTicket."&noncestr=".$nonceStr."×tamp=".$timestamp."&url=".$url; $signature=sha1($string); $signPackage=array( "appId" =>$this->appid, "nonceStr" =>$nonceStr, "timestamp"=>$timestamp, "url" =>$url, "signature"=>$signature, "rawString"=>$string ); return$signPackage; } publicstaticfunctiongetJsApiTicket(){ //使用Redis缓存jsapi_ticket $redis=Yii::$app->redis; $redis_ticket=$redis->get('wechat:jsapi_ticket'); if($redis_ticket){ $ticket=$redis_ticket; }else{ $accessToken=self::getAccessToken(); $url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$accessToken; $res=json_decode(self::curlGet($url)); $ticket=$res->ticket; if($ticket){ $redis->set('wechat:jsapi_ticket',$ticket); $redis->expire('wechat:jsapi_ticket',7000); } } return$ticket; } publicstaticfunctiongetAccessToken(){ //使用Redis缓存access_token $redis=Yii::$app->redis; $redis_token=$redis->get('wechat:access_token'); if($redis_token){ $access_token=$redis_token; }else{ $appid=Yii::$app->params['wechat']['appid']; $appsecret=Yii::$app->params['wechat']['appsecret']; $url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret; $res=json_decode(self::curlGet($url)); $access_token=$res->access_token; if($access_token){ $redis->set('wechat:access_token',$access_token); $redis->expire('wechat:access_token',7000); } } return$access_token; } publicstaticfunctioncurlGet($url='',$options=array()){ $ch=curl_init($url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_TIMEOUT,30); if(!empty($options)){ curl_setopt_array($ch,$options); } //https请求不验证证书和host curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); $data=curl_exec($ch); curl_close($ch); return$data; } publicstaticfunctioncurlPost($url='',$postData='',$options=array()){ if(is_array($postData)){ $postData=http_build_query($postData); } $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_POST,1); curl_setopt($ch,CURLOPT_POSTFIELDS,$postData); curl_setopt($ch,CURLOPT_TIMEOUT,30);//设置cURL允许执行的最长秒数 if(!empty($options)){ curl_setopt_array($ch,$options); } //https请求不验证证书和host curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); $data=curl_exec($ch); curl_close($ch); return$data; } publicstaticfunctioncreateNonceStr($length=16){ $chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str=''; for($i=0;$i<$length;$i++){ $str.=substr($chars,mt_rand(0,strlen($chars)-1),1); } return$str; } }
2.获取config参数接口
publicfunctionactionConfig(){ if(isset($_REQUEST['url'])){ $url=$_REQUEST['url']; //微信支付参数 $appid=Yii::$app->params['wechat']['appid']; $mchid=Yii::$app->params['wechat']['mchid']; $key=Yii::$app->params['wechat']['key']; $wx_pay=newWechatPay($mchid,$appid,$key); $package=$wx_pay->getSignPackage($url); $result['error']=0; $result['msg']='获取成功'; $result['config']=$package; }else{ $result['error']=1; $result['msg']='参数错误'; } return$result; }
以上就是利用Yii2微信后台开发全部过程及示例代码,希望本文对大家基于php的微信公众平台开发有所帮助。