美文网首页
微信app支付

微信app支付

作者: happywho250 | 来源:发表于2017-07-21 01:04 被阅读0次

    这篇博客将会结合自己对接微信app支付服务端的操作进行一次总结,代码都会亮出来,方便大家对接

    支付流程

    介绍一个简单的逻辑,具体需要结合自己的业务进行
    第一步当然是在开放平台下对应的应用申请app支付啦!

    1. 客户下单,客户端需要携带客户id,$uid,商品信息(如价格$rmb),请求后台接口支付接口.
    2. 后台接口,生成系统内的状态为未支付的订单,携带系统订单号$orderNo,金额$rmb等微信要求的配置和参数,请求https://api.mch.weixin.qq.com/pay/unifiedorder地址,在微信服务后台生成预支付订单,注意微信的金额单位为分
    3. 拿到微信返回的正确的交易信息,返回客户端,客户端结合安卓或者ios的sdk调支付页面,用户完成支付.
    4. 用户支付成功以后,微信会回调一个你在操作2里面传给微信的异步回调地址,进行验签,然后更改系统订单状态为以支付,记录一笔交易详情,给用户加值等操作及资金的其他业务逻辑(注意,涉及金额等多表操作,用事物比较靠谱,).

    看代码

    A. 发起微信支付

    <?php
    
    class Payment
    {
        private static $config = array();
        public function __construct()
        {
            self::$config = array(
                'appId'      =>'xxxxxxxx',
                'mch_id'     =>'xxxx',
                'notify_url' => 'http://www.xxx.com/xxx',
                'apiKey'     => 'xxxxxxxxxxxxxxx',
                'URL'        => 'https://api.mch.weixin.qq.com/pay/unifiedorder'
            );
        }
    
        public function appPay($uid,$rmb)
        {
            // 1. 创建系统订单,这里就不去操作了,生成系统内部未支付订单,结合自己的逻辑去做.
            $orderNo = $uid.time();
            // 2. 初始化请求数据.
            $xmlDate = $this->initOrderData($rmb*100,$orderNo);
            // 3. 请求微信服务生成预支付订单凭证.
            $xmlResponse = $this->postXml($xmlDate);
            // 4. xml数据转为数组
            $response = $this->xmlToArray($xmlResponse);
            // 如果失败.
            if (strcmp($response['RETURN_CODE'], 'FAIL') === 0) {
                $message = $response['RETURN_MSG'];
                $code = "1";
                $data = "";
            }
            //如果成功,返回客户端所需要的数据.
            $data = $this->initAppData($response);
            $message = "success";
            $code = "0";
            $data = array();
            return json_encode(array("message" => $message,'code' => $code,'data' => $data));
        }
    
        protected function initOrderData($rmb,$orderNo)
        {
            $params = array(
                'appid' => self::$config["appId"],// 开放平台下,该app应用的appid.
                'mch_id'=> self::$config["mch_id"],// 该开放平台应用对应的商户平台内的商户号.
                'nonce_str' => md5("test".time()),// 随机字符串.
                'body' => '测试',
                'out_trade_no' => $orderNo,
                'fee_type' => 'CNY', //货币类型
                'total_fee' => $rmb,// 支付金额,单位为分
                'spbill_create_ip' => "192.168.1.103",
                'time_start' =>date("YmdHis"),
                'time_expire'=> date("YmdHis",strtotime("+2hours")),
                'notify_url' => self::$config["notify_url"],// 支付异步回调地址,
                'trade_type' => 'APP',
            );
            //参数排序按照键的ascii码值升序排列.
            ksort($params);
            //将参数转化成url键值对的形式.
            $str = $this->arrayToKeyValue($params);
            //拼接商户秘钥apiKey
            $str .= "key=".self::$config["apiKey"];
            //拼接加密参数.
            $params["sign"] = strtoupper(md5($str));
            //将数组转为xml格式
            $xmlDate = $this->arrayToXml($params);
            return $xmlDate;
        }
    
        /**
         * 将数组转化成url键值对格式.
         *
         * @param array $param
         *
         * @return string
         */
        protected function arrayToKeyValue($param)
        {
            $str = '';
            foreach ($param as $k => $v) {
                $str.= $k."=".$v."&";
            }
            return $str;
        }
    
        /**
         * 将数组转为xml格式的数据.
         *
         * @param array $param
         *
         * @return string
         */
        protected function arrayToXml($param)
        {
            $xml = "<xml>";
            foreach ($param as $key => $value) {
                $xml .= "<$key>{$value}<$key>";
            }
            $xml .= "</xml>";
            return $xml;
        }
    
        /**
         * xml格式数据转换成array.
         *
         * @param $xml
         *
         * @return array
         */
        protected function xmlToArray($xml)
        {
            $parser = xml_parser_create();
            xml_parse_into_struct($parser, $xml, $data, $index);
            $arr = array();
            foreach ($data as $key => $value) {
                $arr[$value['tag']] = $value['value'];
            }
            return $arr;
        }
    
        /**
         * 提供客户端发起微信支付所需要的数据.
         *
         * @param $data
         *
         * @return array
         */
        protected function initAppData($data)
        {
            $appData = array(
                'appid' => $data['APPID'],
                'partnerid' => $data['MCH_ID'],
                'prepayid' => $data['PREPAY_ID'],
                'package' => 'Sign=WXPay',
                'noncestr' => time().rand(1000,999),
                'timestamp' => time()."",
            );
    
            ksort($appData);
            $str = $this->arrayToKeyValue($appData);
            //拼接商户秘钥apiKey
            $str .= "key=".self::$config["apiKey"];
            //拼接加密参数.
            $appData["sign"] = strtoupper(md5($str));
            return $appData;
        }
    
        /**
         * post请求微信服务.
         * @param $xml
         * @param int $second
         * @return mixed|string
         */
        protected function postXml($xml, $second = 30)
        {
    
            $ch = curl_init();
            //设置超时
            curl_setopt($ch, CURLOPT_TIMEOUT, $second);
            curl_setopt($ch, CURLOPT_URL, static::$config["URL"]);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);//严格校验
            //post提交方式
            curl_setopt($ch, CURLOPT_POST, TRUE);
            //设置header
            curl_setopt($ch, CURLOPT_HEADER, FALSE);
            //要求结果为字符串且输出到屏幕上
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    
            curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
            //运行curl
            $data = curl_exec($ch);
            curl_close($ch);
            //返回结果
            if ($data) {
                return $data;
            } else {
                return "<xml><return_code>FAIL</return_code><return_msg>系统繁忙!请稍后再试.</return_msg></xml>";
            }
        } 
      }
    

    正确返回格式参考
    客户端ios或者安卓拿到对应的数据就可以发起微信支付啦!

    "data": {
    "appid": "wx6d98ecxxxxxe63a",
    "noncestr": "47b37529df3d9ae3c1fb39a4fafdc63d",
    "package": "Sign=WXPay",
    "partnerid": "1294xxxxx1",
    "prepayid": "wx201xxxxxxxxxxxxxxxxxxxx",
    "timestamp": "1500569824",
    "sign": "9B7364700B450850A505xxxxxxxxxxxx"
    }
    

    B. 回调处理
    回调的处理很简单,将xml数据转为数组,然后验签,然后处理自己后台的逻辑,然后相应微信回调结果.

    相关文章

      网友评论

          本文标题:微信app支付

          本文链接:https://www.haomeiwen.com/subject/emqskxtx.html