公衆號中的微信支付須要經過JS來實現。微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。點擊查看在線文檔。php
1)引入JS腳本文件html
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
2)經過config接口注入權限驗證配置git
<script> wx.config({ debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '', // 必填,公衆號的惟一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名 }); </script>
appId就是應用ID,wx打頭的那串字符,timestamp在php中就用time()獲取,而nonceStr就用uniqid()獲取,而signature根據特定算法獲取。github
protected function getJsapiConfig() { $weixin = new Weixin(); $ticketMongo = new WeixinJsapiTicket(); $data = [ 'appId' => $weixin->getAppId(), 'noncestr' => uniqid(), 'jsapi_ticket' => $ticketMongo->getJsapiTicket(), 'timestamp' => time() ]; //拼裝原始待簽名串 $src = [ 'noncestr=' . $data['noncestr'], 'jsapi_ticket=' . $data['jsapi_ticket'], 'timestamp=' . $data['timestamp'] ]; sort($src); $data['signature'] = sha1(implode('&', $src)); return $data; }
這裏說明下「jsapi_ticket」,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲有時間限制,並且獲取jsapi_ticket的api調用次數很是有限,因此我會將獲取到的jsapi_ticket保存到MongoDB中。算法
/** * 經過access_token獲取jsapi_ticket * @param $access_token * @return string | null */ public function getJsapiTicket($access_token) { $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket'; $param = [ 'access_token' => $access_token, 'type' => 'jsapi' ]; $res = $this->request($url, $param); $result = json_decode($res, true); if (isset($result['errcode']) && $result['errcode'] == 0 && isset($result['ticket'])) { return $result; } return null; }
3)經過ready接口處理成功驗證json
1)prepay_id是根據本地生成的訂單號等獲取的,訂單號每次請求的得不同,否則會報錯的,點擊查看在線文檔。api
2)nonceStr就用md5(uniqid('baiaimama'))獲取微信
3)signType使用MD5app
4)paySign根據代碼的參數,排序後拼接得到。微信公衆平臺
wx.chooseWXPay({ timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: '', // 支付簽名隨機串,不長於 32 位 package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***) signType: '', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: '', // 支付簽名 success: function (res) { // 支付成功後的回調函數 } });
/** * 生成jsapi須要調用的參數 */ public function getJsapiParam(){ $param = [ 'appId' => $this->APPID, 'timeStamp' => time(), 'nonceStr' => md5(uniqid('baiaimama')), 'package' => 'prepay_id='.$this->param['prepay_id'], 'signType' => 'MD5' ]; $str = []; foreach($param as $k=>$v){ if(!empty($v)){ $str[] = "{$k}={$v}"; } } sort($str); $unsignKey = join('&', $str).'&key='.$this->KEY; $sign = strtoupper(md5($unsignKey)); $param['paySign'] = $sign; return $param; }
異步回調中作些修改訂單狀態、發送短信,推送消息等操做。
/** * 微信支付異步回調API * 微信支付成功,會收到異步回調 */ public function actionWxpay() { $weixinPay = new WeixinPay(); $weixin = new Weixin(); $xml = file_get_contents('php://input'); $msg = $weixin->parseMsg($xml); //記錄微信推送日誌 $notifyMongo = new WeixinPayNotify(); $notifyMongo->logPayNotify($xml); if(!$msg || !is_object($msg)){ $weixinPay->notifyXml('FAIL', '通知不合法'); } if(!isset($msg->return_code) || $msg->return_code != 'SUCCESS'){ $weixinPay->notifyXml('FAIL', '通訊失敗'); } if(!isset($msg->result_code) || $msg->result_code != "SUCCESS"){ $weixinPay->notifyXml('FAIL', '交易失敗'); } //簽名驗證失敗 if(!$weixinPay->checkSign($msg)){ $weixinPay->notifyXml('FAIL', '簽名驗證失敗'); } //$notifyMongo->add($msg); //流程走到這裏說明已經支付成功了,這裏無需更新訂單邏輯 $userOrder = new UserOrder(); //記錄微信訂單號 $userOrder->pay($msg->out_trade_no, $msg->transaction_id); }
demo下載: