HEX
Server: nginx/1.22.1
System: Linux VM-16-9-centos 3.10.0-1160.99.1.el7.x86_64 #1 SMP Wed Sep 13 14:19:20 UTC 2023 x86_64
User: www (1001)
PHP: 7.3.31
Disabled: 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
Upload Files
File: /www/wwwroot/softfox.com.cn/wp-content/plugins/spider-analyser/spider.class.php
<?php


if (!defined('ABSPATH')) {
    return;
}



class WP_Spider_Analyser
{

    public static $in_log = false;
    public static $debug = false;
    public static $blocked = false;
    public static $after_request = false;


    public static function init()
    {

        add_action('parse_request', array(__CLASS__, 'parse_request'), 1);

        add_action('admin_menu', array(__CLASS__, 'adminMenu'));
        add_action('edit_post', array(__CLASS__, 'spider_edit_post'), 500, 2);
        add_filter('plugin_action_links', array(__CLASS__, 'actionLinks'), 10, 2);
        register_shutdown_function(array(__CLASS__, 'handle'));

        add_filter('redirect_canonical', function ($redirect_url, $requested_url) {
            if (!self::$in_log && $redirect_url) {
                self::$in_log = true;
                self::log(302);
            }
            return $redirect_url;
        }, 10, 2);


        //
        add_action('wp_wb_spider_analyser_cron', array(__CLASS__, 'wp_wb_spider_analyser_cron'));

        if (!wp_next_scheduled('wp_wb_spider_analyser_cron')) {
            wp_schedule_event(strtotime(current_time('Y-m-d H:i:00', 1)), 'hourly', 'wp_wb_spider_analyser_cron');
        }

        register_activation_hook(WP_SPIDER_ANALYSER_BASE_FILE, array(__CLASS__, 'plugin_activate'));
        register_deactivation_hook(WP_SPIDER_ANALYSER_BASE_FILE, array(__CLASS__, 'plugin_deactivate'));



        WP_Spider_Analyser_Admin::init();

        add_action('wp_ajax_spider_analyser', array(__CLASS__, 'spider_analyser_ajax'));

        add_action('admin_enqueue_scripts', array(__CLASS__, 'admin_enqueue_scripts'), 1);
        add_action('admin_notices', array(__CLASS__, 'admin_notices'));
        self::upgrade();
    }


    public static function parse_request()
    {
        global $wpdb;

        if (!get_option('wb_spider_analyser_ver', 0)) {
            self::$after_request = true;
            return;
        }

        $ip = self::getIp();
        $t = $wpdb->prefix . 'wb_spider_ip';

        //self::txt_log('parse_request');


        $spider = self::spider();
        //self::txt_log('spider '.$spider);
        if (!$spider) {
            return;
        }

        $match = false;

        if ($ip) {
            $ips = explode('.', $ip);
            array_pop($ips);
            $ip3 = implode('.', $ips);
            $sql = "SELECT * FROM $t WHERE (status=4 OR status>10) AND (ip = '' OR ip LIKE %s) AND (name='' OR name = %s) GROUP BY CONCAT_WS('',ip,name) ";

            $list = $wpdb->get_results($wpdb->prepare($sql, $ip3 . '.%', $spider));

            if ($list) foreach ($list as $r) {
                $match = true;
                if ($r->name) { //match name
                    //check ip not match
                    if ($r->ip && $r->ip != $ip3 . '.*' && $ip != $r->ip) {
                        $match = false;
                    }
                } else { //only ip
                    //check ip not match
                    if ($r->ip && $r->ip != $ip3 . '.*' && $ip != $r->ip) {
                        $match = false;
                    }
                }
                if ($match) {
                    break;
                }
            }
        } else {
            $sql = "SELECT * FROM $t WHERE (status=4 OR status>10) AND name = %s GROUP BY name";

            $list = $wpdb->get_results($wpdb->prepare($sql, $spider));
            if ($list) {
                $match = true;
            }
        }

        self::$after_request = true;
        if ($match) {
            self::$blocked = true;
            wp_die('Blocked Spider Access!', 'IP Blocked', array('response' => 403));
            exit();
        }
    }


    public static function admin_notices()
    {
        global $current_screen;
        if (!current_user_can('update_plugins')) {
            return;
        }
        if (!preg_match('#spider_analyser#', $current_screen->parent_base)) {
            return;
        }
        $current         = get_site_transient('update_plugins');
        if (!$current) {
            return;
        }
        $plugin_file = plugin_basename(WP_SPIDER_ANALYSER_BASE_FILE);
        if (!isset($current->response[$plugin_file])) {
            return;
        }
        $all_plugins     = get_plugins();
        if (!$all_plugins || !isset($all_plugins[$plugin_file])) {
            return;
        }
        $plugin_data = $all_plugins[$plugin_file];
        $update = $current->response[$plugin_file];

        //print_r($update);
        $update_url = wp_nonce_url(self_admin_url('update.php?action=upgrade-plugin&plugin=') . $plugin_file, 'upgrade-plugin_' . $plugin_file);

        $html = '<div class="update-message notice inline notice-warning notice-alt"><p>' . $plugin_data['Name'] . '有新版本可用。';
        $html .= '<a href="' . $update->url . '" target="_blank" aria-label="查看' . $plugin_data['Name'] . '版本' . $update->new_version . '详情">查看版本' . $update->new_version . '详情</a>';
        $html .= '或<a href="' . $update_url . '" class="update-link" aria-label="现在更新 ' . $plugin_data['Name'] . '">现在更新</a>。</p></div>';
        echo $html;
    }

    public static function vue_assets()
    {

        $assets = include __DIR__ . '/plugins_assets.php';

        if (!$assets || !is_array($assets)) {
            return;
        }

        $wp_styles = wp_styles();
        if (isset($assets['css']) && is_array($assets['css'])) foreach ($assets['css'] as $r) {
            $wp_styles->add($r['handle'], WP_SPIDER_ANALYSER_URL . $r['src'], $r['dep'], null, $r['args']);
            $wp_styles->enqueue($r['handle']); //.'?v=1'
        }
        if (isset($assets['js']) && is_array($assets['js'])) foreach ($assets['js'] as $r) {
            if (!$r['src'] && $r['in_line']) {
                wp_register_script($r['handle'], false, $r['dep'], false, true);
                wp_enqueue_script($r['handle']);
                wp_add_inline_script($r['handle'], $r['in_line'], 'after');
            } else if ($r['src']) {
                wp_enqueue_script($r['handle'], WP_SPIDER_ANALYSER_URL . $r['src'], $r['dep'], null, true);
            }
        }
    }

    public static function admin_enqueue_scripts($hook)
    {


        if (!preg_match('#wp_spider_analyser#', $hook)) {
            return;
        }

        wp_register_script('wbs-inline-js', false, null, false);
        wp_enqueue_script('wbs-inline-js');

        $wb_cnf = array(
            'home_url' => home_url(),
            'base_url' => admin_url(),
            'ajax_url' => admin_url('admin-ajax.php'),
            'dir_url' => WP_SPIDER_ANALYSER_URL,
            'pd_code' => "spider-analyser",
            'pd_title' => 'Spider Analyser-蜘蛛分析插件',
            'pd_version' => WP_SPIDER_ANALYSER_VERSION,
            'is_pro' => get_option('wb_spider_analyser_ver', 0),
            'action' => array(
                'act' => 'spider_analyser',
                'fetch' => 'get_setting',
                'push' => 'set_setting'
            )
        );

        $options = self::cnf();

        $wb_ajax_nonce = wp_create_nonce('wp_ajax_wb_spider_analyser');

        $spider_auto = isset($options['auto_deny']) && $options['auto_deny'] ? 1 : 0;

        $inline_script = 'var _wb_spider_analyser_ajax_nonce = "' . $wb_ajax_nonce . '",wb_spider_auto = ' . $spider_auto . ',
		    wb_cnf=' . json_encode($wb_cnf) . ';window.wb_vue_path="' . WP_SPIDER_ANALYSER_URL . 'tpl/";' . "\n";

        wp_add_inline_script('wbs-inline-js', $inline_script, 'before');

        add_filter('style_loader_tag', function ($tag, $handle, $href, $media) {
            if (!preg_match('#^vue-#', $media)) {
                return $tag;
            }

            $media = htmlspecialchars_decode($media);
            $r = [];
            parse_str(str_replace('vue-', '', $media), $r);
            $rel = '';
            $attr = [];
            if ($r && is_array($r)) {
                if (isset($r['rel'])) {
                    $rel = $r['rel'];
                    unset($r['rel']);
                }
                foreach ($r as $attr_k => $attr_v) {
                    $attr[] = sprintf('%s="%s"', $attr_k, esc_attr($attr_v));
                }
            }

            $tag = sprintf(
                '<link href="%s" rel="%s" %s/>' . "\n",
                $href,
                $rel,
                implode(" ", $attr)
            );
            return $tag;
        }, 10, 4);
        add_filter('script_loader_tag', function ($tag, $handle, $src) {
            if (!preg_match('#-vue-js-#', $handle)) {
                return $tag;
            }
            $parts = explode('?', $src, 2);
            $src = $parts[0];
            $type = '';
            $attr = '';
            if (isset($parts[1])) {
                $r = [];
                parse_str(htmlspecialchars_decode($parts[1]), $r);
                //print_r($r);
                if ($r) {
                    if (isset($r['type'])) {
                        $type = sprintf(' type="%s"', esc_attr($r['type']));
                        unset($r['type']);
                    }
                    $attr_txt = '';
                    if (isset($r['attr'])) {
                        $attr_txt = $r['attr'];
                        unset($r['attr']);
                    }
                    foreach ($r as $k => $v) {
                        $attr .= sprintf(' %s="%s"', $k, esc_attr($v));
                    }
                    if ($attr_txt) {
                        $attr .= sprintf(' %s', esc_attr($attr_txt));
                    }
                }
            }
            //print_r([$handle,$src]);

            $tag = sprintf('<script%s src="%s"%s id="%s-js"></script>' . "\n", $type, $src, $attr, $handle);
            return $tag;
        }, 10, 3);

        self::vue_assets();
    }


    public static function match_type($url, &$query = null)
    {
        global $wp_filter;
        self::txt_log('match type fun');
        $cnf = self::cnf();

        self::txt_log($cnf);

        $type = null;
        $old_page = null;
        $php_self = null;
        $request_uri = null;

        $reset_url = false;

        do {
            if ($cnf['extral_rule']) foreach ($cnf['extral_rule'] as $r_type => $rule) {
                if (!$rule) {
                    continue;
                }
                $rule = str_replace(array(',', '\\*'), array('|', '.+?'), preg_quote($rule));
                if (preg_match('#(' . $rule . ')#i', $url)) {
                    $type = $r_type;
                    break;
                }
            }
            if ($type) {
                break;
            }

            //['index','post','page','category','tag','search','author','feed','sitemap','api','other'];
            if ($cnf['user_rule']) foreach ($cnf['user_rule'] as $r) {
                if (!$r['rule']) {
                    continue;
                }
                $rule = str_replace(array(',', '\\*'), array('|', '.+?'), preg_quote($r['rule']));
                if (preg_match('#' . $rule . '#i', $url)) {
                    $type = $r['name'];
                    break;
                }
            }
            if ($type) {
                break;
            }

            if (preg_match('#/wp-admin/admin-ajax\.php#', $url)) {
                $type = 'api';
                break;
            } else if (preg_match('#^/sitemap(-[a-z0-9_-]+)?\.xml#i', $url)) {
                $type = 'sitemap';
                break;
            }
            $parse = parse_url($url);
            if (isset($parse['query']) && $parse['query']) {
                parse_str($parse['query'], $param);
                if (isset($param['s'])) {
                    $type = 'search';
                    break;
                }
            }
            if (!$parse['path'] || $parse['path'] == '/') {
                $type = 'index';
                break;
            }
            //if(preg_match('#sitemap#'))
            $request_uri = $_SERVER['REQUEST_URI'];
            $php_self = $_SERVER['PHP_SELF'];
            $path = $parse['path'];
            if (preg_match('#/?$#', $parse['path'])) {
                $path = trim($parse['path'], '/') . '/index.php';
            }

            self::txt_log('new wp');



            $wp = new WP();
            $_SERVER['REQUEST_URI'] = $url;
            $_SERVER['PHP_SELF'] = '/index.php';
            $old_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : null;
            if ($old_page === null) {
            } else {
                unset($_GET['page']);
            }
            $reset_url = true;
            self::txt_log('wp parse request');
            /*ini_set('display_errors',true);
            ini_set('error_reporting',E_ALL);
            $old_filter = isset($wp_filter['parse_request'])?$wp_filter['parse_request']:null;
            remove_all_filters('parse_request');
            $wp->parse_request($url);
            if($old_filter){
                $wp_filter['parse_request'] = $old_filter;
            }*/

            $wp->query_vars = self::url_help($url);

            self::txt_log('wp build query string');
            $wp->build_query_string();
            self::txt_log('wp query_vars');
            self::txt_log($wp->query_vars);

            $old_filter = isset($wp_filter['parse_query']) ? $wp_filter['parse_query'] : null;
            remove_all_filters('parse_query');

            $wp_query = new WP_Query();
            $wp_query->parse_query($wp->query_vars);

            if ($old_filter) {
                $wp_filter['parse_query'] = $old_filter;
            }

            self::txt_log('wp_query query_vars');
            self::txt_log($wp_query->query_vars);

            if ($wp_query->is_author) {
                $type = 'author';
                break;
            }
            if ($wp_query->is_tag) {
                $type = 'tag';
                break;
            }
            if ($wp_query->is_feed) {
                $type = 'feed';
                break;
            }
            if ($wp_query->is_archive) {
                $type = 'category';
                break;
            }


            if ($wp_query->is_singular) {
                //$wp_query->query();
                //print_r($wp_query->get_posts());
                $posts = $wp_query->get_posts();
                if ($posts) {
                    if ($posts[0] instanceof WP_Post) {
                        $query = $posts[0];
                    }
                    if ($posts[0]->post_type == 'page') {
                        $type = 'page';
                        break;
                    }
                }

                $type = 'post';
                break;
            }




            $type = 'other';
        } while (0);

        if ($reset_url) {
            if ($old_page === null) {
            } else {
                $_GET['page'] = $old_page;
            }
            //print_r($wp);
            //print_r($wp_query);
            $_SERVER['PHP_SELF'] = $php_self;
            $_SERVER['REQUEST_URI'] = $request_uri;
        }

        return $type;
    }

