微信Native支付官方文档有点小坑,摸索了半天,总结一下:
1.首先肯定是要开通微信支付功能
2.设置支付授权目录
3.设置js安全域名
4.然后就是代码了:
大概逻辑是这样的:首先是获取openid,然后整合微信统一下单api需要的参数,调用统一下单api,生成订单后整合支付需要的参数,然后给js接口即可.
5具体代码:
这里我没有使用官方给的支付demo,我在网上找了一个,然后自己改了一点。
JsApiPay.class.php 这个文件主要是获取openidde
- <?php
- //require_once "../lib/WxPay.Api.php";
- namespace Lib;
- /**
- *
- * JSAPI支付实现类
- * 该类实现了从微信公众平台获取code、通过code获取openid和access_token、
- * 生成jsapi支付js接口所需的参数、生成获取共享收货地址所需的参数
- *
- * 该类是微信支付提供的样例程序,商户可根据自己的需求修改,或者使用lib中的api自行开发
- *
- * @author widy
- *
- */
- class JsApiPay
- {
- /**
- *
- * 网页授权接口微信服务器返回的数据,返回样例如下
- * {
- * "access_token":"ACCESS_TOKEN",
- * "expires_in":7200,
- * "refresh_token":"REFRESH_TOKEN",
- * "openid":"OPENID",
- * "scope":"SCOPE",
- * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
- * }
- * 其中access_token可用于获取共享收货地址
- * openid是微信支付jsapi支付接口必须的参数
- * @var array
- */
- public $data = null;
- private $_APPID;
- private $_CURL_PROXY_HOST = '0.0.0.0';
- private $_CURL_PROXY_PORT = 0;
- private $_APPSECRET;
- public function __construct($config)
- {
- $this->_APPID = $config['appid'];
- $this->_APPSECRET = $config['secret'];
- if(isset($config['CURL_PROXY_HOST'])){
- $this->_CURL_PROXY_HOST = $config['CURL_PROXY_HOST'];
- }
- if(isset($config['CURL_PROXY_PORT'])){
- $this->_CURL_PROXY_PORT = $config['CURL_PROXY_PORT'];
- }
- }
- /**
- *
- * 通过跳转获取用户的openid,跳转流程如下:
- * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
- * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
- *
- * @return 用户的openid
- */
- public function GetOpenid()
- {
- //通过code获得openid
- if (!isset($_GET['code'])){
- //触发微信返回code码
- //$baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']);
- $baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'?'.$_SERVER['QUERY_STRING']);
- $url = $this->__CreateOauthUrlForCode($baseUrl);
- Header("Location: $url");
- exit();
- } else {
- //获取code码,以获取openid
- $code = $_GET['code'];
- $openid = $this->getOpenidFromMp($code);
- return $openid;
- }
- }
- // /**
- // *
- // * 获取jsapi支付的参数
- // * @param array $UnifiedOrderResult 统一支付接口返回的数据
- // * @throws WxPayException
- // *
- // * @return json数据,可直接填入js函数作为参数
- // */
- // public function GetJsApiParameters($UnifiedOrderResult)
- // {
- // if(!array_key_exists("appid", $UnifiedOrderResult)
- // || !array_key_exists("prepay_id", $UnifiedOrderResult)
- // || $UnifiedOrderResult['prepay_id'] == "")
- // {
- // throw new WxPayException("参数错误");
- // }
- // $jsapi = new WxPayJsApiPay();
- // $jsapi->SetAppid($UnifiedOrderResult["appid"]);
- // $timeStamp = time();
- // $jsapi->SetTimeStamp("$timeStamp");
- // $jsapi->SetNonceStr(WxPayApi::getNonceStr());
- // $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
- // $jsapi->SetSignType("MD5");
- // $jsapi->SetPaySign($jsapi->MakeSign());
- // $parameters = json_encode($jsapi->GetValues());
- // return $parameters;
- // }
- /**
- *
- * 通过code从工作平台获取openid机器access_token
- * @param string $code 微信跳转回来带上的code
- *
- * @return openid
- */
- public function GetOpenidFromMp($code)
- {
- $url = $this->__CreateOauthUrlForOpenid($code);
- //初始化curl
- $ch = curl_init();
- //设置超时
- curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
- curl_setopt($ch, CURLOPT_HEADER, FALSE);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
- 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,结果以jason形式返回
- $res = curl_exec($ch);
- curl_close($ch);
- //取出openid
- $data = json_decode($res,true);
- $this->data = $data;
- $openid = $data['openid'];
- return $openid;
- }
- /**
- *
- * 拼接签名字符串
- * @param array $urlObj
- *
- * @return 返回已经拼接好的字符串
- */
- private function ToUrlParams($urlObj)
- {
- $buff = "";
- foreach ($urlObj as $k => $v)
- {
- if($k != "sign"){
- $buff .= $k . "=" . $v . "&";
- }
- }
- $buff = trim($buff, "&");
- return $buff;
- }
- /**
- *
- * 获取地址js参数
- *
- * @return 获取共享收货地址js函数需要的参数,json格式可以直接做参数使用
- */
- public function GetEditAddressParameters()
- {
- $getData = $this->data;
- $data = array();
- $data["appid"] = $this->_APPID;
- $data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
- $time = time();
- $data["timestamp"] = "$time";
- $data["noncestr"] = "1234568";
- $data["accesstoken"] = $getData["access_token"];
- ksort($data);
- $params = $this->ToUrlParams($data);
- $addrSign = sha1($params);
- $afterData = array(
- "addrSign" => $addrSign,
- "signType" => "sha1",
- "scope" => "jsapi_address",
- "appId" => $this->_APPID,
- "timeStamp" => $data["timestamp"],
- "nonceStr" => $data["noncestr"]
- );
- $parameters = json_encode($afterData);
- return $parameters;
- }
- /**
- *
- * 构造获取code的url连接
- * @param string $redirectUrl 微信服务器回跳的url,需要url编码
- *
- * @return 返回构造好的url
- */
- private function __CreateOauthUrlForCode($redirectUrl)
- {
- $urlObj["appid"] = $this->_APPID;
- $urlObj["redirect_uri"] = "$redirectUrl";
- $urlObj["response_type"] = "code";
- $urlObj["scope"] = "snsapi_base";
- $urlObj["state"] = "STATE"."#wechat_redirect";
- $bizString = $this->ToUrlParams($urlObj);
- return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
- }
- /**
- *
- * 构造获取open和access_toke的url地址
- * @param string $code,微信跳转带回的code
- *
- * @return 请求的url
- */
- private function __CreateOauthUrlForOpenid($code)
- {
- $urlObj["appid"] = $this->_APPID;
- $urlObj["secret"] = $this->_APPSECRET;
- $urlObj["code"] = $code;
- $urlObj["grant_type"] = "authorization_code";
- $bizString = $this->ToUrlParams($urlObj);
- return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
- }
- }
- 这里面GetOpenid函数$baseUrl做了一点修改.如果微信支付参数,配置没有正确,一般都会提示redirect_url参数错误.
- php逻辑:
- public function testWx(){
- GLOBAL $_G;
- $oid = I('get.oid');
- //②、统一下单
- if(C('WECHAT_PAY_DEBUG')){
- $options = $this->getOptions();//调试模式
- }else{
- $options = $this->getOptions($_G['host']['uid'],true);//生产模式
- }
- //①、获取用户openid
- $tools = new \Lib\JsApiPay($options);
- $openId = $tools->GetOpenid();
- //file_put_contents('./a.txt',$openId,FILE_APPEND);
- Vendor('WeChat.WechatAppPay'); //这个类在扫码支付已经给出源码了
- $weChat = new \wechatAppPay($options);
- //file_put_contents('./a.txt',"\r\n".'options-------------->'."\r\n".var_export($options,true),FILE_APPEND);
- $orderInfo = M('order','xyl_')->where(array('oid'=>$oid))->find();
- $params = array();
- $params['body'] = 'ddddddddddd'; //商品描述
- $params['out_trade_no'] = $orderInfo['oid'].time(); //自定义的订单号
- $params['total_fee'] = (Int)(100*$orderInfo['ototal']); //订单金额 只能为整数 单位为分
- $params['trade_type'] = 'JSAPI'; //交易类型 JSAPI | NATIVE | APP | WAP
- $params['openid'] = $openId;
- $params['notify_url'] = C('NOTIFY_URL');
- $result = $weChat->unifiedOrder($params);
- //file_put_contents('./a.txt',"\r\n params---------------->\r\n".var_export($params,true),FILE_APPEND);
- //file_put_contents('./a.txt',"\r\n results---------------->\r\n".var_export($result,true),FILE_APPEND);
- $jsApiParameters = $weChat->GetJsApiParameters($result); //获取JSAPI支付参数
- $this->assign('jsApiParameters',json_encode($jsApiParameters));
- //file_put_contents('./a.txt',"\r\n jsparams---------------->\r\n".var_export($jsApiParameters,true),FILE_APPEND);
- $this->assign('payTotal',$orderInfo['ototal']);
- $this->display('Wap:Shopping:wxpay');
- }
前端页面:
- <span style="white-space:pre;"> </span>
- <html>
- <head>
- <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
- <title>微信支付样例-支付</title>
- <style>
- .wxPay{
- width: 100%;
- text-align: center;
- }
- .wxPay p{
- color: #051b28;
- font-size: 14px;
- margin-top:38px;
- }
- .wxPay span{
- color: #051b28;
- font-size: 34px;
- margin-top:8px;
- }
- .wxPay button{
- width: 93.7%;
- height: 40px;
- border-radius: 5px;
- background: #ff5520;
- color: #fff;
- font-size: 14px;
- border: none;
- margin-top: 37px;
- }
- </style>
- <script type="text/javascript">
- //调用微信JS api 支付
- function jsApiCall()
- {
- WeixinJSBridge.invoke(
- 'getBrandWCPayRequest',
- {$jsApiParameters},
- function(res){
- WeixinJSBridge.log(res.err_msg);
- // alert(res.err_code+res.err_desc+res.err_msg);
- if(res.err_msg == "get_brand_wcpay_request:ok" ) {
- window.location.href = "{:U('App/order/index')}?orderStatus=2";
- }else{
- if(res.err_msg == "get_brand_wcpay_request:cancel"){
- alert('支付取消!');
- return false;
- }else{
- alert('支付失败!');
- return false;
- }
- }
- }
- );
- }
- 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>
- <script type="text/javascript">
- //获取共享地址
- // function editAddress()
- // {
- // WeixinJSBridge.invoke(
- // 'editAddress',
- // <?php echo $editAddress; ?>,
- // function(res){
- // var value1 = res.proviceFirstStageName;
- // var value2 = res.addressCitySecondStageName;
- // var value3 = res.addressCountiesThirdStageName;
- // var value4 = res.addressDetailInfo;
- // var tel = res.telNumber;
- //
- // alert(value1 + value2 + value3 + value4 + ":" + tel);
- // }
- // );
- // }
- window.onload = function(){
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', editAddress, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', editAddress);
- document.attachEvent('onWeixinJSBridgeReady', editAddress);
- }
- }else{
- editAddress();
- }
- };
- </script>
- </head>
- <body>
- <div class="wxPay">
- <p>该笔订单支付金额为</p>
- <span>{$payTotal}</span>
- <button type="button" onclick="callpay()" >立即支付</button>
- </div>
- </body>
- </html>