php微信公众号JSAPI支付

首先是生成签名方法

    //生成签名
    private function MakeSign($params, $KEY)
    {
        //签名步骤一:按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);  //参数进行拼接key=value&k=v
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . $KEY;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
 //模拟post提交(调接口用)

模拟post提交

    //发送http请求

    private function http_request($url, $data = null, $headers = array())
    {
        $curl = curl_init();
        if (count($headers) >= 1) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
//
        $zs1 = APP_PATH . "app/cert/apiclient_cert.pem";
        $zs2 = APP_PATH . "app/cert/apiclient_key.pem";


//        curl_setopt ( $curl, CURLOPT_SSLCERT, $zs1 );
//        curl_setopt ( $curl, CURLOPT_SSLKEY, $zs2 );
        //设置证书
        //使用证书:cert 与 key 分别属于两个.pem文件
        curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($curl, CURLOPT_SSLCERT, $zs1);
        curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($curl, CURLOPT_SSLKEY, $zs2);

        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

xml转换数组

    //获取xml里面数据,转换成array
    private function xml2array($xml)
    {
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = "";
        foreach ($index as $key => $value) {
            if ($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
        }
        return $data;

    }

然后是统一下单方法

   //构建订单/* 首先在服务器端调用微信【统一下单】接口,返回prepay_id和sign签名等信息给前端,前端调用微信支付接口 */

    private function construct_order($total_fee, $openid, $order_sn, $order_id)
    {
        //获取系统的配置
        $appid = '';//如果是公众号 就是公众号的appid;小程序就是小程序的appid
        $body = '商户号构造订单';
        $mch_id = '';
        $KEY = '';
        $nonce_str = $this->rand_str(12);//随机字符串
        $notify_url = config('app_url') . "pay/notify";  //支付完成回调地址url,不能带参数
        $out_trade_no = $order_sn;//商户订单号
        $spbill_create_ip = $_SERVER['SERVER_ADDR'];
        $trade_type = 'JSAPI';//交易类型 默认JSAPI

        //这里是按照顺序的 因为下面的签名是按照(字典序)顺序 排序错误 肯定出错
        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str;//随机字符串
        $post['notify_url'] = $notify_url;
        $post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_create_ip'] = $spbill_create_ip;//服务器终端的ip
        $post['total_fee'] = intval($total_fee);        //总金额 最低为一分钱 必须是整数
        $post['trade_type'] = $trade_type;
        $sign = $this->MakeSign($post, $KEY);              //签名
        $this->sign = $sign;

        //$post_xml = '<xml><appid>'.$appid.'</appid><body>'.$body.'</body><mch_id>'.$mch_id.'</mch_id><nonce_str>'.$nonce_str.'</nonce_str><notify_url>'.$notify_url.'</notify_url><openid>'.$openid.'</openid><out_trade_no>'.$out_trade_no.'</out_trade_no><spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip><total_fee>'.$total_fee.'</total_fee><trade_type>'.$trade_type.'</trade_type><sign>'.$sign.'</sign></xml>';


        $post_xml = "
                <xml>
                    <appid>$appid</appid>
                    <body>$body</body>
                    <mch_id>$mch_id</mch_id>
                    <nonce_str>$nonce_str</nonce_str>
                    <notify_url>$notify_url</notify_url>
                    <openid>$openid</openid>
                    <out_trade_no>$out_trade_no</out_trade_no>
                    <spbill_create_ip>$spbill_create_ip</spbill_create_ip>
                    <total_fee>{$post["total_fee"]}</total_fee>
                    <trade_type>$trade_type</trade_type>
                    <sign>$sign</sign>
                </xml>";

        //统一下单接口prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->http_request($url, $post_xml);     //POST方式请求http
        $array = $this->xml2array($xml);               //将【统一下单】api返回xml数据转换成数组,全要大写
        $array['my_sign'] = $sign;
        $array['post_xml'] = $post_xml;
        $array['source_xml'] = $xml;
        if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
            $time = time();
            $tmp = '';                            //临时数组用于签名
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id=' . $array['PREPAY_ID'];
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = "$time";


            $data['state'] = 1;
            $data['timeStamp'] = "$time";           //时间戳
            $data['nonceStr'] = $nonce_str;         //随机字符串
            $data['signType'] = 'MD5';              //签名算法,暂支持 MD5
            $data['package'] = 'prepay_id=' . $array['PREPAY_ID'];   //统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
            $data['paySign'] = $this->MakeSign($tmp, $KEY);       //签名,具体签名方案参见微信公众号支付帮助文档;
            $data['prepay_id'] = $array['PREPAY_ID'];
            $data['out_trade_no'] = $out_trade_no;
            $data['order_id'] = $order_id;
        } else {
            $data['statusCode'] = USER_ERROR;
            $data['statusMsg'] = "请求错误";
            $data['data']['RETURN_CODE'] = $array['RETURN_CODE'];
            $data['data']['RETURN_MSG'] = $array['RETURN_MSG'];
        }
        return $data;
    }

回调函数

    //订单支付回调
    function notify()
    {
        $post = $this->post_data();    //接受POST数据XML个数
        $post_data = $this->xml_to_array($post);   //微信支付成功,返回回调地址url的数据:XML转数组Array
        //输出订单号
        $order_sn = $post_data['out_trade_no'];
        $key = '';//key

        $postSign = $post_data['sign'];
        unset($post_data['sign']);

        /* 微信官方提醒:
         *  商户系统对于支付结果通知的内容一定要做【签名验证】,
         *  并校验返回的【订单金额是否与商户侧的订单金额】一致,
         *  防止数据泄漏导致出现“假通知”,造成资金损失。
        */
        ksort($post_data);// 对数据进行排序
        $str = $this->ToUrlParams($post_data);//对数组数据拼接成key=value字符串
        $KEY = $key;
        $str .= '&key=';
        $str .= $KEY;
        $user_sign = strtoupper(md5($str));   //再次生成签名,与$postSign比较


        if ($post_data['return_code'] == 'SUCCESS') {
            //判断证书是否正确
            if ($postSign != $user_sign) {
                Log::write('签名不匹配');
                exit;
            }
            $order_info = Db::table('cs_hborders')->where('order_sn', $order_sn)->find();

            if ($order_info['pay_status'] != 1) {
               //支付成功后操作(如推送、更改订单状态等)
                    }
                }
            }
            echo 'success';
        } else {
            echo '微信支付失败';
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值