<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/1/2
 * Time: 13:48
 */

namespace app\modules\third\payment;

use app\modules\sys\log\ImLog;
use app\modules\v6\components\notice\Notice;
use Yii;
use app\modules\common\Helper;
use yii\db\Exception;

class WxAppPay
{

    private $APPID = 'wxb12653b54b456429';
    private $MCHID = '1508407551';
    private $KEY = 'rPA23HATqvhFhGaF9TGFki3l8iXWS4Eq';

    private $notify_url = 'http://cdapitest.ftmore.com/v6/receive/wxapppaycallback';

    private $body = '技术服务费';

    public function __construct()
    {
        //配置文件初始化
        if (isset(Yii::$app->params['wxpay_app_appid'])) {
            $this->APPID = Yii::$app->params['wxpay_app_appid'];
        }
        if (isset(Yii::$app->params['wxpay_app_mchid'])) {
            $this->MCHID = Yii::$app->params['wxpay_app_mchid'];
        }
        if (isset(Yii::$app->params['wxpay_app_key'])) {
            $this->key = Yii::$app->params['wxpay_app_key'];
        }
        if(YII_ENV_PROD){
            $this->notify_url = 'http://mobileapi.chedaiol.com/v6/receive/wxapppaycallback';
        }
    }

    /**
     *
     * 统一下单
     *
     */
    public function unifiedOrder($data, $timeOut = 6)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $nonce_str = Helper::genSalt(16);
        $request_data = [
            'appid' => $this->APPID,
            'mch_id' => $this->MCHID,
            'notify_url' => $this->notify_url,
            'body' => $this->body,
            'nonce_str' => $nonce_str,
            'spbill_create_ip' => Helper::getUserIp(),
            'trade_type' => 'APP',
            'out_trade_no' => $data['order_nid'],
            'total_fee' => $data['money'] * 100,
        ];

        $request_data['sign'] = $this->makeSign($request_data);
        ImLog::instance('wx_app_pay.log')->Log($request_data);
        $xml = $this->toXml($request_data);
        $response = self::postXmlCurl($xml, $url, false, $timeOut);


        if ($response) {
            $result = $this->response($response);
            if (is_array($result)) {
                if ($result['return_code'] == 'SUCCESS') {
                    if ($result['result_code'] == 'SUCCESS') {
                        $return['code'] = Notice::PAY_ORDER_SUCCESS;
                        $pay_data = [
                            'appid' => $this->APPID,
                            'partnerid' => $this->MCHID,
                            'prepayid' => $result['prepay_id'],
                            'noncestr' => $nonce_str,
                            'timestamp' => time(),
                            'package' => 'Sign=WXPay'
                        ];
                        $pay_data['sign'] = $this->makeSign($pay_data);
                        $return['data'] = $pay_data;
                        $return['prepay_id'] = $result['prepay_id'];
                        return $return;
                    } else {
                        $msg = '未知错误';
                        if (isset($result['err_code_des'])) {
                            $msg = $result['err_code_des'];
                        }
                        return ['code' => 0, 'msg' => $msg];
                    }
                } else {
                    return ['code' => 0, 'msg' => $result['return_msg']];
                }
            } else {
                return ['code' => 0, 'msg' => '返回验签失败'];
            }
        } else {
            return ['code' => 0, 'msg' => '请求失败'];
        }

    }


    /**
     * 退费
     */
    public function refund($data, $timeOut = 6)
    {

        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";


        $request_data = [
            'appid' => $this->APPID,
            'mch_id' => $this->MCHID,
            'nonce_str' => Helper::genSalt(16),
            'transaction_id' => $data['transaction_id'],
            'out_refund_no' => $data['order_nid'],
            'total_fee' => $data['money'] * 100,
            'refund_fee' => $data['money'] * 100,
        ];

        $request_data['sign'] = $this->makeSign($request_data);

        $xml = $this->toXml($request_data);

        $response = self::postXmlCurl($xml, $url, true, $timeOut);
        $result = $this->response($response);
        return $result;
    }

    /**
     * 输出xml字符
     *
     **/
    public function toXml($data)
    {

        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
//                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     */
    public function FromXml($xml)
    {


        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);


        return $data;
    }


    public function toUrlParams($data)
    {
        $buff = "";
        foreach ($data as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
            if (is_array($v)) {
                foreach ($v as $t) {
                    $buff .= $k . "=" . $t . "&";
                }
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 生成签名
     *
     */
    public function makeSign($data)
    {
        //签名步骤一：按字典序排序参数
        ksort($data);
        $string = $this->toUrlParams($data);

        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $this->KEY;

        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
    {
        $SSLCERT_PATH = Yii::$app->basePath . '/cert/apiclient_cert.pem';

        $SSLKEY_PATH = Yii::$app->basePath . '/cert/apiclient_key.pem';


        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);


        curl_setopt($ch, CURLOPT_URL, $url);


        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

        if ($useCert == true) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);//严格校验

            //设置证书
            //使用证书：cert 与 key 分别属于两个.pem文件

            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');

            curl_setopt($ch, CURLOPT_SSLCERT, $SSLCERT_PATH);

            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');

            curl_setopt($ch, CURLOPT_SSLKEY, $SSLKEY_PATH);

        } else {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }


        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        $error = curl_errno($ch);


        curl_close($ch);
        return $data;

    }


    /**
     *
     * 检测签名
     */
    public function CheckSign($data)
    {
        $sign = $this->makeSign($data);
        if ($data['sign'] == $sign) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 将xml转为array
     *
     */
    public function response($xml)
    {

        $data = $this->FromXml($xml);

        if ($data['return_code'] != 'SUCCESS') {
            ImLog::instance('wx_pay_calbak.log')->Log('签名错误：' . $xml);
            return $data;
        }

        $result = $this->CheckSign($data);
        if ($result) {
            return $data;
        } else {
            return false;
        }
    }

    public function status($data)
    {
        //需要签名参数
        $order_data = [
            'appid' => $this->APPID,
            'mch_id' => $this->MCHID,
            'out_trade_no' => $data['nid'],
            'nonce_str' => Yii::$app->getSecurity()->generateRandomString(32)
        ];

        $order_data['sign'] = $this->makeSign($order_data);
        $xml_data = $this->toXml($order_data);
        //检测订单状态接口连接
        $check_url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $result_data = $this->postXmlCurl($xml_data, $check_url, true);
        $result_data = $this->FromXml($result_data);
        return $result_data;
    }
}