    public static function url_help($req_url)
    {
        global $wp_rewrite, $wp;
        $private_query_vars = $wp->private_query_vars;
        $public_query_vars = $wp->public_query_vars;
        $query_vars     = array();
        $post_type_query_vars = array();
        $extra_query_vars = array();


        if ($req_url) {
            parse_str($req_url, $extra_query_vars);
        }

        // Fetch the rewrite rules.
        $rewrite = $wp_rewrite->wp_rewrite_rules();



        if (!empty($rewrite)) {
            // If we match a rewrite rule, this will be cleared.
            $error               = '404';

            $pathinfo         = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
            list($pathinfo) = explode('?', $pathinfo);
            $pathinfo         = str_replace('%', '%25', $pathinfo);

            list($req_uri) = explode('?', $_SERVER['REQUEST_URI']);
            $self            = $_SERVER['PHP_SELF'];
            $home_path       = trim(parse_url(home_url(), PHP_URL_PATH), '/');
            $home_path_regex = sprintf('|^%s|i', preg_quote($home_path, '|'));

            /*
             * Trim path info from the end and the leading home path from the front.
             * For path info requests, this leaves us with the requesting filename, if any.
             * For 404 requests, this leaves us with the requested permalink.
             */
            $req_uri  = str_replace($pathinfo, '', $req_uri);
            $req_uri  = trim($req_uri, '/');
            $req_uri  = preg_replace($home_path_regex, '', $req_uri);
            $req_uri  = trim($req_uri, '/');
            $pathinfo = trim($pathinfo, '/');
            $pathinfo = preg_replace($home_path_regex, '', $pathinfo);
            $pathinfo = trim($pathinfo, '/');
            $self     = trim($self, '/');
            $self     = preg_replace($home_path_regex, '', $self);
            $self     = trim($self, '/');

            // The requested permalink is in $pathinfo for path info requests and
            // $req_uri for other requests.
            if (!empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo)) {
                $requested_path = $pathinfo;
            } else {
                // If the request uri is the index, blank it out so that we don't try to match it against a rule.
                if ($req_uri == $wp_rewrite->index) {
                    $req_uri = '';
                }
                $requested_path = $req_uri;
            }
            $requested_file = $req_uri;


            // Look for matches.
            $request_match = $requested_path;
            if (empty($request_match)) {
                // An empty request could only match against ^$ regex.
                if (isset($rewrite['$'])) {
                    $matched_rule = '$';
                    $query              = $rewrite['$'];
                    $matches            = array('');
                }
            } else {
                foreach ((array) $rewrite as $match => $query) {
                    // If the requested file is the anchor of the match, prepend it to the path info.
                    if (!empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path) {
                        $request_match = $requested_file . '/' . $requested_path;
                    }

                    if (
                        preg_match("#^$match#", $request_match, $matches) ||
                        preg_match("#^$match#", urldecode($request_match), $matches)
                    ) {

                        if ($wp_rewrite->use_verbose_page_rules && preg_match('/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch)) {
                            // This is a verbose page match, let's check to be sure about it.
                            $page = get_page_by_path($matches[$varmatch[1]]);
                            if (!$page) {
                                continue;
                            }

                            $post_status_obj = get_post_status_object($page->post_status);
                            if (
                                !$post_status_obj->public && !$post_status_obj->protected
                                && !$post_status_obj->private && $post_status_obj->exclude_from_search
                            ) {
                                continue;
                            }
                        }

                        // Got a match.
                        $matched_rule = $match;
                        break;
                    }
                }
            }


            if (isset($matched_rule)) {
                // Trim the query of everything up to the '?'.
                $query = preg_replace('!^.+\?!', '', $query);

                // Substitute the substring matches into the query.
                $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));



                // Parse the query.
                parse_str($query, $perma_query_vars);

                // If we're processing a 404 request, clear the error var since we found something.
                if ('404' == $error) {
                    unset($error, $_GET['error']);
                }
            }

