403Webshell
Server IP : 43.141.49.119  /  Your IP : 113.219.202.44
Web Server : Apache
System : Linux VM-8-5-opencloudos 6.6.34-9.oc9.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 19 19:35:45 CST 2024 x86_64
User : www ( 1000)
PHP Version : 8.1.27
Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /www/wwwroot/www.ucppt.com/wp-content/plugins/wpcom-member-pro/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /www/wwwroot/www.ucppt.com/wp-content/plugins/wpcom-member-pro/includes/orders.php
<?php
namespace WPCOM\Member;
use WPCOM\Themer\Session;
use WPCOM\Themer\Plugin\Utils;

defined( 'ABSPATH' ) || exit;

class Order {
    protected static $_order_table = 'wpcom_orders';
    protected static $_order_item_table = 'wpcom_order_items';
    function __construct() {
        global $wpdb;
        $wpdb->order_table = $wpdb->prefix . self::$_order_table;
        $wpdb->order_item_table = $wpdb->prefix . self::$_order_item_table;

        add_action('admin_menu', array($this, 'admin_menu'));
        add_action('wpcom_themer_maybe_updated', function(){ $this->init_database(); });

        add_action('wp_ajax_wpcom_setup_payment', array($this, 'setup_payment'));
        add_action('wp_ajax_nopriv_wpcom_setup_payment', array($this, 'setup_payment'));

        add_action('wp_ajax_wpcom_setup_order', array($this, 'setup_order'));
        add_action('wp_ajax_nopriv_wpcom_setup_order', array($this, 'setup_order'));

        add_action('wp_ajax_wpcom_update_order_qty', array($this, 'update_order_qty'));
        add_action('wp_ajax_nopriv_wpcom_update_order_qty', array($this, 'update_order_qty'));

        add_action('wp_ajax_wpcom_get_order_payment', array($this, 'get_order_payment'));
        add_action('wp_ajax_nopriv_wpcom_get_order_payment', array($this, 'get_order_payment'));

        add_action('wp_ajax_wpcom_checkout_payment', array($this, 'checkout_payment_page'));
        add_action('wp_ajax_nopriv_wpcom_checkout_payment', array($this, 'checkout_payment_page'));

        add_action('wp_ajax_wpcom_orders_export', array($this, 'orders_export'));

        add_action('wp_ajax_wpcom_checkout_return', array($this, 'checkout_return_page'));
        add_action('wp_ajax_nopriv_wpcom_checkout_return', array($this, 'checkout_return_page'));

        add_action('wpcom_order_payment_complete', array($this, 'send_order_notify'));

        add_filter('parent_file', array($this, 'parent_file_filter'));
        add_filter('submenu_file', array($this, 'submenu_file_filter'));
        add_filter('wpcom_member_order_metas', array($this, 'order_metas'), 1);
        add_filter('wpcom_account_tabs', array($this, 'account_tabs'), 20);
        add_filter('wpmx_localize_script', array($this, 'localize_script'));

        add_action('rest_api_init', array($this, 'for_rest_api'), 20 );
        add_action('wpcom_auto_close_unpaid_order', array($this, 'close_unpaid_order'));
    }

    public function admin_menu() {
        $options = $GLOBALS['wpmx_options'];
        add_submenu_page('wpcom-member-pro', '订单列表', '订单列表', 'manage_options', 'wpcom-orders', array(&$this, 'orders'), 10);
        add_submenu_page('wpcom-orders', '编辑订单', '编辑订单', 'manage_options', 'wpcom-edit-order', array(&$this, 'edit_order'), 10);

        if(isset($_GET['page']) && $_GET['page'] === 'wpcom-orders' && isset($_POST)){
            $search = isset($_POST['s']) ? sanitize_text_field(trim($_POST['s'])) : '';
            $args = [];
            if($search !== '') $args['s'] = $search;
            if(isset($_POST['filter_action']) && isset($_POST['order_type'])) $args['order_type'] = sanitize_text_field($_POST['order_type']);
            if(!empty($args)){
                wp_redirect(add_query_arg($args));
                exit;
            }
        }

        $days = isset($options['order_close']) && $options['order_close'] ? (int)$options['order_close'] : 3;
        $days = $days && $days > 0 ? $days : 3;
        if (is_numeric($days) && !wp_next_scheduled ( 'wpcom_auto_close_unpaid_order' )) wp_schedule_event(time(), 'hourly', 'wpcom_auto_close_unpaid_order');
    }

    function close_unpaid_order(){
        global $wpdb;
        $options = $GLOBALS['wpmx_options'];
        $days = isset($options['order_close']) && $options['order_close'] ? (int)$options['order_close'] : 3;
        $days = $days && $days > 0 ? $days : 3;
        if(is_numeric($days)){
            $time = current_time('U') - DAY_IN_SECONDS * $days;
            $time = date( 'Y-m-d H:i:s', $time );
            $orders = $this->get_orders(array(
                'status' => 'unpaid',
                'time' => $wpdb->prepare("< %s", $time),
                'per_page' => 100
            ));
            if($orders && is_array($orders) && count($orders) > 0){
                foreach($orders as $order){
                    $wpdb->update($wpdb->order_table, array('status' => 'cancel'), array('ID' => $order->ID));
                }
            }
        }else{
            wp_clear_scheduled_hook('wpcom_auto_close_unpaid_order');
        }
    }

    public function parent_file_filter($parent_file) {
        global $_wp_real_parent_file, $plugin_page, $_wp_menu_nopriv;
        if($plugin_page === 'wpcom-edit-order'){
            $_wp_real_parent_file[$plugin_page] = 'wpcom-member-pro';
            $_wp_menu_nopriv[$plugin_page] = 'wpcom-member-pro';
            if ($parent_file === 'wpcom-orders') $parent_file = 'wpcom-member-pro';
        }
        return $parent_file;
    }

    public function submenu_file_filter($submenu_file) {
        global $pagenow;
        $screen = get_current_screen();
        if ($pagenow == 'admin.php' && $screen->base == 'admin_page_wpcom-edit-order') {
            $submenu_file = 'wpcom-orders';
        }
        return $submenu_file;
    }

    function for_rest_api(){
        $this->register_api_routes();
    }

    public function register_api_routes(){
        register_rest_route(
            'wpcom/v1',
            '/payment-notify/(?P<api>[a-zA-Z0-9_-]+)/(?P<id>[\d]+)',
            [
                [
                    'methods'             => ['GET', 'POST'],
                    'callback'            => [$this, 'notify_set_data'],
                    'args'                => [
                        'api' => [
                            'description' => '支付接口',
                            'type'        => 'string',
                        ],
                        'id' => [
                            'description' => '订单号',
                            'type'        => 'integer',
                        ]
                    ],
                    'permission_callback' => '__return_true'
                ]
            ]
        );

        // 用于 paypal webhook 异步通知
        register_rest_route(
            'wpcom/v1',
            '/payment-notify/(?P<api>[a-zA-Z0-9_-]+)',
            [
                [
                    'methods'             => ['GET', 'POST'],
                    'callback'            => [$this, 'notify_set_data'],
                    'args'                => [
                        'api' => [
                            'description' => '支付接口',
                            'type'        => 'string',
                        ]
                    ],
                    'permission_callback' => '__return_true'
                ]
            ]
        );

        if(defined('WWA_VERSION')){
            register_rest_route('wpcom/v1', '/order',
                array(
                    array(
                        'methods'             => \WP_REST_Server::READABLE,
                        'callback'            => array($this, 'rest_order_status'),
                        'args'                => array(
                            'order_id' => array(
                                'required'          => true,
                                'type'              => 'integer',
                                'validate_callback' => 'rest_validate_request_arg',
                            ),
                            'nonce' => array(
                                'required'          => true,
                                'type'              => 'string',
                                'validate_callback' => 'rest_validate_request_arg',
                            )
                        ),
                        'permission_callback' => array( $this, 'pay_permission_check' )
                    ),
                    array(
                        'methods'             => \WP_REST_Server::CREATABLE,
                        'callback'            => array($this, 'rest_order'),
                        'args'                => array(
                            'items' => array(
                                'required'           => true,
                                'type'              => 'array',
                                'validate_callback' => 'rest_validate_request_arg',
                                'items' => array(
                                    'type' => 'object',
                                    'properties' => array(
                                        'title' => array(
                                            'type' => 'string'
                                        ),
                                        'number' => array(
                                            'type' => 'integer',
                                            'default' => 1
                                        ),
                                        'price' => array(
                                            'type' => 'string',
                                            'required' => true
                                        ),
                                        'type' => array(
                                            'type' => 'string',
                                            'required' => true
                                        ),
                                        'type_id' => array(
                                            'type' => 'string',
                                            'required' => true
                                        ),
                                        'url' => array(
                                            'type' => 'string'
                                        )
                                    )
                                )
                            ),
                            'total' => array(
                                'type' => 'string',
                                'required' => true
                            ),
                            // 用户微信小程序支付
                            'code' => array(
                                'type' => 'string',
                                'required' => true
                            ),
                            'sign' => array(
                                'type' => 'string'
                            ),
                            'timestamp' => array(
                                'type' => 'integer'
                            ),
                            'nonce' => array(
                                'required'          => true,
                                'type'              => 'string',
                                'validate_callback' => 'rest_validate_request_arg',
                            )
                        ),
                        'permission_callback' => array( $this, 'pay_permission_check' )
                    )
                )
            );
        }
    }

