序言javascript
隨着微信被愈來愈多的人使用,微信商城成爲現在的熱門。每個商城都須要有本身的支付方式,微信商城也不例外。微信公衆號支付就是微信商城的一種支付方式,微信支付隨着微信的推廣使用也被普遍應用。今天我主要講的是yii2嵌入微信公衆號支付,微信官網的微信支付文檔比較簡潔,接下來跟着我來看一下yii2如何嵌入微信公衆號支付,以及須要注意的事項吧!php
前期準備工做html
首先必須有一個微信公衆號,而且須要在微信公衆平臺申請微信支付。微信公衆平臺的地址是:https://mp.weixin.qq.com/cgi-bin/loginpage。申請的過程我這邊就不寫了,錄公衆平臺之後就能夠看到。
其次須要先配置一個域名,必須是80端口,而後在申請完微信支付之後配置上支付受權目錄。
準備工做完成之後咱們能夠開始開發了。java
代碼分析git
一、咱們須要獲取到關注微信公衆號的人的openid。獲取openid,我這邊是經過網頁受權獲取用戶基本信息接口獲取的。其實在github上已經有封裝好的關於微信的開發的接口,咱們能夠直接從上面下載,之後基於yii2的開發微信的其餘的功能能夠使用。網址是:https://github.com/callmez/yii2-wechat-sdk 你們能夠下載而後安裝。個人openid的獲取也是在此基礎上更改的。安裝完成之後的目錄結構以下圖:github
我這邊使用的是MpWechat.php,在MpWechat.php中我增長了一個方法獲取openid。web
public function getOpenid($turl) { if (!isset($_GET['code'])){ //觸發微信返回code碼 $url=$this->getOauth2AuthorizeUrl($turl, $this->state, 'snsapi_userinfo'); Header("Location: $url"); exit(); } else { //獲取code碼,以獲取openid $code = $_GET['code']; $access_info = $this->getOauth2AccessToken($code); return $access_info; } }
$turl是獲取到code之後須要跳轉的地址。
在控制其中獲取openid我是這樣寫的:ajax
public function actionView($id) { $openid=isset($_COOKIE['openid'])?$_COOKIE['openid']:''; if(empty($openid)) { $t_url=Url::to(['@web/clue/view?id='.$id],true);//這個是獲取到code之後須要跳轉的url。Url這個是在頭部須要增長:use yii\helpers\Url $info=$this->wechat->getOpenid($t_url);//注:$this->wechat安裝完成yii2-wechat-sdk之後配置之後能夠使用 if($info){ setcookie('access_token',$info['access_token'],time()+86400*365); setcookie('openid',$info['openid'],time()+86400*365); } } }
將獲取到的openid放入的cookie中儲存。
二、openid獲取之後能夠進行開發微信支付,我這邊將微信支付封裝成了一個類,能夠配置訪問。json
第一步、咱們能夠在common/config/main.php中配置api
return [ 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'language' => 'zh-CN', // 啓用國際化支持 'sourceLanguage' => 'zh-CN', // 源代碼採用中文 'timeZone' => 'Asia/Shanghai', // 設置時區 'components' => [ 'cache' => [ 'class' => 'yii\caching\FileCache', ], 'user' => [ 'identityClass' => 'login\models\User', 'enableAutoLogin' => false, //開啓authTimeout失效 'identityCookie' => ['name' => '_identity', 'httpOnly' => true,'domain' => '.' . DOMAIN], // 'returnUrl'=>'//' . DOMAIN_HOME, 'authTimeout' => 24*3600*30, // 30 days ], 'session' => [ 'timeout' => 24*3600*30, // 30 days 'useCookies' => true, 'cookieParams' => [ 'domain' => '.' . DOMAIN, 'lifetime' => 24*3600*30, ], ], //這個是支付的 'payment' => [ 'class'=>'common\widgets\payment\Instance', 'weixinjspi_config' => [ 'code' => 2, 'appid' => 'wx88ee3ca8c06be5c6',//微信的appid 'secret' => '48180f87c2693d50b29d822d019999',//appsecret,在申請完公衆號之後能夠看到 'mch_id' => '13260614455',//商戶號 'key' => '16ceshi',//key須要設置 'cert_path' => '',//能夠不用填寫 'key_path' => '',//能夠不用填寫 ], ], ],
我上面的appid、key等都是錯誤信息須要大家根據本身申請的微信支付進行填寫
第二步、在commonwidgets中加入payment文件夾,在文件夾中增長Instance.php
<?php namespace common\widgets\payment; use yii\base\Component; class Instance extends Component{ private $weixin_config; private $weixins_config; private $weixinjspi_config; private $alipay_config; private $balance_config; private $_weixin = null; private $_weixins = null; private $_alipay = null; private $_balance = null; private $_weixinjspi = null; public function setWeixin_config($config) { $this->weixin_config = $config; } public function setWeixins_config($config) { $this->weixins_config = $config; } public function setWeixinjspi_config($config) { $this->weixinjspi_config = $config; } public function setAlipay_config($config) { $this->alipay_config = $config; } public function setBalance_config($config) { $this->balance_config = $config; } /** * 組合使用餘額支付和其餘支付 * @param $order * @param $payment * @param $balance */ public function unionPay($order,$payment,$balance,$notify) { $res = []; $total_fee = $order['total_fee']; if($balance > 0) { $pay = $this->getBalance(); if($balance >= $total_fee) { $res['balance'] = $pay->pay($order); return $res; } else { $order['total_fee'] = $balance; $res['balance'] = $pay->pay($order); $total_fee -= $balance; } } $order['total_fee'] = $total_fee; $pay = $this->$payment; $pay->setNotifyUrl($notify); $res[$payment] = $pay->prepay($order); //$res[$payment]['balance'] = $balance; return $res; } /** * 得到支付寶支付 * @param null $notify_url * @return mixed|object */ public function getAlipay($notify_url = null) { $this->alipay_config = array_merge(['class'=>Alipay::className()],$this->alipay_config); //'var_dump($this->alipay_config);exit; return $this->_getPayment('_alipay',$notify_url); } /** * 得到微信app c端支付 * @param null $notify_url * @return mixed|object */ public function getWeixin($notify_url = null) { $this->weixin_config = array_merge(['class'=>Weixin::className()],$this->weixin_config); return $this->_getPayment('_weixin',$notify_url); } /** * 得到手機微信端支付 * @param null $notify_url * @return mixed|object */ public function getWeixinjspi($notify_url = null) { $this->weixinjspi_config = array_merge(['class'=>Weixinjspi::className()],$this->weixinjspi_config); return $this->_getPayment('_weixinjspi',$notify_url); } /** * 得到微信app s端支付 * @param null $notify_url * @return mixed|object */ public function getWeixins($notify_url = null) { $this->weixins_config = array_merge(['class'=>Weixin::className()],$this->weixins_config); return $this->_getPayment('_weixins',$notify_url); } /** * 得到餘額支付 * @return mixed|object */ public function getBalance() { $this->balance_config = array_merge(['class'=>Balance::className()],$this->balance_config); return $this->_getPayment('_balance',null); } /** * @param $name * @param $notify_url * @return mixed|object * @throws \yii\base\InvalidConfigException */ private function _getPayment($name, $notify_url) { $config = substr($name.'_config',1); if(is_null($this->{$name})) { $this->{$name} = \Yii::createObject($this->{$config}); } if(!is_null($notify_url)) { $this->{$name}->setNotifyUrl($notify_url); } return $this->{$name}; } }
這個類實際上是結合了其餘的支付方式,其中如今最主要的是getWeixinjspi($notify_url = null)這個方法。
除了這個還須要增長Weixinjspi.php
<?php namespace common\widgets\payment; use Yii; use yii\base\InvalidConfigException; use yii\base\InvalidValueException; class Weixinjspi extends Payment { public $order_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; public $search_order_url = 'https://api.mch.weixin.qq.com/pay/orderquery'; public $close_order_url = 'https://api.mch.weixin.qq.com/pay/closeorder'; public $refund_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'; public $notify_url; public $search_refund_url = 'https://api.mch.weixin.qq.com/pay/refundquery'; public $order_pre = 'Weixin'; private $appid; private $mch_id; private $key; private $key_path; private $secret; private $cert_path; private $notify_data; private $curl_proxy_host; private $curl_proxy_port; public function setAppid($appid) { $this->appid = $appid; } public function setKey($key) { $this->key = $key; } public function setSecret($secret) { $this->secret = $secret; } public function setKey_path($key_path) { $this->key_path = Yii::getAlias($key_path); } public function setCert_path($cert_path) { $this->cert_path = Yii::getAlias($cert_path); } public function setMch_id($mch_id) { $this->mch_id = $mch_id; } public function init() { parent::init(); $needs = array('appid','mch_id','key','secret'); foreach($needs as $need) { if(empty($this->{$need})) { throw new InvalidConfigException(get_class($this) . " must define weixin's params {$need}."); } } } private function _checkRefund() { $needs = array('key_path','cert_path'); foreach($needs as $need) { if(empty($this->{$need})) { throw new InvalidConfigException(get_class($this) . " must define weixin's params {$need}."); } } } /** * jsapi支付接口 * @param $order * @return mixed */ public function pay($order) { $paras = [ 'body' =>$order['goods_desc'],//設置商品或支付單簡要描述 'attach' =>'PC',//設置附加數據,在查詢API和支付通知中原樣返回,該字段主要用於商戶攜帶訂單的自定義數據 'out_trade_no' =>$this->order_pre.$order['order_sn'],//訂單號 'total_fee' =>(int)($order['total_fee'] * 100),//訂單總金額 'detail' =>$order['body'], 'time_start' =>empty($order['time_start'])? '':$order['time_start'], 'time_expire' =>empty($order['time_expire'])? '':$order['time_expire'], 'goods_tag' =>empty($order['goods_tag'])? '':$order['goods_tag'],//設置商品標記,代金券或立減優惠功能的參數,說明詳見代金券或立減優惠 'notify_url' =>empty($order['notify_url'])? '':$this->setNotifyUrl($order['notify_url']),//回調地址 'trade_type' =>'JSAPI', 'product_id' =>empty($order['order_sn'])? '':$order['order_sn'], 'openid' =>empty($order['openid'])? '':$order['openid'], 'nonce_str' =>$this->randomStr(), ]; ///var_dump($paras);exit; $timeout = empty($order['timeout'])? 6 :$order['timeout']; if($order['total_fee'] <= 0) { throw new InvalidValueException(get_class($this) . " 支付金額必須大於0"); } $trade = $this->createOrder($paras,$timeout); if(isset($trade['return_code']) && $trade['return_code'] == 'SUCCESS') { if(isset($trade['result_code']) && $trade['result_code'] == 'SUCCESS') { $data=[ 'appId' =>$trade['appid'], 'timeStamp'=>"".time()."", 'nonceStr' =>$this->randomStr(), 'signType'=>'MD5', 'package' =>'prepay_id='.$trade['prepay_id'], ]; $data['paySign']=$this->sign($data); //$data['signature']=$order['signature']; $parameters = json_encode($data); return $parameters;//二維碼的信息 } else { return false; } } else { return false; } } public function getJs($parameters,$order_sn) { $str="<script type=\"text/javascript\"> //調用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', ".$parameters.", function(res){ if(res.err_msg == \"get_brand_wcpay_request:ok\") { $.ajax({ type:\"get\", url:\"/clue/pay_status?order_sn=".$order_sn."\", datatype:\"json\", data:{}, success: function(data_) { window.location.reload(); } }) alert('支付成功!'); }else if(res.err_msg == \"get_brand_wcpay_request:cancel\") { alert('支付過程當中用戶取消!'); }else{ alert('支付失敗!'); } } ); } function callpay() { if (typeof WeixinJSBridge ==\"undefined\"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> "; return $str; } /** * 預支付接口,在APP上發起支付 * @param $order * @return mixed */ public function prepay($order) { $needs = array('title','order_sn','body','total_fee'); foreach($needs as $need) { if(!isset($order[$need])) { throw new InvalidConfigException(get_class($this) . " \$order 中必須包含鍵 {$need}."); } } $paras = [ 'trade_type' =>'APP', 'time_start' =>empty($order['time_start'])? '':$order['time_start'], 'time_expire' =>empty($order['time_expire'])? '':$order['time_expire'], 'goods_tag' =>empty($order['goods_tag'])? '':$order['goods_tag'], 'device_info' =>empty($order['device_info'])? '':$order['device_info'], 'out_trade_no' =>$this->order_pre.$order['order_sn'], 'detail' =>$order['body'], 'total_fee' =>(int)($order['total_fee'] * 100), 'body' =>$order['title'], 'fee_type' =>empty($order['fee_type'])? '':$order['fee_type'], 'product_id' =>empty($order['product_id'])? '':$order['product_id'], 'openid' =>empty($order['openid'])? '':$order['openid'], 'attach' =>empty($order['attach'])? '':$order['attach'], 'notify_url' =>empty($order['notify_url'])? '':$this->setNotifyUrl($order['notify_url']),//回調地址 ]; $timeout = empty($order['timeout'])? 6 :$order['timeout']; if($order['total_fee'] <= 0) { throw new InvalidValueException(get_class($this) . " 支付金額必須大於0"); } $trade = $this->createOrder($paras,$timeout); if(isset($trade['return_code']) && $trade['return_code'] == 'SUCCESS') { if(isset($trade['result_code']) && $trade['result_code'] == 'SUCCESS') { $trade['total_fee'] = $order['total_fee']; return $this->getSign($trade); } else { throw new InvalidValueException(get_class($this) . $trade['err_code_des']); } } else { throw new InvalidValueException(get_class($this) . $trade['return_msg']); } } public function getSign($order) { $total_fee = $order['total_fee']; $keys = ['appid','partnerid','prepayid','package','noncestr','timestamp','sign']; $order['partnerid'] = $order['mch_id']; $order['prepayid'] = $order['prepay_id']; $order = array_intersect_key($order,array_fill_keys($keys,'')); $order['package'] = 'Sign=WXPay'; $order['timestamp'] = time(); $order['noncestr'] = $this->randomStr(30); $order['sign'] = $this->sign($order); $order['total_fee'] = $total_fee; return $order; } public function notify() { //獲取通知的數據 $xml = $GLOBALS['HTTP_RAW_POST_DATA']; //若是返回成功則驗證簽名 //try { $result = $this->fromXml($xml); if($result['return_code'] == 'SUCCESS') { $sign = $this->sign($result); if($sign == $result['sign']) { $result['trade_no']=$result['transaction_id']; $result['out_trade_no']=substr($result['out_trade_no'],strlen($this->order_pre)); $result['trade_status']='TRADE_SUCCESS'; return $result; } else { return false; } } else { return false; } // } catch (\Exception $e){ // throw new InvalidValueException(get_class($this) . $e->errorMessage()); // } } /** * 退款接口 * @param $order * @return mixed */ public function refund($order) { $this->_checkRefund(); $needs = array('order_sn','total_fee'); foreach($needs as $need) { if(!isset($order[$need])) { throw new InvalidConfigException(get_class($this) . " \$order 中必須包含鍵 {$need}."); } } $order['out_trade_no'] = $this->order_pre.$order['order_sn']; $order['total_fee'] = round($order['total_fee'],2) * 100; $order['refund_fee'] = $order['total_fee']; $order['op_user_id'] = $this->mch_id; $need = array('out_trade_no','out_refund_no','total_fee','refund_fee','op_user_id'); $keys = ['device_info','refund_fee_type','transaction_id']; foreach($need as $key) { if(empty($order[$key])) { throw new InvalidConfigException("缺乏退款申請接口必填參數{$key}!"); } } $order = array_intersect_key($order,array_fill_keys(array_merge($need, $keys),'')); $order['appid'] = $this->appid; $order['mch_id'] = $this->mch_id; $order['nonce_str'] = $this->randomStr(); $order['sign'] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->refund_url); $result = $this->convertResponse($response); return $result; } /** * Notify處理完成接口 * @return mixed */ public function finish() { $arr = ['return_code'=>'SUCCESS']; $xml = $this->toXml($arr); return $xml; } /** * 設置Notify回調接口 * @return mixed */ public function setNotifyUrl($url) { $this->notify_url = $url; } /** * 得到Notify返回的支付金額 * @return mixed */ public function getTotalFee($total_fee = null) { if($total_fee) { return round($total_fee/100,2,PHP_ROUND_HALF_DOWN); } if(isset($this->notify_data['total_fee'])) { return round($this->notify_data['total_fee']/100,2,PHP_ROUND_HALF_DOWN); } return false; } /** * 得到Notify返回的交易號 * @return mixed */ public function getSerialNo($arr = null) { if(isset($arr['transaction_id'])) { return $arr['transaction_id']; } if(isset($this->notify_data['transaction_id'])) { return $this->notify_data['transaction_id']; } return false; } /** * 得到Notify返回的原始數據 * @return mixed */ public function getNotifyRaw() { return $GLOBALS['HTTP_RAW_POST_DATA']; } public function randomStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } public function getIp() { if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $strIp = $arr[0]; } elseif (isset($_SERVER["HTTP_CLIENT_IP"])) { $strIp = $_SERVER["HTTP_CLIENT_IP"]; } elseif (isset($_SERVER["REMOTE_ADDR"])) { $strIp = $_SERVER["REMOTE_ADDR"]; } else { $strIp = "0.0.0.0"; } return $strIp; } private function toXml($values) { if(!is_array($values) || count($values) <= 0) { throw new InvalidValueException("數組數據異常!"); } //var_dump($values);exit; $xml = "<xml>"; foreach ($values as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; //echo $xml;exit; return $xml; } private function fromXml($xml) { if(!$xml){ throw new InvalidValueException("xml數據異常!"); } try { $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); } catch(\Exception $e) { throw new InvalidValueException("xml數據異常!"); } return $values; } public function sign($values) { ksort($values); $string = ""; foreach ($values as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $string .= $k . "=" . $v . "&"; } } $string = trim($string, "&"); $string = $string . "&key=".$this->key; $string = md5($string); return strtoupper($string); } public function checkSign($values) { if($this->sign($values) == $values['sign']){ return true; } throw new InvalidValueException("驗證簽名錯誤!"); } private function convertResponse($xml) { $result = $this->fromXml($xml); if($result['return_code'] != 'SUCCESS') { throw new InvalidValueException($result['return_msg']); } if($this->checkSign($result) === true){ return $result; }else{ return false; } } public function searchOrder($out_trade_no, $transaction_id = '',$timeOut = 6) { if(empty($out_trade_no) && empty($transaction_id)) { throw new InvalidValueException("缺乏訂單查詢接口必填參數out_trade_no或transaction_id!"); } $order = ['out_trade_no'=>$out_trade_no,'transaction_id'=>$transaction_id]; $order['appid'] = $this->appid; $order['mch_id'] = $this->mch_id; $order['nonce_str'] = $this->randomStr(); $order['sign'] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->search_order_url, false, $timeOut); $result = $this->convertResponse($response); return $result; } public function closeOrder($out_trade_no, $timeOut = 6) { if(empty($out_trade_no)) { throw new InvalidValueException("缺乏訂單查詢接口必填參數out_trade_no!"); } $order = ['out_trade_no'=>$out_trade_no]; $order['appid'] = $this->appid; $order['mch_id'] = $this->mch_id; $order['nonce_str'] = $this->randomStr(); $order['sign'] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->close_order_url, false, $timeOut); $result = $this->convertResponse($response); return $result; } public function createOrder(array $order, $timeOut = 6) { //檢測必填參數 $need = array('out_trade_no','body','total_fee','trade_type'); $keys = array('appid','mch_id','device_info','nonce_str','sign','detail','attach','fee_type', 'spbill_create_ip','time_start','time_expire','goods_tag','notify_url','product_id','openid'); $keys = array_merge($need,$keys); foreach($need as $key) { if(empty($order[$key])) { throw new InvalidValueException("缺乏統一下單接口必填參數{$key}!"); } } //關聯參數 if($order['trade_type'] == "JSAPI" && empty($order['openid'])){ throw new InvalidValueException("統一支付接口中,缺乏必填參數openid!trade_type爲JSAPI時,openid爲必填參數!"); } if($order['trade_type'] == "NATIVE" && empty($order['product_id'])){ throw new InvalidValueException("統一支付接口中,缺乏必填參數product_id!trade_type爲JSAPI時,product_id爲必填參數!"); } $order = array_intersect_key($order,array_fill_keys($keys,'')); $order['appid'] = $this->appid; $order['mch_id'] = $this->mch_id; $order['notify_url'] = $this->notify_url; $order['spbill_create_ip'] = $this->getIp(); $order['nonce_str'] = $this->randomStr(); $order['sign'] = $this->sign($order); $xml = $this->toXml($order); // var_dump( $order['notify_url'] );exit; $response = $this->postXmlCurl($xml, $this->order_url, false, $timeOut); //var_dump($response);exit; $result = $this->convertResponse($response); return $result; } public function searchRefund($order, $timeOut = 6) { $keys = ['out_refund_no','out_trade_no','transaction_id','refund_id']; if(empty($order['out_trade_no']) && empty($order['transaction_id']) && empty($order['out_refund_no']) && empty($order['refund_id'])) { throw new InvalidValueException("退款查詢接口中,out_refund_no、out_trade_no、transaction_id、refund_id四個參數必填一個!"); } $order = array_intersect_key($order,array_fill_keys($keys,'')); $order['appid'] = $this->appid; $order['mch_id'] = $this->mch_id; $order['nonce_str'] = $this->randomStr(); $order['sign'] = $this->sign($order); $xml = $this->toXml($order); $response = $this->postXmlCurl($xml, $this->search_refund_url, true, $timeOut); $result = $this->convertResponse($response); return $result; } private function postXmlCurl($xml, $url, $useCert = false, $second = 30) { $ch = curl_init(); //設置超時 curl_setopt($ch, CURLOPT_TIMEOUT, $second); //若是有配置代理這裏就設置代理 if($this->curl_proxy_host != "0.0.0.0" && $this->curl_proxy_port != 0){ curl_setopt($ch,CURLOPT_PROXY, $this->curl_proxy_host); curl_setopt($ch,CURLOPT_PROXYPORT, $this->curl_proxy_port); } curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //設置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求結果爲字符串且輸出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if($useCert == true && !empty($this->cert_path) && !empty($this->key_path)){ //設置證書 //使用證書:cert 與 key 分別屬於兩個.pem文件 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $this->cert_path); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $this->key_path); } //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //運行curl $data = curl_exec($ch); //返回結果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); throw new InvalidValueException("curl出錯,錯誤碼:{$error}"); } } }
還須要增長一個Notifyurl.php
<?php namespace common\widgets\payment; use Yii; use common\widgets\payment\Weixinjspi; class Notifyurl { public function notify($code) { $funame='get'.$code; $respmodel=Yii::$app->payment->$funame(); $result=$respmodel->notify(); if($result){ //商戶訂單號 $out_trade_no = $result['out_trade_no']; //交易號 $trade_no = $result['trade_no']; //交易狀態 $trade_status = $result['trade_status']; if ($trade_status == 'TRADE_SUCCESS') { $this->update_status($out_trade_no,$trade_no,1); echo "success"; }else{ echo "fail"; } }else{ echo "fail"; } } //支付狀態更改 public function update_status($out_trade_no,$trade_no,$pay_status) { } } ?>
第三步、咱們如何使用呢,
在咱們需支付的controller中,
//微信支付
public function actionWeixinpay() { $openid=isset($_COOKIE['openid'])?$_COOKIE['openid']:''; if($openid) { $order_=[ 'goods_desc'=>'測試', 'order_sn' =>'2222', 'total_fee' =>12, 'body'=>'測試', 'time_start' =>date("YmdHis"), 'time_expire'=>date("YmdHis", time() + 86400*300), 'goods_tag' =>'', 'notify_url'=>Url::to(['@web/respond/updatepay'],true),//這是回調地址,微信通知的地址 'openid'=>$openid, ]; $paymodel=Yii::$app->payment->getWeixinjspi(); $result=$paymodel->pay($order_);//生成預付單 if($result) { $jsstr=$paymodel->getJs($result,$order_['order_sn']); //根據預付單信息生成js,詳細的能夠看上面的類的方法。 } } echo $jsstr; }
第四步、在view層咱們能夠這樣寫:
<button type="button" class="btn red-sunglo" onclick="pay_(2)" > <div id="js_"> </div> <script> //支付 function pay_(id) { $.ajax({ type:"get", url:"/ceshi/weixinpay?id="+id,//這是訪問的地址 datatype:"json", data:{}, success: function(data) { if(data!='') { $("#js_").html(data); callpay(); } //alert(data); } }) } </script>
我這邊是採用的ajax的形式進行支付的,能夠根據本身的狀況進行調整
第五步、支付最重要的是須要回調,yii2增長了Csrf驗證,禁止了外部的訪問,咱們在控制其中寫回調方法的時候必須增長:
public function beforeAction($action) { $this->enableCsrfValidation = false; return parent::beforeAction($action); }
否則微信將訪問不到。
回調的方法使用:
use common\widgets\payment\Weixinjspi; use common\widgets\payment\Notifyurl; public function actionUpdatepay() { $model=new Notifyurl(); $model->notify('Weixinjspi'); }
以上就是個人微信支付。第一次寫文章,有不完善的地方請多包涵,有不對的地方請指出我這邊再完善