微信jssdk支付

微信的开发文档花里胡哨的看的眼花....我参考多种方法总结出来一个比较简单的单文件支付文件

以下为thinkphp5的示例

需要有授权登陆方可使用!!!!

注意命名空间,代码需要根据业务逻辑修改!!!

<?php

namespace app\shop\controller;

use think\Controller;
use think\Cookie;
use think\Db;
use think\Exception;
use think\Request;
use think\cache\driver\Redis;

/**
 *
 * @package    app微信登录和手机站微信网页授权登录
 */

// 1.前往$config配置参数 最好单独从配置文件调用参数
// 2.wexinpay_js 生成订单号存入数据库后去 getParameters调取支付
// 3.unifiedOrder 统一下单处设置回调
// 4.isnotify 获取回调支付状态修改数据库购买状态
class Pay extends Controller
{
    /**
     * 微信 公众号jssdk支付 生成订单号后去调取支付
     */
    public function wexinpay_js()
    {
        $data = request()->param();
        unset($data['/shop/Pay/wexinpay_js_html']);
        // 此处根据实际业务情况生成订单 然后拿着订单去支付(请根据实际业务更改)
        $order_sn = date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
        // 组合url
        $url = url("shop/Pay/getParameters", array('out_trade_no' => $order_sn));
        // 前往支付
        echo json_encode($url);
    }
    /**
     * 公众号支付 必须以get形式传递 out_trade_no 参数
     */

    /**
     * 获取jssdk需要用到的数据
     * @return array jssdk需要用到的数据
     */
    public function getParameters()
    {
        header("Access-Control-Allow-Origin: *");
        $out_trade_no = request()->param('out_trade_no');
        $openid='xxxxxx';//获取客户微信id
        // 订单数据  请根据订单号out_trade_no 从数据库中查出实际的body、total_fee、out_trade_no、product_id
        $order = array(
            'body' => 'test',// 商品描述(需要根据自己的业务修改)
            'total_fee' => 1,// 订单金额  以(分)为单位(需要根据自己的业务修改)
            'out_trade_no' => $out_trade_no,// 订单号(需要根据自己的业务修改)
            'product_id' => 1,// 商品id(需要根据自己的业务修改)
            'trade_type' => 'JSAPI',// JSAPI公众号支付
            'openid' => $openid// 获取到的openid
        );

        // 统一下单 获取prepay_id
        $unified_order = $this->unifiedOrder($order);
        // 获取当前时间戳
        $time = time();
        // 组合jssdk需要用到的数据
        $data = array(
            'appId' => 'wxpay.APPID', //appid
            'timeStamp' => strval($time), //时间戳
            'nonceStr' => $unified_order['nonce_str'],// 随机字符串
            'package' => 'prepay_id=' . $unified_order['prepay_id'],// 预支付交易会话标识
            'signType' => 'MD5'//加密方式
        );
        // 生成签名
        $data['paySign'] = $this->makeSign($data);
        echo json_encode($data);
        exit();
//        }
    }

    /**
     * 统一下单
     * @param  array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
     */
    public function unifiedOrder($order)
    {
        // 生成随机加密盐
        $nonce_str = $this->makeCode(32);
        // 获取配置项
        $config = array(
            'appid' => 'wxpay.APPID',//appid
            'mch_id' => 'wxpay.MCHID',//mch_id
            'nonce_str' => $nonce_str,
            'spbill_create_ip' => '192.168.0.1',
            'notify_url' => 'XXXXXXXXX/Pay/isnotify'//你的域名
        );
        // 合并配置数据和订单数据
        $data = array_merge($order, $config);
        // 生成签名
        $sign = $this->makeSign($data);
        $data['sign'] = $sign;
        $xml = $this->toXml($data);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//接收xml数据的文件
        $header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地没有指定curl.cainfo路径的错误
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $response = curl_exec($ch);
        if (curl_errno($ch)) {
            // 显示报错信息;终止继续执行
            die(curl_error($ch));
        }
        curl_close($ch);
        $result = $this->toArray($response);
        // 显示错误信息
        if ($result['return_code'] == 'FAIL') {
            die($result['return_msg']);
        }
        $result['sign'] = $sign;
        $result['nonce_str'] = $nonce_str;
        return $result;
    }