    function pay_permission_check($request){
        if(isset($request['nonce']) && wp_verify_nonce($request['nonce'], 'wpcom_payment_form')){
            return true;
        }else{
            return new \WP_Error( 'rest_pay_nonce_fail', '请求验证失败' );
        }
    }

    function rest_order($request){
        $type = isset($_SERVER['AppType']) ? $_SERVER['AppType'] : (isset($_SERVER['HTTP_APPTYPE']) ? $_SERVER['HTTP_APPTYPE'] : '');
        $gateways = apply_filters('wpcom_payment_gateways', []);
        $api = $type === 'swan' ? 'bdpay' : 'wxpay';
        if($api === 'wxpay' && isset($gateways['wxpay-xunhu'])){
            $api = 'wxpay-xunhu';
        }
        $_POST = array(
            'nonce' => $request['nonce'],
            'items' => stripslashes_deep($request['items']),
            'total' => $request['total'],
            'sign' => $request['sign'],
            'timestamp' => $request['timestamp'],
            'code' => $request['code'],
            'gateway' => $api
        );

        // 低版本组装数据进行兼容
        if(defined('WWA_VERSION') && version_compare(WWA_VERSION, '3.10.1', '<=')){
            $_POST['timestamp'] = current_time('timestamp', 1);
            $data = array(
                'result' => 0,
                'items' => $request['items'],
                'timestamp' => $_POST['timestamp'],
                'total' => $request['total']
            );
            $_POST['sign'] = self::make_sign($data);
        }
        $res = $this->setup_order(true);
        if($res && isset($res['result']) && $res['result'] == 0 && $res['order_id']){
            if (isset($gateways[$api])) {
                do_action("wpcom_payment_{$api}_receipt_page", $res['order_id']);
            }else{
                $res['result'] = -9;
                $res['msg'] = '支付接口异常';
            }
        }
        return rest_ensure_response( $res );
    }

    function rest_order_status($request){
        $res = [];
        $order_id = isset($request['order_id']) && $request['order_id'] ? $request['order_id'] : '';

        $order = $order_id ? Order::get_order($order_id) : '';
        $user_id = get_current_user_id();
        if ($order && isset($order->ID) && (!$order->user || ((int) $order->user === $user_id)) && $order->status === 'paid') {
            $res['status'] = 'paid';
        }
        wp_send_json($res);
    }

    public function notify_set_data($request){
        if($request['api']) {
            $order = $request['id'] && is_numeric($request['id']) ? self::get_order($request['id']) : null;
            $gateways = apply_filters('wpcom_payment_gateways', []);
            $api = $request['api'];

            if (isset($gateways[$api]) && $order && isset($order->ID)) {
                do_action("wpcom_payment_{$api}_check_response", $request['id']);
            } else if(isset($gateways[$api]) && $input = file_get_contents('php://input')){
                do_action("wpcom_payment_{$api}_check_response", json_decode($input, true));
            }
        }
    }

    public function orders() {
        if (!class_exists('Orders_List')) require_once WPCOM_MP_DIR . '/includes/orders-list.php';
        $list = new Orders_List();
        $list->prepare_items();?>
        <div class="wrap">
            <h1 class="wp-heading-inline">订单列表</h1>
            <a href="<?php echo admin_url('admin.php?page=wpcom-edit-order'); ?>" class="page-title-action">添加订单</a>
            <a href="javascript:;" class="page-title-action j-orders-export">导出</a>
            <hr class="wp-header-end">
            <?php $list->views();?>
            <form method="post">
                <?php
                $list->search_box('搜索订单', 'messages');
                $list->display();
                ?>
            </form>
            <?php $list->export();?>
        </div>
    <?php }

    public function edit_order() {
        $order_id = isset($_GET['id']) ? sanitize_text_field($_GET['id']) : 0;
        require_once WPCOM_ADMIN_PATH . 'includes/class-utils.php';
        Utils::panel_script();
        $error = $this->save_order();
        ?>
        <div class="wrap">
            <h1 class="wp-heading-inline">
                <?php echo $order_id ? '编辑' : '新增';?>订单
                <a class="page-title-action" href="<?php echo admin_url('admin.php?page=wpcom-orders') ?>"><span class="dashicons dashicons-arrow-left-alt" style="line-height: inherit;width:1em;height:1em;font-size:inherit;"></span> 返回</a>
            </h1>
                <?php if ($error === false || (isset($_GET['status']) && $_GET['status'] === 'success')) { ?>
                    <div id="message" class="notice notice-success">
                        <p><strong>订单已更新。</strong></p>
                        <p>
                            <a href="<?php echo admin_url('admin.php?page=wpcom-orders'); ?>" style="text-decoration: none;">
                                <span class="dashicons dashicons-arrow-left-alt" style="line-height: inherit;width:1em;height:1em;font-size:inherit;"></span> 返回"订单列表"页面
                            </a>
                        </p>
                    </div>
                <?php } else if ($error) { ?>
                    <div id="message" class="notice notice-error">
                        <p><strong>订单更新失败。</strong></p>
                        <p><?php echo $error; ?></p>
                    </div>
                <?php } ?>

                <form name="edit-order" id="edittag" method="post" action="" class="order-edit validate">
                    <input type="hidden" name="action" value="<?php echo  $order_id ? 'edit' : 'new';?>" />
                    <input type="hidden" name="order_id" value="<?php echo $order_id; ?>" />
                    <?php wp_nonce_field('order-edit', 'order-edit-nonce'); ?>
                    <table class="form-table" role="presentation">
                        <tr id="wpcom-plugin-panel" class="wpcom-term-wrap">
                            <td colspan="2">
                                <term-panel :ready="ready" />
                            </td>
                        </tr>
                    </table>
                    <input type="submit" class="button button-primary" value="提交" />
                </form>
                <div style="display: none;"><?php wp_editor('EDITOR', 'WPCOM-EDITOR', Utils::editor_settings(array('textarea_name' => 'EDITOR-NAME'))); ?></div>
                <script>
                    if (typeof _plugins_options === 'undefined') _plugins_options = [];
                    _plugins_options.push(<?php echo $this->get_order_metas(); ?>);
                </script>
        </div>
    <?php }

