完美利用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的微信公众平台开发有所帮助。