序言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'); }
以上就是个人微信支付。第一次写文章,有不完善的地方请多包涵,有不对的地方请指出我这边再完善