    function save_order() {
        global $wpdb;
        if (current_user_can('manage_options') && isset($_POST['order_id']) && $_POST['action'] && isset($_POST['wpcom_number'])) {
            $data = map_deep(stripslashes_deep($_POST), 'sanitize_text_field');
            $order_id = $data['order_id'];
            $number = $data['wpcom_number'];
            $user = $data['wpcom_user'];
            $price = $data['wpcom_price'];
            $status = $data['wpcom_status'];
            $item_id = $data['wpcom_item_id'];
            $item_title = $data['wpcom_item_title'];
            $item_price = $data['wpcom_item_price'];
            $item_type = $data['wpcom_item_type'];
            $item_type_id = $data['wpcom_item_type_id'];
            $item_data = stripslashes_deep($data['wpcom_item_data']);

            // nonce
            if (!wp_verify_nonce($data['order-edit-nonce'], 'order-edit')) {
                return '表单校验失败,请刷新页面重试';
            }

            // price
            if ($price === '' || !is_numeric($price)) {
                return '订单合计价格填写错误';
            }

            // user
            if ($user !== '' && !is_numeric($user)) {
                return '用户ID格式错误:用户ID应是数字';
            } else if (is_numeric($user) && $user > 0) {
                $_user = get_user_by('ID', $user);
                if (!$_user) {
                    return '用户ID错误:查询无此用户';
                }
            }

            // 订单号
            if ($number) {
                $order = $this->get_order_by_number($number);
                if ($order && $order->ID != $order_id) {
                    return '订单号已存在,请修改';
                }
            } else {
                $number = $this->init_order_number();
            }

            // items
            if (!$item_price || empty($item_price)) {
                return '请添加订单项目';
            } else {
                foreach ($item_price as $i => $p) {
                    if ($item_title[$i] === '') {
                        return '订单项目标题不能为空';
                    } else if ($p === '' || !is_numeric($p)) {
                        return '订单项目【' . $item_title[$i] . '】价格填写错误';
                    }
                }
            }

            $_order = array(
                'number' => $number,
                'price' => $price,
                'user' => $user,
                'status' => $status
            );
            if ($order_id && $order = Order::get_order($order_id)) {
                $res = $wpdb->update($wpdb->order_table, $_order, array('ID' => $order_id));
                $_status = $order->status;
                if ($res !== false) {
                    $next = 1;
                } else {
                    return '订单更新失败,请稍后再试!';
                }
            } else if ($order_id) {
                return '订单错误,请稍后再试!';
            } else if($data['action'] === 'new'){
                $_status = 'unpaid';
                $_order['time'] = current_time('mysql');
                $_order['payment_gateway'] = '';

                $format = array('%s', '%f', '%d', '%s', '%s', '%s');
                $wpdb->insert($wpdb->order_table, $_order, $format);
                $order_id = $wpdb->insert_id;
                if ($order_id) {
                    $next = 1;
                }
            }

            if (isset($next) && $next) {
                $items = $this->get_order_items($order_id);
                $ids = $items ? array_column($items, 'ID') : [];
                if ($item_id && is_array($item_id)) {
                    // 根据提交信息依次保存更新
                    foreach ($item_id as $x => $_id) {
                        $_item = array(
                            'price' => $item_price[$x],
                            'title' => $item_title[$x],
                            'type' => $item_type[$x],
                            'type_id' => $item_type_id[$x]
                        );
                        $_item['data'] = apply_filters('wpcom_update_order_item_data', $item_data[$x], $_item);
                        if ($_id && in_array($_id, $ids)) {
                            $res = $wpdb->update($wpdb->order_item_table, $_item, array('ID' => $_id));
                            if ($res === false) {
                                return '更新订单项目失败';
                            }
                        } else { // 无ID项目(有ID但是不在当前订单内)为新添加
                            $_item['order_id'] = $order_id;
                            $format = array('%f', '%s', '%s', '%s', '%s', '%d');
                            $wpdb->insert($wpdb->order_item_table, $_item, $format);
                            $_item_id = $wpdb->insert_id;
                            if (!$_item_id) {
                                return '添加订单项目失败';
                            }
                        }
                    }
                    // 根据查询到的已有项目,检查未使用的到,删除
                    if (!empty($ids)) {
                        foreach ($ids as $_id) {
                            if (!in_array($_id, $item_id)) {
                                $wpdb->delete($wpdb->order_item_table, array('ID' => $_id));
                            }
                        }
                    }
                } else {
                    return '更新订单出错,请稍后再试';
                }
            }

            // 订单被设置为已支付
            if(isset($_status) && $_status !== $_order['status'] && $_order['status'] === 'paid'){
                self::payment_complete($order_id, isset($_order['payment_gateway']) ? $_order['payment_gateway'] : $order->payment_gateway);
            }

            if(isset($_status) && $_status !== $_order['status']) do_action('wpcom_order_status_changed', $_order['status'], $_status, $order_id);

            if($data['action'] === 'new'){
                wp_redirect(admin_url("admin.php?page=wpcom-edit-order&id=$order_id&status=success"));
                exit;
            }
            return false;
        }
    }

    function orders_export(){
        global $wpdb;
        $res = ['result' => 0];
        if (current_user_can('manage_options')) {
            $nonce = isset($_REQUEST['wpcom_orders_export_nonce']) ? sanitize_text_field($_REQUEST['wpcom_orders_export_nonce']) : '';
            if(wp_verify_nonce($nonce, 'wpcom_orders_export')){
                $status = isset($_REQUEST['status']) && $_REQUEST['status'] ? sanitize_text_field($_REQUEST['status']) : '';
                $begin_time = isset($_REQUEST['begin_time']) && $_REQUEST['begin_time'] ? sanitize_text_field($_REQUEST['begin_time']) : '';
                $end_time = isset($_REQUEST['end_time']) && $_REQUEST['end_time'] ? sanitize_text_field($_REQUEST['end_time']) : current_time('Y-m-d');
                $ext = isset($_REQUEST['ext']) && $_REQUEST['ext'] ? sanitize_text_field($_REQUEST['ext']) : 'xlsv';
                $time = '';
                if($begin_time && $end_time) {
                    $time = $wpdb->prepare(">= %s AND `time` <= %s", $begin_time . ' 00:00:00', $end_time . ' 23:59:59');
                }else if($begin_time) {
                    $time = $wpdb->prepare(">= %s", $begin_time . ' 00:00:00');
                }else if($end_time) {
                    $time = $wpdb->prepare("<= %s", $end_time . ' 23:59:59');
                }
                $args = array(
                    'orderby' => 'time',
                    'per_page' => 0
                );
                if($status !== '') $args['status'] = $status;
                if($time !== '') $args['time'] = $time;
                $orders = $this->get_orders($args);
                if($orders && !empty($orders)){
                    if(isset($_GET['action'])){
                        $lists = [
                            ['订单号', '购买项目', '用户', '时间', '状态', '合计', '付款方式' ],
                        ];
                        foreach($orders as $order){
                            $items = Order::get_order_items($order->ID);
                            $_items = '';
                            if ($items) {
                                foreach ($items as $item) {
                                    if($_items !== '') $_items .= "\n";
                                    $_items .= $item->title;
                                    $_items .= ' - ¥'.$item->price;
                                }
                            }
                            $_user = '';
                            if(!$order->user) {
                                $_user = '-';
                            }else{
                                $user = get_user_by('ID', $order->user);
                                if($user && $user->ID){
                                    $_user = $ext === 'csv' ? $user->display_name : '<a href="'.esc_url(get_author_posts_url($user->ID)).'">'.$user->display_name.'</a>';
                                }else{
                                    $_user = '无效用户';
                                }
                            }

                            $payment_gateway = '';
                            if($order->payment_gateway){
                                $gateways = apply_filters('wpcom_payment_gateways', []);
                                if($gateways && isset($gateways[$order->payment_gateway])){
                                    $payment_gateway = $gateways[$order->payment_gateway]->title;
                                }else{
                                    $payment_gateway = $order->payment_gateway;
                                }
                            }

                            $lists[] = [
                                ($ext === 'csv' ? "\t" : '') . $order->number,
                                $_items,
                                $_user,
                                ($ext === 'csv' ? "\t" : '') . $order->time,
                                Order::get_order_status_display($order->status),
                                $order->price,
                                $payment_gateway
                            ];
                        }
                        if($ext === 'csv'){
                            $output = fopen('php://output', 'w') or die("Can't open php://output");
                            header("Content-type:application/csv");
                            header('Content-Disposition:attachment; filename="Orders.csv"');
                            foreach ($lists as $list) {
                                fputcsv($output, $list);
                            }
                            fclose($output) or die("can't close php://output");
                        }else{
                            require_once WPCOM_MP_DIR . 'sdk/xlsx.php';
                            $xlsx = \Shuchkin\SimpleXLSXGen::fromArray( $lists );
                            $xlsx->downloadAs('Orders.xlsx');
                        }
                        exit;
                    }
                }else{
                    $res['result'] = 1;
                    $res['msg'] = '未查询到符合条件的订单';
                }
            }else{
                $res['result'] = -2;
                $res['msg'] = '状态异常,建议刷新页面后重试!';
            }
        }else{
            $res['result'] = -1;
            $res['msg'] = '抱歉,当前用户没有操作权限';
        }
        wp_send_json($res);
    }

    function get_order_metas() {
        require_once WPCOM_ADMIN_PATH . 'includes/class-utils.php';
        $res = array('type' => 'taxonomy', 'tax' => 'orders');
        $order_id = isset($_GET['id']) ? sanitize_text_field($_GET['id']) : 0;
        $items = Order::get_order_items($order_id);
        if ($order_id && $order = Order::get_order($order_id)) {
            $res['options'] = array(
                'number' => $order->number,
                'price' => $order->price,
                'user' => $order->user,
                'status' => $order->status
            );
            $item_title = [];
            $item_price = [];
            $item_type = [];
            $item_type_id = [];
            $item_data = [];
            $item_id = [];
            if (is_array($items)) {
                foreach ($items as $i => $item) {
                    $item_id[$i] = $item->ID;
                    $item_title[$i] = $item->title;
                    $item_price[$i] = $item->price;
                    $item_type[$i] = $item->type;
                    $item_type_id[$i] = $item->type_id;
                    $item_data[$i] = $item->data;
                }
            }
            $res['options']['item_id'] = $item_id;
            $res['options']['item_title'] = $item_title;
            $res['options']['item_price'] = $item_price;
            $res['options']['item_type'] = $item_type;
            $res['options']['item_type_id'] = $item_type_id;
            $res['options']['item_data'] = $item_data;
        }else if(!isset($_GET['id'])){
            $data = map_deep(stripslashes_deep($_POST), 'sanitize_text_field');
            if(isset($data['wpcom_price'])){
                $res['options'] = array(
                    'number' => $data['wpcom_number'],
                    'price' => $data['wpcom_price'],
                    'user' => $data['wpcom_user'],
                    'status' => $data['wpcom_status'],
                    'item_id' => $data['wpcom_item_id'],
                    'item_title' => $data['wpcom_item_title'],
                    'item_price' => $data['wpcom_item_price'],
                    'item_type' => $data['wpcom_item_type'],
                    'item_type_id' => $data['wpcom_item_type_id'],
                    'item_data' => $data['wpcom_item_data']
                );
            }else{
                $res['options'] = array('number' => $this->init_order_number());
            }
        }
        $plugin = $GLOBALS['wpcom_mp']->info;
        $res['filters'] = apply_filters('wpcom_member_order_metas', []);
        $res['ver'] = $plugin['ver'];
        $res['plugin-id'] = $plugin['plugin_id'];
        $res['plugin-slug'] = $plugin['slug'];
        $res['framework_ver'] = Utils::framework_version($plugin['slug']);
        $res = apply_filters('wpcom_init_order_options', $res, $order);
        return wp_json_encode($res);
    }

