<?php
namespace app\index\controller;
use think\facade\Db;

define('APPID', 'wx45bb3b49e7ababa6');
define('MCHID', '1637503702');
define('KEY', 'BDo3itW3m8pNd6ti9L9qoK4mVGfvS8Kq');
define('SECRET', 'b4b90b7a44fd65c4269190ddc74cde05');

class WechatPay
{
    public function jsapi()
    {
        $code    = input('post.code');
        $appid   = APPID;
        $secret  = SECRET;
        $api     = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$secret}&js_code={$code}&grant_type=authorization_code";
        $json    = json_decode(file_get_contents($api), true);
        $openid  = $json['openid'];

        $params = [
            'openid'       => $openid,
            'out_trade_no' => time(),
            'total_fee'    => input('post.total_fee')*100,
            'body'         => '鹿眸生活',
            'trade_type'   => 'JSAPI',
            'notify_url'   => 'http://'.$_SERVER['HTTP_HOST'].'/wechat_pay/notify.html',
            'attach'       => input('order_id')
        ];

        $unifiedorder = $this->unifiedorder($params);

        $data = [
            'appId'     => APPID,
            'timeStamp' => time(),
            'nonceStr'  => $this->create_nonce_str(),
            'package'   => 'prepay_id='.$unifiedorder['prepay_id'],
            'signType'  => 'MD5'
        ];
        $sign = $this->make_sign($data);
        $data['sign'] = $sign;
        return json($data);
    }

    public function notify(){
        $resp = $this->notify_parse();

        if(isset($resp['trade_state']) && $resp['trade_state'] == 'SUCCESS'){
            $order_id = $resp['attach'];
            $order  = Db::name('order')->where('order_id', $order_id)->find();
            $member = Db::name('member')->where('member_id', $order['member_id'])->find();
            $user   = Db::name('user')->where('user_id', $order['user_id'])->find();
            $vip_day = $member['member_vip_day']+$member['member_give_day'];
            $user_overdue_time = 0;
            if (time() > $user['user_overdue_time']) {
                $user_overdue_time = time() + $vip_day*86400;
            } else {
                $user_overdue_time = $user['user_overdue_time'] + $vip_day*86400;
            }
            Db::name('user')->where('user_id', $order['user_id'])->update(['user_is_vip'=>1,'user_overdue_time'=>$user_overdue_time]);
            Db::name('order')->where('order_id', $order_id)->update(['order_status'=>1,'order_pay_time'=>time()]);
            echo 'SUCCESS';
        }
    }

    public function notify_parse()
    {
        $xml = file_get_contents("php://input");
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        $transaction_id = $data['transaction_id'];
        $out_trade_no = $data['out_trade_no'];

        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $data = [
            'appid'          => APPID,
            'mch_id'         => MCHID,
            'nonce_str'      => $this->create_nonce_str(),
            'sign_type'      => 'MD5',
            'transaction_id' => $transaction_id,
        ];

        $data['sign'] = $this->make_sign($data);
        $xml          = $this->to_xml($data);
        $dataxml      = $this->post_xml_curl($xml,$url);
        $result       = (array)simplexml_load_string($dataxml, 'SimpleXMLElement', LIBXML_NOCDATA);
        return $result;
    }

    public function unifiedorder($params){
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $data = [
            'appid'            => APPID,
            'mch_id'           => MCHID,
            'nonce_str'        => $this->create_nonce_str(),
            'sign_type'        => 'MD5',
            'body'             => isset($params['body']) ? $params['body'] : '',
            'attach'           => isset($params['attach']) ? $params['attach'] : '',
            'out_trade_no'     => isset($params['out_trade_no']) ? $params['out_trade_no'] : '',
            'fee_type'         => 'CNY',
            'total_fee'        => isset($params['total_fee']) ? $params['total_fee'] : '',
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'goods_tag'        => isset($params['goods_tag']) ? $params['goods_tag'] : '',
            'notify_url'       => isset($params['notify_url']) ? $params['notify_url'] : '',
            'trade_type'       => isset($params['trade_type']) ? $params['trade_type'] : '',
            'openid'           => isset($params['openid']) ? $params['openid'] : ''
        ];

        $data['sign'] = $this->make_sign($data);
        $xml          = $this->to_xml($data);
        $dataxml      = $this->post_xml_curl($xml,$url);
        $result       = (array)simplexml_load_string($dataxml, 'SimpleXMLElement', LIBXML_NOCDATA);
        return $result;
    }

    public function post_xml_curl($xml,$url,$second = 30){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $data = curl_exec($ch);
        if($data){
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            echo "curl 出错，错误码:$error"."<br>";
        }
    }

    public function create_nonce_str($length = 32){
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for($i=0;$i<$length;$i++){
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }

    public function from_xml($xml){
        if(!$xml){
            throw new WxPayException("xml数据异常！");
        }
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }

    public function to_xml($array){
        if(!is_array($array)|| count($array) <= 0){
           return ;
        }
        $xml = '<xml>';
        foreach ($array as $key=>$val){
            if (is_numeric($val)){
              $xml .= "<".$key.">".$val."</".$key.">";
            } else {
                $xml .= "<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    public function make_sign($data){
        ksort($data);
        $string = $this->to_url_params($data);
        $string = $string . "&key=".KEY;
        $string = md5($string);
        $result = strtoupper($string);
        return $result;
    }

    public function to_url_params($array){
        $buff = "";
        foreach($array as $k => $v){
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }
}