PHP实现APP端微信支付

参数配置

//PHP使用的TP3框架
    'WEIXINPAY_CONFIG'       => array(
        'APPID'              => '', // 应用的appid
        'MCHID'              => '', // 商户号
        'KEY'                => '', // 微信支付V3密钥
        'NOTIFY_URL'         => 'http://'.$_SERVER['HTTP_HOST'].'/index.php/User/Wechat/wechatNotify', 
    ),

接口代码

<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

// 定义时区
ini_set('date.timezone', 'Asia/Shanghai');

class Weixinpay
{
    
    
    // 定义配置项
    private $config = array();
    private $uid;
    private $nonce_str;
    private $fee;

    // 构造函数
    public function __construct($uid, $nonce_str, $fee)
    {
    
    
        // 如果配置项为空 则直接返回
        $this->config = C('WEIXINPAY_CONFIG');
        $this->uid = $uid;
        $this->nonce_str = $nonce_str;//交易类型
        $this->fee = $fee;
    }

    /**
     * 统一下单
     * @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
     */
    public function unifiedOrder($order)
    {
    
    
        // 获取配置项
        $weixinpay_config = $this->config;
        $config = array(
            'appid' => $weixinpay_config['APPID'],
            'mch_id' => $weixinpay_config['MCHID'],
            'nonce_str' => $this->nonce_str,
            'spbill_create_ip' => '192.168.0.1',
            'notify_url' => $weixinpay_config['NOTIFY_URL']
        );
        // 合并配置数据和订单数据
        $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;charset=utf-8";//定义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'] = $this->nonce_str;
        return $result;
    }

    /**
     * 输出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
        $config = $this->config;
        $string_sign_temp = $string_a . "&key=" . $config['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;
    }

    /**
     * 获取jssdk需要用到的数据
     * @return array jssdk需要用到的数据
     */
    public function getParameters()
    {
    
    
        // 获取配置项
        $config = $this->config;
        // 如果没有get参数没有code;则重定向去获取openid;
        //$openid = $this->openid;
        $out_trade_no = time() . '_' . $this->uid;
        // 订单数据  请根据订单号out_trade_no 从数据库中查出实际的body、total_fee、out_trade_no、product_id
        $order = array(
            'body' => '下单支付',// 商品描述(需要根据自己的业务修改)
            //'total_fee' => intval($this->fee),// 订单金额  以(分)为单位(需要根据自己的业务修改)
            'total_fee' => 1,
            'out_trade_no' => $out_trade_no,// 订单号(需要根据自己的业务修改)
            'trade_type' => 'APP',// APP支付
            'sign_type' => 'MD5'
        );
        // 统一下单 获取prepay_id
        $unified_order = $this->unifiedOrder($order);
        // 获取当前时间戳
        $time = time();
        $data = array(
            'appid' => $config['APPID'],//appid
            'partnerid' => $config['MCHID'],//商户号
            'timestamp' => strval($time),//时间戳
            'noncestr' => $unified_order['nonce_str'],//随机字符串
            'package' => 'Sign=WXPay',//预支付交易会话标识
            'prepayid' => $unified_order['prepay_id'],//预支付回话标志
            //'sign_type'=>'MD5'//加密方式
        );
        // 生成签名
        $data['paySign'] = $this->makeSign($data);
        return $data;
    }
}

引入支付接口类调用

        // 导入微信支付sdk
        Vendor('Weixinpay.Weixinpay');
        $wxpay = new \Weixinpay($order['user_id'], $orderSn, ($order['express_price'] + $order['price'])*100);

回调处理

    public function wechatNotify()
    {
    
    
        //获取返回的xml
        $testxml = file_get_contents("php://input");
        //将xml转化为json格式
        $jsonxml = json_encode(simplexml_load_string($testxml, 'SimpleXMLElement', LIBXML_NOCDATA));
        //转成数组
        $result = json_decode($jsonxml, true);
        try {
    
    
            if ($result['result_code'] != 'SUCCESS') {
    
    
                throw new \Exception("支付失败");
                exit();
            }
            $result = M('order')->where([
                ['order_num'=>['eq',$result['nonce_str']]]
            ])->save(['is_pay'=>1]);
            if ($result) {
    
    
                echo '<xml> <return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
            } else {
    
    
                throw new \Exception("支付成功,订单异常");
                exit();
            }
        } catch (\Exception $e) {
    
    
            Log::write($e->getMessage());
        }
    }

微信号:wx_zhuyanbin

猜你喜欢

转载自blog.csdn.net/qq_41526316/article/details/107339988