    /**
     * 验证
     * @return array 返回数组格式的notify数据
     */
    public function notify()
    {
        // 获取xml
        $xml = file_get_contents('php://input', 'r');
        // 转成php数组
        $data = $this->toArray($xml);
        // 保存原sign
        $data_sign = $data['sign'];
        // sign不参与签名
        unset($data['sign']);
        $sign = $this->makeSign($data);
        // 判断签名是否正确  判断支付状态
        if ($sign === $data_sign && $data['return_code'] == 'SUCCESS' && $data['result_code'] == 'SUCCESS') {
            $result = $data;
        } else {
            $result = false;
        }
        // 返回状态给微信服务器
        if ($result) {
            $str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        } else {
            $str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
        }
        echo $str;
        return $result;
    }

    public function isnotify()
    {
        $result = $this->notify();
        if ($result) {
//            // 验证成功 修改数据库的订单状态等 $result['out_trade_no']为订单id
            $order = $result['out_trade_no'];
//            操作数据库修改购买状态
        } else {
//           验证失败 那就没交易成功
            $order = $result['out_trade_no'];
        }
    }

    /**
     * 输出xml字符
     * @throws WxPayException
     **/
    public function toXml($data)
    {
        if (!is_array($data) || count($data) <= 0) {
            throw new WxPayException("数组数据异常!");
        }
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 生成签名
     * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
     */
    public function makeSign($data)
    {
        // 去空
        $data = array_filter($data);
        //签名步骤一:按字典序排序参数
        ksort($data);
        $string_a = http_build_query($data);
        $string_a = urldecode($string_a);
        //签名步骤二:在string后加入KEY
        $string_sign_temp = $string_a . "&key=" . config('wxpay.KEY');
        //签名步骤三:MD5加密
        $sign = md5($string_sign_temp);
        // 签名步骤四:所有字符转为大写
        $result = strtoupper($sign);
        return $result;
    }

    /**
     * 将xml转为array
     * @param  string $xml xml字符串
     * @return array       转换得到的数组
     */
    public function toArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $result;
    }

    /**
     * 生成随机串
     * @param $count 随机串个数
     */
    public function makeCode($count)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $nonce_str = '';
        for ($i = 0; $i < $count; $i++) {
            $nonce_str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $nonce_str;
    }

    /**
     * curl 请求http
     */
    public function curl_get_contents($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);                //设置访问的url地址
        // curl_setopt($ch,CURLOPT_HEADER,1);               //是否显示头部信息
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);               //设置超时
        curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);   //用户访问代理 User-Agent
        curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_HOST']);        //设置 referer
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);          //跟踪301
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        //返回结果
        $r = curl_exec($ch);
        curl_close($ch);
        return $r;
    }

    /**
     *   生成10位绝不重复订单号
     */
    function order_number()
    {
        static $ORDERSN = array();                                        //静态变量
        $ors = date('ymd') . substr(time(), -5) . substr(microtime(), 2, 5);     //生成16位数字基本号
        if (isset($ORDERSN[$ors])) {                                    //判断是否有基本订单号
            $ORDERSN[$ors]++;                                           //如果存在,将值自增1
        } else {
            $ORDERSN[$ors] = 1;
        }
        return $ors . str_pad($ORDERSN[$ors], 2, '0', STR_PAD_LEFT);     //链接字符串
    }
}

前端进行请求获取参数调起微信支付

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>调用支付</title>
</head>
<body>
<button type="button" class="mui-btn mui-btn-warning" onclick="buy()">调用支付</button>
<script>
    // 生成订单
    function buy() {
        $.ajax({
            type:"get",
            url:"{:url('shop/weixinzhifu/wexinpay_js')}",
            data:{id:id},//传产品id(根据业务需求修改)
            dataType:"json",
            success:function(data){
                console.log(data);
                // window.location.href = data;
                var urll=data;
                gobuy(urll);
            },
            error: function (data) {
                console.log(data);
                console.log( JSON.stringify(data))
            }

        });
    }
    //用订单好去调起统一下单获取参数
    function gobuy(urll){
        $.ajax({
            type:"get",
            url:urll,
            data:{},
            dataType:"json",
            success:function(data){
                console.log(data);
                //调用支付
                onBridgeReady(data)
            },
            error: function (data) {
                console.log(data);
//                 console.log( JSON.stringify(data))
            }
        });
    }
    function onBridgeReady(data){
        WeixinJSBridge.invoke(
            'getBrandWCPayRequest', data,
            function(res){
                if(res.err_msg == "get_brand_wcpay_request:ok" ){
                    // 使用以上方式判断前端返回,微信团队郑重提示:
                    //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
                    alert("用户支付成功!");
                }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
                    alert("用户取消支付!");
                }else{
                    alert("支付失败!");
                }
            });
    }

</script>

</body>
</html>

可以使用,大致逻辑没问题......新手,勿喷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值