<?php

class ControllerPaymentUseepay extends Controller
{
    public function log($msg)
    {
        $logger = new Log('useepay.log');
        $logger->write($msg);
    }

    /**
     * 支付页面展示
     * @return mixed
     */
    public function index()
    {
        $this->language->load('payment/useepay');

        $data['entry_card_number'] = $this->language->get('entry_card_number');
        $data['entry_card_expiration_date'] = $this->language->get('entry_card_expiration_date');
        $data['entry_card_cvv2'] = $this->language->get('entry_card_cvv2');
        $data['text_credit_card'] = $this->language->get('text_credit_card');
        $data['text_wait'] = $this->language->get('text_wait');
        $data['text_loading'] = $this->language->get('text_loading');
        $data['button_back'] = $this->language->get('button_back');
        $data['button_confirm'] = $this->language->get('button_confirm');

        $data['months'][0] = array(
            'text' => 'Month',
            'value' => '00'
        );
        for ($i = 1; $i <= 12; $i++) {
            $data['months'][] = array(
                'text' => sprintf('%02d', $i),
                'value' => sprintf('%02d', $i)
            );
        }

        $data['year_expire'][0] = array(
            'text' => 'Year',
            'value' => '00'
        );

        $today = getdate();
        for ($i = $today['year']; $i < $today['year'] + 21; $i++) {
            $data['year_expire'][] = array(
                'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)),
                'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i))
            );
        }

        $data['card_types'] = $this->config->get('useepay_supported_card_type');
        $data['env'] = "sandbox";
        $env = $this->config->get('useepay_env');
        if ($env == "https://pay-gateway.useepay.com/cashier") {
            $data['env'] = "production";
        }
        $data['merchantNo'] = trim(
            $this->config->get('useepay_merchant_no')
        );

        return $this->load->view('payment/useepay', $data);
    }