            // If req_uri is empty or if it is a request for ourself, unset error.
            if (empty($requested_path) || $requested_file == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) {
                unset($error, $_GET['error']);

                if (isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) {
                    unset($perma_query_vars);
                }
            }
        }

        /**
         * Filters the query variables allowed before processing.
         *
         * Allows (publicly allowed) query vars to be added, removed, or changed prior
         * to executing the query. Needed to allow custom rewrite rules using your own arguments
         * to work, or any other custom query variables you want to be publicly available.
         *
         * @since 1.5.0
         *
         * @param string[] $public_query_vars The array of allowed query variable names.
         */
        $public_query_vars = apply_filters('query_vars', $public_query_vars);

        foreach (get_post_types(array(), 'objects') as $post_type => $t) {
            if (is_post_type_viewable($t) && $t->query_var) {
                $post_type_query_vars[$t->query_var] = $post_type;
            }
        }

        foreach ($public_query_vars as $wpvar) {
            if (isset($extra_query_vars[$wpvar])) {
                $query_vars[$wpvar] = $extra_query_vars[$wpvar];
            } elseif (isset($_GET[$wpvar]) && isset($_POST[$wpvar]) && $_GET[$wpvar] !== $_POST[$wpvar]) {
                wp_die(__('A variable mismatch has been detected.'), __('Sorry, you are not allowed to view this item.'), 400);
            } elseif (isset($_POST[$wpvar])) {
                $query_vars[$wpvar] = $_POST[$wpvar];
            } elseif (isset($_GET[$wpvar])) {
                $query_vars[$wpvar] = $_GET[$wpvar];
            } elseif (isset($perma_query_vars[$wpvar])) {
                $query_vars[$wpvar] = $perma_query_vars[$wpvar];
            }

            if (!empty($query_vars[$wpvar])) {
                if (!is_array($query_vars[$wpvar])) {
                    $query_vars[$wpvar] = (string) $query_vars[$wpvar];
                } else {
                    foreach ($query_vars[$wpvar] as $vkey => $v) {
                        if (is_scalar($v)) {
                            $query_vars[$wpvar][$vkey] = (string) $v;
                        }
                    }
                }

                if (isset($post_type_query_vars[$wpvar])) {
                    $query_vars['post_type'] = $post_type_query_vars[$wpvar];
                    $query_vars['name']      = $query_vars[$wpvar];
                }
            }
        }

        // Convert urldecoded spaces back into '+'.
        foreach (get_taxonomies(array(), 'objects') as $taxonomy => $t) {
            if ($t->query_var && isset($query_vars[$t->query_var])) {
                $query_vars[$t->query_var] = str_replace(' ', '+', $query_vars[$t->query_var]);
            }
        }

        // Don't allow non-publicly queryable taxonomies to be queried from the front end.
        if (!is_admin()) {
            foreach (get_taxonomies(array('publicly_queryable' => false), 'objects') as $taxonomy => $t) {
                /*
                 * Disallow when set to the 'taxonomy' query var.
                 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
                 */
                if (isset($query_vars['taxonomy']) && $taxonomy === $query_vars['taxonomy']) {
                    unset($query_vars['taxonomy'], $query_vars['term']);
                }
            }
        }

        // Limit publicly queried post_types to those that are 'publicly_queryable'.
        if (isset($query_vars['post_type'])) {
            $queryable_post_types = get_post_types(array('publicly_queryable' => true));
            if (!is_array($query_vars['post_type'])) {
                if (!in_array($query_vars['post_type'], $queryable_post_types, true)) {
                    unset($query_vars['post_type']);
                }
            } else {
                $query_vars['post_type'] = array_intersect($query_vars['post_type'], $queryable_post_types);
            }
        }

        // Resolve conflicts between posts with numeric slugs and date archive queries.
        $query_vars = wp_resolve_numeric_slug_conflicts($query_vars);

        foreach ((array) $private_query_vars as $var) {
            if (isset($extra_query_vars[$var])) {
                $query_vars[$var] = $extra_query_vars[$var];
            }
        }

        if (isset($error)) {
            $query_vars['error'] = $error;
        }

        return $query_vars;
    }

    public static function chart_data($day, $type, $compare = 0, $spider = null)
    {
        global $wpdb;

        $time = strtotime(current_time('mysql'));
        if ($day) {
            $time = $time - 86400 * $day;
        }

        if ($compare) {
            $time = $time - 86400 * ($day > 0 ? $day : 1);
        }
        $ymd = date('Y-m-d', $time);
        $t = $wpdb->prefix . 'wb_spider_log';

        if ($day > 2) {
            //group by h
            $format = '%m/%d';
            $op = '>=';

            $xdata = [];
            for ($i = 0; $i < $day; $i++) {
                $xdata[] = date('m/d', $time + $i * 86400);
            }
        } else {
            $format = '%H:00-%H:59';
            $op = '=';
            $xdata = [];

            for ($i = 0; $i < 24; $i++) {
                $xdata[] = $i < 10 ? ('0' . $i . ':00-0' . $i . ':59') : ('' . $i . ':00-' . $i . ':59');
            }
        }
        $filed_more = '';
        $group_more = '';
        $where_more = '';
        if ($type == 3) {
            $filed_more = ',code';
            $group_more = ',code';
            $where_more = ' AND code IN(200,301,302,404)';
        }

        if ($spider) {
            $where_more = $wpdb->prepare(" AND spider = %s", $spider);
        }

        $sql = "SELECT COUNT(1) num,COUNT(DISTINCT spider) spider,DATE_FORMAT(visit_date,'$format') ymd $filed_more FROM (SELECT * FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd' $where_more) AS a GROUP BY ymd $group_more ORDER BY ymd";
        $list = $wpdb->get_results($sql);
        $tmp = [];
        foreach ($list as $r) {
            if ($type == 2) {
                $tmp[$r->ymd] = $r->num;
            } else if ($type == 3) {
                //$tmp[$r->ymd] = $r->spider > 0 ? ceil($r->num/$r->spider) : 0;
                if (!isset($tmp[$r->ymd])) {
                    $tmp[$r->ymd] = [];
                }
                $code = in_array($r->code, ['301', '302']) ? '301/302' : $r->code;
                $tmp[$r->ymd][$code] = isset($tmp[$r->ymd][$code]) ?  $tmp[$r->ymd][$code] + $r->num : $r->num;
            } else {
                $tmp[$r->ymd] = $r->spider;
            }
        }

        $ydata = [];
        $codes = ['200', '301/302', '404'];
        $empty = 0;
        if ($type == 3) {
            $empty = [];
            foreach ($codes as $c) {
                $ydata[$c] = [];
                $empty[$c] = 0;
            }
        }

        foreach ($xdata as $v) {
            if ($type == 3) {
                $val = isset($tmp[$v]) ? $tmp[$v] : $empty;
                foreach ($codes as $c) {
                    $ydata[$c][] = isset($val[$c]) ? $val[$c] : 0;
                }
            } else {
                $ydata[] = isset($tmp[$v]) ? $tmp[$v] : $empty;
            }
        }


        return [$xdata, $ydata];
    }


    public static function  array_sanitize_text_field($value)
    {
        if (is_array($value)) {
            foreach ($value as $k => $v) {
                $value[$k] = self::array_sanitize_text_field($v);
            }
            return $value;
        } else {
            return sanitize_text_field($value);
        }
    }

    public static function spider_analyser_ajax()
    {
        global $wpdb;

        $op = isset($_POST['op']) ? sanitize_text_field($_POST['op']) : (isset($_GET['op']) ? sanitize_text_field($_GET['op']) : null);


        switch ($op) {
            case 'chk_ver':
                $http = wp_remote_get('https://www.wbolt.com/wb-api/v1/themes/checkver?code=spider-analyser&ver=' . WP_SPIDER_ANALYSER_VERSION . '&chk=1', array('sslverify' => false, 'headers' => array('referer' => home_url()),));

                if (wp_remote_retrieve_response_code($http) == 200) {
                    echo wp_remote_retrieve_body($http);
                }

                exit();
                break;
            case 'promote':
                header('content-type:text/json;charset=utf-8');
                $ret = ['code' => 0, 'desc' => 'success', 'data' => ''];
                $data = [];
                $expired = 0;
                $update_cache = false;
                do {
                    $option = get_option('wb_spider_analyser_promote', null);
                    do {
                        if (!$option || !is_array($option)) {
                            break;
                        }

                        if (!isset($option['expired']) || empty($option['expired'])) {
                            break;
                        }

                        $expired = intval($option['expired']);
                        if ($expired < current_time('U')) {
                            $expired = 0;
                            break;
                        }

                        if (!isset($option['data']) || empty($option['data'])) {
                            break;
                        }

                        $data = $option['data'];
                    } while (0);

                    if ($data) {
                        $ret['data'] = $data;
                        break;
                    }
                    if ($expired) {
                        break;
                    }

                    $update_cache = true;
                    $param = ['c' => 'spider-analyser', 'h' => $_SERVER['HTTP_HOST']];
                    $http = wp_remote_post('https://www.wbolt.com/wb-api/v1/promote', array('sslverify' => false, 'body' => $param, 'headers' => array('referer' => home_url()),));

                    if (is_wp_error($http)) {
                        $ret['error'] = $http->get_error_message();
                        break;
                    }
                    if (wp_remote_retrieve_response_code($http) !== 200) {
                        $ret['error-code'] = '201';
                        break;
                    }
                    $body = trim(wp_remote_retrieve_body($http));
                    if (!$body) {
                        $ret['empty'] = 1;
                        break;
                    }
                    $data = json_decode($body, true);
                    if (!$data) {
                        $ret['json-error'] = 1;
                        $ret['body'] = $body;
                        break;
                    }
                    //data = [title=>'',image=>'','expired'=>'2021-05-12','url=>'']
                    $ret['data'] = $data;
                    if (isset($data['expired']) && $data['expired'] && preg_match('#^\d{4}-\d{2}-\d{2}$#', $data['expired'])) {
                        $expired = strtotime($data['expired'] . ' 23:50:00');
                    }
                } while (0);
                if ($update_cache) {
                    if (!$expired) {
                        $expired = current_time('U') + 21600;
                    }
                    update_option('wb_spider_analyser_promote', ['data' => $ret['data'], 'expired' => $expired], false);
                }


                echo json_encode($ret);
                exit();
                break;
            case 'chart_data':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $spider = isset($_POST['spider']) ? trim(sanitize_text_field($_POST['spider'])) : '';
                    $day = isset($_POST['day']) ? absint($_POST['day']) : 0;
                    $type = isset($_POST['type']) ? absint($_POST['type']) : 1;

                    $cache_param = ['op' => 'chart_data', 'day' => $day, 'type' => $type, 'spider' => $spider];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $data = self::chart_data($day, $type, 0, $spider);
                    //$compare_day = $day>0?$day * 2 : 1;
                    $compare = [];
                    if ($type != 3) {
                        $compare = self::chart_data($day, $type, 1, $spider);
                    }


                    $ret = array(
                        //'sql'=>$sql,
                        'code' => 0,
                        'data' => $data,
                        'compare' => $compare,
                    );

                    self::cache($cache_param, $ret, 3600); //60*60

                } while (0);



                echo json_encode($ret);

                exit();
                break;

            case 'top_url':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $day = isset($_POST['day']) ? absint($_POST['day']) : 0;
                    $cache_param = ['op' => 'top_url', 'day' => $day];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $time = strtotime(current_time('mysql'));
                    if ($day) {
                        $time = $time - 86400 * $day;
                    }
                    $ymd = date('Y-m-d', $time);
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $op = '=';
                    if ($day > 1) {
                        $op = '>=';
                    }

                    $total = $wpdb->get_var("SELECT COUNT(1) total FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd'");

                    $sql = "SELECT COUNT(1) num,url FROM (SELECT * FROM  $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd') AS a GROUP BY url_md5 ORDER BY num DESC LIMIT 10";

                    $list = $wpdb->get_results($sql);
                    $data = [];

                    foreach ($list as $r) {
                        $r->rate = round($r->num / $total * 100, 2);
                        $data[] = $r;
                    }

                    $ret = array(
                        //'sql'=>$sql,
                        'code' => 0,
                        'data' => $data,
                    );

                    self::cache($cache_param, $ret, 3600);
                } while (0);



                echo json_encode($ret);

                exit();
                break;

            case 'top_post':
                $ret = array('code' => 0, 'desc' => 'success');
                $ret['data'] = array();
                header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'top_spider':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }

                    $day = isset($_POST['day']) ? absint($_POST['day']) : 0;
                    $cache_param = ['op' => 'top_spider', 'day' => $day];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $time = strtotime(current_time('mysql'));
                    if ($day) {
                        $time = $time - 86400 * $day;
                    }
                    $ymd = date('Y-m-d', $time);
                    $t2 = $wpdb->prefix . 'wb_spider';
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $op = '=';
                    if ($day > 1) {
                        $op = '>=';
                    }
                    $total = $wpdb->get_var("SELECT COUNT(1) total FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd'");

                    //LEFT JOIN $t2 b ON a.spider=b.name
                    $sql = "SELECT COUNT(1) num,a.spider,1 AS udg FROM (SELECT  * FROM $t  WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd') AS a GROUP BY a.spider ORDER BY num DESC LIMIT 10";

                    $list = $wpdb->get_results($sql);
                    $data = [];

                    foreach ($list as $r) {
                        $r->rate = round($r->num / $total * 100, 2);
                        $data[] = $r;
                    }

                    $ret = array(
                        //'sql'=>$sql,
                        'code' => 0,
                        'data' => $data,
                    );
                    self::cache($cache_param, $ret, 3600);
                } while (0);


                echo json_encode($ret);

                exit();
                break;

            case 'summary':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }

                    $cache_param = ['op' => 'summary'];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $ymd = current_time('Y-m-d');
                    $t = $wpdb->prefix . 'wb_spider_log';
                    //蜘蛛数
                    $data = [['spider' => 0, 'url' => 0, 'avg_url' => 0], ['spider' => 0, 'url' => 0, 'avg_url' => 0], ['spider' => 0, 'url' => 0, 'avg_url' => 0]];


                    $row = $wpdb->get_row("SELECT COUNT(1) url,COUNT(DISTINCT spider) spider FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d')='$ymd' ");

                    if ($row) {
                        $data[0]['spider'] = $row->spider;
                        $data[0]['url'] = $row->url;
                        $data[0]['avg_url'] = $row->spider > 0 ? ceil($row->url / $row->spider) : 0;
                    }
                    $ymd = date('Y-m-d', strtotime(current_time('mysql')) - 86400);

                    $row = $wpdb->get_row("SELECT COUNT(1) url,COUNT(DISTINCT spider) spider FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d')='$ymd' ");

                    if ($row) {
                        $data[1]['spider'] = $row->spider;
                        $data[1]['url'] = $row->url;
                        $data[1]['avg_url'] = $row->spider > 0 ? ceil($row->url / $row->spider) : 0;
                    }

                    $ymd = date('Y-m-d', strtotime(current_time('mysql')) - 86400 * 30);
                    $row = $wpdb->get_row("SELECT COUNT(1) url FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d')>='$ymd' ");
                    if ($row) {
                        $data[2]['url'] = ceil($row->url / 30);
                    }
                    $row2 = $wpdb->get_row("SELECT SUM(num) spider FROM (SELECT COUNT(DISTINCT  spider) num,DATE_FORMAT(visit_date,'%Y-%m-%d') ymd FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d')>='$ymd' GROUP BY ymd) as tmp ");
                    if ($row2) {
                        $data[2]['spider'] = ceil($row2->spider / 30);
                    }

                    $data[2]['avg_url'] = $data[2]['spider'] > 0 ? ceil($data[2]['url'] / $data[2]['spider']) : 0;



                    $ret = array(
                        //'sql'=>$sql,
                        'code' => 0,
                        'data' => $data,
                    );

                    self::cache($cache_param, $ret, 3600);
                } while (0);


                echo json_encode($ret);

                exit();

                break;

            case 'list':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    if (isset($_POST['skip']) && $_POST['skip']) {

                        if (is_array($_POST['skip'])) {
                            $skips = self::array_sanitize_text_field($_POST['skip']);
                            foreach ($skips as $skip) {
                                self::skip_spider($skip);
                                self::delete_log(['spider' => $skip]);
                            }
                        } else {
                            $spider = trim(sanitize_text_field($_POST['skip']));
                            self::skip_spider($spider);
                            self::delete_log(['spider' => $spider]);
                            //$cnf = self::cnf();
                            /*if(!in_array($spider,$cnf['forbid'])){
                                array_push($cnf['forbid'],$spider);
                                $key = WP_Spider_Analyser_Admin::$option;
                                update_option($key,$cnf);
                                self::delete_log(['spider'=>$spider]);
                            }*/
                        }

                        break;
                    }


                    //$spider_info = self::spider_info();

                    $q = isset($_POST['q']) && is_array($_POST['q']) ? self::array_sanitize_text_field($_POST['q']) : array();

                    $day = isset($q['day']) ? intval($q['day']) : -1;
                    $t2 = $wpdb->prefix . 'wb_spider';
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $where = array();
                    $total_where = array();
                    if ($day > -1) {
                        $time = strtotime(current_time('mysql'));
                        if ($day) {
                            $time = $time - 86400 * $day;
                        }
                        $ymd = date('Y-m-d', $time);

                        $op = '=';
                        if ($day > 1) {
                            $op = '>=';
                        }

                        $where[] = "DATE_FORMAT(a.visit_date,'%Y-%m-%d') $op '$ymd'";
                        $total_where[] = "DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd'";
                    }
                    if (isset($q['code']) && $q['code']) {
                        $where[] = $wpdb->prepare("a.code=%s", $q['code']);
                    }
                    /*if(isset($q['spider']) && $q['spider']){
                        $where[] = $wpdb->prepare("spider=%s",$q['spider']);
                    }
                    */

                    /*if(isset($q['type']) && $q['type']){

                        $a = array();
                        foreach($spider_info as $sk=>$sy){
                            if($sy['bot_type'] == $q['type']){
                                $a[] = $wpdb->prepare('%s',$sk);
                            }

                        }
                        if($a){
                            $where[] = "spider IN (".implode(',',$a).")";
                        }
                    }*/
                    if (isset($q['spider']) && $q['spider']) {
                        $where[] = $wpdb->prepare("a.spider = %s", $q['spider']);
                    }
                    if (isset($q['name']) && $q['name']) {
                        $where[] = $wpdb->prepare("a.spider REGEXP %s", preg_quote($q['name']));
                    }
                    $num = 100;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    if ($where) {
                        $where = implode(' AND ', $where);
                    } else {
                        $where = '1=1';
                    }

                    if ($total_where) {
                        $total_where = implode(' AND ', $total_where);
                    } else {
                        $total_where = '1=1';
                    }

                    $order_by = 'num';
                    if (isset($_POST['sort']) && $_POST['sort']) {
                        $sort = sanitize_text_field($_POST['sort']);
                        if ($sort == 'type') {
                            $order_by = 'a.spider';
                        } else if (in_array($sort, ['num', 'last_visit', 'spider'])) {
                            if ($sort == 'num') {
                                $order_by = $sort;
                            } else {
                                $order_by = 'a.' . $sort;
                            }
                        }
                    }
                    $sort_order = isset($_POST['order']) ? sanitize_text_field($_POST['order']) : '';
                    $order_by .=  $sort_order == 'asc' ? ' ASC' : ' DESC';

                    $cache_param = ['list', $where, $order_by, $total_where];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $total = $wpdb->get_var("SELECT COUNT(1) total FROM $t WHERE $total_where");

                    $sql = "SELECT a.spider,COUNT(1) num,MAX(a.visit_date) last_visit,b.bot_type,b.bot_url,b.status AS udg FROM $t a LEFT JOIN $t2 b ON a.spider=b.name WHERE $where GROUP BY a.spider ORDER BY $order_by ";
                    $list = $wpdb->get_results($sql);
                    $not_found = array();
                    foreach ($list as $r) {
                        $r->rate = round($r->num / $total * 100, 2);
                        /*if(isset($spider_info[$r->spider])){
                            $info = $spider_info[$r->spider];
                            $r->type = $info['bot_type'];
                            $r->url = $info['bot_url'];
                        }else{
                            $r->type = '';
                            $r->url = '';
                            $not_found[] = $r->spider;
                        }*/

                        //$data[] = $r;
                    }
                    if ($not_found) {
                        //self::update_spider($not_found);
                    }

                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => count($list),
                        'code' => 0,
                        'data' => $list,
                    );
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                // header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'log':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $q = isset($_POST['q']) && is_array($_POST['q']) ? self::array_sanitize_text_field($_POST['q']) : array();
                    $day = isset($q['day']) ? intval($q['day']) : -1;
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $t2 = $wpdb->prefix . 'wb_spider';
                    $where = array();
                    if ($day > -1) {
                        $time = strtotime(current_time('mysql'));
                        if ($day) {
                            $time = $time - 86400 * $day;
                        }
                        $ymd = date('Y-m-d', $time);

                        $op = '=';
                        if ($day > 1) {
                            $op = '>=';
                        }

                        $where[] = "DATE_FORMAT(a.visit_date,'%Y-%m-%d') $op '$ymd'";
                    }

                    if (isset($q['spider']) && $q['spider']) {
                        $where[] = $wpdb->prepare("a.spider=%s", $q['spider']);
                    }
                    if (isset($q['code']) && $q['code']) {
                        if ($q['code'] == '301/302') {
                            $where[] = "(a.code='301' OR a.code='302')";
                        } else {
                            $where[] = $wpdb->prepare("a.code=%s", $q['code']);
                        }
                    }
                    if (isset($q['url']) && $q['url']) {
                        $where[] = $wpdb->prepare("a.url REGEXP %s", preg_quote($q['url']));
                    }
                    if (isset($q['ip']) && $q['ip']) {
                        $where[] = $wpdb->prepare("a.visit_ip REGEXP %s", preg_quote($q['ip']));
                    }
                    $num = 50;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    if ($where) {
                        $where = implode(' AND ', $where);
                    } else {
                        $where = '1=1';
                    }

                    $cache_param = ['log', $where, $offset, $num];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $sql = "SELECT SQL_CALC_FOUND_ROWS a.*,b.status AS udg FROM $t a left join $t2 b on a.spider=b.name WHERE $where ORDER BY a.id DESC LIMIT $offset,$num";
                    $list = $wpdb->get_results($sql);

                    $total = $wpdb->get_var("SELECT FOUND_ROWS()");
                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => $total,
                        'code' => 0,
                        'data' => $list,
                    );
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                // header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'log_cnf':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $cache_param = ['log_cnf'];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $ret['data'] = self::spider_log();
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                //header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'path_cnf':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $cache_param = ['path_cnf'];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }
                    $ret['data'] = self::spider_path();
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                //header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'path':
                header('content-type:text/json;charset=utf-8');
                $ret = array('code' => 0, 'desc' => 'success', 'data' => []);
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $q = isset($_POST['q']) && is_array($_POST['q']) ? self::array_sanitize_text_field($_POST['q']) : array();
                    $day = isset($q['day']) ? intval($q['day']) : -1;
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $where = array();
                    if ($day > -1) {
                        $time = strtotime(current_time('mysql'));
                        if ($day) {
                            $time = $time - 86400 * $day;
                        }
                        $ymd = date('Y-m-d', $time);

                        $op = '=';
                        if ($day > 1) {
                            $op = '>=';
                        }

                        $where[] = "DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd'";
                    }
                    $is_chart = isset($_POST['chart']) ? sanitize_text_field($_POST['chart']) : null;
                    if ($is_chart) {
                        if ($where) {
                            $where = implode(' AND ', $where);
                        } else {
                            $where = '1=1';
                        }
                        $cache_param = ['path', $is_chart, $where];
                        $cache_file = self::cache($cache_param);
                        if ($cache_file) {
                            include $cache_file;
                        }


                        $sql = "SELECT url_type,COUNT(1) num FROM (SELECT * FROM $t WHERE $where) AS a GROUP  BY url_type ";
                        $list = $wpdb->get_results($sql);


                        $url_types = WP_Spider_Analyser_Admin::url_types();
                        $cnf = self::cnf();
                        if ($cnf['user_rule']) foreach ($cnf['user_rule'] as $r) {
                            $url_types[$r['name']] = $r['name'];
                        }
                        $data = [];
                        foreach ($url_types as $k => $v) {
                            $data[$k] = ['value' => 0, 'name' => $v];
                        }
                        foreach ($list as $r) {
                            $data[$r->url_type]['value'] = $r->num;
                        }


                        $ret['data'] = array_values($data);
                        self::cache($cache_param, $ret, 3600);
                        break;
                    }



                    if (isset($q['spider']) && $q['spider']) {
                        $where[] = $wpdb->prepare("spider=%s", $q['spider']);
                    }
                    if (isset($q['code']) && $q['code']) {
                        $where[] = $wpdb->prepare("code=%s", $q['code']);
                    }
                    if (isset($q['url']) && $q['url']) {
                        $where[] = $wpdb->prepare("url REGEXP %s", preg_quote($q['url']));
                    }
                    if (isset($q['ip']) && $q['ip']) {
                        $where[] = $wpdb->prepare("visit_ip REGEXP %s", preg_quote($q['ip']));
                    }
                    if (isset($q['type']) && $q['type']) {
                        $where[] = $wpdb->prepare("url_type=%s", $q['type']);
                    }
                    $num = 50;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    if ($where) {
                        $where = implode(' AND ', $where);
                    } else {
                        $where = '1=1';
                    }

                    $order_by = 'num';

                    if (isset($_POST['sort'])) {
                        $sort = sanitize_text_field($_POST['sort']);
                        if (in_array($sort, ['num', 'url_type', 'url'])) {
                            $order_by = $sort;
                        }
                    }
                    $sort_by = 'desc';
                    if (isset($_POST['order'])) {
                        $sort_by = sanitize_text_field($_POST['order']);
                    }
                    $order_by .=  $sort_by == 'asc' ? ' ASC' : ' DESC';


                    $cache_param = ['path', $where, $order_by, $offset, $num];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $sum = $wpdb->get_var("SELECT COUNT(1) num FROM $t WHERE $where");

                    $sql = "SELECT SQL_CALC_FOUND_ROWS COUNT(1) num,url,url_type,'' type,ROUND(COUNT(1)/$sum * 100,2) percent 
                                FROM (SELECT * FROM $t WHERE $where ) AS a GROUP BY url_md5 ORDER BY $order_by LIMIT $offset,$num";

                    $list = $wpdb->get_results($sql);

                    $total = $wpdb->get_var("SELECT FOUND_ROWS()");
                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => $total,
                        'code' => 0,
                        'data' => $list,
                    );
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                //header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'clean_log':
                if (current_user_can('manage_options')) {
                    //,'wb_spider'
                    foreach (array('wb_spider_sum', 'wb_spider_visit', 'wb_spider_log', 'wb_spider_post', 'wb_spider_post_link', 'wb_spider_ip') as $v) {
                        $t = $wpdb->prefix . $v;
                        $wpdb->query("TRUNCATE $t");
                    }
                }

                $ret = array('code' => 0, 'desc' => 'success');

                header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'ip':
                $ret = array('code' => 0, 'desc' => 'success', 'data' => [], 'total' => 0);
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    if (!get_option('wb_spider_analyser_ver', 0)) {
                        break;
                    }
                    $q = isset($_POST['q']) && is_array($_POST['q']) ? self::array_sanitize_text_field($_POST['q']) : array();
                    $day = isset($q['day']) ? intval($q['day']) : -1;
                    $t2 = $wpdb->prefix . 'wb_spider';
                    $t = $wpdb->prefix . 'wb_spider_log';
                    $where = array();
                    if ($day > -1) {
                        $time = strtotime(current_time('mysql'));
                        if ($day) {
                            $time = $time - 86400 * $day;
                        }
                        $ymd = date('Y-m-d', $time);

                        $op = '=';
                        if ($day > 1) {
                            $op = '>=';
                        }

                        $where[] = "DATE_FORMAT(a.visit_date,'%Y-%m-%d') $op '$ymd'";
                    }

                    if (isset($q['spider']) && $q['spider']) {
                        $where[] = $wpdb->prepare("a.spider=%s", $q['spider']);
                    }
                    if (isset($q['name']) && $q['name']) {
                        $where[] = $wpdb->prepare("a.spider REGEXP %s", preg_quote($q['name']));
                    }

                    /*if(isset($q['url']) && $q['url']){
                        $where[] = $wpdb->prepare("url REGEXP %s",preg_quote($q['url']));
                    }

                    if(isset($q['type']) && $q['type']){
                        $where[] = $wpdb->prepare("url_type=%s",$q['type']);
                    }*/
                    $num = 50;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    if ($where) {
                        $where = implode(' AND ', $where);
                    } else {
                        $where = '1=1';
                    }

                    $order_by = 'num';
                    if (isset($_POST['sort'])) {
                        $sort = sanitize_text_field($_POST['sort']);
                        if (in_array($sort, ['num'])) {
                            $order_by = $sort;
                        } else if (in_array($sort, ['ip_range', 'spider'])) {
                            $order_by = 'a.' . $sort;
                        }
                    }
                    $sort_by = 'desc';
                    if (isset($_POST['order'])) {
                        $sort_by = sanitize_text_field($_POST['order']);
                    }
                    $order_by .=  $sort_by == 'asc' ? ' ASC' : ' DESC';

                    $cache_param = ['ip', $where, $order_by, $offset, $num];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }
                    $sum = $wpdb->get_var("SELECT COUNT(1) num FROM $t a WHERE $where");

                    $sql = "SELECT SQL_CALC_FOUND_ROWS COUNT(1) num,a.spider,SUBSTRING_INDEX(a.visit_ip,'.',3) ip_range,ROUND(COUNT(1)/$sum * 100,2) percent,b.status AS udg 
                            FROM (SELECT * FROM $t a WHERE $where) AS a LEFT JOIN $t2 b ON a.spider=b.name 
                            GROUP BY a.spider,ip_range ORDER BY $order_by LIMIT $offset,$num";

                    //echo $sql;exit();
                    $list = $wpdb->get_results($sql);

                    $total = $wpdb->get_var("SELECT FOUND_ROWS()");
                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => $total,
                        'code' => 0,
                        'data' => $list,
                    );
                    self::cache($cache_param, $ret, 3600);
                } while (0);

                header('content-type:text/json;');
                echo json_encode($ret);
                exit();
                break;
            case 'stop':
                $t = $wpdb->prefix . 'wb_spider_ip';
                $ret = array('code' => 0, 'desc' => 'success', 'data' => [], 'total' => 0);
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    if (!get_option('wb_spider_analyser_ver', 0)) {
                        break;
                    }
                    if (isset($_POST['add']) && $_POST['add'] && is_array($_POST['add'])) {
                        $add_data = self::array_sanitize_text_field($_POST['add']);
                        list($name, $ip) = $add_data;
                        $cid = 4;
                        if (isset($_POST['cid']) && in_array($_POST['cid'], [11, 12, 13, 14, 15, 16, 17])) {
                            $cid = intval($_POST['cid']);
                        }
                        $wpdb->suppress_errors();
                        if (is_array($ip)) {

                            //$ret['ips'] = $ip;

                            foreach ($ip as $v) {
                                $sql = $wpdb->prepare("INSERT INTO $t(`name`, `ip`, `status`) VALUES(%s, %s, $cid)", $name, $v);
                                if (!$wpdb->query($sql)) {
                                    $sql = $wpdb->prepare("UPDATE $t SET status=$cid WHERE name=%s AND ip=%s", $name, $v);
                                    $wpdb->query($sql);
                                }
                                self::delete_log(['spider' => $name, 'ip' => $v]);
                            }
                        } else if ($ip || $name) {
                            $sql = $wpdb->prepare("INSERT INTO $t(`name`, `ip`, `status`) VALUES(%s, %s, $cid)", $name, $ip);
                            if (!$wpdb->query($sql)) {
                                $sql = $wpdb->prepare("UPDATE $t SET status=$cid WHERE name=%s AND ip=%s", $name, $ip);
                                $wpdb->query($sql);
                            }
                            self::delete_log(['spider' => $name, 'ip' => $ip]);
                        }


                        break;
                    } else if (isset($_POST['removes']) && is_array($_POST['removes'])) {
                        $removes = self::array_sanitize_text_field($_POST['removes']);
                        foreach ($removes as $r) {
                            $wpdb->query("DELETE FROM $t WHERE status=15 AND " . $wpdb->prepare("name=%s AND ip=%s", $r[0], $r[1]));
                            $sql = $wpdb->prepare("UPDATE $t SET status=1 WHERE name=%s AND ip=%s", $r[0], $r[1]);
                            $wpdb->query($sql);
                        }

                        $wpdb->query("DELETE FROM $t WHERE ip = '' AND status=1");
                        $wpdb->query("DELETE FROM $t WHERE ip LIKE '%.*' AND status=1");
                        self::clear_cache();
                        break;
                    } else if (isset($_POST['remove']) && is_array($_POST['remove'])) {
                        $remove = self::array_sanitize_text_field($_POST['remove']);
                        list($name, $ip) =  $remove;
                        if ($name || $ip) {
                            $wpdb->query("DELETE FROM $t WHERE status=15 AND " . $wpdb->prepare("name=%s AND ip=%s", $name, $ip));
                            $sql = $wpdb->prepare("UPDATE $t SET status=1 WHERE name=%s AND ip=%s", $name, $ip);
                            $wpdb->query($sql);
                        }

                        $wpdb->query("DELETE FROM $t WHERE ip = '' AND status=1");
                        $wpdb->query("DELETE FROM $t WHERE ip LIKE '%.*' AND status=1");
                        self::clear_cache();

                        break;
                    } else if (isset($_POST['new']) && is_array($_POST['new'])) {
                        $new_data = self::array_sanitize_text_field($_POST['new']);
                        list($name, $ip) =  $new_data;
                        $cid = 4;
                        if (isset($_POST['cid']) && in_array($_POST['cid'], [11, 12, 13, 14, 15, 16, 17])) {
                            $cid = intval($_POST['cid']);
                        }
                        $wpdb->suppress_errors();
                        if ($ip && is_array($ip)) {
                            //$ret['ips'] = $ip;
                            foreach ($ip as $v) {
                                $sql = $wpdb->prepare("INSERT INTO $t(`name`, `ip`, `status`) VALUES(%s, %s, $cid)", $name, $v);
                                if (!$wpdb->query($sql)) {
                                    $sql = $wpdb->prepare("UPDATE $t SET status=$cid WHERE name=%s AND ip=%s", $name, $v);
                                    $wpdb->query($sql);
                                }
                                self::delete_log(['spider' => $name, 'ip' => $v]);
                            }
                        } else if ($name && is_array($name)) {
                            foreach ($name as $v) {
                                $sql = $wpdb->prepare("INSERT INTO $t(`name`, `ip`, `status`) VALUES(%s, %s, $cid)", $v, $ip);
                                if (!$wpdb->query($sql)) {
                                    $sql = $wpdb->prepare("UPDATE $t SET status=$cid WHERE name=%s AND ip=%s", $v, $ip);
                                    $wpdb->query($sql);
                                }
                                self::delete_log(['spider' => $v, 'ip' => $ip]);
                            }
                        } else if ($ip || $name) {
                            $sql = $wpdb->prepare("INSERT INTO $t(`name`, `ip`, `status`) VALUES(%s, %s, $cid)", $name, $ip);
                            if (!$wpdb->query($sql)) {
                                $sql = $wpdb->prepare("UPDATE $t SET status=$cid WHERE name=%s AND ip=%s", $name, $ip);
                                $wpdb->query($sql);
                            }
                            self::delete_log(['spider' => $name, 'ip' => $ip]);
                        }

                        self::clear_cache();
                        break;
                    }


                    if (isset($_POST['status'])) {
                        $query_status = intval($_POST['status']);
                        if ($query_status == 4) {
                            $where = "(status=4 OR status>10)";
                        } else {
                            $where = "status=" . $query_status;
                        }
                    } else {
                        $where = "(status=4 OR status>10)";
                    }
                    $num = 30;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    $cache_param = ['stop', $where, $offset, $num];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }
                    $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM $t WHERE $where LIMIT $offset,$num";

                    $list = $wpdb->get_results($sql);

                    $total = $wpdb->get_var("SELECT FOUND_ROWS()");
                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => $total,
                        'code' => 0,
                        'data' => $list,
                    );

                    self::cache($cache_param, $ret, 3600);
                } while (0);

                header('content-type:text/json;');
                echo json_encode($ret);
                exit();
                break;

            case 'post':
                $ret = array('code' => 0, 'desc' => 'success', 'data' => [], 'total' => 0);
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    if (!get_option('wb_spider_analyser_ver', 0)) {
                        break;
                    }
                    $dsb = isset($_POST['dsb']) && $_POST['dsb'] ? 1 : 0;
                    $q = isset($_POST['q']) && is_array($_POST['q']) ? self::array_sanitize_text_field($_POST['q']) : array();
                    $day = isset($q['day']) ? intval($q['day']) : -1;

                    //if($dsb){

                    //}


                    $t = $wpdb->prefix . 'wb_spider_log';
                    $t2 = $wpdb->prefix . 'wb_spider_post';
                    $where = array();
                    $where2 = array();
                    $where[] = "url_type='post'";
                    if ($day > -1) {
                        $time = strtotime(current_time('mysql'));
                        if ($day) {
                            $time = $time - 86400 * $day;
                        }
                        $ymd = date('Y-m-d', $time);

                        $op = '=';
                        if ($day > 1) {
                            $op = '>=';
                        }

                        $where[] = "DATE_FORMAT(visit_date,'%Y-%m-%d') $op '$ymd'";
                    }

                    if (isset($q['spider']) && $q['spider']) {
                        $where[] = $wpdb->prepare("spider=%s", $q['spider']);
                    }
                    if (isset($q['name']) && $q['name']) {
                        $kw = str_replace(home_url('/'), '/', $q['name']);
                        //$where[] = $wpdb->prepare("CONCAT_WS('',a.url,c.post_title) REGEXP %s",preg_quote($kw));
                        $where[] = $wpdb->prepare("url LIKE %s", "%$kw%");
                        $where2[] = $wpdb->prepare("c.post_title LIKE %s", "%$kw%");;
                    }
                    /*if(isset($q['url']) && $q['url']){
                        $where[] = $wpdb->prepare("url REGEXP %s",preg_quote($q['url']));
                    }
                    if(isset($q['ip']) && $q['ip']){
                        $where[] = $wpdb->prepare("visit_ip REGEXP %s",preg_quote($q['ip']));
                    }
                    */
                    if (isset($q['type']) && $q['type']) {
                        $type = $q['type'];
                        if ($q['type'] == 3) {
                            $type = 0;
                        }
                        $where2[] = $wpdb->prepare("b.status=%s", $type);
                    }

                    $num = 50;
                    if (isset($_POST['num'])) {
                        $num = max(10, absint($_POST['num']));
                    }
                    if (isset($_POST['page'])) {
                        $page = absint($_POST['page']);
                    }

                    $offset = max(0, ($page - 1) * $num);

                    if ($where) {
                        $where = implode(' AND ', $where);
                    } else {
                        $where = '1=1';
                    }
                    if ($where2) {
                        $where2 = ' AND ' . implode(' AND ', $where2);
                    } else {
                        $where2 = '';
                    }

                    $order_by = 'num';
                    if (isset($_POST['sort'])) {
                        $sort = $_POST['sort'];
                        if (in_array($sort, ['num', 'url_in', 'url_out', 'post_date'])) {
                            $order_by = $sort;
                        }
                    }
                    $sort_by = 'desc';
                    if (isset($_POST['order'])) {
                        $sort_by = sanitize_text_field($_POST['order']);
                    }
                    $order_by .=  $sort_by == 'asc' ? ' ASC' : ' DESC';

                    /*$oby = 'num DESC';

                    if(isset($q['sort']) && $q['sort']){
                        $oby = $q['sort'].' DESC';
                    }*/
                    $cache_param = ['post', $where, $where2, $order_by, $offset, $num];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $sql = "SELECT SQL_CALC_FOUND_ROWS COUNT(1) num,a.url_md5,a.url,b.url_in,b.url_out,b.status,b.post_id,c.post_title,c.post_date 
                                FROM (SELECT * FROM $t WHERE $where ) AS a,$t2 b,$wpdb->posts c 
                                WHERE a.url_md5=b.url_md5 AND b.post_id=c.ID $where2 ";
                    $sql .= " GROUP BY a.url_md5 ORDER BY $order_by LIMIT $offset,$num";

                    $list = $wpdb->get_results($sql);
                    $total = $wpdb->get_var("SELECT FOUND_ROWS()");
                    foreach ($list as $k => $r) {
                        $list[$k]->post_url = get_permalink($r->post_id);
                    }


                    $ret = array(
                        //'sql'=>$sql,
                        'num' => $num,
                        'total' => $total,
                        'code' => 0,
                        'data' => $list,
                    );

                    //if($dsb){
                    self::cache($cache_param, $ret, 3600);
                    //}
                } while (0);




                header('content-type:text/json;');

                echo json_encode($ret);

                exit();
                break;

            case 'clean_all':
                $ret = array('code' => 0, 'desc' => 'fail');
                do {
                    if (!current_user_can('manage_options')) {
                        break;
                    }
                    $t = $wpdb->prefix . 'wb_spider_ip';
                    $wpdb->query("DELETE FROM $t  WHERE (status=4 OR status>10)");
                    $wpdb->query("DELETE FROM $t WHERE ip = '' AND status=1");
                    $wpdb->query("DELETE FROM $t WHERE ip LIKE '%.*' AND status=1");
                } while (0);
                header('content-type:text/json;');
                echo json_encode($ret);
                exit();
                break;

            case 'verify':
                if (!wp_verify_nonce(sanitize_text_field($_POST['_ajax_nonce']), 'wp_ajax_wb_spider_analyser')) {

                    echo json_encode(array('code' => 1, 'data' => '非法操作'));
                    exit(0);
                }
                if (!current_user_can('manage_options')) {
                    echo json_encode(array('code' => 1, 'data' => '没有权限'));
                    exit(0);
                }

                $param = array(
                    'code' => sanitize_text_field(trim($_POST['key'])),
                    'host' => sanitize_text_field(trim($_POST['host'])),
                    'ver' => 'spider-analyser',
                );
                $err = '';
                do {
                    $http = wp_remote_post('https://www.wbolt.com/wb-api/v1/verify', array('sslverify' => false, 'body' => $param, 'headers' => array('referer' => home_url()),));
                    if (is_wp_error($http)) {
                        $err = '校验失败,请稍后再试(错误代码001[' . $http->get_error_message() . '])';
                        break;
                    }

                    if ($http['response']['code'] != 200) {
                        $err = '校验失败,请稍后再试(错误代码001[' . $http['response']['code'] . '])';
                        break;
                    }

                    $body = $http['body'];

                    if (empty($body)) {
                        $err = '发生异常错误,联系<a href="https://www.wbolt.com/?wb=member#/contact" target="_blank">技术支持</a>(错误代码 010)';
                        break;
                    }

                    $data = json_decode($body, true);

                    if (empty($data)) {
                        $err = '发生异常错误,联系<a href="https://www.wbolt.com/?wb=member#/contact" target="_blank">技术支持</a>(错误代码011)';
                        break;
                    }
                    if (empty($data['data'])) {
                        $err = '校验失败,请稍后再试(错误代码004)';
                        break;
                    }
                    if ($data['code']) {
                        $err_code = $data['data'];
                        switch ($err_code) {
                            case 100:
                            case 101:
                            case 102:
                            case 103:
                                $err = '插件配置参数错误,联系<a href="https://www.wbolt.com/?wb=member#/contact" target="_blank">技术支持</a>(错误代码' . $err_code . ')';
                                break;
                            case 200:
                                $err = '输入key无效,请输入正确key(错误代码200)';
                                break;
                            case 201:
                                $err = 'key使用次数超出限制范围(错误代码201)';
                                break;
                            case 202:
                            case 203:
                            case 204:
                                $err = '校验服务器异常,联系<a href="https://www.wbolt.com/?wb=member#/contact" target="_blank">技术支持</a>(错误代码' . $err_code . ')';
                                break;
                            default:
                                $err = '发生异常错误,联系<a href="https://www.wbolt.com/?wb=member#/contact" target="_blank">技术支持</a>(错误代码' . $err_code . ')';
                        }

                        break;
                    }

                    update_option('wb_spider_analyser_ver', $data['v'], false);
                    update_option('wb_spider_analyser_cnf_' . $data['v'], $data['data'], false);


                    echo json_encode(array('code' => 0, 'data' => 'success'));
                    exit(0);
                } while (false);
                echo json_encode(array('code' => 1, 'data' => $err));
                exit(0);
                break;
            case 'options':
                if (!current_user_can('manage_options') || !wp_verify_nonce(sanitize_text_field($_GET['_ajax_nonce']), 'wp_ajax_wb_spider_analyser')) {
                    echo json_encode(array('o' => ''));
                    exit(0);
                }

                $ver = get_option('wb_spider_analyser_ver', 0);
                $cnf = '';
                if ($ver) {
                    $cnf = get_option('wb_spider_analyser_cnf_' . $ver, '');
                }
                $list = array('o' => $cnf);
                header('content-type:text/json;charset=utf-8');
                echo json_encode($list);
                exit();
                break;

            case 'update_setting':
                $data = null;
                if (current_user_can('manage_options')) {
                    $data = WP_Spider_Analyser_Admin::update_cnf();
                }
                $ret = array('code' => 0, 'desc' => 'success', 'data' => $data);

                header('content-type:text/json;');
                echo json_encode($ret);
                exit();
                break;

            case 'get_setting':
                $ret = array('code' => 0, 'desc' => 'success');
                $ret['data'] = WP_Spider_Analyser_Admin::wp_spider_analyser_conf();

                header('content-type:text/json;');
                echo json_encode($ret);
                exit();
                break;

            case 'down_log':
                set_time_limit(0);
                ini_set('memory_limit', '500M');
                $filename = 'spider-log.txt';
                header('Content-Type: application/application/octet-stream	');
                header('Content-Disposition: attachment;filename="' . $filename . '"');
                header('Cache-Control: max-age=0');
                header('Cache-Control: max-age=1');
                header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
                header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
                header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
                header('Pragma: public'); // HTTP/1.0
                $fileHandle = fopen('php://output', 'wb+');
                $page = -1;
                $num = 1000;
                $t = $wpdb->prefix . 'wb_spider_log';
                do {
                    $page++;
                    $offset = $num * $page;
                    $list = $wpdb->get_results("SELECT * FROM $t WHERE 1 LIMIT $offset,$num");
                    if (!$list) {
                        break;
                    }
                    foreach ($list as $r) {
                        fwrite($fileHandle, json_encode($r) . "\n");
                    }
                } while (1);

                fclose($fileHandle);
                exit();
                break;
            case 'spider_history':
                $ret = array('code' => 0, 'desc' => 'success');
                $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
                $list = array();
                do {
                    if (!$post_id) {
                        break;
                    }
                    $url = get_permalink($post_id);
                    $url = str_replace(home_url(), '', $url);
                    $url_md5 = md5($url);
                    $limit = '';
                    $cache_param = ['spider_history', $url_md5, $limit];
                    $cache_file = self::cache($cache_param);
                    if ($cache_file) {
                        include $cache_file;
                    }

                    $sql = "SELECT `spider`, `visit_date`, `visit_ip` FROM `{$wpdb->prefix}wb_spider_log` WHERE `url_md5`=%s  ORDER BY visit_date DESC $limit";

                    $ret['data'] = $wpdb->get_results($wpdb->prepare($sql, $url_md5));
                    self::cache($cache_param, $ret, 3600);
                } while (0);


                header('content-type:text/json;');
                echo json_encode($ret);

                exit();

                break;
        }
    }

    public static function delete_log($param)
    {
        global $wpdb;

        $t = $wpdb->prefix . 'wb_spider_log';
        $where = [];
        if (isset($param['spider']) && $param['spider']) {
            $where[] = $wpdb->prepare("spider=%s", $param['spider']);
        }
        if (isset($param['ip']) && $param['ip']) {

            if (strpos($param['ip'], '*') > 0) {
                $where[] = $wpdb->prepare("visit_ip LIKE  %s", str_replace('*', '%', $param['ip']));
            } else {
                $where[] = $wpdb->prepare("visit_ip = %s", $param['ip']);
            }
            $t_ip = $wpdb->prefix . 'wb_spider_ip';
            $wpdb->query("DELETE FROM $t_ip WHERE status=2 AND " . $wpdb->prepare("ip=%s", $param['ip']));
        }
        if ($where) {
            $wpdb->query("DELETE FROM $t WHERE " . implode(' AND ', $where));
        }
        self::clear_cache();
    }

    public static function txt_log($msg, $mod = null)
    {

        if (!self::$debug) {
            return;
        }


        if (is_array($msg) || is_object($msg)) {
            $msg = json_encode($msg);
        }

        if ($mod) {
            $msg = '[' . $mod . '] ' . $msg;
        }
        error_log('[' . current_time('mysql') . '] ' . $msg . "\n", 3, __DIR__ . '/#log/running.log');
    }

    public static function plugin_activate()
    {
        if (!is_dir(__DIR__ . '/#log/')) {
            mkdir(__DIR__ . '/#log/', 0755);
        }
        self::set_up();

        self::upgrade();
    }

    public static function plugin_deactivate()
    {
        wp_clear_scheduled_hook('wb_wp_spider_trace_cron');
        wp_clear_scheduled_hook('wp_wb_spider_analyser_cron');
    }

    public static function wp_wb_spider_analyser_cron()
    {
        $cnf = self::cnf();
        self::txt_log('start do action wp_wb_spider_analyser_cron');

        self::log2db($cnf['log_update'], 0);

        self::check_404();


        if (current_time('H') == '01') {
            self::calc_log(date('Y-m-d', strtotime(current_time('Y-m-d 00:00:00') - 1)));
            self::sync_wb_spider();
        }

        self::calc_log();

        self::del_old_log();

        self::set_url_type();

        if (get_option('wb_spider_analyser_ver', 0)) {
            self::cron_set_spider_post();

            self::scan_post_inner_link();
            self::update_post_url_num();

            self::check_ip();

            self::set_auto_deny();
        }


        self::txt_log('finnish do action wp_wb_spider_analyser_cron');
    }

    public static function log2db($type, $force = 0)
    {
        if ($type == 'db') {
            return;
        }
        if ($type == 'hour') {
            $dir = glob(__DIR__ . '/#log/log-*.txt');
            $match = '#log-' . current_time('dH') . '\.txt$#';
            if ($dir) foreach ($dir as $txt) {
                if (!$force && preg_match($match, $txt)) {
                    continue;
                }
                self::read_txt($txt);
            }
        } else if ($type == 'day') {
            $dir = glob(__DIR__ . '/#log/log-*.txt');
            $match = '#log-' . current_time('d') . '[0-9]{2}\.txt$#';
            if ($dir) foreach ($dir as $txt) {
                if (!$force && preg_match($match, $txt)) {
                    continue;
                }
                self::read_txt($txt);
            }
        }
    }

    public static function read_txt($file)
    {
        global $wpdb;

        $f = fopen($file, 'r');
        if (!$f) {
            return;
        }

        while (!feof($f)) {
            $line = fgets($f);
            if (!$line) {
                break;
            }
            $d = json_decode($line, true);
            //self::txt_log($line);
            $wpdb->insert($wpdb->prefix . 'wb_spider_log', $d);
        }
        fclose($f);
        unlink($file);
    }

    public static function set_auto_deny()
    {
        global $wpdb;
        $cnf = self::cnf();
        if (!isset($cnf['auto_deny']) || !$cnf['auto_deny']) {
            return;
        }

        $t = $wpdb->prefix . 'wb_spider_ip';
        $wpdb->query("UPDATE $t SET status=16 WHERE status = 2");
    }

    public static function check_ip()
    {

        global $wpdb;

        //status[2=>可疑ip,1=>正常,3=>检测中,4=>禁止]
        $t = $wpdb->prefix . 'wb_spider_ip';
        $t_log = $wpdb->prefix . 'wb_spider_log';

        //SELECT DISTINCT visit_ip FROM `wp_wb_spider_log` WHERE
        $sql = "INSERT INTO $t(ip,name) ";
        $sql .= "SELECT DISTINCT a.visit_ip,a.spider FROM $t_log a WHERE a.visit_date > DATE_ADD(a.visit_date,INTERVAL -1 DAY)";
        $sql .= " AND NOT EXISTS(SELECT b.id FROM $t b WHERE b.ip=a.visit_ip AND b.name=a.spider)";

        $wpdb->query($sql);

        $col = $wpdb->get_col("SELECT DISTINCT ip FROM $t WHERE status = 0 LIMIT 1000 ");


        $api = 'https://www.wbolt.com/wb-api/v1/spider/ip';
        $arg = array(
            'timeout'   => 10,
            'sslverify' => false,
            'body' => array('ver' => get_option('wb_spider_analyser_ver', 0), 'host' => $_SERVER['HTTP_HOST'], 'ip' => implode(',', $col)),
            'headers' => array('referer' => home_url()),
        );
        $http = wp_remote_post($api, $arg);
        $body = wp_remote_retrieve_body($http);

        if (is_wp_error($http)) {
            self::txt_log($http->get_error_message());
        }
        self::txt_log($body);
        if ($body && preg_match('#^[0-9,]+$#', trim($body))) {
            $exp = explode(',', $body);
            foreach ($col as $k => $ip) {
                if (isset($exp[$k]) && $exp[$k]) {
                    $wpdb->query($wpdb->prepare("UPDATE $t SET status=%d WHERE ip=%s", $exp[$k], $ip));
                }
            }
        }
    }

    public static function update_post_url_num()
    {
        global $wpdb;

        $prefix = $wpdb->prefix;

        $sql = "UPDATE `{$prefix}wb_spider_post` a,(SELECT COUNT(1) num, post_id FROM `{$prefix}wb_spider_post_link` ";
        $sql .= "WHERE link_url_md5 <> 'e10adc3949ba59abbe56e057f20f883e' GROUP BY post_id ) AS b";
        $sql .= " SET a.url_out = b.num  WHERE a.post_id=b.post_id";
        $wpdb->query($sql);


        $sql = "UPDATE `{$prefix}wb_spider_post` a,(SELECT COUNT(1) num, link_url_md5 FROM `{$prefix}wb_spider_post_link` ";
        $sql .= " WHERE link_url_md5 <> 'e10adc3949ba59abbe56e057f20f883e' GROUP BY link_url_md5 ) AS b ";
        $sql .= " SET a.url_in = b.num  WHERE a.url_md5=b.link_url_md5";

        $wpdb->query($sql);
    }

    public static function scan_post_inner_link()
    {
        global $wpdb;
        $error = $wpdb->suppress_errors();
        $t = $wpdb->prefix . 'wb_spider_post_link';
        $sql = "SELECT * FROM $wpdb->posts p WHERE p.post_status='publish'";
        $sql .= " AND NOT EXISTS (SELECT post_id FROM $t a WHERE a.post_id=p.ID) LIMIT 1000";
        $list = $wpdb->get_results($sql);
        foreach ($list as $r) {
            self::post_inner_link($r);
        }
        $wpdb->suppress_errors($error);
    }

    public static function post_inner_link($post)
    {

        global $wpdb;
        $t = $wpdb->prefix . 'wb_spider_post_link';
        $wpdb->query($wpdb->prepare("DELETE FROM $t WHERE post_id=%d", $post->ID));

        $num = 0;
        if (preg_match_all("#href=('|\")(.+?)('|\")#is", $post->post_content, $match)) {
            //print_r($match[2]);
            foreach ($match[2] as $url) {
                $url = str_replace(home_url('/'), '/', $url);
                if ($url[0] != '/') {
                    continue;
                }
                $query_post = null;
                $type = self::match_type($url, $query_post);
                if ($type != 'post') {
                    continue;
                }
                self::txt_log([$type, $url]);
                $d = ['post_id' => $post->ID, 'link_url_md5' => md5($url), 'link_post_id' => 0];
                if ($query_post) {
                    $d['link_post_id'] = $query_post->ID;
                }

                if ($wpdb->insert($t, $d)) {
                    $num++;
                }
            }
        }
        if (!$num) {
            $d = ['post_id' => $post->ID, 'link_url_md5' => md5('123456'), 'link_post_id' => 0];
            $wpdb->insert($t, $d);
        }
    }

    public static function spider_edit_post($post_id, $post)
    {
        global $wpdb;
        if (!get_option('wb_spider_analyser_ver', 0)) {
            return;
        }


        if ($post->post_status != 'publish') {
            return;
        }
        $t = $wpdb->prefix . 'wb_spider_post';
        $d = array('post_id' => $post_id, 'url_md5' => md5(str_replace(home_url('/'), '/', get_permalink($post))));
        $error = $wpdb->suppress_errors();
        if (!$wpdb->insert($t, $d)) {
            $wpdb->update($t, array('url_md5' => $d['url_md5']), array('post_id' => $post_id));
        }
        //更新收录状态
        $post_id = intval($post_id);
        $wpdb->query("UPDATE $t a ,$wpdb->postmeta b SET a.status=b.meta_value WHERE a.post_id=$post_id AND a.post_id=b.post_id AND b.meta_key='url_in_baidu'");
        self::post_inner_link($post);
        $wpdb->suppress_errors($error);
    }

    public static function cron_set_spider_post()
    {
        global $wpdb;
        $error = $wpdb->suppress_errors();

        //存量文章入库
        $t = $wpdb->prefix . 'wb_spider_post';
        $sql = "INSERT INTO $t(`post_id`,`status`)  ";
        $sql .= "SELECT a.ID,IFNULL(b.meta_value,0) status FROM $wpdb->posts a LEFT JOIN $wpdb->postmeta b ON a.ID=b.post_id";
        $sql .= " AND b.meta_key='url_in_baidu' WHERE a.post_status='publish' ";
        $sql .= " AND NOT EXISTS (SELECT post_id FROM $t c WHERE c.post_id = a.ID )";
        $wpdb->query($sql);

        //更新文章URL
        $list = $wpdb->get_results("SELECT * FROM $t WHERE url_md5 IS NULL LIMIT 500");
        foreach ($list as $r) {
            $url = str_replace(home_url('/'), '/', get_permalink($r->post_id));
            $wpdb->update($t, array('url_md5' => md5($url)), array('post_id' => $r->post_id));
        }

        //更新收录状态
        $wpdb->query("UPDATE $t a ,$wpdb->postmeta b SET a.status=b.meta_value WHERE a.post_id=b.post_id AND b.meta_key='url_in_baidu'");

        $wpdb->suppress_errors($error);
    }

    public static function set_url_type()
    {
        global $wpdb;

        $t = $wpdb->prefix . 'wb_spider_log';

        $list = $wpdb->get_results("SELECT url,url_md5 FROM $t WHERE url_type IS NULL ORDER BY id DESC LIMIT 200");

        if ($list) foreach ($list as $r) {
            self::txt_log('match url ' . $r->url);
            $result = [];
            $type = self::match_type($r->url, $result);
            self::txt_log('match url type [' . $type . ']');
            if ($type) {
                self::txt_log('update url type [' . $r->url_md5 . ']');
                $wpdb->query($wpdb->prepare("UPDATE $t SET url_type=%s WHERE url_md5=%s", $type, $r->url_md5));
            }
        }
    }

    public static function check_404()
    {
        global $wpdb;
        $max_id = get_option('sp_an_max_id', 0);

        $t = $wpdb->prefix . 'wb_spider_log';
        $list = $wpdb->get_results("SELECT max(id) max_id,url,url_md5 FROM $t WHERE `code`='404' AND id>$max_id GROUP BY url_md5 ORDER BY max_id ASC LIMIT 500");


        foreach ($list as $r) {
            $url = home_url($r->url);
            $http = wp_remote_head($url);
            $code = wp_remote_retrieve_response_code($http);
            if ($code) {
                $wpdb->query($wpdb->prepare("UPDATE $t SET `code`=%s WHERE url_md5 =%s ", $code, $r->url_md5));
                $max_id = $r->max_id;
            }
        }
        update_option('sp_an_max_id', $max_id, false);
    }

    public static function del_old_log()
    {
        global $wpdb;

        $cnf = self::cnf();
        $month = intval($cnf['log_keep']);
        if (!$month) {
            $month = 2;
        }


        $time_str = '-' . $month . ' month';
        if ($month == 1) {
            $time_str = '-7 day';
        } else if ($month == 2) {
            $time_str = '-1 month';
        }

        if ($month > 12) {
            return;
        }

        $t = $wpdb->prefix . 'wb_spider_log';

        $ymd = date('Y-m-d', strtotime($time_str));

        $wpdb->query("DELETE FROM $t WHERE DATE_FORMAT(visit_date,'%Y-%m-%d') < '$ymd' ");
    }

    public static function calc_all_log()
    {
        global $wpdb;


        $t = $wpdb->prefix . 'wb_spider_log';

        $cols = $wpdb->get_col("SELECT DISTINCT DATE_FORMAT(visit_date,'%Y-%m-%d') FROM $t ");


        if ($cols) foreach ($cols as $ymd) {
            self::calc_log($ymd);
        }
    }

    public static function calc_log($ymd = null)
    {

        global $wpdb;

        $t = $wpdb->prefix . 'wb_spider';
        $t_log = $t . '_log';
        $t_sum = $t . '_sum';
        $t_visit = $t . '_visit';
        if (!$ymd) {
            $ymd = current_time('Y-m-d');
        }

        //new spider
        $wpdb->query("INSERT INTO $t(name) SELECT DISTINCT spider FROM $t_log a WHERE NOT EXISTS(SELECT id FROM $t b WHERE a.spider=b.name)");


        $list = $wpdb->get_results("SELECT id,name FROM $t ");
        $spiders = [];
        foreach ($list as $r) {
            $spiders[$r->name] = $r->id;
        }

        //spider

        $sql = "SELECT COUNT(1) num,DATE_FORMAT(a.visit_date,'%Y%m%d%H') ymdh,MIN(a.visit_date) visit_date,a.spider,b.id AS spider_id FROM $t_log a,$t b WHERE a.spider=b.name AND DATE_FORMAT(a.visit_date,'%Y-%m-%d')='$ymd' GROUP BY a.spider,ymdh ";

        $list = $wpdb->get_results($sql);

        //foreach($list as $r->r);

        //删除旧数据
        $wpdb->query("DELETE FROM $t_sum WHERE FROM_UNIXTIME(created,'%Y-%m-%d')='$ymd'");

        foreach ($list as $r) {
            $d = array(
                'ymdh' => $r->ymdh,
                'created' => strtotime($r->visit_date),
                'spider' => $r->spider_id,
                'visit_times' => $r->num
            );
            $wpdb->insert($t_sum, $d);
        }



        return;

        //spider url

        $sql = "SELECT COUNT(1) num,DATE_FORMAT(visit_date,'%Y%m%d') ymdh,MIN(visit_date) visit_date,spider,url FROM $t_log WHERE DATE_FORMAT(visit_date,'%Y-%m-%d')='$ymd' GROUP BY spider,ymdh,url_md5 ";

        $list = $wpdb->get_results($sql);

        //foreach($list as $r->r);

        //删除旧数据
        $wpdb->query("DELETE FROM $t_visit WHERE FROM_UNIXTIME(created,'%Y-%m-%d')='$ymd'");

        foreach ($list as $r) {
            $d = array(
                'ymdh' => $r->ymdh,
                'created' => strtotime($r->visit_date),
                'spider' => $spiders[$r->spider],
                'visit_times' => $r->num,
                'url_md5' => $r->url_md5,
                'url' => $r->url
            );
            $wpdb->insert($t_visit, $d);
        }
    }

    public static function handle()
    {
        if (self::$in_log) {
            return;
        }

        if (self::$blocked) {
            return;
        }

        if (!self::$after_request) {
            return;
            /*$headers = headers_list();
            $is_30x = 0;
            foreach($headers as $s){
                if(preg_match('#^location#i',$s)){
                    $is_30x = 1;
                    break;
                }
            }
            if($is_30x){
                return;
            }
            */
        }

        self::$in_log = true;

        $has_error = error_get_last();

        global $wp, $wp_query;

        if ($has_error && self::should_handle_error($has_error)) {
            $code = '500';
        } else if (is_404()) {
            $code = '404';
        } else {
            $code = '200';
        }
        self::log($code);
    }

    protected static function should_handle_error($error)
    {
        $error_types_to_handle = array(
            E_ERROR,
            E_PARSE,
            E_USER_ERROR,
            E_COMPILE_ERROR,
            E_RECOVERABLE_ERROR,
        );

        if (isset($error['type']) && in_array($error['type'], $error_types_to_handle, true)) {
            return true;
        }

        return (bool) apply_filters('wp_should_handle_php_error', false, $error);
    }

    public static function cnf()
    {
        static $option = null;
        if (!$option) {
            $option = WP_Spider_Analyser_Admin::cnf();
        }

        return $option;
    }

    public static function spider()
    {
        try {
            if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] != 'GET') {
                return null;
            }
            if (!isset($_SERVER['HTTP_USER_AGENT']) || empty($_SERVER['HTTP_USER_AGENT'])) {
                return null;
            }
            $agent = $_SERVER['HTTP_USER_AGENT'];
            $cnf = self::cnf();
            //forbid
            do {

                if (preg_match('#spider#i', $agent)) {
                    break;
                }
                if (preg_match('#bot#i', $agent)) {
                    break;
                }
                if (preg_match('#crawler#i', $agent)) {
                    break;
                }
                if (preg_match('#(Daumoa|Yahoo!|Qwantify|Seeker|Elefent|13TABS|iqdb|TinEye|Plukkie|PDFDriveCrawler)#i', $agent)) {
                    break;
                }

                $find_match = false;
                if ($cnf['user_define']) foreach ($cnf['user_define'] as $v) {
                    if (preg_match('#' . preg_quote($v) . '#i', $agent)) {
                        $find_match = true;
                        break;
                    }
                }
                if ($find_match) {
                    break;
                }

                return null;
            } while (0);

            $spider = '';

            //自定义蜘蛛
            if ($cnf['user_define']) foreach ($cnf['user_define'] as $v) {
                if (preg_match('#' . preg_quote($v) . '#i', $agent)) {
                    $spider = $v;
                    break;
                }
            }

            if ($spider) {
            } else if (preg_match('#sogou (web|inst|news|pic|wap) spider#i', $agent, $spider_match)) {
                $spider = 'sogou spider';
            } else if (preg_match('#[a-z0-9\.-]+ spider#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#[a-z0-9\.-]+ bot#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#[a-z0-9\.-]*spider[a-z0-9]*#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#[a-z0-9\.-]*bot[a-z0-9]*#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#[a-z0-9\.-]+ crawler#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#[a-z0-9\.-]*crawler[a-z0-9]*#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else if (preg_match('#(Daumoa|Yahoo!|Qwantify|Seeker|Elefent|13TABS|iqdb|TinEye|Plukkie|PDFDriveCrawler)#i', $agent, $spider_match)) {
                $spider = $spider_match[0];
            } else {
                $spider = 'other';
            }

            return $spider;
        } catch (Exception $ex) {
        }
        return null;
    }

    public static function getIp()
    {
        if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP']) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']) {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR']) {
            return $_SERVER['REMOTE_ADDR'];
        }
        return null;
    }

    public static function log($status = '')
    {
        global $wp_the_query, $wpdb;
        try {
            $spider = self::spider();
            if (!$spider) {
                return;
            }
            $cnf = self::cnf();
            //$agent = $_SERVER['HTTP_USER_AGENT'];
            //用户禁用,不记录
            $skip_list = self::get_skip_spider();
            if ($skip_list) foreach ($skip_list as $v) {
                if ($v && preg_match('#^' . preg_quote($v) . '$#i', $spider)) {
                    return;
                }
            }

            $url = $_SERVER['REQUEST_URI'];

            $d = array(
                'spider' => $spider,
                'visit_date' => current_time('mysql'),
                'code' => $status,
                'visit_ip' => self::getIp(),
                'url' => $url,
                'url_md5' => md5($url),
            );

            $type = null;

            if ($cnf['extral_rule']) foreach ($cnf['extral_rule'] as $r_type => $rule) {
                if (!$rule) {
                    continue;
                }

                $rule = str_replace(array(',', '\\*'), array('|', '.+?'), preg_quote($rule));
                if (preg_match('#(' . $rule . ')#i', $url)) {
                    $type = $r_type;
                    break;
                }
            }
            if (!$type && $cnf['user_rule']) foreach ($cnf['user_rule'] as $r) {
                if (!$r['rule']) {
                    continue;
                }
                $rule = str_replace(array(',', '\\*'), array('|', '.+?'), preg_quote($r['rule']));
                if (preg_match('#(' . $rule . ')#i', $url)) {
                    $type = $r['name'];
                    break;
                }
            }

            //['index','post','page','category','tag','search','author','feed','sitemap','api','other'];
            if ($type) {
            } else if (preg_match('#^/sitemap(-[a-z0-9_-]+)?\.xml#i', $d['url'])) {
                $type = 'sitemap';
            } else if (preg_match('#wp-admin/admin-ajax\.php#', $d['url'])) {
                $type = 'api';
            } else if ($wp_the_query && $wp_the_query instanceof WP_Query) {
                if ($wp_the_query->is_search()) {
                    $type = 'search';
                } else if ($wp_the_query->is_feed()) {
                    $type = 'feed';
                } else if ($wp_the_query->is_tag()) {
                    $type = 'tag';
                } else if ($wp_the_query->is_author()) {
                    $type = 'author';
                } else if ($wp_the_query->is_category() || $wp_the_query->is_archive()) {
                    $type = 'category';
                } else if ($wp_the_query->is_singular(array('page'))) {
                    $type = 'page';
                } else if ($wp_the_query->is_singular()) {
                    $type = 'post';
                } else if ($wp_the_query->is_home() || $wp_the_query->is_front_page()) {
                    $type = 'index';
                }
            }

            if ($type) {
                $d['url_type'] = $type;
            }


            if ($cnf['log_update'] == 'db') {
                $wpdb->insert($wpdb->prefix . 'wb_spider_log', $d);
            } else {
                $log_file = __DIR__ . '/#log/log-' . current_time('dH') . '.txt';
                error_log(json_encode($d) . "\n", 3, $log_file);
                //error_log();
            }
        } catch (Exception $ex) {
        }
    }

    public static function adminMenu()
    {
        global $wb_settings_page_hook_theme, $submenu;
        $wb_settings_page_hook_theme = add_menu_page(
            '蜘蛛分析',
            '蜘蛛分析',
            'administrator',
            'wp_spider_analyser',
            array(__CLASS__, 'spider_views'), //
            WP_SPIDER_ANALYSER_URL . 'assets/ico.svg'
        );
        add_submenu_page('wp_spider_analyser', '蜘蛛概况', '蜘蛛概况', 'administrator', 'wp_spider_analyser#/home', array(__CLASS__, 'spider_views'));
        add_submenu_page('wp_spider_analyser', '蜘蛛日志', '蜘蛛日志', 'administrator', 'wp_spider_analyser#/log', array(__CLASS__, 'spider_views'));
        add_submenu_page('wp_spider_analyser', '蜘蛛列表', '蜘蛛列表', 'administrator', 'wp_spider_analyser#/list', array(__CLASS__, 'spider_views'));
        add_submenu_page('wp_spider_analyser', '访问路径', '访问路径', 'administrator', 'wp_spider_analyser#/path', array(__CLASS__, 'spider_views'));
        add_submenu_page('wp_spider_analyser', '文章爬取', '文章爬取', 'administrator', 'wp_spider_analyser#/post', array(__CLASS__, 'spider_views'));
        add_submenu_page('wp_spider_analyser', '插件设置', '插件设置', 'administrator', 'wp_spider_analyser#/setting', array(__CLASS__, 'spider_views'));
        if (!get_option('wb_spider_analyser_ver', 0)) {
            add_submenu_page('wp_spider_analyser', '升至Pro版', '<span style="color: #FCB214;">升至Pro版</span>', 'administrator', "https://www.wbolt.com/plugins/spider-analyser' target='_blank'");
        }

        unset($submenu['wp_spider_analyser'][0]);
    }

    public static function actionLinks($links, $file)
    {

        //print_r([$file]);
        if (!preg_match('#spider-analyser/#', $file)) {
            return $links;
        }
        if (!get_option('wb_spider_analyser_ver', 0)) {
            $a_link = '<a href="https://www.wbolt.com/plugins/spider-analyser" target="_blank"><span style="color: #FCB214;">升至Pro版</span></a>';
            array_unshift($links, $a_link);
        }
        $a_link = '<a href="' . menu_page_url('wp_spider_analyser', false) . '#/setting">设置</a>';
        array_unshift($links, $a_link);



        return $links;
    }

    public static function update_spider($spider)
    {
        $api = 'https://www.wbolt.com/wb-api/v1/spider/info';
        $arg = array(
            'timeout'   => 1,
            'blocking'  => false,
            'sslverify' => false,
            'body' => array('spider' => json_encode($spider)),
            'headers' => array('referer' => home_url()),
        );
        wp_remote_post($api, $arg);
    }

    public static function spider_views()
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('You do not have sufficient permissions to access this page.'));
        }
        global $wpdb;

        $t = $wpdb->prefix . 'wb_spider';
        $t_log = $t . '_log';

        $wpdb->query("INSERT INTO $t(name) SELECT DISTINCT spider FROM $t_log a WHERE NOT EXISTS(SELECT id FROM $t b WHERE a.spider=b.name)");

        $time = get_option('sync_wb_spider', 0);

        if (time() > $time) {
            update_option('sync_wb_spider', time() + 3600);
            self::sync_wb_spider();
        }


        echo '<div class="wbs-wrap" id="optionsframework-wrap">';
        echo '<div id="app"></div>';
        //include __DIR__.'/tpl/index.html';
        echo '</div>';
    }


    public static function spider_path()
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('You do not have sufficient permissions to access this page.'));
        }

        global $wpdb;
        $t = $wpdb->prefix . 'wb_spider_log';
        $spider = $wpdb->get_col("SELECT DISTINCT spider FROM $t");
        $code = $wpdb->get_col("SELECT DISTINCT code FROM $t");
        $url_types = WP_Spider_Analyser_Admin::url_types();
        $cnf = self::cnf();
        if ($cnf['user_rule']) foreach ($cnf['user_rule'] as $r) {
            $url_types[$r['name']] = $r['name'];
        }

        $res['spider'] = $spider;
        $res['code'] = $code;
        $res['url_types'] = $url_types;
        $res['day'] = array(
            array(
                'value' => '-1',
                'label' => '所有时间'
            ),
            array(
                'value' => '0',
                'label' => '今天'
            ),
            array(
                'value' => '7',
                'label' => '近7天'
            ),
            array(
                'value' => '30',
                'label' => '近30天'
            )
        );

        return $res;
    }

    public static function spider_log()
    {
        $res = array();
        global $wpdb;
        $t = $wpdb->prefix . 'wb_spider_log';
        $spider = $wpdb->get_col("SELECT DISTINCT spider FROM $t");
        $code = $wpdb->get_col("SELECT DISTINCT code FROM $t");
        $res['spider'] = $spider;
        $res['code'] = $code;

        $res['day'] = array(
            array(
                'value' => '-1',
                'label' => '所有时间'
            ),
            array(
                'value' => '0',
                'label' => '今天'
            ),
            array(
                'value' => '7',
                'label' => '近7天'
            ),
            array(
                'value' => '30',
                'label' => '近30天'
            )
        );

        return $res;
    }

    public static function get_skip_spider()
    {
        global $wpdb;
        $t = $wpdb->prefix . 'wb_spider';
        return $wpdb->get_col("SELECT `name` FROM $t WHERE `skip` = 1");
    }

    public static function skip_spider($spider)
    {
        global $wpdb;
        $t = $wpdb->prefix . 'wb_spider';
        $wpdb->query($wpdb->prepare("UPDATE $t SET `skip`=1 WHERE `name`=%s", $spider));
    }

    public static function sync_wb_spider()
    {
        global $wpdb;

        $t = $wpdb->prefix . 'wb_spider';
        $spiders = $wpdb->get_col("SELECT name FROM $t");
        if (empty($spiders)) {
            return;
        }

        $api = 'https://www.wbolt.com/wb-api/v1/spider/info';
        $param = [
            'timeout' => 5,
            'sslverify' => false,
            'headers' => array('referer' => home_url()),
            'body' => ['udg' => 1]
        ];
        $http = wp_remote_get($api, $param);
        do {
            if (is_wp_error($http)) {
                break;
            }
            $body = wp_remote_retrieve_body($http);
            if (!$body) {
                break;
            }
            $data = json_decode($body, true);
            if (!$data) {
                break;
            }
            if (!is_array($data)) {
                break;
            }

            $t = $wpdb->prefix . 'wb_spider';
            $wpdb->query("UPDATE $t set `status` = 1 WHERE `status` = 2");
            foreach ($data['data'] as $r) {
                if (!in_array($r['name'], $spiders)) {
                    continue;
                }
                $wpdb->query($wpdb->prepare("UPDATE $t SET `status` = 2,`bot_type` = %s,`bot_url`=%s WHERE name = %s", $r['bot_type'], $r['bot_url'], $r['name']));
            }
        } while (0);
    }

    public static function spider_info()
    {
        global $wpdb;

        $time = current_time('U', 1);
        $info = get_option('wb_spider_info', array());

        if ($info && isset($info['expired']) &&  $info['expired'] > $time && isset($info['data'])) {
            return $info['data'];
        }
        $spider_data = array();
        if ($info && $info['data']) {
            $spider_data = $info['data'];
        }

        $info = array('expired' => $time + 1 * HOUR_IN_SECONDS, 'data' => array());
        $api = 'https://www.wbolt.com/wb-api/v1/spider/info';
        $http = wp_remote_get($api, array('sslverify' => false, 'headers' => array('referer' => home_url()),));
        do {
            if (is_wp_error($http)) {
                break;
            }
            $body = wp_remote_retrieve_body($http);
            if (!$body) {
                break;
            }
            $data = json_decode($body, true);
            if (!$data) {
                break;
            }
            if (!is_array($data)) {
                break;
            }
            $t = $wpdb->prefix . 'wb_spider_log';
            $spider = $wpdb->get_col("SELECT DISTINCT spider FROM $t WHERE 1");
            //$spider_data = array();
            foreach ($data['data'] as $k => $r) {
                if (isset($spider_data[$k])) {
                    $old = $spider_data[$k];
                    if (!$old['bot_type'] && $r['bot_type'] && $r['bot_type'] != '未分类') {
                        $old['bot_type'] = $r['bot_type'];
                    }
                    if (!$old['bot_url'] && $r['bot_url']) {
                        $old['bot_url'] = $r['bot_url'];
                    }
                    $spider_data[$k] = $old;
                    continue;
                }
                if (!$r['bot_type']) continue;
                if (!in_array($k, $spider)) continue;
                $spider_data[$k] = $r;
            }
            $info['data'] = $spider_data;
        } while (0);
        update_option('wb_spider_info', $info, false);
        return $info['data'];
    }


    public static function db_ver()
    {
        return 1.5;
    }

    public static function set_up()
    {
        self::setup_db();
    }

    public static function setup_db($create_tables = null)
    {

        global $wpdb;


        $wb_tables = array(
            'wb_spider',
            'wb_spider_ip',
            'wb_spider_log',
            'wb_spider_post',
            'wb_spider_post_link',
            'wb_spider_sum',
            'wb_spider_visit',
        );
        if (!$create_tables && is_array($create_tables)) {
            $wb_tables = $create_tables;
        }

        //数据表
        $tables = $wpdb->get_col("SHOW TABLES LIKE '" . $wpdb->prefix . "wb_spider%'");


        $set_up = array();
        foreach ($wb_tables as $table) {
            if (in_array($wpdb->prefix . $table, $tables)) {
                continue;
            }
            $set_up[] = $table;
        }

        if (empty($set_up)) {
            return;
        }

        $sql = file_get_contents(__DIR__ . '/install/init.sql');

        $charset_collate = $wpdb->get_charset_collate();



        $sql = str_replace('`wp_wb_', '`' . $wpdb->prefix . 'wb_', $sql);
        $sql = str_replace('ENGINE=InnoDB', $charset_collate, $sql);



        $sql_rows = explode('-- row split --', $sql);

        foreach ($sql_rows as $row) {

            if (preg_match('#`' . $wpdb->prefix . '(wb_spider.*?)`\s+\(#', $row, $match)) {
                if (in_array($match[1], $set_up)) {
                    $wpdb->query($row);
                }
            }
            //print_r($row);exit();
        }

        update_option('wb_spider_analyser_db_ver', self::db_ver());
    }

    public static function upgrade()
    {
        global $wpdb;


        $db_ver = get_option('wb_spider_analyser_db_ver');
        if (!$db_ver) {
            return;
        }

        if (version_compare($db_ver, '1.2') < 0) {
            $t = $wpdb->prefix . 'wb_spider_log';
            $sql = $wpdb->get_var('SHOW CREATE TABLE `' . $t . '`', 1);
            if (!preg_match('#`url_type`#is', $sql)) {
                $wpdb->query("ALTER TABLE $t ADD `url_type` varchar(32) DEFAULT NULL");
                $wpdb->query("ALTER TABLE $t ADD INDEX(`url_type`)");
            }
            update_option('wb_spider_analyser_db_ver', '1.2');
        }
        if (version_compare($db_ver, '1.3') < 0) {
            self::setup_db(array('wb_spider_ip', 'wb_spider_post', 'wb_spider_post_link'));
            update_option('wb_spider_analyser_db_ver', '1.3');
        }
        if (version_compare($db_ver, '1.4') < 0) {
            $t = $wpdb->prefix . 'wb_spider';
            $sql = $wpdb->get_var('SHOW CREATE TABLE `' . $t . '`', 1);
            if (!preg_match('#`skip`#is', $sql)) {
                $wpdb->query("ALTER TABLE $t ADD `skip` tinyint(3) UNSIGNED NOT NULL DEFAULT '0'");
            }
            if (!preg_match('#`bot_type`#is', $sql)) {
                $wpdb->query("ALTER TABLE $t ADD `bot_type` varchar(32) DEFAULT NULL");
                $wpdb->query("ALTER TABLE $t ADD INDEX(`bot_type`)");
            }
            if (!preg_match('#`bot_url`#is', $sql)) {
                $wpdb->query("ALTER TABLE $t ADD `bot_url` varchar(256) DEFAULT NULL");
            }
            update_option('wb_spider_analyser_db_ver', '1.4');

            $cnf = WP_Spider_Analyser_Admin::cnf();
            if (isset($cnf['forbid']) && is_array($cnf['forbid'])) {
                $t = $wpdb->prefix . 'wb_spider';
                foreach ($cnf['forbid'] as $v) {
                    $wpdb->query($wpdb->prepare("UPDATE $t SET `skip` = 1 WHERE `name` = %s", $v));
                }
                unset($cnf['forbid']);
                update_option(WP_Spider_Analyser_Admin::$option, $cnf);
            }

            self::sync_wb_spider();
        }

        if (version_compare($db_ver, '1.5') < 0) {
            self::setup_db(array('wb_spider'));
            update_option('wb_spider_analyser_db_ver', '1.5');
        }
    }

    public static function cache($param, $data = null, $expire = 0, $code = 'json')
    {
        $key = md5(json_encode($param));
        if (!is_dir(__DIR__ . '/#log/')) {
            mkdir(__DIR__ . '/#log/', 0755);
        }
        $cache_file = __DIR__ . '/#log/' . $key . '.php';
        if (null === $data) {
            if (file_exists($cache_file)) {
                return $cache_file;
            }
            return false;
        }
        if (is_array($data)) {
            $data = json_encode($data);
        }
        $expired = time() +  $expire;
        $content = '<' . '?php if(time()>' . $expired . '){return;}';
        if ($code) {
            if ($code == 'json') {
                $code = 'header("content-type:text/json;");';
            }
            $content .= $code;
        }
        $content .= '?' . '>' . $data . '<' . '?php exit();';
        file_put_contents($cache_file, $content);
    }

    public static function clear_cache()
    {
        $cache_file = __DIR__ . '/#log/*.php';
        $files = glob($cache_file);
        if ($files && is_array($files)) {
            foreach ($files as $file) {
                unlink($file);
            }
        }
    }
}