    public function account_tabs($tabs){
        $tabs[20] = array(
            'slug' => 'orders-list',
            'title' => '我的订单',
            'icon' => 'order-circle'
        );
        $tabs[99991] = array(
            'slug' => 'order',
            'title' => '我的订单',
            'icon' => 'order-circle',
            'parent' => 'orders-list'
        );
        add_action('wpcom_account_tabs_orders-list', array($this, 'account_tabs_orders'));
        add_action('wpcom_account_tabs_order', array($this, 'account_tabs_order'));
        return $tabs;
    }

    public function account_tabs_orders(){
        global $wpcom_member;
        $user_id = get_current_user_id();
        if($user_id){
            $per_page = 10;
            $paged = get_query_var('pageid') ? get_query_var('pageid') : 1;
            $orders = $this->get_orders(array('user' => $user_id, 'per_page' => $per_page, 'paged' => $paged, 'orderby' => 'time'));
            $all = $this->get_orders(array('user' => $user_id));
            $total = $all && is_array($all) ? count($all) : 0;
            $pages = ceil($total / $per_page);
        }

        $args = array(
            'orders' => $orders,
            'pages' => $pages,
            'paged' => $paged
        );
        echo $wpcom_member->load_template('orders', $args);
    }

    public function account_tabs_order(){
        global $wp_query, $wpcom_member;
        $order_id = $wp_query->get('pageid');
        if($order_id) {
            $order = self::get_order($order_id);
            $user_id = get_current_user_id();
            if($order && $order->user != $user_id){ // 检查订单是否为当前用户的
                $order = null;
            }else{
                $items = self::get_order_items($order_id);
            }
        }
        $args = array(
            'order' => $order ??  null,
            'items' => $items ??  null
        );
        echo $wpcom_member->load_template('order', $args);
    }

    public function order_metas($metas) {
        $metas['orders'] = array(
            array(
                'n' => 'number',
                'l' => '订单号',
                'd' => '留空则会自动生成,无特殊情况不建议修改'
            ),
            array(
                'n' => 'user',
                'l' => '用户ID',
                'd' => '购买用户ID,无特殊情况不建议修改'
            ),
            array(
                'n' => 'items',
                'l' => '项目',
                't' => 'rp',
                'o' => array(
                    array(
                        'n' => 'item_id',
                        'l' => 'ID',
                        'hidden' => 1
                    ),
                    array(
                        'n' => 'item_title',
                        'l' => '标题'
                    ),
                    array(
                        'n' => 'item_price',
                        'l' => '价格',
                        'd' => '此处价格仅供参考,实际支付价格以<b>合计</b>选项价格为准'
                    ),
                    array(
                        'n' => 'item_type',
                        'l' => '类型',
                        'd' => '用于和具体业务关联,不建议修改,如果无关联业务可为空,如果需要新建订单不会填写的话建议创建一个同类订单然后编辑参考对应选项'
                    ),
                    array(
                        'n' => 'item_type_id',
                        'l' => '类型ID',
                        'd' => '用于和具体业务关联,不建议修改,如果无关联业务可为空,如果需要新建订单不会填写的话建议创建一个同类订单然后编辑参考对应选项'
                    ),
                    array(
                        'n' => 'item_data',
                        't' => 'ta',
                        'rows' => 2,
                        'l' => '其他',
                        'd' => '部分订单类型会用到,不建议修改,如果需要新建订单不会填写的话建议创建一个同类订单然后编辑参考对应选项'
                    ),
                )
            ),
            array(
                'n' => 'price',
                'l' => '合计',
                'd' => '订单实际付款费用,可修改'
            ),
            array(
                'n' => 'status',
                'l' => '状态',
                't' => 's',
                'o' => array(
                    '' => '请选择',
                    'unpaid' => '未付款',
                    'paid' => '已付款',
                    'refund' => '已退款',
                    'cancel' => '已取消'
                )
            )
        );
        return $metas;
    }

    public function setup_payment() {
        $res = array('nonce' => wp_create_nonce('wpcom_payment_form'));
        $res['gateways'] = apply_filters('wpcom_payment_gateways', []);
        $res['help_url'] = wpcom_mp_options('help_url');
        if(isset($_POST['order_type']) && $_POST['order_type'] === 'wallet'){
            unset($res['gateways']['wallet']);
        }else if($res['gateways'] && isset($res['gateways']['wallet'])) {
            $res['gateways']['wallet']->balance = $res['gateways']['wallet']->get_balance();
        }
        if(array_key_exists('points', $res['gateways'])) unset($res['gateways']['points']); // 订单支付方式排除积分
        wp_send_json($res);
    }