    /**
     * 处理支付,json交互方式
     */
    public function payment()
    {
        // 创建对账订单数据并存表
//        $useepay_order_id = $this->createUseepayOrderId();
        $this->language->load('payment/useepay');
        $this->load->model('checkout/order');
        $this->load->model('payment/useepay');
        $order_info = $this->model_checkout_order->getOrder(
            $this->session->data['order_id']
        );
        $order_id = $this->session->data['order_id'];

        $firstName = 'opencart2';
        $lastName = 'opencart2';
        if (!empty($order_info['firstname'])) {
            $firstName = $order_info['firstname'];
        }
        if (!empty($order_info['lastname'])) {
            $lastName = $order_info['lastname'];
        }

        $payer_info = [
            'paymentMethod'       =>  trim(
                $this->config->get('useepay_payment_method')
            ),
            'authorizationMethod' => 'cvv',
            'billingAddress' => [
                'firstName' => empty($order_info['payment_firstname'])
                    ? $order_info['shipping_firstname']
                    : $order_info['payment_firstname'], // 收货人名
                'lastName' => empty($order_info['payment_lastname'])
                    ? $order_info['shipping_lastname']
                    : $order_info['payment_lastname'],
                'email' => $order_info['email'],
                'phoneNo' => $order_info['telephone'],
                'street' => $order_info['payment_address_1'], // 账单街道
                'houseNo' => $order_info['payment_address_2'],
                'postalCode' => $order_info['payment_postcode'], // 账单邮政编码
                'city' => $order_info['payment_city'], // 账单城市
                'state' => $order_info['payment_zone'], // 账单省份
                'country' => $order_info['payment_iso_code_2'], // 账单国家英文二字码
            ],

        ];

        //  商品信息
        $products = $this->cart->getProducts();
        $goods_name = "";
        foreach ($products as $product) {
            $goods_name .= "|" . $product['name'];
        }
        $goods_name = $this->filter(trim($goods_name, "|"));
        $ip = $order_info['ip'];
        if($order_info['forwarded_ip']){
            $ip = explode(', ',$order_info['forwarded_ip']);
            $ip = $ip['0'];
        }

        $risk_info_goods = [];
        foreach ($products as $product) {
            $temp = [];
            $temp['id'] = strval($product['product_id']);
            $temp['name'] = strval($product['name']);
            $temp['price'] = $this->formatPrice($order_info['currency_code'], $product['price']);
            $temp['quantity'] = strval($product['quantity']);
            $risk_info_goods[] = $temp;
        }

        // 订单信息
        $req_order_info = [
            'subject' => str_replace(
                ["\r", "\n", "\r\n"],
                [' ', ' ', ' '],
                $goods_name
            ), // 订单标题
            'goodsInfo' => $risk_info_goods, // 商品信息
            'shippingAddress' => [
                'email' => $order_info['email'],
                'phoneNo' => $order_info['telephone'], // 收货联系电话
                'firstName' => empty($order_info['shipping_firstname'])
                    ? $order_info['payment_firstname']
                    : $order_info['shipping_firstname'], // 收货人名
                'lastName' => empty($order_info['shipping_firstname'])
                    ? $order_info['payment_lastname']
                    : $order_info['shipping_lastname'], // 收货人姓
                'street' => empty($order_info['shipping_address_1'])
                    ? $order_info['payment_address_1']
                    : $order_info['shipping_address_1'], // 收货人街道
                'postalCode' => empty($order_info['shipping_postcode'])
                    ? $order_info['payment_postcode']
                    : $order_info['shipping_postcode'], // 收货人邮政编码
                'city' => empty($order_info['shipping_city'])
                    ? $order_info['payment_city']
                    : $order_info['shipping_city'], // 收货人城市
                'state' => empty($order_info['shipping_zone'])
                    ? $order_info['payment_zone']
                    : $order_info['shipping_zone'], // 收货人省份
                'country' => empty($order_info['shipping_iso_code_2'])
                    ? $order_info['payment_iso_code_2']
                    : $order_info['shipping_iso_code_2'], // 收货人国家英文二字码
            ],
        ];

        // 用户信息
        $user_info = [
            'ip' => $ip, // 用户下单IP
            'email' => $order_info['email'], // 用户email
            'phoneNo' => $order_info['telephone'], // 用户phone
        ];
        if (!empty($order_info['customer_id']) && $order_info['customer_id'] != 0){// 0代表游客
            $user_info['userId'] = $order_info['customer_id']; // 用户在商户系统的id
        }

        // 价格总额
        // format price
        $actual_price = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false);
        $amount = $this->formatPrice($order_info['currency_code'], $actual_price);

//        $order_map = $this->model_payment_useepay->getOrderById($order_id);
//        if ($order_map) {
//            $useepay_order_id = $order_map['useepay_order_id'];
//            $this->model_payment_useepay->updateOrder($order_id, $useepay_order_id);
//        } else {
//            $this->model_payment_useepay->addOrder($order_id, $useepay_order_id);
//        }

        // 参数组装
        $param = [
            'version' => '1.0', // 版本
            'merchantNo' => trim(
                $this->config->get('useepay_merchant_no')
            ), //  商户号
            'transactionId' => $order_id, // 交易流水号
            'transactionType' => trim(
                $this->config->get('useepay_transaction_type')
            ),
            'transactionExpirationTime' => trim(
                $this->config->get(
                    'useepay_transaction_expiration_time'
                )
            ), //  订单有效时长
            'appId' => trim($this->config->get('useepay_app_id')), //  交易主体的网址域名或app英文名
            'currency' => $order_info['currency_code'],
            'amount' => $amount,
            'country' => $order_info['payment_iso_code_2'],
            'language'                  => 'en',
            'payerInfo' => json_encode($payer_info), //  付款人信息
            'orderInfo' => json_encode($req_order_info), //  订单信息
            'userInfo' => json_encode($user_info), //  用户信息
            'notifyUrl' =>
                HTTPS_SERVER .
                'index.php?route=payment/useepay/notify', //  异步通知地址
            'terminalType'   => $this->getTerminalType(),
            //            'echoParam' => '',    // 回声参数
            'reserved' => json_encode([
                'pluginName' => 'opencart-api',
                'pluginVersion' => '1.0',
                'origVersion' => '2.2',
            ]), // 保留字段
            'charset'                   => 'utf-8',
            'signType' => trim($this->config->get('useepay_sign_type')), // 签名类型
            'autoRedirect'              => 'false',
            'sign' => '', // 签名串
        ];

