Maison >Applet WeChat >Développement WeChat >Yii2.0 implémente le développement backend des comptes publics WeChat
Cet article contient beaucoup de contenu, notamment l'accès à WeChat, l'obtention d'informations sur les utilisateurs WeChat, le paiement WeChat et l'obtention des paramètres de configuration JSSDK. Si le lecteur n'a pas une compréhension subjective du développement de WeChat, il est recommandé qu'il étudie d'abord la Documentation du développeur de la plateforme publique WeChat, puis de lire cet article pour de meilleurs résultats ! De plus, la version chapitre par section de cet article est disponible sur le blog de Babao Porridge.
1. Configurez les paramètres du jeton dans app/config/params.php
return [ //微信接入 'wechat' =>[ 'token' => 'your token', ], ];
2. . Configurez le routage
dans app/config/main.php car le module d'interface utilise l'API RESTful, vous devez donc définir des règles de routage . .
'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ [ 'class' => 'yii\rest\UrlRule', 'controller' => 'wechat', 'extraPatterns' => [ 'GET valid' => 'valid', ], ], ], ],
3. Créez un nouveau WechatController dans app/controllers
<?php namespace api\controllers; use Yii; use yii\rest\ActiveController; class WechatController extends ActiveController { public $modelClass = ''; public function actionValid() { $echoStr = $_GET["echostr"]; $signature = $_GET["signature"]; $timestamp = $_GET["timestamp"]; $nonce = $_GET["nonce"]; //valid signature , option if($this->checkSignature($signature,$timestamp,$nonce)){ echo $echoStr; } } private function checkSignature($signature,$timestamp,$nonce) { // you must define TOKEN by yourself $token = Yii::$app->params['wechat']['token']; if (!$token) { echo 'TOKEN is not defined!'; } else { $tmpArr = array($token, $timestamp, $nonce); // use SORT_STRING rule sort($tmpArr, SORT_STRING); $tmpStr = implode( $tmpArr ); $tmpStr = sha1( $tmpStr ); if( $tmpStr == $signature ){ return true; }else{ return false; } } } }
Configurez l'URL et le jeton en arrière-plan du compte officiel WeChat. , puis soumettez-le. Vérifiez simplement.
URL:http://app.demo.com/wechats/valid Token:your token
CREATE TABLE `wechat_user` ( `id` int(11) NOT NULL, `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `nickname` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '微信昵称', `sex` tinyint(4) NOT NULL COMMENT '性别', `headimgurl` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '头像', `country` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '国家', `province` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '省份', `city` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '城市', `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `refresh_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; ALTER TABLE `wechat_user` ADD PRIMARY KEY (`id`);
Interface d'autorisation utilisateur : obtenir access_token , openid, etc. ; obtenir et enregistrer les informations utilisateur dans la base de données
public function actionAccesstoken() { $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. Obtenir les informations utilisateur de WeChat
public function getUserInfo($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. Obtenir l'interface d'informations utilisateur
public function actionUserinfo() { 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; }Paiement WeChat1. Interface de paiement WeChat : données de paiement packagées
public function actionPay(){ 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 = new WechatPay($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. Recevez une notification de résultat de paiement asynchrone envoyée par WeChat
public function actionNotify(){ $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); // if ($postObj === false) { die('parse xml error'); } 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 = new WechatPay($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 ($orders as $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. . Classe de paiement WeChat WechatPay.php
<?php namespace api\sdk; use Yii; class WechatPay { protected $mchid; protected $appid; protected $key; public function construct($mchid, $appid, $key){ $this->mchid = $mchid; $this->appid = $appid; $this->key = $key; } public function createJsBizPackage($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('parse xml error'); } 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; } public static function curlGet($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; } public static function curlPost($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; } public static function createNonceStr($length = 16){ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i = 0; $i<$length; $i++){ $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } public static function arrayToXml($arr){ $xml = "<xml>"; foreach ($arr as $key => $val){ if (is_numeric($val)) { $xml .= "<" . $key . ">" . $val . "</" . $key . ">"; } else { $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">"; } } $xml .= "</xml>"; return $xml; } public static function getSign($params, $key){ ksort($params, SORT_STRING); $unSignParaString = self::formatQueryParaMap($params, false); $signStr = strtoupper(md5($unSignParaString . "&key=" . $key)); return $signStr; } protected static function formatQueryParaMap($paraMap, $urlEncode = false){ $buff = ""; ksort($paraMap); foreach ($paraMap as $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; } }Obtenez les paramètres de configuration du JS-SDKSelon la documentation du développeur de la plateforme publique WeChat : Toutes les pages qui doivent le faire. utiliser JS-SDK doit d'abord injecter les informations de configuration, sinon elles ne seront pas appelées (la même URL ne doit être appelée qu'une seule fois. L'application Web du SPA qui modifie l'URL peut être appelée à chaque fois que l'URL change. Actuellement C'est-à-dire :
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });1. Classe de paiement Wechat WechatPay.php
<?php namespace api\sdk; use Yii; class WechatPay { public function getSignPackage($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; } public static function getJsApiTicket() { //使用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; } public static function getAccessToken() { //使用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; } public static function curlGet($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; } public static function curlPost($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; } public static function createNonceStr($length = 16){ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i = 0; $i<$length; $i++){ $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } }2. Obtenez l'interface des paramètres de configuration .
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!