zoukankan      html  css  js  c++  java
  • 封装微信小程序支付

    <?php
    
    /**
     * User: Eden
     * Date: 2019/3/21
     * 共有内容
     */
    namespace CommonService;
    use ThinkException;
    use VendorFuncHttp;
    
    class WxPayService extends CommonService {
        public static function unifiedOrder($openid,$order_num,$total_fee,$products_name,$notify_url = ''){
            $trade_no = $order_num;
            $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
            $data = [
                'appid'             => C('APPID'),
                'mch_id'            => C('MCHID'),
                'nonce_str'         => self::createNonceStr(),
                'sign_type'         => 'MD5',
                'body'              => $products_name,  //商品名称组合
                'attach'            => C('APP_NAME').'-附加信息',
                'out_trade_no'      => $trade_no,       //订单号
                'fee_type'          => 'CNY',
                'total_fee'         => $total_fee,
                'spbill_create_ip'  => $_SERVER['REMOTE_ADDR'],
                'goods_tag'         => C('APP_NAME').'-商品标记',
                'notify_url'        => $notify_url ?:C('NOTIFY_URL'),
                'trade_type'        => 'JSAPI',
                'openid'            => $openid
            ];
    
            $sign = self::MakeSign($data);
            $data['sign'] = $sign;
            $xml = self::ToXml($data);
            $result = self::FromXml(Http::postXmlCurl($url,$xml));
    
            // 加工数据
            $data = [
                'appId' => $result['appid'] ?: C('APPID'),
                'timeStamp' => time(),
                'nonceStr' => self::createNonceStr(),
                'package' => 'prepay_id=' . $result['prepay_id'],
                'signType' => 'MD5'
            ];
            $sign = self::MakeSign($data);
            $data['sign'] = $sign;
            return $data;
        }
    
    
        public static function FromXml($xml)
        {
            if(!$xml){
                throw new Exception("xml数据异常!");
            }
            //将XML转为array
            //禁止引用外部xml实体
            libxml_disable_entity_loader(true);
            $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $values;
        }
    
        public static function ToXml($array){
            if(!is_array($array)|| count($array) <= 0){
                return ;
            }
            $xml = '<xml version="1.0">';
            foreach ($array as $key=>$val){
                if (is_numeric($val)){
                    $xml.="<".$key.">".$val."</".$key.">";
                }else{
                    $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
                }
            }
            $xml.="</xml>";
            return $xml;
        }
    
        public static function createNonceStr($length = 16) {
            $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
            $str = '';
            for ( $i = 0; $i < $length; $i++ )  {
                $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
            }
            return $str;
        }
    
        public static function MakeSign($data)
        {
            //签名步骤一:按字典序排序参数
            ksort($data);
            $string = self::ToUrlParams($data);
            //签名步骤二:在string后加入KEY
            $string = $string . "&key=".C('WEIXIN_PAY_KEY');
            //签名步骤三:MD5加密
            $string = md5($string);
            //签名步骤四:所有字符转为大写
            $result = strtoupper($string);
            return $result;
        }
    
        public static function ToUrlParams($array)
        {
            $buff = "";
            foreach ($array as $k => $v)
            {
                if($k != "sign" && $v != "" && !is_array($v)){
                    $buff .= $k . "=" . $v . "&";
                }
            }
            $buff = trim($buff, "&");
            return $buff;
        }
    }
    
    /***
     * 发起捐赠
     */
    public function pay()
    {
        if (!$openid = trim($_POST['openid'])) {
            $this->json->setErr(10001, '缺少参数');
            $this->json->Send();
        }
        if (!$donate_id = $_POST['donate_id']) {
            $this->json->setErr(10001, '缺少参数donate_id');
            $this->json->Send();
        }
        $amount = (float)$_POST['amount']; // 实际支付金额
        if ($amount <= 0) {
            $this->json->setErr(10002, '支付金额不可为0或负数');
            $this->json->Send();
        }
        $donate = M('donate');
        $donate_info = $donate->where(array('id' => $donate_id, 'status' => 1, 'is_show' => 1))->find();
        if (!$donate_info) {
            $this->json->setErr(10002, '捐赠内容不存在');
            $this->json->Send();
        }
    
        // 判断当前是否可以捐赠
        $now = time();
        if ($now < (int)$donate_info['start_time']) {
            $this->json->setErr(10003, '捐赠未开始');
            $this->json->Send();
        }
    
        if ($now > (int)$donate_info['end_time']) {
            $this->json->setErr(10004, '捐赠已结束');
            $this->json->Send();
        }
    
        $money = $donate_info['money']; // 已有捐赠金额
        $user = M('user');
        $user_info = $user->where(array('openid' => $openid))->find();
        if (!$user_info) {
            $this->json->setErr(10001, '用户信息不存在');
            $this->json->Send();
        }
        $uid = $user_info['id'];
    
        // step1 生成订单
        $order_info = $this->makeOrder($uid, $donate_id, $amount, $money);
        $order_num = $order_info['order_num'];
        $products_name = $order_info['products_name'];
    
        // step2  unifiedOrder
        $unifiedorder = WxPayService::unifiedOrder($openid, $order_num, $amount * 100, $products_name);
    
        // step3 将数据package下放到小程序中
        $this->json->setAttr('data', $unifiedorder);
        $this->json->Send();
    }
    
    
    /***
     * 生成捐赠订单
     * @param $uid
     * @param $donate_id
     * @param $amount
     * @param $money
     * @return mixed
     */
    private function makeOrder($uid, $donate_id, $amount, $money)
    {
        $donate_order = M('donate_order');
        $now = time();
        $order_num = 'do' . $uid . substr($now, 3) . rand(1000, 9999);
        $order_add_data = [
            'donate_id' => $donate_id,
            'order_num' => $order_num,
            'amount' => $amount,    //订单价格
            'money' => $money + $amount,
            'uid' => $uid,
            'status' => 1,               //未到账
            'create_time' => $now,            //订单生成时间
        ];
        $order_add_flag = $donate_order->add($order_add_data);
        if (!$order_add_flag) {
            $this->json->setErr(10003, '生成订单失败');
            $this->json->Send();
        }
        $return_data['order_num'] = $order_num;
        $return_data['products_name'] = '捐赠';
        return $return_data;
    }
    
    
    //微信支付回调
    public function order_notice()
    {
        $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
        $data = WxPayService::FromXml($xml);
        // 保存微信服务器返回的签名sign
        $data_sign = $data['sign'];
        // sign不参与签名算法
        unset($data['sign']);
        $sign = WxPayService::MakeSign($data);
        Clog::setLog($data, 'order_notice 回调数据');
        // 判断签名是否正确  判断支付状态
        if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
            //获取服务器返回的数据
            $order_num = $data['out_trade_no'];         //订单单号
            $openid = $data['openid'];                  //付款人openID
            $total_fee = $data['total_fee'];            //付款金额
            $transaction_id = $data['transaction_id'];  //微信支付流水号
            $user = M('user');
            $user_info = $user->where(array('openid' => $openid))->find();
            $total_payed_price = $total_fee / 100;
            $save_data = array(
                'total_payed_price' => $total_payed_price,     //实际到帐金额
                'transaction_id' => $transaction_id,
                'pay_time' => time(),
                'status' => 2,
            );
    
            // 开启事务
            M()->startTrans();
            $error_count = 0;
    
            // step 1 修改充值订单数据
            $donate_order = M('donate_order');
            $donate_order_info = $donate_order->where(array('order_num' => $order_num, 'uid' => $user_info['id']))->find();
            $donate_amount = $donate_order_info['amount'];
            $save_flag = $donate_order->where(array('order_num' => $order_num, 'uid' => $user_info['id']))->save($save_data);
            if (!$save_flag) {
                $error_count++;
                Clog::setLog('修改订单失败', 'order_notice 订单数据');
            }
    
            // step 2 修改捐赠总数
            $donate = M('donate');
            $donate_info = $donate->where(['id' => $donate_order_info['donate_id']])->find();
            $save_donate_data = [
                'money' => $donate_info['money'] + $donate_amount
            ];
            $money_save_flag = $donate->where(['id' => $donate_order_info['donate_id']])->save($save_donate_data);
            if (!$money_save_flag) {
                $error_count++;
                Clog::setLog('修改捐赠总数失败', 'order_notice 捐款数据');
            }
    
            // step 3 处理configs中的统计信息
            $configService = new ConfigService();
            $key = ['key' => ['in', ['total_donate', 'total_help', 'total_join']]];
            $total_data = $configService->queryKey($key);
            $edit_donate = $configService->updateOneKey('total_donate',$total_data['total_donate']+$total_payed_price);
            if (!$edit_donate && $edit_donate !== 0) {
                $error_count ++;
            }
            if ((float)$donate_info['money'] === 0.00) {
                // 第一次被帮助
                $edit_help = $configService->updateOneKey('total_help',$total_data['total_help']+1);
                if (!$edit_help && $edit_help !== 0) {
                    $error_count ++;
                }
            }
    
            $save_join = $configService->updateOneKey('total_join',$total_data['total_join']+1);
            if (!$save_join && $save_join !== 0) {
                $error_count ++;
            }
    
            if ($error_count > 0) {
                Clog::setLog('回滚了', 'order_notice');
                M()->rollback();
                $result = -2;
            } else {
                Clog::setLog('commit了', 'order_notice');
                M()->commit();
                $result = 0;
            }
        } else {
            Clog::setLog('签名有误', 'order_notice');
            $result = -1;
        }
        Clog::setLog($result, 'order_notice');
        // 返回状态给微信服务器
        $str = '';
        if ($result === 0) { // 成功之后不会再回调
            $str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        } elseif ($result === -1) { // 失败后会继续发送几次回调
            $str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
        } elseif ($result === -2) { // 失败后会继续发送几次回调
            $str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[操作失败]]></return_msg></xml>';
        }
        exit($str);
    }
    
  • 相关阅读:
    ArrayList集合封装 类 并通过方法调用
    ArrayList集合的基本操作
    方法的重复定义和重载
    方法间值的传递,二维数组的定义和遍历
    赋值运算,逻辑运算符,引用数据类型
    Javase;jdk的安装调试;基础语法和变量以及基础数据类型
    E-R画图规则和数据库设计的三大范式
    sql多表查询和子查询
    sql约束的使用
    sql表操作的基础语法
  • 原文地址:https://www.cnblogs.com/jiqing9006/p/10628143.html
Copyright © 2011-2022 走看看