        // 生成签名串
        $param['sign'] = $this->createSign($param, $this->config->get('useepay_sign_key'));

        // 发送请求
        $pay_url = $this->config->get('useepay_env');
        $this->log('$pay_url: ' . $pay_url);
        $this->log('$param: ' . json_encode($param));
        $result = $this->submitWithReturn($pay_url, $param);
        $this->log('$result: ' . $result);

        if (empty($result)) {
            $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('useepay_failed_order_status_id'), 'No Data Return', true);
            $json['message'] = 'Sorry, payment is failed without any data returned! Please try again.';
            $json['result'] = 'error';
            $json['redirectUrl'] = $this->errorPageUrl();
            $this->response->setOutput(json_encode($json));
            return -1;
        }

        // 生成验证签名串
        $res = json_decode($result, true);
        $res_sign = $this->createUnsign($res, $this->config->get('useepay_sign_key'));

        if ($res_sign != $res['sign'] && !'' == $res_sign) {
            $message = "Sorry, payment is failed! The reason is:\n" . $res['errorMsg']; // 统一消息提示方式
            $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('useepay_failed_order_status_id'), $message . "\npayment order id is:" . $res['reference'], true);
            $json['message'] = $message;
            $json['result'] = 'error';
            $json['redirectUrl'] = $this->errorPageUrl();
        } else {
            // 根据status判断成功与否
            $history_status = $this->model_checkout_order->getOrder($order_id)['order_status_id'];
            if (!empty($res) && is_array($res) && !empty($res['token'])) {
                $json['result'] = 'success';
                $json['token'] = $res['token'];
            } else {
                $message = "Sorry, payment is failed! The reason is:\n" . $res['errorMsg'];
                if (
                    empty($history_status) ||
                    $history_status !=
                    $this->config->get(
                        'useepay_failed_order_status_id'
                    )
                ) {
                    $this->model_checkout_order->addOrderHistory(
                        $order_id,
                        $this->config->get(
                            'useepay_failed_order_status_id'
                        ),
                        $message . "\npayment order id is:" . $res['reference'],
                        true
                    );
                }
                $json['message'] = $message;
                $json['result'] = 'error';
            }
        }

        $this->response->addHeader('Content-Type: application/json');
        $this->response->setOutput(json_encode($json));
    }

    /**
     * 异步通知
     */
    public function notify()
    {
        $res = $_POST;
        $this->log('notify res: ' . json_encode($res));
        $this->load->model('checkout/order');
        $this->load->model('payment/useepay');

        sleep(2); //  推迟异步通知的处理，防止出现并发问题

        // 验签
        $sign = $this->createUnsign($res, $this->config->get('useepay_sign_key'));
        if ($res['sign'] != $sign || empty($res['sign'])) {
            $this->log('notify: check sign failed.');
            return -1;
        }

        if (isset($res['resultCode'])) {
//            $order_map = $this->model_payment_useepay->getOrderByUseepayId($res['transactionId']);
//            $res['transactionId'] = $order_map['order_id'];
            $history_status = $this->model_checkout_order->getOrder($res['transactionId'])['order_status_id'];
            $this->log('UseePay notify response: order_id is ' . $res['transactionId'] . ' and code is ' . $res['errorCode'] . ', and message is "' . $res['errorMsg'] . '"');

            if ('succeed' == $res['resultCode']) {
                if (empty($history_status) || $history_status != $this->config->get('useepay_succeed_order_status_id')) {
                    $message = "Congratulations, payment is successful. ";
                    $this->model_checkout_order->addOrderHistory($res['transactionId'], $this->config->get('useepay_succeed_order_status_id'), $message . "\npayment order id is:" . $res['reference'], true);
                }
            } else if ('failed' == $res['resultCode'] || 'closed' == $res['resultCode'] || 'cancelled' == $res['resultCode']) {
                if (empty($history_status) || $history_status != $this->config->get('useepay_failed_order_status_id')) {
                    $message = "Sorry, payment is failed! The reason is:\n" . $res['errorMsg'];
                    $this->model_checkout_order->addOrderHistory($res['transactionId'], $this->config->get('useepay_failed_order_status_id'), $message . "\npayment order id is:" . $res['reference'], true);
                }
            } else {
                $message = "The transaction was submitted successfully, wait to confirm.";
                $this->model_checkout_order->addOrderHistory($res['transactionId'], $this->config->get('useepay_order_status_id'), $message . "\npayment order id is:" . $res['reference'], true);
            }
        }
        echo 'ok';
    }

    /**
     * 处理结果跳转
     */
    public function result()
    {
        $this->language->load('payment/useepay');

        if (!isset($this->request->server['HTTPS']) || ($this->request->server['HTTPS'] != 'on')) {
            $data['base'] = HTTP_SERVER;
        } else {
            $data['base'] = HTTPS_SERVER;
        }

        $data['title'] = sprintf($this->language->get('heading_title'), $this->config->get('config_name'));
        $data['charset'] = $this->language->get('charset');
        $data['language'] = $this->language->get('code');
        $data['direction'] = $this->language->get('direction');
        $data['heading_title'] = sprintf($this->language->get('heading_title'), $this->config->get('config_name'));
        $data['text_response'] = $this->language->get('text_response');
        $data['text_billno'] = '<font color="green">' . $this->session->data['order_id'] . '</font>';
        $data['column_left'] = $this->load->controller('common/column_left');
        $data['column_right'] = $this->load->controller('common/column_right');
        $data['content_top'] = $this->load->controller('common/content_top');
        $data['content_bottom'] = $this->load->controller('common/content_bottom');
        $data['footer'] = $this->load->controller('common/footer');
        $data['header'] = $this->load->controller('common/header');
        $data['continue'] = $data['base'] . 'index.php?route=account/order';

        if ($this->request->get['route'] != 'checkout/guest_step_3') {
            $data['text_result_wait'] = sprintf($this->language->get('text_result_wait'), HTTPS_SERVER . 'index.php?route=checkout/cart');
        } else {
            $data['text_result_wait'] = sprintf($this->language->get('text_result_wait'), HTTPS_SERVER . 'index.php?route=checkout/guest_step_2');
        }

        $data['text_result'] = '';
        if (!empty($_GET['status'])) {
            if ('pending' == $_GET['status']) {
                $data['text_result'] = 'and your payment is <strong><span style="color: blue;">processing</span></strong>. please check again later!';
            } else if ('failed' == $_GET['status']) {
                $data['text_result'] = 'and your payment is <strong><span style="color: red;">failed</span></strong>.';
            }
        }

        if (!empty($_GET['msg'])) {
            $data['text_result_reason'] = $_GET['msg'];
        } else {
            $data['text_result_reason'] = '';
        }

        $this->response->setOutput($this->load->view('payment/useepay_failure', $data));
    }

    private function getTerminalType()
    {
        $terminalType = 'WEB';
        $useragent    = $_SERVER['HTTP_USER_AGENT'];
        if (preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $useragent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($useragent, 0, 4))) {
            $terminalType = 'H5';
        }
        return $terminalType;
    }

    /***********************************************************************************/

    /**
     * 生成对账订单ID
     * @param bool $withIP
     * @return string
     */
    private function createUseepayOrderId($withIP = false)
    {
        $useepay_order_id = "";

        // 当前日期
        $str_time = date("YmdHis", time());
        $useepay_order_id .= $str_time;

        // IP
        if ($withIP) {
            $str_ip = "";
            $server_addr = $_SERVER['SERVER_ADDR'];
            $server_addr_arr = explode('.', $server_addr);
            foreach ($server_addr_arr as $value) {
                for ($i = 3; $i > strlen($value); $i--) {
                    $str_ip .= "0";
                }
                $str_ip .= $value;
            }
            $useepay_order_id .= $str_ip;
        }

        // 进程号
        $pid = getmypid();
        $pid_all = "00000" . $pid;
        $str_pid = substr($pid_all, -5);
        $useepay_order_id .= $str_pid;

        // 两位随机数
        $randnum = mt_rand(10, 99);
        $useepay_order_id .= $randnum;

        return $useepay_order_id;
    }

    /**
     * 生成签名串
     * @param $param
     * @return string
     */
    public function createSign($param, $sign_key)
    {
        $sign_str = '';
        $sign = '';
        ksort($param);
        foreach ($param as $key => $value) {
            $v = trim($value);
            if (strlen($v) > 0) {
                $sign_str .= '&' . $key . '=' . $v;
            }
        }
        $sign_str = substr($sign_str, 1);
        $sign_str .= "&pkey=" . trim($sign_key);

        if ('MD5' == $param['signType']) {
            $sign = strtolower(md5($sign_str));
        }

        return $sign;
    }

    /**
     * 生成验证签名串
     * @param $param
     * @param $key
     * @return string
     */
    public function createUnsign($param, $sign_key)
    {
        $sign_str = '';
        $sign = '';
        ksort($param);
        foreach ($param as $key => $value) {
            if (!is_array($value) && '' != $value && 'sign' != $key) {
                $sign_str .= '&' . $key . '=' . trim($value);
            }
        }
        $sign_str = substr($sign_str, 1);
        $sign_str .= "&pkey=" . trim($sign_key);
        if ('MD5' == $param['signType']) {
            $sign = strtolower(md5($sign_str));
        }

        return $sign;
    }

    /**
     * Format price to int
     * @param $currency
     * @param $price
     * @return int
     */
    private function formatPrice($currency, $price)
    {
        $currency_map_json = '{"EUR":2,"AMD":2,"BOV":2,"XAF":0,"COP":2,"COU":2,"CUP":2,"ANG":2,"DOP":2,"HKD":2,"IRR":2,"NPR":2,"PYG":0,"QAR":2,"RON":2,"SBD":2,"SOS":2,"LKR":2,"TWD":2,"VUV":0,"XTS":0,"XAU":0,"AOA":2,"ARS":2,"BRL":2,"BGN":2,"KHR":2,"KMF":0,"CDF":2,"GNF":0,"HNL":2,"ISK":0,"ILS":2,"JPY":0,"KWD":3,"LBP":2,"LYD":3,"MWK":2,"MXV":2,"PKR":2,"RWF":0,"STD":2,"SLL":2,"CHW":2,"UGX":0,"USN":2,"UZS":2,"XBB":0,"BBD":2,"XOF":0,"BMD":2,"CAD":2,"NZD":2,"CZK":2,"FJD":2,"GBP":2,"ZAR":2,"LRD":2,"PHP":2,"WST":2,"SCR":2,"SDG":2,"TMT":2,"UYI":0,"XBA":0,"BAM":2,"BWP":2,"CLP":0,"CRC":2,"GYD":2,"JOD":3,"MKD":2,"MUR":2,"MDL":2,"MNT":2,"NGN":2,"SRD":2,"SEK":2,"TZS":2,"TOP":2,"UAH":2,"UYU":2,"ZWL":2,"USD":2,"BSD":2,"BYN":2,"BZD":2,"CLF":4,"GHS":2,"GTQ":2,"IQD":3,"KRW":0,"MOP":2,"MXN":2,"MAD":2,"NIO":2,"XSU":0,"SZL":2,"THB":2,"VND":0,"ZMW":2,"XPD":0,"AFN":2,"AUD":2,"BOB":2,"CNY":2,"HRK":2,"DJF":0,"EGP":2,"ETB":2,"GEL":2,"HTG":2,"XDR":0,"JMD":2,"KZT":2,"KPW":2,"MGA":2,"MVR":2,"XUA":0,"MMK":2,"NAD":2,"OMR":3,"PGK":2,"RUB":2,"TTD":2,"XXX":0,"ALL":2,"DZD":2,"XCD":2,"AZN":2,"BDT":2,"INR":2,"BTN":2,"NOK":2,"BND":2,"BIF":0,"CUC":2,"SVC":2,"FKP":2,"XPF":0,"GMD":2,"HUF":2,"KES":2,"KGS":2,"LAK":2,"MYR":2,"MRO":2,"PAB":2,"PEN":2,"RSD":2,"SGD":2,"CHE":2,"TND":3,"TRY":2,"VEF":2,"YER":2,"XBD":0,"XPT":0,"XAG":0,"AWG":2,"BHD":3,"CVE":2,"KYD":2,"DKK":2,"ERN":2,"GIP":2,"IDR":2,"LSL":2,"CHF":2,"MZN":2,"PLN":2,"SHP":2,"SAR":2,"SSP":2,"SYP":2,"TJS":2,"AED":2,"XBC":0}';

        $currency_map = json_decode($currency_map_json, true);
        $times = 2;
        if (array_key_exists($currency, $currency_map)) {
            $times = $currency_map[$currency];
        }
        while ($times--) {
            $price *= 10;
        }
        return intval($price);
    }

    /**
     * Filter special characters
     * @param $str
     * @return mixed
     */
    private function filter($str)
    {
        return str_replace(
            ["<", ">", "'", "\"", "&"],
            ["", "", "", "", ""],
            trim($str)
        );
    }

    /**
     * 发送http请求，返回结果
     * @param $url
     * @param $data
     * @return mixed
     */
    function submitWithReturn($paymentUrl, $paymentData)
    {
        if (function_exists('curl_init') && function_exists('curl_exec')) {
            $info = $this->vpost($paymentUrl, $paymentData);
        } else {
            $info = $this->hpost($paymentUrl, $paymentData);
        }
        return $info;
    }

    function vpost($url, $data)
    {
        $curl_cookie = "";
        foreach ($_COOKIE as $key => $value) {
            $curl_cookie .= $key . "=" . $value . ";";
        }
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
        curl_setopt($curl, CURLOPT_REFERER, $_SERVER['HTTP_HOST']);
        curl_setopt($curl, CURLOPT_POST, 1);
//        if (substr($url, 0, 6) == "https:")
//            curl_setopt($curl, CURLOPT_PORT, 443);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_TIMEOUT, 300);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_COOKIE, $curl_cookie);
        $tmpInfo = curl_exec($curl);
        curl_close($curl);
        return $tmpInfo;
    }

    function hpost($url, $data)
    {
        $website = $_SERVER['HTTP_HOST'];
        $cookie = "";
        foreach ($_COOKIE as $key => $value) {
            $cookie .= $key . "=" . $value . ";";
        }
        $options = array(
            'http' => array(
                'method' => "POST",
                'header' =>
                    "Accept-language: en\r\n" .
                    "Cookie: $cookie\r\n" .
                    "referer:$website \r\n",
                'content-type' => "multipart/form-data",
                'content' => $data,
                'timeout' => 15 * 60
            )
        );
        //创建并返回一个流的资源
        $context = stream_context_create($options);
        //var_dump($options);exit;
        $result = file_get_contents($url, false, $context);
        return $result;
    }

    /**
     * 支付失败页面
     */
    public function failure()
    {
        $this->language->load('payment/useepay');

        $data['title'] = sprintf(
            $this->language->get('heading_title'),
            $this->config->get('config_name')
        );

        if (
            !isset($this->request->server['HTTPS']) ||
            $this->request->server['HTTPS'] != 'on'
        ) {
            $data['base'] = HTTP_SERVER;
        } else {
            $data['base'] = HTTPS_SERVER;
        }

        $data['charset'] = $this->language->get('charset');
        $data['language'] = $this->language->get('code');
        $data['direction'] = $this->language->get('direction');
        $data['heading_title'] = sprintf(
            $this->language->get('heading_title'),
            $this->config->get('config_name')
        );
        $data['text_response'] = $this->language->get('text_response');
        $data['text_success'] = $this->language->get('text_success');
        $data['text_success_wait'] = sprintf(
            $this->language->get('text_success_wait'),
            HTTPS_SERVER . 'index.php?route=checkout/success'
        );
        $data['text_failure'] = $this->language->get('text_failure');
        $data['text_billno'] =
            '<font color="green">' .
            $this->session->data['order_id'] .
            '</font>';

        if ($this->request->get['route'] != 'checkout/guest_step_3') {
            $data['text_failure_wait'] = sprintf(
                $this->language->get('text_failure_wait'),
                HTTPS_SERVER . 'index.php?route=checkout/cart'
            );
        } else {
            $data['text_failure_wait'] = sprintf(
                $this->language->get('text_failure_wait'),
                HTTPS_SERVER . 'index.php?route=checkout/guest_step_2'
            );
        }

        $data['column_left'] = $this->load->controller('common/column_left');
        $data['column_right'] = $this->load->controller('common/column_right');
        $data['content_top'] = $this->load->controller('common/content_top');
        $data['content_bottom'] = $this->load->controller(
            'common/content_bottom'
        );
        $data['footer'] = $this->load->controller('common/footer');
        $data['header'] = $this->load->controller('common/header');
        $data['continue'] = HTTPS_SERVER . 'index.php?route=checkout/cart';

        if (
        file_exists(
            DIR_TEMPLATE .
            $this->config->get('config_template') .
            '/template/payment/useepay_failure'
        )
        ) {
            $this->response->setOutput(
                $this->load->view(
                    $this->config->get('config_template') .
                    '/template/payment/useepay_failure',
                    $data
                )
            );
        } else {
            $this->response->setOutput(
                $this->load->view('payment/useepay_failure', $data)
            );
        }
    }

    /**
     * 支付pending页面
     */
    public function pending()
    {
        $this->language->load('payment/useepay');

        $data['title'] = sprintf(
            $this->language->get('heading_title'),
            $this->config->get('config_name')
        );

        if (
            !isset($this->request->server['HTTPS']) ||
            $this->request->server['HTTPS'] != 'on'
        ) {
            $data['base'] = HTTP_SERVER;
        } else {
            $data['base'] = HTTPS_SERVER;
        }

        $data['charset'] = $this->language->get('charset');
        $data['language'] = $this->language->get('code');
        $data['direction'] = $this->language->get('direction');
        $data['heading_title'] = sprintf(
            $this->language->get('heading_title'),
            $this->config->get('config_name')
        );
        $data['text_response'] = $this->language->get('text_response');
        $data['text_pending'] = $this->language->get('text_pending');
        $data['text_pending_wait'] = sprintf(
            $this->language->get('text_pending_wait'),
            HTTPS_SERVER . 'index.php?route=account/order'
        );
        $data['text_failure'] = $this->language->get('text_failure');
        $data['text_billno'] =
            '<font color="green">' .
            $this->session->data['order_id'] .
            '</font>';

        if ($this->request->get['route'] != 'checkout/guest_step_3') {
            $data['text_failure_wait'] = sprintf(
                $this->language->get('text_failure_wait'),
                HTTPS_SERVER . 'index.php?route=checkout/cart'
            );
        } else {
            $data['text_failure_wait'] = sprintf(
                $this->language->get('text_failure_wait'),
                HTTPS_SERVER . 'index.php?route=checkout/guest_step_2'
            );
        }

        $data['column_left'] = $this->load->controller('common/column_left');
        $data['column_right'] = $this->load->controller('common/column_right');
        $data['content_top'] = $this->load->controller('common/content_top');
        $data['content_bottom'] = $this->load->controller(
            'common/content_bottom'
        );
        $data['footer'] = $this->load->controller('common/footer');
        $data['header'] = $this->load->controller('common/header');
        $data['continue'] = HTTPS_SERVER . 'index.php?route=account/order';

        $this->response->setOutput(
            $this->load->view('payment/useepay_pending', $data)
        );
    }

    public function syncResult()
    {
        $response = $_POST;
        $response = json_decode($response["result"], true);
        $this->log('$response: ' . json_encode($response));
        $this->load->model('checkout/order');
        $this->load->model('payment/useepay');

        // 验签
        $sign = $this->createUnsign(
            $response,
            $this->config->get('useepay_sign_key')
        );
//        $order_map = $this->model_payment_useepay->getOrderByUseepayId(
//            $response['transactionId']
//        );
        $order_id = $response['transactionId'];
        if ($response['sign'] != $sign || empty($response['sign'])) {
            $message =
                "Sorry, payment is failed! The reason is:\n" .
                $response['errorMsg']; // 统一消息提示方式
            $this->model_checkout_order->addOrderHistory(
                $order_id,
                $this->config->get('useepay_failed_order_status_id'),
                $message .
                "\npayment order id is:" .
                $response['reference'],
                true
            );
            $json['message'] = $message;
            $json['result'] = 'error';
            $json['redirectUrl'] = $this->errorPageUrl();
        } else {
            if ('succeed' == $response['resultCode']) {
                $message = "Congratulations, payment is successful. \n";
                if (
                    empty($history_status) ||
                    $history_status !=
                    $this->config->get(
                        'useepay_succeed_order_status_id'
                    )
                ) {
                    $this->model_checkout_order->addOrderHistory(
                        $order_id,
                        $this->config->get(
                            'useepay_succeed_order_status_id'
                        ),
                        $message .
                        "\npayment order id is:" .
                        $response['reference'],
                        true
                    );
                }
                $json['message'] = $message;
                $json['result'] = 'success';
                $json['redirectUrl'] = $this->successPageUrl();
            } elseif (
                'failed' == $response['resultCode'] ||
                'closed' == $response['resultCode'] ||
                'cancelled' == $response['resultCode']
            ) {
                $message =
                    "Sorry, payment is failed! The reason is:\n" .
                    $response['errorMsg'];
                if (
                    empty($history_status) ||
                    $history_status !=
                    $this->config->get(
                        'useepay_failed_order_status_id'
                    )
                ) {
                    $this->model_checkout_order->addOrderHistory(
                        $order_id,
                        $this->config->get(
                            'useepay_failed_order_status_id'
                        ),
                        $message .
                        "\npayment order id is:" .
                        $response['reference'],
                        true
                    );
                }
                $json['message'] = $message;
                $json['result'] = 'error';
                $json['redirectUrl'] = $this->errorPageUrl();
            } else {
                $message =
                    "Sorry, payment is processing, please check again later. The reason is:\n" .
                    $response['errorMsg'];
                $this->model_checkout_order->addOrderHistory(
                    $order_id,
                    $this->config->get('useepay_order_status_id'),
                    $message .
                    "\npayment order id is:" .
                    $response['reference'],
                    true
                );
                $json['message'] = $message;
                $json['result'] = 'pending';
                $json['redirectUrl'] = $this->pendingPageUrl();
            }
        }
        $this->response->addHeader('Content-Type: application/json');
        $this->response->setOutput(json_encode($json));
    }

    private function errorPageUrl()
    {
        return 'index.php?route=payment/useepay/failure';
    }

    private function pendingPageUrl()
    {
        return 'index.php?route=payment/useepay/pending';
    }

    private function successPageUrl()
    {
        return $this->url->link('checkout/success', '', 'SSL');
    }

    private function isMobile($user_agent)
    {
        return preg_match(
                '/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',
                $user_agent
            ) ||
            preg_match(
                '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',
                substr($user_agent, 0, 4)
            );
    }

    private function getValidColorDepth($color_depth)
    {
        $valid_color_array = [48, 32, 24, 16, 15, 8, 4, 1];
        $integer_color_depth = intval($color_depth);

        $color_array = array();
        foreach ($valid_color_array as $valid_color) {
            if ($valid_color <= $integer_color_depth){
                array_push($color_array, $valid_color);
            }
        }

        if (count($color_array) > 0){
            return $color_array[0];
        } else {
            return 1;
        }
    }
}