    public function setup_order($return = false) {
        global $wpdb;
        $res = array('result' => 0);
        $nonce = isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '';
        $items = isset($_POST['items']) ? map_deep( stripslashes_deep($_POST['items']), 'sanitize_text_field' ) : [];
        $total = isset($_POST['total']) ? sanitize_text_field($_POST['total']) : 0;
        $order_id = isset($_POST['order_id']) ? sanitize_text_field($_POST['order_id']) : 0;
        $gateway = isset($_POST['gateway']) ? sanitize_text_field($_POST['gateway']) : '';
        $points = isset($_POST['points']) && $_POST['points'] == 1 ? 1 : 0;
        $gateway = $points ? 'points' : $gateway;

        $gateways = apply_filters('wpcom_payment_gateways', []);

        // 保留data参数的HTML代码,系统sanitize_text_field会过滤
        if($items && !empty($items)){
            foreach($items as $i => $_item){
                if(isset($_item['data']) && $_item['data'] && isset($_POST['items'][$i]) && isset($_POST['items'][$i]['data'])){
                    $data = stripslashes_deep($_POST['items'][$i]['data']);
                    if(is_array($data) && !empty($data)){
                        foreach($data as $k => $v){
                            $data[$k] = wp_kses_post($v);
                        }
                    }else{
                        $data = wp_kses_post($data);
                    }
                    $items[$i]['data'] = $data;
                }
            }
        }

        if ($points == 0 && (!$gateway || !isset($gateways[$gateway]) || $gateway === 'points')) {
            $res['result'] = -5;
            $res['msg'] = '支付网关错误,请检查选择的付款接口';
            if($return) return $res;
            wp_send_json($res);
        }

        if (!wp_verify_nonce($nonce, 'wpcom_payment_form')) {
            $res['result'] = -6;
            $res['msg'] = '支付请求校验失败,请稍后再试';
            if($return) return $res;
            wp_send_json($res);
        }else if(!self::check_sign($_POST)){
            $res['result'] = -7;
            $res['msg'] = '订单信息校验失败,请检查订单信息';
            if($return) return $res;
            wp_send_json($res);
        }

        // 支付已有订单
        if($order_id && $order = self::get_order($order_id)){
            if($order->user && get_current_user_id() == $order->user){
                $update = $points ? [] : array('payment_gateway' => $gateway); // 积分支付不更新支付方式,只能还是积分支付
                if($order->price != $total && $total == self::get_total_price($items, $points)){// 价格不一样,数量变化
                    $update['price'] = $total;
                    $_items = $this->get_order_items($order_id);
                    if (is_array($_items) && !empty($_items)) {
                        foreach ($_items as $_item) {
                            foreach($items as $_item2){
                                if($_item2 && $_item2['ID'] == $_item->ID && isset($_item2['data'])){
                                    $item_update = [
                                        'data' => wp_json_encode($_item2['data'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
                                    ];
                                    $wpdb->update($wpdb->order_item_table, $item_update, array('ID' => $_item->ID));
                                    break;
                                }
                            }
                        }
                    }
                }else if($order->price != $total){ //价格不一样,重新计算也不一样
                    $res['result'] = -7;
                    $res['msg'] = '订单校验失败,请重试';
                    if($return) return $res;
                    wp_send_json($res);
                }

                // 检查库存
                $items2 = $this->get_order_items($order_id);
                $stock_check = true;
                foreach($items2 as $item){
                    if(! apply_filters('wpcom_' . $item->type . '_stock_check', true, (array)$item)){
                        $stock_check = false;
                        break;
                    }
                }
                if(!$stock_check){
                    $res['result'] = -10;
                    $res['msg'] = '库存不足,无法购买';
                }else{
                    $res = $wpdb->update($wpdb->order_table, $update, array('ID' => $order->ID));
                    $res = $points ? $this->process_points_payment($order_id) : $this->process_payment($order_id, $gateway);
                    if($return) $res['order_id'] = $order_id;
                    $res = apply_filters('wpcom_setup_exists_order', $res, $order, $items);
                }
            }else{
                $res['result'] = -7;
                $res['msg'] = '订单校验失败,请重试';
            }
            if($return) return $res;
            wp_send_json($res);
        }

        $_total = 0;
        $stock_check = true;
        foreach ($items as $item) {
            $price = number_format($item['price'], $points ? 0 : 2, '.', '');
            if(is_numeric($item['price']) && is_numeric($price)){
                $_total += (isset($item['number']) && $item['number'] ? $item['number'] : 1) * $price;
            }else{
                $price = new \WP_Error('item_price_error', '商品价格获取错误');
                break;
            }
            if(!apply_filters('wpcom_' . $item['type'] . '_stock_check', true, $item)){
                $stock_check = false;
                break;
            }
        }

        if(!$stock_check){
            $res['result'] = -10;
            $res['msg'] = '库存不足,无法购买';
        }else if (is_wp_error($price)) {
            $res['result'] = -2;
            $res['msg'] = $price->get_error_message();
        } else if ((float)$_total !== (float)$total) {
            $res['result'] = -3;
            $res['msg'] = '订单价格校验失败,请重试';
        } else if ($_total === 0 || $_total === 0.00 || $total === '0' || $total === '0.00') {
            $res['result'] = -5;
            $res['msg'] = '当前商品价格暂不支持下单';
        } else {
            /**
             * 订单价格,特殊业务场景需要对价格进行调整时备用
             * @param number $total 合计价格
             * @param array $items  购买项目
             *
             * @return number 返回价格
             */
            $total = apply_filters('wpcom_order_price', $total, $items);

            if (is_numeric($total)) {
                // 创建订单
                $order_id = $this->insert_order($total, $items, $gateway);
                if ($order_id) { // 订单创建成功,调用支付接口支付
                    $res = $points ? $this->process_points_payment($order_id) : $this->process_payment($order_id, $gateway);
                    if($return) $res['order_id'] = $order_id;
                } else {
                    $res['result'] = -1;
                    $res['msg'] = '创建订单失败,请稍后再试';
                }
            } else {
                $res['result'] = -4;
                $res['msg'] = '价格类型错误,请重试';
            }
        }

        if($return) return $res;
        wp_send_json($res);
    }

    function update_order_qty(){
        $res = array('result' => 0);
        $nonce = isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '';
        $items = isset($_POST['items']) ? map_deep( stripslashes_deep($_POST['items']), 'sanitize_text_field' ) : [];
        $order_id = isset($_POST['order_id']) ? sanitize_text_field($_POST['order_id']) : 0;
        $points = isset($_POST['points']) && $_POST['points'] == 1 ? 1 : 0;

        // 保留data参数的HTML代码,系统sanitize_text_field会过滤
        if($items && !empty($items)){
            foreach($items as $i => $_item){
                if(isset($_item['data']) && $_item['data'] && isset($_POST['items'][$i]) && isset($_POST['items'][$i]['data'])){
                    $data = stripslashes_deep($_POST['items'][$i]['data']);
                    if(is_array($data) && !empty($data)){
                        foreach($data as $k => $v){
                            $data[$k] = wp_kses_post($v);
                        }
                    }else{
                        $data = wp_kses_post($data);
                    }
                    $items[$i]['data'] = $data;

                }
                if(isset($_item['update_number'])){
                    unset($_POST['items'][$i]['update_number']);
                }
            }
        }
        if (!wp_verify_nonce($nonce, 'wpcom_payment_form')) {
            $res['result'] = -6;
            $res['msg'] = '当前请求校验失败,请稍后再试';
            wp_send_json($res);
        }else if(!self::check_sign($_POST)){
            $res['result'] = -7;
            $res['msg'] = '订单信息校验失败,请检查订单信息';
            wp_send_json($res);
        }else if($items){
            foreach($items as $i => $item){
                if(isset($item['update_number']) && $item['update_number']){
                    $items[$i]['number'] = $item['update_number'];
                    unset($items[$i]['update_number']);
                    if(isset($item['data']) && is_array($item['data'])){
                        $items[$i]['data']['quantity'] = $item['update_number'];
                    }else{
                        $items[$i]['data'] = ['quantity' => $item['update_number']];
                    }
                    $stock_check = apply_filters('wpcom_' . $item['type'] . '_stock_check', true, $item);
                    if(!$stock_check){
                        $res['result'] = -10;
                        $res['msg'] = '库存不足,无法购买';
                        wp_send_json($res);
                    }
                }
            }
            $res['items'] = $items;
            $res['total'] = self::get_total_price($items, $points);
            $res['points'] = $points;
            if($order_id) $res['order_id'] = $order_id;
            $res = self::setup_order_data($res);
        }

        wp_send_json($res);
    }

    public function get_order_payment(){
        $res = array('result' => 0);
        $user = wp_get_current_user();
        if (isset($user->ID) && $user->ID) {
            $order_id = isset($_POST['order_id']) ? sanitize_text_field($_POST['order_id']) : 0;
            if ($order_id && $order = self::get_order($order_id)) {
                if($order->user != $user->ID){
                    $res['result'] = -2;
                }else{
                    $points = $order->payment_gateway === 'points' ? 1 : 0;
                    $items = Order::get_order_items($order_id);
                    foreach($items as $i => $item){
                        $items[$i] = (array)$item;
                        if(isset($item->type) && $item->type){
                            $set_number = apply_filters('wpcom_order_'.$item->type.'_set_number', false);
                            if($set_number) {
                                $items[$i]['set_number'] = 1;
                                $data = $item->data ? json_decode($item->data, true) : '';
                                if($data && isset($data['quantity']) && $data['quantity']){
                                    $items[$i]['number'] = $data['quantity'];
                                }
                                $items[$i]['price'] = number_format($items[$i]['price'], $points ? 0 : 2, '.', '');
                                $items[$i]['data'] = $data;
                            }
                        }
                    }
                    $res['total'] = number_format($order->price, $points ? 0 : 2, '.', '');
                    $res['items'] = $items;
                    $res['order_id'] = $order->ID;
                    if($points) $res['points'] = 1;
                    $res = Order::setup_order_data($res);
                }
            }
        }else{
            $res['result'] = -1;
        }
        wp_send_json($res);
    }

    public static function get_total_price($items, $points = 0){
        $total = 0;
        if(is_array($items) && !empty($items)){
            foreach($items as $item){
                $total += (isset($item['number']) && $item['number'] ? (int)$item['number'] : 1) * number_format($item['price'], $points ? 0 : 2, '.', '');
            }
        }
        return number_format($total, $points ? 0 : 2, '.', '');
    }

    function insert_order($total, $items, $gateway = '') {
        global $wpdb;
        // 检查是否已经有同样的订单,避免重复创建订单
        $order = $this->order_exists($total, $items);
        $user_id = get_current_user_id();

        if ($order) {
            $_order = array(
                'number' => $this->init_order_number($order->number),
                'user' => $user_id,
                'time' => current_time('mysql'),
                'status' => 'unpaid',
                'payment_gateway' => $gateway
            );
            $res = $wpdb->update($wpdb->order_table, $_order, array('ID' => $order->ID));
            if ($res) return $order->ID;
        } else {
            $order = array(
                'number' => $this->init_order_number(),
                'price' => $total,
                'user' => $user_id,
                'time' => current_time('mysql'),
                'status' => 'unpaid',
                'payment_gateway' => $gateway
            );

            $format = array('%s', '%f', '%d', '%s', '%s', '%s');
            $wpdb->insert($wpdb->order_table, $order, $format);
            $order_id = $wpdb->insert_id;

            $order_inserted = true;

            // 订单创建成功,然后添加订单购买项目数据
            if ($order_id) {
                if(!$user_id && isset($GLOBALS['wpmx_options']['anonymous_order']) && $GLOBALS['wpmx_options']['anonymous_order'] == '1'){
                    $this->setup_anonymous_order($order_id);
                }
                foreach ($items as $item) {
                    $data = isset($item['data']) && $item['data'] ? $item['data'] : '';
                    $data = wp_json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
                    $_item = array(
                        'order_id' => $order_id,
                        'price' => number_format($item['price'], 2, '.', ''),
                        'title' => isset($item['title']) ? $item['title'] : '',
                        'type' => isset($item['type']) ? $item['type'] : '',
                        'type_id' => isset($item['type_id']) ? $item['type_id'] : '',
                        'data' => $data
                    );
                    $format = array('%d', '%f', '%s', '%s', '%s', '%s');
                    $wpdb->insert($wpdb->order_item_table, $_item, $format);
                    $item_id = $wpdb->insert_id;
                    if (!$item_id) {
                        $order_inserted = false;
                        break;
                    }
                }
            } else {
                $order_inserted = false;
            }

            do_action('wpcom_after_insert_order', $order_id, $order_inserted);

            if ($order_inserted) return $order_id;
        }
    }

    public static function delete_order($id){
        global $wpdb;
        if($id && is_numeric($id)){
            $order = self::get_order($id);
            if($wpdb->delete($wpdb->order_table, array('ID' => $id))){
                do_action('wpcom_order_deleted', $id, $order);
                $wpdb->delete($wpdb->order_item_table, array('order_id' => $id));
            }
        }
    }

    public static function update_order_number($order_id){
        $order = self::get_order( $order_id );
        if($order && $order->status && $order->status !== 'paid'){
            global $wpdb;
            $number = self::init_order_number();
            return $wpdb->update($wpdb->order_table, array('number' => $number), array('ID' => $order_id));
        }
    }

    private static function init_order_number($number='') {
        if($number && preg_match('/^'.wp_date('Ymd', current_time('timestamp', 1)).'/', $number)) return $number;
        $num = wp_date('YmdHis', current_time('timestamp', 1));
        $microtime = explode('.', microtime(true));
        $num = $num . $microtime[1];
        $num = $num . rand(0, 9); // 添加1个随机数字

        // 检查重复
        $order = self::get_order_by_number($num);
        if ($order) return self::init_order_number();

        return $num;
    }

    static function get_order_by_number($num) {
        global $wpdb;
        $order_table = $wpdb->order_table;
        $order = $wpdb->get_row($wpdb->prepare("SELECT * FROM `$order_table` WHERE number = %s", $num));
        if ($order && $order->ID) return $order;
    }

    /**
     * 执行付款操作,调用支付接口
     */
    function process_payment($order_id, $gateway) {
        $res = array('result' => 0);
        $gateways = apply_filters('wpcom_payment_gateways', []);
        if ($gateway && $gateway !== 'points' && isset($gateways[$gateway]) && $gateways[$gateway]->id) {
            $payment = $gateways[$gateway]->process_payment($order_id);
            if ($payment['result'] === 'success' && $payment['redirect']) {
                $res['redirect'] = $payment['redirect'];
                if (isset($payment['height'])) $res['height'] = $payment['height'];
                if (isset($payment['modal-size'])) $res['modal-size'] = $payment['modal-size'];
                $res['color'] = $gateways[$gateway]->color;

                // 新窗口打开,需要补充弹框提示按钮链接
                if (!$gateways[$gateway]->modal) {
                    $res['return_url'] = isset($payment['return_url']) ? $payment['return_url'] : self::get_checkout_return_url($order_id, $gateway);
                    $res['help_url'] = wpcom_mp_options('help_url');
                }
            } else {
                if(isset($payment['msg'])) $res['msg'] = $payment['msg'];
                $res['result'] = -5;
            }
        } else {
            $res['result'] = -5;
        }

        if ($res['result'] !== 0 && !isset($res['msg'])) {
            $res['msg'] = '支付网关错误,请检查选择的付款接口';
        }

        return $res;
    }

    /**
     * 执行积分付款操作,调用积分支付
     */
    function process_points_payment($order_id){
        $res = array('result' => 0);
        $gateways = apply_filters('wpcom_payment_gateways', []);
        if(isset($gateways['points'])){
            $res += $gateways['points']->process_payment($order_id);
            $res['color'] = $gateways['points']->color;
        }else {
            $res['result'] = -5;
        }

        if ($res['result'] !== 0 && !isset($res['msg'])) {
            $res['msg'] = '支付网关错误,请检查选择的付款接口';
        }

        return $res;
    }

    public static function get_orders($args) {
        global $wpdb;
        $order_table = $wpdb->order_table;
        $where = '';
        if($args && isset($args['user'])) $where .= ($where ? ' AND' : ' WHERE') . $wpdb->prepare(" `user` = %s", $args['user']);
        if($args && isset($args['status'])) $where .= ($where ? ' AND' : ' WHERE') . $wpdb->prepare(" `status` = %s", $args['status']);
        if($args && isset($args['time'])) $where .= ($where ? ' AND' : ' WHERE') . " `time` " . $args['time'];
        $per_page = $args && isset($args['per_page']) ? (int)$args['per_page'] : 0;
        $limit = '';
        if($per_page && $per_page > 0){
            $paged = $args && isset($args['paged']) ? $args['paged'] : 1;
            $limit = $wpdb->prepare(" LIMIT %d, %d", ($paged-1) * $per_page, $per_page);
        }
        $_orderby = $args && isset($args['orderby']) ? esc_sql($args['orderby']) : '';
        $orderby = '';
        if($_orderby !== ''){
            $order = $args && isset($args['order']) ? esc_sql($args['order']) : ' DESC';
            $orderby = " ORDER BY $_orderby $order";
        }
        $orders = $wpdb->get_results("SELECT * FROM $order_table" . $where . $orderby . $limit);
        if($orders && !is_wp_error($orders)) return $orders;
    }

    public static function get_order($id, $by = 'ID') {
        global $wpdb;
        $order_table = $wpdb->order_table;
        $by = esc_sql($by);
        $order = $wpdb->get_row($wpdb->prepare("SELECT * FROM `$order_table` WHERE `$by` = %s", $id));
        if ($order) return $order;
    }

    public static function get_order_items($id) {
        global $wpdb;
        if (!$id) return false;
        $items_table = $wpdb->order_item_table;
        $items = $wpdb->get_results($wpdb->prepare("SELECT * FROM `$items_table` WHERE order_id = %s", $id));
        if (is_array($items) && count($items) > 0) return $items;
    }

    public static function get_item_sales($type, $type_id){
        global $wpdb;
        if($type && $type_id){
            $item_table = $wpdb->order_item_table;
            $order_table = $wpdb->order_table;
            $count = $wpdb->get_var($wpdb->prepare("SELECT count(O.ID) FROM (SELECT order_id FROM `$item_table` WHERE `type` = %s AND `type_id` = %s) I LEFT JOIN `$order_table` O ON I.order_id=O.id WHERE O.status='paid'", $type, $type_id));
            if ($count) return $count;
        }
        return 0;
    }

    public static function is_item_paid($type, $type_id, $user_id=''){
        global $wpdb;
        $res = false;
        if($type && $type_id){
            $user_id = $user_id ?: get_current_user_id();
            $item_table = $wpdb->order_item_table;
            $order_table = $wpdb->order_table;
            if($user_id){
                $res = $wpdb->get_var($wpdb->prepare("SELECT O.ID FROM $item_table I RIGHT JOIN $order_table O ON I.order_id=O.ID WHERE O.user = %s AND I.type = %s AND I.type_id = %s AND O.status='paid'", $user_id, $type, $type_id));
                if($res) return $res;
            }else{ // 匿名订单
                $orders = maybe_unserialize(Session::get('anonymous_orders'));
                $orders = $orders ?: [];
                if(is_array($orders) && !empty($orders)){
                    $orders = array_map('esc_sql', $orders);
                    $orders = array_filter($orders); // 过滤空值
                    $_orders = "'" . implode("','", $orders) . "'";
                    $res = $wpdb->get_var($wpdb->prepare("SELECT O.ID FROM $item_table I RIGHT JOIN $order_table O ON I.order_id=O.ID WHERE O.ID in ($_orders) AND I.type = %s AND I.type_id = %s AND O.status='paid'", $type, $type_id));
                    if($res) return $res;
                }
            }
        }
        return apply_filters('wpcom_is_item_paid', $res, $type, $type_id, $user_id);
    }

    public static function is_admin_free($post_id = 0){
        global $wpmx_options;
        if($wpmx_options && isset($wpmx_options['admin_free']) && $wpmx_options['admin_free'] == 1){
            if(current_user_can('manage_options')){
                return true;
            }else if($post_id && $user_id = get_current_user_id()){
                $author = get_post_field('post_author', $post_id);
                return $user_id == $author;
            }
        }
        return false;
    }

    public static function order_url($order_id){
        $permalink_structure = get_option('permalink_structure');
        $page = wpcom_subpage_url('order');
        if ($permalink_structure) { // 默认链接规则
            $url = trailingslashit($page) . $order_id;
        }else{
            $url =  add_query_arg('pageid', $order_id, $page);
        }
        return $url;
    }

    public static function get_order_status_display($status){
        $_status = array(
            'paid' => '已付款',
            'unpaid' => '未付款',
            'refund' => '已退款',
            'cancel' => '已取消'
        );
        if(isset($_status[$status])) return $_status[$status];
    }

    public static function payment_complete($order_id, $gateway){
        global $wpdb;
        $order_table = $wpdb->order_table;
        $res = $wpdb->update($order_table, array('status' => 'paid', 'time' => current_time('mysql'), 'payment_gateway' => $gateway), array('ID' => $order_id));
        if($res) {
            $order = self::get_order($order_id);
            // 订单支付完成后的常规操作,比如通知消息
            do_action('wpcom_order_payment_complete', $order);
            // 订单完成后对于具体某个产品类型的操作
            $items = self::get_order_items($order_id);
            if($items){
                foreach($items as $item){
                    do_action("wpcom_{$item->type}_payment_complete", $item, $order);
                }
            }
        }
        return $res;
    }

    /**
     * 订单重复检查,只检查24小时内的重复订单,不翻旧账,避免检查的数据过大影响性能
     */
    private function order_exists($total, $items) {
        global $wpdb;
        if ($total && is_array($items) && count($items) > 0) {
            $user = get_current_user_id();
            $time = wp_date('Y-m-d H:i:s', current_time('timestamp', 1) - 24 * 60 * 60);
            if($user){
                $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM `$wpdb->order_table` WHERE status = 'unpaid' AND user = %s AND price = %s AND time > %s", $user, $total, $time));
            }else{ // 匿名用户
                $orders = maybe_unserialize(Session::get('anonymous_orders'));
                $orders = $orders ?: [];
                if(is_array($orders) && !empty($orders)){
                    $orders = array_map('esc_sql', $orders);
                    $orders = array_filter($orders); // 过滤空值
                    $_orders = "'" . implode("','", $orders) . "'";
                    $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM `$wpdb->order_table` WHERE status = 'unpaid' AND ID in ($_orders) AND price = %s AND time > %s", $total, $time));
                }else{
                    return false;
                }
            }
            if (is_array($results) && count($results) > 0) {
                $_order = null;
                foreach ($results as $order) {
                    $order_items = self::get_order_items($order->ID);
                    $check = false;
                    if ($order_items && count($order_items) === count($items)) {
                        $check = true;
                        foreach ($order_items as $item) {
                            $found = false;
                            foreach ($items as $i => $item2) {
                                if (
                                    isset($item2['price']) && $item2['title'] === $item->title && $item2['price'] == $item->price &&
                                    $item2['type'] === $item->type && $item2['type_id'] === $item->type_id
                                ) {
                                    $data = isset($item2['data']) && $item2['data'] ? $item2['data'] : '';
                                    if ($data) $data = wp_json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

                                    if ($data === $item->data) {
                                        $found = true;
                                        unset($items[$i]);
                                        break;
                                    }
                                }
                            }
                            if (!$found) {
                                $check = false;
                                break;
                            }
                        }
                    }

                    if ($check) {
                        $order->items = $order_items;
                        $_order = $order;
                    }
                }
                return $_order;
            }
        }
    }

    public static function get_checkout_payment_url($order_id) {
        return $order_id ? admin_url('admin-ajax.php?action=wpcom_checkout_payment&order_id=' . $order_id) : false;
    }

    public static function get_checkout_return_url($order_id, $api = '') {
        return $order_id ? admin_url('admin-ajax.php?action=wpcom_checkout_return&order_id=' . $order_id . ($api ? '&api='.$api : '')) : false;
    }

    public static function get_checkout_notify_url($order_id, $api) {
        return get_rest_url(null, 'wpcom/v1/payment-notify/'.$api.'/'.$order_id);
    }

    public function send_order_notify($order){
        // 通知用户
        if($order && $order->user && $order->status === 'paid'){
            $title = '订单支付成功';
            $content = '亲爱的用户:你好!<br>';
            $content .= '你的订单「<b>'.$order->number.'</b>」已完成支付!详情<a href="' . esc_url(self::order_url($order->ID)) . '" target="_blank">点击此处查看订单</a>。';
            do_action('wpcom_add_notification', $order->user, $title, $content);

            if(wpcom_mp_options('order_notify_user')){
                $user = get_user_by('ID', $order->user);
                if($user->user_email && !wpcom_is_empty_mail($user->user_email)){
                    $headers = array('Content-Type: text/html; charset=UTF-8');
                    if ( is_multisite() ) {
                        $site_name = get_network()->site_name;
                    } else {
                        $site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
                    }
                    wp_mail( $user->user_email, wp_specialchars_decode( '【' . $site_name . '】' . $title ), $content, $headers );
                }
            }
        }

        // 通知管理员
        if($order && $order->status === 'paid' && wpcom_mp_options('order_notify_admin') && $admin_email = get_bloginfo ('admin_email')){
            $headers = array('Content-Type: text/html; charset=UTF-8');
            if ( is_multisite() ) {
                $site_name = get_network()->site_name;
            } else {
                $site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
            }
            $title = '订单支付成功';
            $content = '亲爱的管理员:你好!<br>';
            $content .= '你的网站有新订单「<b>'.$order->number.'</b>」已完成支付!详情<a href="' . esc_url(admin_url('admin.php?page=wpcom-orders')) . '" target="_blank">点击此处查看订单</a>。';
            wp_mail( $admin_email, wp_specialchars_decode( '【' . $site_name . '】' . $title ), $content, $headers );
        }
    }

    public function setup_anonymous_order($order_id){
        if($order_id){
            $orders = maybe_unserialize(Session::get('anonymous_orders'));
            $orders = $orders ?: [];
            if(!in_array($order_id, $orders)) {
                $orders[] = $order_id;
                Session::set('anonymous_orders', maybe_serialize($orders), 2592000);
            }
        }
    }

    public function checkout_payment_page() {
        $order_id = isset($_GET['order_id']) && $_GET['order_id'] ? sanitize_text_field($_GET['order_id']) : 0;
        if(!$order_id && isset($_POST['total']) && isset($_POST['gateway']) && isset($_POST['nonce'])){
            $res = $this->setup_order(1);
            $gateways = apply_filters('wpcom_payment_gateways', []);
            $api = sanitize_text_field($_POST['gateway']);
            if($res && isset($res['order_id']) && $res['order_id'] && isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER']){
                Session::set('_order_referer_' . $res['order_id'], urlencode($_SERVER['HTTP_REFERER']));
            }
            if ($api && (isset($gateways[$api]) || $api === 'points')) do_action("wpcom_payment_{$api}_submit_page", $res, map_deep( $_POST, 'sanitize_text_field' ));
            wp_die();
        }else{
            $checked = true;
            if (is_numeric($order_id)) {
                $order = self::get_order($order_id);
                if ($order && isset($order->ID)) {
                    $api = $order && $order->payment_gateway ? $order->payment_gateway : '';
                    $gateways = apply_filters('wpcom_payment_gateways', []);
                    if ($api && (isset($gateways[$api]) || $api === 'points')) do_action("wpcom_payment_{$api}_receipt_page", $order_id);
                    wp_die();
                } else {
                    $checked = false;
                }
            } else {
                $checked = false;
            }

            if ($checked === false) {
                $msg = '参数错误,请传入正确的订单号';
                if (function_exists('_default_wp_die_handler')) {
                    _default_wp_die_handler($msg);
                } else {
                    wp_die($msg);
                }
            }
        }
    }

    public function checkout_return_page() {
        // 兼容易支付参数&转义的问题
        if(isset($_GET['amp;api']) && ($_GET['amp;api'] === 'alipay-yzf' || $_GET['amp;api'] === 'wxpay-yzf')){
            $_GET['api'] = $_GET['amp;api'];
            $_GET['order_id'] = $_GET['amp;order_id'];
        }
        $order_id = isset($_GET['order_id']) && $_GET['order_id'] ? sanitize_text_field($_GET['order_id']) : 0;
        if (is_numeric($order_id)) {
            $order = self::get_order($order_id);
            $user_id = get_current_user_id();
            if ($order && isset($order->ID) && (!$order->user || ((int) $order->user === $user_id))) {
                $api = isset($_GET['api']) && $_GET['api'] ? sanitize_text_field($_GET['api']) : ($order && $order->payment_gateway ? $order->payment_gateway : '');
                $gateways = apply_filters('wpcom_payment_gateways', []);
                if ($api && isset($gateways[$api])) do_action("wpcom_payment_{$api}_return_page", $order_id);
                wp_die();
            }
        }
        wp_die('fail');
    }

    public static function setup_order_data($data){
        if($data && is_array($data)){
            $data['timestamp'] = current_time('timestamp', 1);
            $data['user_id'] = get_current_user_id();
            $data['sign'] = self::make_sign($data);
        }
        return $data;
    }

    function localize_script($script){
        if(isset($GLOBALS['wpmx_options']['anonymous_order']) && $GLOBALS['wpmx_options']['anonymous_order'] == '1'){
            $script['anonymous_order'] = true;
        }
        return $script;
    }

    public static function make_sign($data){
        if($data){
            $key = wp_salt('secure_auth');
            ksort($data);
            $string = '';
            foreach ($data as $k => $v){
                if($k === 'key' || is_null($v) || $v === ''){continue;}
                $v = self::loop_to_string($v);
                $string .= $k . "=" . $v . "&";
            }
            $string = trim($string, "&");
            //签名步骤二:在string后加入KEY
            $string = $string . '&key=' . $key;
            //签名步骤三:MD5加密或者HMAC-SHA256
            $result = hash_hmac('sha256', $string, $key);
            //签名步骤四:所有字符转为小写
            $result = strtolower($result);
            return $result;
        }
    }

    public static function check_sign($data){
        if($data && isset($data['sign']) && $data['sign']){
            if(current_time('timestamp', 1) - $data['timestamp'] > 24*60*60) return false; // 24小时超时
            $sign = $data['sign'];
            $key = wp_salt('secure_auth');
            $_data = array(
                'result' => 0,
                'items' => stripslashes_deep($data['items']),
                'timestamp' => $data['timestamp'],
                'user_id' => get_current_user_id(),
                'total' => $data['total'],
            );
            if(isset($data['order_id']) && $data['order_id']) $_data['order_id'] = $data['order_id'];
            if(isset($data['points'])) $_data['points'] = $data['points'];
            ksort($_data);

            $string = '';
            foreach ($_data as $k => $v){
                if($k === 'key' || is_null($v) || $v === ''){continue;}
                $v = self::loop_to_string($v);
                $string .= $k . "=" . $v . "&";
            }
            $string = trim($string, "&");
            $string = $string . '&key=' . $key;
            $result = hash_hmac('sha256', $string, $key);
            return $sign === strtolower($result);
        }
        return false;
    }

    private static function loop_to_string($data){
        if($data && (is_array($data) || is_object($data))){
            $_data = [];
            foreach($data as $i => $v){
                if(is_array($v) || is_object($v)){
                    $_data[$i] = self::loop_to_string($v);
                }else if(is_numeric($v)){
                    $_data[$i] = (string)$v;
                }else{
                    $_data[$i] = $v;
                }
            }
            $data = wp_json_encode($_data);
        }else if(is_numeric($data)){
            $data = (string)$data;
        }
        return $data;
    }

    /**
     * 统计订单数量
     * @param string $period 支持 'today', 'month', 'year', 'total'
     * @param string $start 自定义开始时间(Y-m-d 或 Y-m-d H:i:s)
     * @param string $end   自定义结束时间(Y-m-d 或 Y-m-d H:i:s)
     * @return int
     */
    public static function get_order_count($period = 'total', $start = '', $end = '') {
        global $wpdb;

        $cache_key = 'wpcom_order_count_' . substr(md5(serialize([$period, $start, $end])), 0, 12);

        $cached = get_transient($cache_key);
        if ($cached !== false) {
            return $cached;
        }

        $order_table = $wpdb->order_table;
        $where = ["status = 'paid'", "payment_gateway != 'points'"];
        if ($start && $end) {
            $where[] = $wpdb->prepare('time >= %s AND time <= %s', $start . (strlen($start) == 10 ? ' 00:00:00' : ''), $end . (strlen($end) == 10 ? ' 23:59:59' : ''));
        } elseif ($start) {
            $where[] = $wpdb->prepare('time >= %s', $start . (strlen($start) == 10 ? ' 00:00:00' : ''));
        } elseif ($end) {
            $where[] = $wpdb->prepare('time <= %s', $end . (strlen($end) == 10 ? ' 23:59:59' : ''));
        } else {
            switch ($period) {
                case 'today':
                    $where[] = $wpdb->prepare('DATE(time) = %s', current_time('Y-m-d'));
                    break;
                case 'month':
                    $where[] = $wpdb->prepare('YEAR(time) = %d AND MONTH(time) = %d', date_i18n('Y'), date_i18n('n'));
                    break;
                case 'year':
                    $where[] = $wpdb->prepare('YEAR(time) = %d', date_i18n('Y'));
                    break;
                case 'total':
                default:
                    // 只统计全部已支付订单
                    break;
            }
        }
        $sql = "SELECT COUNT(*) FROM $order_table WHERE " . implode(' AND ', $where);

        $count = (int)$wpdb->get_var($sql);
        // 缓存 10 分钟
        set_transient($cache_key, $count, MINUTE_IN_SECONDS * 10);

        return $count;
    }

    /**
     * 统计订单收入
     * @param string $period 支持 'today', 'month', 'year', 'total'
     * @param string $start 自定义开始时间(Y-m-d 或 Y-m-d H:i:s)
     * @param string $end   自定义结束时间(Y-m-d 或 Y-m-d H:i:s)
     * @return float
     */
    public static function get_order_income($period = 'total', $start = '', $end = '') {
        global $wpdb;

        $cache_key = 'wpcom_order_income_' . substr(md5(serialize([$period, $start, $end])), 0, 12);

        $cached = get_transient($cache_key);
        if ($cached !== false) {
            return $cached;
        }

        $order_table = $wpdb->order_table;
        $where = ["status = 'paid'", "payment_gateway != 'points'", "payment_gateway != 'wallet'"];
        if ($start && $end) {
            $where[] = $wpdb->prepare('time >= %s AND time <= %s', $start . (strlen($start) == 10 ? ' 00:00:00' : ''), $end . (strlen($end) == 10 ? ' 23:59:59' : ''));
        } elseif ($start) {
            $where[] = $wpdb->prepare('time >= %s', $start . (strlen($start) == 10 ? ' 00:00:00' : ''));
        } elseif ($end) {
            $where[] = $wpdb->prepare('time <= %s', $end . (strlen($end) == 10 ? ' 23:59:59' : ''));
        } else {
            switch ($period) {
                case 'today':
                    $where[] = $wpdb->prepare('DATE(time) = %s', current_time('Y-m-d'));
                    break;
                case 'month':
                    $where[] = $wpdb->prepare('YEAR(time) = %d AND MONTH(time) = %d', date_i18n('Y'), date_i18n('n'));
                    break;
                case 'year':
                    $where[] = $wpdb->prepare('YEAR(time) = %d', date_i18n('Y'));
                    break;
                case 'total':
                default:
                    // 只统计全部已支付订单
                    break;
            }
        }
        $sql = "SELECT SUM(price) FROM $order_table WHERE " . implode(' AND ', $where);
        $income = $wpdb->get_var($sql);
        $income = number_format($income ? (float)$income : 0, 2, '.', '');
        // 缓存 10 分钟
        set_transient($cache_key, $income, MINUTE_IN_SECONDS * 10);

        return $income;
    }

    private function init_database() {
        global $wpdb;
        $order_table = $wpdb->order_table;
        $order_item_table = $wpdb->order_item_table;

        if ($wpdb->get_var("SHOW TABLES LIKE '$order_table'") != $order_table) {
            $charset_collate = $wpdb->get_charset_collate();
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

            $create_order_table_sql = "CREATE TABLE $order_table (" .
                "ID BIGINT(20) NOT NULL auto_increment," .
                "number BIGINT(20) NOT NULL," .
                "price decimal(10,2) NOT NULL," .
                "user BIGINT(20) NOT NULL," .
                "time datetime NOT NULL," .
                "status varchar(20) NOT NULL," .
                "payment_gateway varchar(20)," .
                "PRIMARY KEY (ID)) $charset_collate;";

            dbDelta($create_order_table_sql);

            $create_item_table_sql = "CREATE TABLE $order_item_table (" .
                "ID BIGINT(20) NOT NULL auto_increment," .
                "order_id BIGINT(20) NOT NULL," .
                "price decimal(10,2) NOT NULL," .
                "title longtext," .
                "type varchar(20)," .
                "type_id varchar(60)," .
                "data longtext," .
                "PRIMARY KEY (ID)) $charset_collate;";

            dbDelta($create_item_table_sql);
        }
    }
}

class_alias(Order::class, 'WPCOM_Order');
new Order();

Youez - 2016 - github.com/yon3zu
LinuXploit