<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/1/2
 * Time: 13:48
 */

namespace app\modules\third\payment;
use Yii;
use app\modules\common\Helper;
use yii\db\Exception;
use app\modules\sys\log\ImLog;
class H5pay
{
    
    //查数估H5支付参数
    const APPID = 'wxdd3d2c71ad906f27';
    ///const MCHID = '1556784471';
    const MCHID = '1563941181';
    const KEY = 'B8910EA69419B782B4683CBDC55E871B';
    const APPSECRET = 'd3652b3704c3ec9d18d54b540b1a69c5';
    private $body = '精誉美车-服务';

    /**
     *
     * 统一下单
     *
     */
    public function unifiedOrder($data, $timeOut = 6)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $scene_info = [
            'h5_info' => [
                'type' => "Wap",
//                'wap_url' => 'http://csg.ftmore.com/',
                'wap_url' => Yii::$app->params['h5redirectUrl'],
                'wap_name' => '精誉美车-服务',
            ],
        ];
        $notify_url = Yii::$app->params['payNotifyUrl'];
        $request_data = [
            'appid' => self::APPID,
            'mch_id' => self::MCHID,
            'body' => isset($data['body'])?$data['body']:$this->body,
            'nonce_str' => Helper::genSalt(16),
            'spbill_create_ip' => Helper::getUserIp(),
            'trade_type' => 'MWEB',
            'out_trade_no' => $data['order_nid'],
            'total_fee' => $data['money'] * 100,
            'scene_info' =>  json_encode($scene_info),
        ];
        if(!empty($notify_url)){
           $request_data['notify_url'] = $notify_url;
        }
        $request_data['sign'] = $this->makeSign($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'] = 1;
                        $redirect_url = Yii::$app->params['h5redirectUrl'];
                        $pay_data = [
                            'url' => $result['mweb_url'].'&redirect_url='.urlencode($redirect_url),
                        ];
                        $pay_data['paySign'] = $this->makeSign($pay_data);
                        $return['data'] = $pay_data;
                        $return['data']['nid'] = $data['order_nid'];
                        $return['prepay_id'] =  $result['prepay_id'];
                        $return['data']['orig_ret'] = $result;
                       /* $return['appid'] =  self::APPID;
                        $return['noncestr'] =  $request_data['nonce_str'];*/
                        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 status($data)
    {
        //需要签名参数
        $order_data = [
            'appid' => self::APPID,
            'mch_id' => self::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, false);
        $result_data = $this->FromXml($result_data);
        return $result_data;
    }

    /**
     * 退费
     */
    public function refund($data, $timeOut = 6)
    {
        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        $request_data = [
            'appid' => self::APPID,
            'mch_id' => self::MCHID,
            'nonce_str' => Helper::genSalt(16),
            'out_trade_no' => $data['out_trade_no'],
            'out_refund_no' => $data['out_refund_no'],
            'transaction_id' => $data['transaction_id'],
            '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 .= "</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     */
    public function FromXml($xml)
    {

        libxml_disable_entity_loader(true);
        $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 . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 生成签名
     *
     */
    public function makeSign($data)
    {
        //签名步骤一：按字典序排序参数
        ksort($data);
        $string = $this->toUrlParams($data);

        //签名步骤二：在string后加入KEY

        $string = $string . "&key=" . self::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);
        $error_s = curl_error($ch);
        if($error || $error_s){
             ImLog::instance('wx_pay_post_error.log')->Log('error:'.$error.'error_s:'.$error_s);
        }

        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') {
            return $data;
        }

        $result = $this->CheckSign($data);
        if ($result) {
            return $data;
        } else {
            return false;
        }
    }
}