diff --git a/admin/class-wpicp-admin.php b/admin/class-wpicp-admin.php new file mode 100644 index 0000000..d561df7 --- /dev/null +++ b/admin/class-wpicp-admin.php @@ -0,0 +1,2553 @@ +' . __('请输入您的ICP备案基本信息。', 'wpicp') . '

'; + } + + /** + * 打印显示设置部分信息 + */ + public function print_display_section_info() { + echo '

' . __('控制ICP备案信息在前台的显示方式。', 'wpicp') . '

'; + } + + /** + * 打印API设置部分信息 + */ + public function print_api_section_info() { + echo '

' . __('设置验证和查询方式。', 'wpicp') . '

'; + } + + /** + * 打印合规设置部分信息 + */ + public function print_compliance_section_info() { + echo '

' . __('网站内容合规性检查设置。', 'wpicp') . '

'; + } + + /** + * ICP备案号设置字段回调 + */ + public function icp_number_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['icp_number']) ? $options['icp_number'] : ''; + echo ''; + echo '

' . __('请输入您的ICP备案号,例如:京ICP备12345678号-1', 'wpicp') . '

'; + } + + /** + * 自定义链接设置字段回调 + */ + public function custom_link_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['custom_link']) ? $options['custom_link'] : 'https://beian.miit.gov.cn/'; + echo ''; + echo '

' . __('自定义ICP备案链接,默认为工信部网站', 'wpicp') . '

'; + } + + /** + * 新增 - 公安备案号设置字段回调 + */ + public function police_number_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['police_number']) ? $options['police_number'] : ''; + echo ''; + echo '

' . __('请输入您的公安备案号,例如:京公网安备11010502030216号', 'wpicp') . '

'; + } + + /** + * 新增 - 公安备案链接设置字段回调 + */ + public function police_link_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['police_link']) ? $options['police_link'] : 'http://www.beian.gov.cn/'; + echo ''; + echo '

' . __('自定义公安备案链接,默认为公安部网站', 'wpicp') . '

'; + } + + /** + * 显示位置设置字段回调 + */ + public function display_location_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['display_location']) ? $options['display_location'] : 'footer'; + ?> + +

+ + +

+ + +

+ + +

+ '; + echo '

' . __('如使用API验证,请输入API密钥', 'wpicp') . '

'; + } + + /** + * 新增 - 实名验证API提供商设置字段回调 + */ + public function verification_api_provider_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['verification_api_provider']) ? $options['verification_api_provider'] : ''; + ?> + +

+ '; + echo '

' . __('如使用实名验证API,请输入API密钥', 'wpicp') . '

'; + } + + /** + * 新增 - 备案查询方式设置字段回调 + */ + public function beian_query_method_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['beian_query_method']) ? $options['beian_query_method'] : 'manual'; + ?> + +

+ '; + echo '

' . __('如使用备案查询API,请输入API密钥', 'wpicp') . '

'; + } + + /** + * 启用敏感内容检查设置字段回调 + */ + public function enable_sensitive_check_callback() { + $options = get_option('wpicp_options'); + $value = isset($options['enable_sensitive_check']) ? $options['enable_sensitive_check'] : 'no'; + ?> + +

+ + +

+ + +

+ +
+

+ +
+ +
+ +
+

+

+

+
    +
  1. +
  2. +
  3. +
  4. +
  5. +
+

+

+

+
+ + display_status_summary(); + ?> +
+ 0) { + $core->update_icp_record($record_id, $name, $icp_number, $domain, $approval_date); + echo '

' . __('ICP备案记录已更新!', 'wpicp') . '

'; + } else { + $core->add_icp_record($name, $icp_number, $domain, $approval_date); + echo '

' . __('ICP备案记录已添加!', 'wpicp') . '

'; + } + } else { + echo '

' . __('名称和备案号为必填项!', 'wpicp') . '

'; + } + } + + // 处理删除请求 + if(isset($_GET['action']) && $_GET['action'] == 'delete' && isset($_GET['record']) && check_admin_referer('wpicp_delete_record')) { + $record_id = intval($_GET['record']); + $core->delete_icp_record($record_id); + echo '

' . __('ICP备案记录已删除!', 'wpicp') . '

'; + } + + // 获取编辑的记录 + $edit_record = null; + if(isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['record'])) { + $record_id = intval($_GET['record']); + $edit_record = $core->get_icp_record($record_id); + } + + // 获取所有记录 + $records = $core->get_all_icp_records(); + + // 获取历史记录 + $history_record_id = isset($_GET['action']) && $_GET['action'] == 'history' && isset($_GET['record']) ? intval($_GET['record']) : 0; + $history_records = $history_record_id ? $core->get_record_history($history_record_id) : array(); + ?> +
+

+ + +
+

+ + + + + + + + + + + + + + + + + + + + + +
created_at); ?> + action) { + case 'create': + _e('创建', 'wpicp'); + break; + case 'update': + _e('更新', 'wpicp'); + break; + case 'delete': + _e('删除', 'wpicp'); + break; + default: + echo esc_html($history->action); + } + ?> + user_name); ?> + action == 'create') { + echo sprintf(__('创建备案记录:%s (%s)', 'wpicp'), + esc_html($history->data['name']), + esc_html($history->data['icp_number']) + ); + } elseif($history->action == 'update') { + echo __('更新备案记录,变更前:', 'wpicp') . '
'; + echo sprintf(__('名称:%s,备案号:%s', 'wpicp'), + esc_html($history->data['old']['name']), + esc_html($history->data['old']['icp_number']) + ) . '
'; + echo __('变更后:', 'wpicp') . '
'; + echo sprintf(__('名称:%s,备案号:%s', 'wpicp'), + esc_html($history->data['new']['name']), + esc_html($history->data['new']['icp_number']) + ); + } elseif($history->action == 'delete') { + echo sprintf(__('删除备案记录:%s (%s)', 'wpicp'), + esc_html($history->data['name']), + esc_html($history->data['icp_number']) + ); + } + ?> +
+
+ + +
+

+
+ + + + + + + + + + + + + + + + + + + + + + +
+ +

+
+ +

+
+ +

+
+ +

+
+ + + + + +
+
+ +
+

+ + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
id); ?>name); ?>icp_number); ?>domain); ?>approval_date); ?> + + + +
+ +
+

+

+ +
+ +
+ +
+ export_icp_records(); + exit; + } + } + + /** + * 新增 - 显示实名认证页面 + */ + public function display_verification_page() { + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 获取实名认证信息(如果有) + $domain = parse_url(get_site_url(), PHP_URL_HOST); + $real_name_info = $core->get_real_name_info_by_domain($domain); + + // 获取编辑的记录 + $edit_record = null; + if(isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['id'])) { + $record_id = intval($_GET['id']); + $edit_record = $core->get_real_name_info($record_id); + } + + // 获取所有实名认证记录 + $all_records = $core->get_all_real_name_info(); + ?> +
+

+ +
+

+

+
+ +
+

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

+
+ +

+
+ +

+
+ /> + +

+ +

+ +
+ +

+
+ +

+
+ +

+
+ +

+
+ +

+
+ + + + + +
+
+ + +
+

+ +
+ + + + + + + + + +
+ +

+ entity_type == 'personal') { + _e('请上传身份证正反面照片合并成一张图片', 'wpicp'); + } elseif($edit_record->entity_type == 'enterprise') { + _e('请上传营业执照副本照片', 'wpicp'); + } else { + _e('请上传组织机构代码证照片', 'wpicp'); + } + ?> +

+
+ + +
+
+ + + verification_method == 'api'): ?> +
+

+ +

+ + +
+

+
+ +
+ + + +

+ +

+
+ +
+ + +
+

+ + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
id); ?> + entity_type) { + case 'personal': + _e('个人', 'wpicp'); + break; + case 'enterprise': + _e('企业', 'wpicp'); + break; + case 'organization': + _e('组织/机构', 'wpicp'); + break; + default: + echo esc_html($record->entity_type); + } + ?> + entity_name); ?>domain); ?> + verification_status) { + case 'pending': + echo '' . __('待验证', 'wpicp') . ''; + break; + case 'verified': + echo '' . __('已验证', 'wpicp') . ''; + break; + case 'rejected': + echo '' . __('验证失败', 'wpicp') . ''; + break; + default: + echo esc_html($record->verification_status); + } + ?> + + verification_method) { + case 'manual': + _e('人工审核', 'wpicp'); + break; + case 'api': + _e('API验证', 'wpicp'); + break; + default: + echo esc_html($record->verification_method); + } + ?> + verification_date) ? esc_html($record->verification_date) : '-'; ?> + + verification_status != 'verified'): ?> +
+ + + + +
+ + +
+
+ +
+ 0) { + $core->verify_real_name_info($record_id, 'manual', 'verified', ''); + echo '

' . __('验证已通过!', 'wpicp') . '

'; + echo ''; + } + } + + // 处理API验证 + if(isset($_POST['verify_action']) && $_POST['verify_action'] == 'api_verify' && check_admin_referer('wpicp_api_verify', 'wpicp_nonce')) { + $record_id = isset($_POST['record_id']) ? intval($_POST['record_id']) : 0; + if($record_id > 0) { + $record = $core->get_real_name_info($record_id); + + if($record) { + // 执行API验证 + $verify_result = $core->verify_identity_with_api( + $record->entity_name, + $record->id_type, + $record->id_number + ); + + if($verify_result['success']) { + $status = isset($verify_result['data']['verified']) && $verify_result['data']['verified'] ? 'verified' : 'rejected'; + $core->verify_real_name_info($record_id, 'api', $status, json_encode($verify_result)); + + if($status == 'verified') { + echo '

' . __('API验证成功!', 'wpicp') . '

'; + } else { + echo '

' . __('API验证未通过:', 'wpicp') . esc_html($verify_result['message']) . '

'; + } + + echo ''; + } else { + echo '

' . __('API调用失败:', 'wpicp') . esc_html($verify_result['message']) . '

'; + } + } + } + } + + // 处理删除请求 + if(isset($_GET['action']) && $_GET['action'] == 'delete' && isset($_GET['id']) && check_admin_referer('wpicp_delete_verification')) { + $record_id = intval($_GET['id']); + $core->delete_real_name_info($record_id); + echo '

' . __('实名认证记录已删除!', 'wpicp') . '

'; + echo ''; + } + } + + /** + * 新增 - 显示备案状态页面 + */ + public function display_status_page() { + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 处理手动设置备案状态 + if(isset($_POST['wpicp_set_status']) && check_admin_referer('wpicp_set_status', 'wpicp_nonce')) { + $domain = sanitize_text_field($_POST['domain']); + $icp_status = sanitize_text_field($_POST['icp_status']); + $police_status = sanitize_text_field($_POST['police_status']); + $icp_number = sanitize_text_field($_POST['icp_number']); + $police_number = sanitize_text_field($_POST['police_number']); + + $core->set_manual_status($domain, $icp_status, $police_status, $icp_number, $police_number); + echo '

' . __('备案状态已更新!', 'wpicp') . '

'; + } + + // 当前站点域名 + $current_domain = parse_url(get_site_url(), PHP_URL_HOST); + + // 获取状态信息 + $status = $core->check_domain_icp_status($current_domain); + $status_data = $status ? maybe_unserialize($status->check_result) : array(); + ?> +
+

+ +
+

+

+
+ + display_status_summary(); ?> + +
+

+

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ +

+
+ +

+
+ +

+
+ +

+
+ +

+
+ + +
+
+ +
+

+ +

last_check))); ?>

+ +

+ + +
+ + +

+
+
+
+ prefix . 'wpicp_status'; + $wpdb->delete($table_name, array('domain' => $current_domain)); + + // 重新检查 + $core->check_domain_icp_status($current_domain); + + echo '

' . __('备案状态已重新检查!', 'wpicp') . '

'; + echo ''; + } + } + + /** + * 显示合规检查页面 + */ + public function display_compliance_check_page() { + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + $options = get_option('wpicp_options'); + $enable_check = isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes'; + + // 处理开始检查请求 + $check_results = null; + if(isset($_POST['wpicp_start_check']) && check_admin_referer('wpicp_compliance_check', 'wpicp_nonce')) { + $check_results = $core->check_site_compliance(); + } + + ?> +
+

+ + +
+

+

+
+ +

+ +
+ + + + + + + +
+
+
+
+
+ +
+ + +
+ + +
+

+ + +
+

+
+ +
+

+
+ + + + + + + + + + + + + + + + + + + + +
+ + +
+

+

+

+

+
+ +
+

+
+ + + + +
+
+
+ + +
+ prefix . 'wpicp_sensitive_words'; + + // 处理表单提交 + if(isset($_POST['wpicp_add_word']) && check_admin_referer('wpicp_manage_words', 'wpicp_nonce')) { + $word = sanitize_text_field($_POST['word']); + $category = sanitize_text_field($_POST['category']); + $level = intval($_POST['level']); + + if(!empty($word)) { + $exists = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM $table_name WHERE word = %s", + $word + )); + + if($exists) { + $wpdb->update( + $table_name, + array( + 'category' => $category, + 'level' => $level + ), + array('word' => $word) + ); + echo '

' . __('敏感词已更新!', 'wpicp') . '

'; + } else { + $wpdb->insert( + $table_name, + array( + 'word' => $word, + 'category' => $category, + 'level' => $level + ) + ); + echo '

' . __('敏感词已添加!', 'wpicp') . '

'; + } + + // 清除缓存 + delete_transient('wpicp_sensitive_words'); + } else { + echo '

' . __('敏感词不能为空!', 'wpicp') . '

'; + } + } + + // 处理删除请求 + if(isset($_GET['action']) && $_GET['action'] == 'delete' && isset($_GET['id']) && check_admin_referer('wpicp_delete_word')) { + $word_id = intval($_GET['id']); + $wpdb->delete($table_name, array('id' => $word_id)); + delete_transient('wpicp_sensitive_words'); + echo '

' . __('敏感词已删除!', 'wpicp') . '

'; + } + + // 获取敏感词列表 + $words = $wpdb->get_results("SELECT * FROM $table_name ORDER BY category, level DESC, word", ARRAY_A); + + // 获取词语类别 + $categories = $wpdb->get_col("SELECT DISTINCT category FROM $table_name ORDER BY category"); + if(!in_array('general', $categories)) { + $categories[] = 'general'; + } + ?> +
+

+ +
+

+

+
+ +
+

+
+ + + + + + + + + + + + + + + +
+ +

+
+ + +

+ +
+ +

+
+ + +
+
+ +
+

+ +
+

+
+ + +

+ +

+

+ +
+
+ +
+

+
+ + + +
+
+
+ +
+

+ + +

+ +

+ + + + + + + + + + + + + + + + + + + + + + +
+ ' . __('低', 'wpicp') . ''; + break; + case 2: + echo '' . __('中', 'wpicp') . ''; + break; + case 3: + echo '' . __('高', 'wpicp') . ''; + break; + default: + echo esc_html($word['level']); + } + ?> + + +
+ +
+
+ get_beian_guide_data($province); + ?> +
+

+ +
+

+

+
+ + +
+

+
+ +
+

+ + + + + + + + + + + + + + + + + + + + + + +
+ +

+ +
+ +
+

+ +
+ + +
+

+

+ +
+ +
+

+
+
+ +
+ +
+

+
    + +
  • + +
+
+ + +
+
+ get_faq_data(); + ?> +
+

+ +
+

+
+ +
+ $faq): ?> +
+

+
+
+ +
+ +
+

+

+ +
+
+ get_status_message($domain); + + $status_class = ''; + switch($status_info['type']) { + case 'success': + $status_class = 'wpicp-status-summary-success'; + break; + case 'error': + $status_class = 'wpicp-status-summary-error'; + break; + case 'warning': + case 'info': + default: + $status_class = 'wpicp-status-summary-warning'; + } + ?> +
+

+

+ + + + + + + + + + + + +
+ ' . __('已备案', 'wpicp') . ''; + break; + case 'not_registered': + echo '' . __('未备案', 'wpicp') . ''; + break; + default: + echo '' . __('未知', 'wpicp') . ''; + } + ?> + + + + +
+ ' . __('已备案', 'wpicp') . ''; + break; + case 'not_registered': + echo '' . __('未备案', 'wpicp') . ''; + break; + default: + echo '' . __('未知', 'wpicp') . ''; + } + ?> + + + + +
+ +
+ + + + + +
+
+ ' . __('设置', 'wpicp') . ''; + array_unshift($links, $settings_link); + return $links; + } + + /** + * 显示管理员通知 + */ + public function display_admin_notices() { + // 只在管理页面显示 + if(!is_admin()) { + return; + } + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 获取当前域名 + $domain = parse_url(get_site_url(), PHP_URL_HOST); + $status_info = $core->get_status_message($domain); + + // 如果ICP或公安备案未完成,显示通知 + if($status_info['icp_status'] != 'registered' || $status_info['police_status'] != 'registered') { + // 检查是否已经关闭通知 + $notice_dismissed = get_transient('wpicp_admin_notice_dismissed'); + + if(!$notice_dismissed) { + $notice_class = $status_info['icp_status'] != 'registered' ? 'notice-error' : 'notice-warning'; + ?> +
+

+

+

+ + + +

+
+ + check_domain_icp_status($domain); + + // 如果启用了自动检查网站内容 + $options = get_option('wpicp_options'); + if(isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes' && + isset($options['scheduled_check']) && $options['scheduled_check'] != 'no') { + + // 记录上次检查时间 + $last_check = get_option('wpicp_last_scheduled_check'); + $now = time(); + + $check_interval = DAY_IN_SECONDS; // 默认一天 + + switch($options['scheduled_check']) { + case 'daily': + $check_interval = DAY_IN_SECONDS; + break; + case 'weekly': + $check_interval = 7 * DAY_IN_SECONDS; + break; + case 'monthly': + $check_interval = 30 * DAY_IN_SECONDS; + break; + } + + // 如果到了检查时间 + if(!$last_check || ($now - $last_check) >= $check_interval) { + // 构造POST数据 + $_POST['check_posts'] = 1; + $_POST['check_pages'] = 1; + $_POST['check_comments'] = 1; + $_POST['check_links'] = 1; + $_POST['check_beian_info'] = 1; + + // 执行合规检查 + $check_results = $core->check_site_compliance(); + + // 保存检查结果 + update_option('wpicp_last_check_results', $check_results); + update_option('wpicp_last_scheduled_check', $now); + + // 如果有问题,发送邮件通知 + if(!empty($check_results['issues'])) { + $this->send_compliance_notification($check_results); + } + } + } + } + + /** + * 新增 - 发送合规检查通知邮件 + */ + private function send_compliance_notification($check_results) { + $admin_email = get_option('admin_email'); + $site_name = get_bloginfo('name'); + $issues_count = count($check_results['issues']); + + $subject = sprintf(__('[%s] 网站合规性检查发现 %d 个问题', 'wpicp'), $site_name, $issues_count); + + $message = sprintf(__('网站"%s"的自动合规性检查发现了 %d 个潜在问题。', 'wpicp'), $site_name, $issues_count) . "\n\n"; + $message .= __('问题摘要:', 'wpicp') . "\n"; + + foreach($check_results['issues'] as $index => $issue) { + if($index < 10) { // 只显示前10个问题 + $message .= sprintf( + "%d. [%s] %s - %s\n", + $index + 1, + $issue['type'], + $issue['location'], + $issue['details'] + ); + } + } + + if($issues_count > 10) { + $message .= sprintf(__('... 和其他 %d 个问题。', 'wpicp'), $issues_count - 10) . "\n"; + } + + $message .= "\n" . __('请登录管理后台查看详细信息并采取措施解决这些问题。', 'wpicp') . "\n"; + $message .= admin_url('admin.php?page=wpicp-compliance') . "\n\n"; + $message .= __('此邮件由系统自动发送,请勿回复。', 'wpicp'); + + wp_mail($admin_email, $subject, $message); + } + + /** + * 检查发布的文章内容 + */ + public function check_post_content($post_id, $post, $update) { + // 如果是自动保存或者不是发布状态,则跳过 + if(wp_is_post_autosave($post_id) || wp_is_post_revision($post_id) || $post->post_status != 'publish') { + return; + } + + $options = get_option('wpicp_options'); + + // 检查是否启用了敏感内容检查和发布前检查 + if(isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes' && + isset($options['check_on_publish']) && $options['check_on_publish'] != 'no') { + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 检查标题和内容 + $content_issues = $core->check_content_for_sensitive_words($post->post_title . ' ' . $post->post_content); + + if(!empty($content_issues)) { + // 创建警告消息 + $warning = __('警告:文章中包含敏感内容:', 'wpicp') . "\n"; + + foreach($content_issues as $issue) { + $warning .= sprintf( + "- %s (%s,级别:%d)\n", + $issue['word'], + $issue['category'], + $issue['level'] + ); + } + + // 如果设置为阻止发布 + if($options['check_on_publish'] == 'block') { + // 将文章状态改为草稿 + wp_update_post(array( + 'ID' => $post_id, + 'post_status' => 'draft' + )); + + // 添加错误消息 + add_filter('redirect_post_location', function($location) use ($warning) { + return add_query_arg('wpicp_content_blocked', urlencode($warning), $location); + }); + } else { + // 只显示警告 + add_filter('redirect_post_location', function($location) use ($warning) { + return add_query_arg('wpicp_content_warning', urlencode($warning), $location); + }); + } + } + } + } + + /** + * 检查评论内容 + */ + public function check_comment_content($comment_id, $comment_approved, $comment_data) { + // 如果评论已经被屏蔽,跳过 + if($comment_approved === 'spam' || $comment_approved === 'trash') { + return; + } + + $options = get_option('wpicp_options'); + + // 检查是否启用了敏感内容检查 + if(isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes') { + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 获取评论内容 + $comment = get_comment($comment_id); + + // 检查评论内容 + $content_issues = $core->check_content_for_sensitive_words($comment->comment_content); + + if(!empty($content_issues)) { + // 更改评论状态为待审核 + wp_set_comment_status($comment_id, '0'); + + // 添加说明 + $note = __('【自动审核】检测到敏感内容:', 'wpicp') . "\n"; + + foreach($content_issues as $issue) { + $note .= sprintf( + "- %s (%s,级别:%d)\n", + $issue['word'], + $issue['category'], + $issue['level'] + ); + } + + // 添加元数据 + add_comment_meta($comment_id, 'wpicp_sensitive_content', $note); + } + } + } + + /** + * 过滤文章内容 + */ + public function filter_post_content($content) { + $options = get_option('wpicp_options'); + + // 检查是否启用了敏感内容检查 + if(isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes') { + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 检查内容 + $content_issues = $core->check_content_for_sensitive_words($content); + + if(!empty($content_issues)) { + // 在编辑界面添加警告 + if(is_admin()) { + $warning = '

' . __('警告:检测到敏感内容:', 'wpicp') . '

'; + + // 将警告添加到内容的顶部 + $content = $warning . $content; + } + } + } + + return $content; + } + + /** + * 过滤评论内容 + */ + public function filter_comment_content($content) { + $options = get_option('wpicp_options'); + + // 检查是否启用了敏感内容检查 + if(isset($options['enable_sensitive_check']) && $options['enable_sensitive_check'] == 'yes' && is_admin()) { + // 获取当前评论ID + $comment_id = 0; + if(isset($_GET['c']) && is_numeric($_GET['c'])) { + $comment_id = intval($_GET['c']); + } elseif(isset($_GET['comment']) && is_numeric($_GET['comment'])) { + $comment_id = intval($_GET['comment']); + } + + // 如果有敏感内容标记,显示警告 + if($comment_id > 0) { + $sensitive_content = get_comment_meta($comment_id, 'wpicp_sensitive_content', true); + + if(!empty($sensitive_content)) { + $warning = '

' . __('系统检测:', 'wpicp') . ' ' . nl2br(esc_html($sensitive_content)) . '

'; + + // 将警告添加到内容的顶部 + $content = $warning . $content; + } + } + } + + return $content; + } + + /** + * 新增 - 处理实名信息表单提交 + */ + public function handle_real_name_form() { + // 验证nonce + if(!isset($_POST['wpicp_nonce']) || !wp_verify_nonce($_POST['wpicp_nonce'], 'wpicp_save_real_name')) { + wp_die(__('安全验证失败,请重试。', 'wpicp')); + } + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 收集表单数据 + $data = array( + 'entity_type' => sanitize_text_field($_POST['entity_type']), + 'entity_name' => sanitize_text_field($_POST['entity_name']), + 'id_type' => sanitize_text_field($_POST['id_type']), + 'contact_phone' => sanitize_text_field($_POST['contact_phone']), + 'contact_email' => sanitize_text_field($_POST['contact_email']), + 'domain' => sanitize_text_field($_POST['domain']), + 'server_location' => sanitize_text_field($_POST['server_location']), + 'verification_status' => 'pending', + 'verification_method' => sanitize_text_field($_POST['verification_method']) + ); + + // 如果提供了ID号码,添加到数据中 + if(!empty($_POST['id_number'])) { + $data['id_number'] = sanitize_text_field($_POST['id_number']); + } + + // 保存或更新数据 + if(isset($_POST['record_id']) && !empty($_POST['record_id'])) { + $record_id = intval($_POST['record_id']); + $success = $core->update_real_name_info($record_id, $data); + $message = __('实名认证信息已更新。', 'wpicp'); + } else { + $record_id = $core->add_real_name_info($data); + $success = ($record_id !== false); + $message = __('实名认证信息已保存。请上传验证材料或进行API验证。', 'wpicp'); + } + + // 重定向到结果页面 + if($success) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'message' => urlencode($message) + ), admin_url('admin.php'))); + } else { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'error' => urlencode(__('保存信息时出错,请重试。', 'wpicp')) + ), admin_url('admin.php'))); + } + + exit; + } + + /** + * 新增 - 处理验证文件上传 + */ + public function handle_verification_upload() { + // 验证nonce + if(!isset($_POST['wpicp_nonce']) || !wp_verify_nonce($_POST['wpicp_nonce'], 'wpicp_upload_verification')) { + wp_die(__('安全验证失败,请重试。', 'wpicp')); + } + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + $record_id = isset($_POST['record_id']) ? intval($_POST['record_id']) : 0; + + if($record_id <= 0) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'error' => urlencode(__('无效的记录ID。', 'wpicp')) + ), admin_url('admin.php'))); + exit; + } + + // 检查文件上传 + if(!isset($_FILES['verification_proof']) || $_FILES['verification_proof']['error'] != UPLOAD_ERR_OK) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'error' => urlencode(__('文件上传失败,请重试。', 'wpicp')) + ), admin_url('admin.php'))); + exit; + } + + // 设置允许的文件类型 + $allowed_types = array('jpg', 'jpeg', 'png', 'pdf'); + $file_type = pathinfo($_FILES['verification_proof']['name'], PATHINFO_EXTENSION); + + if(!in_array(strtolower($file_type), $allowed_types)) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'error' => urlencode(__('不支持的文件类型,请上传JPG、PNG或PDF文件。', 'wpicp')) + ), admin_url('admin.php'))); + exit; + } + + // 上传文件 + $upload_dir = wp_upload_dir(); + $target_dir = $upload_dir['basedir'] . '/wpicp-verification/'; + + // 创建目录(如果不存在) + if(!file_exists($target_dir)) { + mkdir($target_dir, 0755, true); + } + + // 创建索引文件防止目录浏览 + if(!file_exists($target_dir . 'index.php')) { + file_put_contents($target_dir . 'index.php', 'verify_real_name_info($record_id, 'manual', 'pending', $file_url); + + if($success) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'message' => urlencode(__('验证文件已上传,等待审核。', 'wpicp')) + ), admin_url('admin.php'))); + } else { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'error' => urlencode(__('更新数据库时出错。', 'wpicp')) + ), admin_url('admin.php'))); + } + } else { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-verification', + 'action' => 'edit', + 'id' => $record_id, + 'error' => urlencode(__('移动上传文件时出错。', 'wpicp')) + ), admin_url('admin.php'))); + } + + exit; + } + + /** + * 新增 - 处理敏感词导入 + */ + public function handle_sensitive_words_import() { + // 验证nonce + if(!isset($_POST['wpicp_nonce']) || !wp_verify_nonce($_POST['wpicp_nonce'], 'wpicp_import_sensitive_words')) { + wp_die(__('安全验证失败,请重试。', 'wpicp')); + } + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 检查文件上传 + if(!isset($_FILES['words_file']) || $_FILES['words_file']['error'] != UPLOAD_ERR_OK) { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-sensitive', + 'error' => urlencode(__('文件上传失败,请重试。', 'wpicp')) + ), admin_url('admin.php'))); + exit; + } + + // 读取文件内容 + $file_type = pathinfo($_FILES['words_file']['name'], PATHINFO_EXTENSION); + $words_array = array(); + + if($file_type == 'csv') { + $file = fopen($_FILES['words_file']['tmp_name'], 'r'); + + while(($line = fgetcsv($file)) !== false) { + if(count($line) >= 1) { + $word_data = array( + 'word' => $line[0], + 'category' => isset($line[1]) ? $line[1] : 'general', + 'level' => isset($line[2]) ? intval($line[2]) : 1 + ); + + $words_array[] = $word_data; + } + } + + fclose($file); + } elseif($file_type == 'txt') { + $content = file_get_contents($_FILES['words_file']['tmp_name']); + $lines = explode("\n", $content); + + foreach($lines as $line) { + $line = trim($line); + if(!empty($line)) { + $parts = explode(',', $line); + + $word_data = array( + 'word' => $parts[0], + 'category' => isset($parts[1]) ? $parts[1] : 'general', + 'level' => isset($parts[2]) ? intval($parts[2]) : 1 + ); + + $words_array[] = $word_data; + } + } + } else { + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-sensitive', + 'error' => urlencode(__('不支持的文件类型,请上传CSV或TXT文件。', 'wpicp')) + ), admin_url('admin.php'))); + exit; + } + + // 导入敏感词 + $count = $core->import_sensitive_words($words_array); + + wp_redirect(add_query_arg(array( + 'page' => 'wpicp-sensitive', + 'message' => urlencode(sprintf(__('成功导入 %d 个敏感词。', 'wpicp'), $count)) + ), admin_url('admin.php'))); + + exit; + } + + /** + * 新增 - 处理敏感词导出 + */ + public function handle_sensitive_words_export() { + // 验证nonce + if(!isset($_POST['wpicp_nonce']) || !wp_verify_nonce($_POST['wpicp_nonce'], 'wpicp_export_sensitive_words')) { + wp_die(__('安全验证失败,请重试。', 'wpicp')); + } + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + + // 导出敏感词 + $core->export_sensitive_words(); + exit; + } +} diff --git a/assets/admin.css b/assets/admin.css new file mode 100644 index 0000000..67f9131 --- /dev/null +++ b/assets/admin.css @@ -0,0 +1,537 @@ +/* WPBan Pro Admin Styles - WordPress Native Experience */ + +.wpban-wrap { + margin-top: 20px; + max-width: 1400px; +} + +/* Dashboard Grid */ +.wpban-dashboard { + margin-top: 20px; +} + +.wpban-stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 20px; + margin-bottom: 30px; +} + +.wpban-stat-card { + background: #fff; + border: 1px solid #c3c4c7; + padding: 20px; + text-align: center; + box-shadow: 0 1px 1px rgba(0,0,0,0.04); + position: relative; + transition: all 0.3s ease; +} + +.wpban-stat-card:hover { + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + transform: translateY(-2px); +} + +.wpban-stat-card h3 { + margin: 0 0 10px 0; + font-size: 14px; + font-weight: 600; + color: #1d2327; +} + +.wpban-stat-number { + font-size: 36px; + font-weight: 300; + color: #2271b1; + line-height: 1; +} + +.wpban-stat-trend { + margin-top: 10px; + font-size: 12px; +} + +.wpban-stat-trend .up { + color: #d63638; +} + +.wpban-stat-trend .down { + color: #00a32a; +} + +/* Grid Layout */ +.wpban-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + margin-bottom: 20px; +} + +@media (max-width: 1200px) { + .wpban-grid { + grid-template-columns: 1fr; + } +} + +/* Cards */ +.wpban-card { + background: #fff; + border: 1px solid #c3c4c7; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0 1px 1px rgba(0,0,0,0.04); +} + +.wpban-card h2 { + margin: 0 0 15px 0; + font-size: 1.3em; + font-weight: 600; + color: #1d2327; +} + +.wpban-card h3 { + margin: 20px 0 10px 0; + font-size: 1.1em; + font-weight: 600; +} + +/* Actions */ +.wpban-actions { + display: flex; + gap: 10px; + margin: 20px 0; + flex-wrap: wrap; +} + +/* Bypass URL */ +.wpban-bypass-url { + margin: 20px 0; +} + +.wpban-bypass-url label { + display: block; + margin-bottom: 10px; + font-weight: 600; +} + +.wpban-input-group { + display: flex; + gap: 10px; + margin-bottom: 10px; +} + +.wpban-input-group input { + flex: 1; +} + +/* Templates Grid */ +.wpban-templates-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 20px; +} + +.wpban-template-card { + background: #f6f7f7; + border: 1px solid #dcdcde; + padding: 20px; + border-radius: 4px; + transition: all 0.2s; +} + +.wpban-template-card:hover { + background: #fff; + border-color: #2271b1; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.wpban-template-card h3 { + margin: 0 0 10px 0; + font-size: 16px; + font-weight: 600; +} + +.wpban-template-card p { + margin: 0 0 15px 0; + color: #50575e; + font-size: 13px; + line-height: 1.5; +} + +/* Tabs */ +.wpban-tabs { + margin-top: 20px; +} + +.tab-content { + display: none; + background: #fff; + border: 1px solid #c3c4c7; + border-top: none; + padding: 20px; +} + +.tab-content.active { + display: block; +} + +.tab-content h2 { + margin-top: 0; +} + +/* Crawler Controls */ +.wpban-crawler-controls { + margin-bottom: 20px; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +/* Crawler Grid */ +.wpban-crawler-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 10px; + margin-bottom: 30px; +} + +.wpban-crawler-item { + display: block; + padding: 12px; + background: #f6f7f7; + border: 1px solid #dcdcde; + cursor: pointer; + transition: all 0.2s; +} + +.wpban-crawler-item:hover { + background: #fff; + border-color: #2271b1; +} + +.wpban-crawler-item input[type="checkbox"] { + margin-right: 8px; +} + +.wpban-crawler-name { + font-weight: 600; + display: inline-block; + margin-right: 8px; + font-family: Consolas, Monaco, monospace; + font-size: 13px; +} + +.wpban-crawler-desc { + font-size: 12px; + color: #50575e; + display: inline; +} + +/* Notices */ +.wpban-notice { + padding: 12px; + margin: 15px 0; + border-left: 4px solid; + background: #fff; +} + +.wpban-notice-warning { + border-left-color: #f0b849; + background-color: #fef8ee; +} + +.wpban-notice-warning p { + margin: 0; +} + +/* Logs */ +.wpban-logs-filters { + background: #fff; + border: 1px solid #c3c4c7; + padding: 15px; + margin-bottom: 20px; +} + +.wpban-logs-filters form { + display: flex; + gap: 10px; + align-items: center; + flex-wrap: wrap; +} + +.wpban-logs-filters input[type="date"], +.wpban-logs-filters input[type="text"], +.wpban-logs-filters select { + height: 30px; + line-height: 28px; +} + +/* Badges */ +.wpban-badge { + display: inline-block; + padding: 3px 8px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; +} + +.wpban-badge-banned { + background: #d63638; + color: #fff; +} + +.wpban-badge-blocked { + background: #f0b849; + color: #000; +} + +.wpban-badge-failed_login { + background: #dba617; + color: #fff; +} + +.wpban-badge-bypass { + background: #00a32a; + color: #fff; +} + +/* Truncate */ +.wpban-truncate { + display: inline-block; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: middle; +} + +/* Country Selector */ +.wpban-country-selector select { + font-family: Consolas, Monaco, monospace; + font-size: 13px; +} + +/* Rate Limit Settings */ +.form-table input[type="number"] { + width: 80px; +} + +/* Tools Grid */ +.wpban-tools-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: 20px; +} + +/* Chart Container */ +#wpban-country-chart { + max-height: 300px; +} + +/* Activity List */ +.wpban-activity-list { + margin: 0; + padding: 0; + list-style: none; +} + +.wpban-activity-list li { + padding: 8px 0; + border-bottom: 1px solid #f0f0f1; +} + +.wpban-activity-list li:last-child { + border-bottom: none; +} + +/* Form Elements */ +.form-table textarea.code { + font-family: Consolas, Monaco, monospace; + font-size: 13px; + line-height: 1.5; +} + +/* Pagination */ +.tablenav-pages { + margin: 20px 0; + text-align: right; +} + +.tablenav-pages .pagination-links { + display: inline-block; +} + +.tablenav-pages a, +.tablenav-pages span { + display: inline-block; + padding: 3px 8px; + margin: 0 2px; + background: #f6f7f7; + border: 1px solid #dcdcde; + text-decoration: none; +} + +.tablenav-pages .current { + background: #2271b1; + color: #fff; + border-color: #2271b1; +} + +/* Responsive Tables */ +@media (max-width: 782px) { + .wp-list-table { + display: block; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .wpban-stats-grid { + grid-template-columns: 1fr; + } + + .wpban-templates-grid { + grid-template-columns: 1fr; + } + + .wpban-crawler-grid { + grid-template-columns: 1fr; + } + + .wpban-tools-grid { + grid-template-columns: 1fr; + } + + .wpban-logs-filters form { + flex-direction: column; + align-items: stretch; + } + + .wpban-logs-filters input, + .wpban-logs-filters select, + .wpban-logs-filters button { + width: 100%; + margin-bottom: 10px; + } +} + +/* Loading States */ +.wpban-loading { + opacity: 0.6; + pointer-events: none; + position: relative; +} + +.wpban-loading::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 20px; + height: 20px; + margin: -10px 0 0 -10px; + border: 2px solid #f3f3f3; + border-top: 2px solid #2271b1; + border-radius: 50%; + animation: wpban-spin 1s linear infinite; +} + +@keyframes wpban-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Buttons */ +.button.button-small { + padding: 0 8px; + line-height: 26px; + height: 28px; + font-size: 12px; +} + +/* WP Editor in Settings */ +.tab-content .wp-editor-wrap { + margin-top: 10px; +} + +/* Empty States */ +.wpban-empty-state { + text-align: center; + padding: 40px; + color: #646970; +} + +.wpban-empty-state p { + font-size: 16px; + margin: 0; +} + +/* Success/Error Messages */ +.wpban-message { + padding: 12px; + margin: 15px 0; + border-left: 4px solid; + background: #fff; + animation: wpban-fade-in 0.3s ease; +} + +.wpban-message.success { + border-left-color: #00a32a; + background-color: #f0f8f0; +} + +.wpban-message.error { + border-left-color: #d63638; + background-color: #fef1f1; +} + +@keyframes wpban-fade-in { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Row Actions */ +.row-actions { + font-size: 12px; + padding-top: 4px; +} + +.row-actions a { + text-decoration: none; +} + +/* Status Indicators */ +.wpban-status { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + margin-right: 5px; +} + +.wpban-status.active { + background: #00a32a; +} + +.wpban-status.inactive { + background: #787c82; +} + +/* Code Preview */ +.wpban-code-preview { + background: #f6f7f7; + border: 1px solid #dcdcde; + padding: 15px; + font-family: Consolas, Monaco, monospace; + font-size: 13px; + overflow-x: auto; + white-space: pre; + max-height: 300px; + overflow-y: auto; +} \ No newline at end of file diff --git a/assets/admin.js b/assets/admin.js new file mode 100644 index 0000000..4c791e8 --- /dev/null +++ b/assets/admin.js @@ -0,0 +1,335 @@ +/** + * WPBan Pro Admin JavaScript + */ + +(function($) { + 'use strict'; + + // Tab Navigation + $(document).on('click', '.nav-tab', function(e) { + e.preventDefault(); + const target = $(this).attr('href'); + + $('.nav-tab').removeClass('nav-tab-active'); + $(this).addClass('nav-tab-active'); + + $('.tab-content').removeClass('active'); + $(target).addClass('active'); + + // Save active tab to localStorage + localStorage.setItem('wpban_active_tab', target); + }); + + // Restore active tab + $(document).ready(function() { + const activeTab = localStorage.getItem('wpban_active_tab'); + if (activeTab && $(activeTab).length) { + $('.nav-tab[href="' + activeTab + '"]').trigger('click'); + } + }); + + // Settings Form Handler + $('#wpban-settings-form').on('submit', function(e) { + e.preventDefault(); + + const $form = $(this); + const $button = $('#wpban-save-settings'); + const $spinner = $button.next('.spinner'); + + $button.prop('disabled', true); + $spinner.addClass('is-active'); + + $.ajax({ + url: wpban.ajax_url, + type: 'POST', + data: { + action: 'wpban_save_settings', + settings: $form.serialize(), + _ajax_nonce: $('#wpban_nonce').val() + }, + success: function(response) { + if (response.success) { + showMessage('success', response.data.message); + } else { + showMessage('error', response.data || wpban.i18n.error); + } + }, + error: function() { + showMessage('error', wpban.i18n.error); + }, + complete: function() { + $button.prop('disabled', false); + $spinner.removeClass('is-active'); + } + }); + }); + + // Apply Template + window.wpbanApplyTemplate = function(templateId) { + if (!confirm(wpban.i18n.confirm_template)) { + return; + } + + $.post(wpban.ajax_url, { + action: 'wpban_apply_template', + template: templateId, + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + showMessage('success', response.data.message); + setTimeout(() => location.reload(), 1500); + } else { + showMessage('error', response.data || wpban.i18n.error); + } + }); + }; + + // Copy Text to Clipboard + window.wpbanCopyText = function(text) { + navigator.clipboard.writeText(text).then(() => { + showMessage('success', 'Copied to clipboard!'); + }).catch(() => { + // Fallback for older browsers + const $temp = $(''); + $('body').append($temp); + $temp.val(text).select(); + document.execCommand('copy'); + $temp.remove(); + showMessage('success', 'Copied to clipboard!'); + }); + }; + + // Crawler Selection + window.wpbanSelectCrawlers = function(type, select) { + if (type === 'all') { + $('.wpban-crawler-item input').prop('checked', select); + } else { + $(`.wpban-crawler-item[data-type="${type}"] input`).prop('checked', select); + } + }; + + // Export Logs + window.wpbanExportLogs = function() { + window.location.href = wpban.ajax_url + '?action=wpban_export_logs&_ajax_nonce=' + wpban.nonce; + }; + + // Clear Logs + window.wpbanClearLogs = function() { + if (!confirm(wpban.i18n.confirm_clear)) { + return; + } + + $.post(wpban.ajax_url, { + action: 'wpban_clear_logs', + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + showMessage('success', response.data.message); + setTimeout(() => location.reload(), 1500); + } + }); + }; + + // Test Email + window.wpbanTestEmail = function() { + const $button = event.target; + $button.disabled = true; + + $.post(wpban.ajax_url, { + action: 'wpban_test_email', + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + showMessage('success', response.data.message); + } else { + showMessage('error', response.data || wpban.i18n.error); + } + }).always(function() { + $button.disabled = false; + }); + }; + + // Export Settings + window.wpbanExportSettings = function() { + $.get(wpban.ajax_url, { + action: 'wpban_export_settings', + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + const blob = new Blob([response.data], {type: 'application/json'}); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'wpban-settings-' + new Date().toISOString().split('T')[0] + '.json'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + }); + }; + + // Optimize Database + window.wpbanOptimizeDatabase = function() { + const $button = event.target; + $button.disabled = true; + + $.post(wpban.ajax_url, { + action: 'wpban_optimize_database', + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + showMessage('success', 'Database optimized successfully!'); + } + }).always(function() { + $button.disabled = false; + }); + }; + + // Clear Old Logs + window.wpbanClearOldLogs = function() { + if (!confirm('This will permanently delete all logs older than 30 days. Continue?')) { + return; + } + + $.post(wpban.ajax_url, { + action: 'wpban_clear_old_logs', + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + showMessage('success', response.data.message); + setTimeout(() => location.reload(), 1500); + } + }); + }; + + // Live Search for Crawlers + let searchTimeout; + $(document).on('input', '#wpban-crawler-search', function() { + const query = $(this).val().toLowerCase(); + clearTimeout(searchTimeout); + + searchTimeout = setTimeout(() => { + $('.wpban-crawler-item').each(function() { + const $item = $(this); + const text = $item.text().toLowerCase(); + $item.toggle(text.indexOf(query) > -1); + }); + }, 300); + }); + + // Real-time Log Updates (optional) + if ($('#wpban-logs-container').length) { + // Auto-refresh logs every 30 seconds + setInterval(function() { + if (document.visibilityState === 'visible') { + refreshLogs(); + } + }, 30000); + } + + function refreshLogs() { + const params = new URLSearchParams(window.location.search); + + $.get(wpban.ajax_url, { + action: 'wpban_get_logs', + page: params.get('paged') || 1, + date_from: params.get('date_from'), + date_to: params.get('date_to'), + action_filter: params.get('action_filter'), + ip_filter: params.get('ip_filter'), + _ajax_nonce: wpban.nonce + }, function(response) { + if (response.success) { + $('#wpban-logs-container tbody').html(response.data.html); + } + }); + } + + // Show Message + function showMessage(type, message) { + const $message = $('
') + .addClass('wpban-message ' + type) + .text(message) + .prependTo('.wpban-wrap') + .hide() + .fadeIn(); + + setTimeout(() => { + $message.fadeOut(() => $message.remove()); + }, 5000); + } + + // Geo Blocking Mode Toggle + $('input[name="settings[geo_blocking][mode]"]').on('change', function() { + const mode = $(this).val(); + const $label = $('.wpban-country-selector').prev('th').find('label'); + + if (mode === 'whitelist') { + $label.text('Allowed Countries'); + } else { + $label.text('Blocked Countries'); + } + }); + + // Initialize Select2 for country selector (if available) + if ($.fn.select2) { + $('.wpban-country-selector select').select2({ + placeholder: 'Select countries...', + width: '100%' + }); + } + + // Handle browser restrictions toggle + $('input[name="settings[browser_restrictions][wechat_qq][enabled]"]').on('change', function() { + const $fields = $(this).closest('table').find('tr').not(':first'); + $fields.toggle($(this).is(':checked')); + }).trigger('change'); + + // Email notifications toggle + $('input[name="settings[email_notifications][enabled]"]').on('change', function() { + const $fields = $(this).closest('table').find('tr').not(':first'); + $fields.toggle($(this).is(':checked')); + }).trigger('change'); + + // Geo blocking toggle + $('input[name="settings[geo_blocking][enabled]"]').on('change', function() { + const $fields = $(this).closest('table').find('tr').not(':first'); + $fields.toggle($(this).is(':checked')); + }).trigger('change'); + + // Keyboard shortcuts + $(document).on('keydown', function(e) { + // Ctrl/Cmd + S to save + if ((e.ctrlKey || e.metaKey) && e.key === 's') { + e.preventDefault(); + $('#wpban-save-settings').trigger('click'); + } + }); + + // Tooltip initialization + $('.wpban-tooltip').tooltip({ + position: { + my: 'center bottom-10', + at: 'center top' + } + }); + + // Confirm before leaving with unsaved changes + let formChanged = false; + $('#wpban-settings-form').on('change', 'input, select, textarea', function() { + formChanged = true; + }); + + window.addEventListener('beforeunload', function(e) { + if (formChanged) { + e.preventDefault(); + e.returnValue = 'You have unsaved changes. Are you sure you want to leave?'; + } + }); + + $('#wpban-save-settings').on('click', function() { + formChanged = false; + }); + +})(jQuery); \ No newline at end of file diff --git a/includes/class-wpicp-core.php b/includes/class-wpicp-core.php new file mode 100644 index 0000000..061596b --- /dev/null +++ b/includes/class-wpicp-core.php @@ -0,0 +1,1388 @@ +load_sensitive_words(); + } + + /** + * 创建数据库表 + */ + public function create_database_tables() { + global $wpdb; + + $charset_collate = $wpdb->get_charset_collate(); + + // 创建ICP备案记录表 + $table_name = $wpdb->prefix . 'wpicp_records'; + $sql = "CREATE TABLE IF NOT EXISTS $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + name varchar(255) NOT NULL, + icp_number varchar(100) NOT NULL, + domain varchar(255) DEFAULT '' NOT NULL, + approval_date date DEFAULT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id) + ) $charset_collate;"; + + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); + + // 创建敏感词表 + $table_name = $wpdb->prefix . 'wpicp_sensitive_words'; + $sql = "CREATE TABLE IF NOT EXISTS $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + word varchar(255) NOT NULL, + category varchar(100) DEFAULT 'general' NOT NULL, + level tinyint(1) DEFAULT 1 NOT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY word (word) + ) $charset_collate;"; + + dbDelta($sql); + + // 新增 - 创建实名认证信息表 + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + $sql = "CREATE TABLE IF NOT EXISTS $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + entity_type varchar(50) NOT NULL, + entity_name varchar(255) NOT NULL, + id_type varchar(50) NOT NULL, + id_number varchar(255) NOT NULL, + contact_phone varchar(50) NOT NULL, + contact_email varchar(100) NOT NULL, + domain varchar(255) NOT NULL, + server_location varchar(255) NOT NULL, + verification_status varchar(50) DEFAULT 'pending' NOT NULL, + verification_method varchar(50) DEFAULT 'manual' NOT NULL, + verification_date datetime DEFAULT NULL, + verification_proof varchar(255) DEFAULT '' NOT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id) + ) $charset_collate;"; + + dbDelta($sql); + + // 新增 - 创建备案历史记录表 + $table_name = $wpdb->prefix . 'wpicp_record_history'; + $sql = "CREATE TABLE IF NOT EXISTS $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + record_id mediumint(9) NOT NULL, + action varchar(50) NOT NULL, + data text NOT NULL, + user_id bigint(20) UNSIGNED NOT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id), + KEY record_id (record_id) + ) $charset_collate;"; + + dbDelta($sql); + + // 新增 - 创建备案状态表 + $table_name = $wpdb->prefix . 'wpicp_status'; + $sql = "CREATE TABLE IF NOT EXISTS $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + domain varchar(255) NOT NULL, + icp_status varchar(50) DEFAULT 'unknown' NOT NULL, + police_status varchar(50) DEFAULT 'unknown' NOT NULL, + last_check datetime DEFAULT NULL, + check_result text DEFAULT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY domain (domain) + ) $charset_collate;"; + + dbDelta($sql); + + // 初始化敏感词数据 + $this->initialize_sensitive_words(); + } + + /** + * 初始化敏感词数据 + */ + private function initialize_sensitive_words() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_sensitive_words'; + + // 检查表是否为空 + $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); + + if($count == 0) { + // 添加一些默认敏感词 + $default_words = array( + array('word' => '政治敏感词1', 'category' => 'politics', 'level' => 3), + array('word' => '政治敏感词2', 'category' => 'politics', 'level' => 3), + array('word' => '违法词1', 'category' => 'illegal', 'level' => 3), + array('word' => '违法词2', 'category' => 'illegal', 'level' => 2), + array('word' => '色情词1', 'category' => 'adult', 'level' => 2), + array('word' => '色情词2', 'category' => 'adult', 'level' => 2), + array('word' => '广告词1', 'category' => 'spam', 'level' => 1), + array('word' => '广告词2', 'category' => 'spam', 'level' => 1), + // 新增更多敏感词 + array('word' => '非法组织', 'category' => 'politics', 'level' => 3), + array('word' => '颠覆', 'category' => 'politics', 'level' => 3), + array('word' => '暴力恐怖', 'category' => 'violence', 'level' => 3), + array('word' => '赌博', 'category' => 'gambling', 'level' => 3), + array('word' => '毒品', 'category' => 'drugs', 'level' => 3), + array('word' => '非法交易', 'category' => 'illegal', 'level' => 3), + array('word' => '侵权内容', 'category' => 'copyright', 'level' => 2), + array('word' => '淫秽色情', 'category' => 'adult', 'level' => 3), + array('word' => '诈骗', 'category' => 'scam', 'level' => 3), + array('word' => '虚假信息', 'category' => 'fake', 'level' => 2) + ); + + foreach($default_words as $word) { + $wpdb->insert( + $table_name, + array( + 'word' => $word['word'], + 'category' => $word['category'], + 'level' => $word['level'], + ) + ); + } + } + } + + /** + * 加载敏感词列表 + */ + private function load_sensitive_words() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_sensitive_words'; + + // 从缓存获取敏感词 + $sensitive_words = get_transient('wpicp_sensitive_words'); + + if($sensitive_words === false) { + // 如果缓存不存在,从数据库加载 + $results = $wpdb->get_results("SELECT word, category, level FROM $table_name", ARRAY_A); + + if($results) { + $sensitive_words = array(); + foreach($results as $row) { + $sensitive_words[] = array( + 'word' => $row['word'], + 'category' => $row['category'], + 'level' => intval($row['level']), + ); + } + + // 保存到缓存,缓存一天 + set_transient('wpicp_sensitive_words', $sensitive_words, DAY_IN_SECONDS); + } else { + $sensitive_words = array(); + } + } + + $this->sensitive_words = $sensitive_words; + } + + /** + * 添加ICP备案记录 + */ + public function add_icp_record($name, $icp_number, $domain = '', $approval_date = '') { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $result = $wpdb->insert( + $table_name, + array( + 'name' => $name, + 'icp_number' => $icp_number, + 'domain' => $domain, + 'approval_date' => $approval_date, + ) + ); + + if($result !== false) { + $record_id = $wpdb->insert_id; + $this->add_record_history($record_id, 'create', array( + 'name' => $name, + 'icp_number' => $icp_number, + 'domain' => $domain, + 'approval_date' => $approval_date + )); + } + + return $result !== false; + } + + /** + * 更新ICP备案记录 + */ + public function update_icp_record($id, $name, $icp_number, $domain = '', $approval_date = '') { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $old_record = $this->get_icp_record($id); + + $result = $wpdb->update( + $table_name, + array( + 'name' => $name, + 'icp_number' => $icp_number, + 'domain' => $domain, + 'approval_date' => $approval_date, + ), + array('id' => $id) + ); + + if($result !== false) { + $this->add_record_history($id, 'update', array( + 'old' => array( + 'name' => $old_record->name, + 'icp_number' => $old_record->icp_number, + 'domain' => $old_record->domain, + 'approval_date' => $old_record->approval_date + ), + 'new' => array( + 'name' => $name, + 'icp_number' => $icp_number, + 'domain' => $domain, + 'approval_date' => $approval_date + ) + )); + } + + return $result !== false; + } + + /** + * 删除ICP备案记录 + */ + public function delete_icp_record($id) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $old_record = $this->get_icp_record($id); + + $result = $wpdb->delete( + $table_name, + array('id' => $id) + ); + + if($result !== false && $old_record) { + $this->add_record_history($id, 'delete', array( + 'name' => $old_record->name, + 'icp_number' => $old_record->icp_number, + 'domain' => $old_record->domain, + 'approval_date' => $old_record->approval_date + )); + } + + return $result !== false; + } + + /** + * 获取单条ICP备案记录 + */ + public function get_icp_record($id) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $result = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $table_name WHERE id = %d", + $id + )); + + return $result; + } + + /** + * 获取所有ICP备案记录 + */ + public function get_all_icp_records() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $results = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC"); + + return $results; + } + + /** + * 导出ICP备案记录 + */ + public function export_icp_records() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_records'; + + $results = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC", ARRAY_A); + + if(!$results) { + wp_die(__('没有记录可供导出', 'wpicp')); + } + + $filename = 'wpicp_records_' . date('Y-m-d') . '.csv'; + + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=' . $filename); + + $output = fopen('php://output', 'w'); + + // 输出CSV标头 + fputcsv($output, array('ID', '名称', 'ICP备案号', '域名', '批准日期', '创建时间', '更新时间')); + + // 输出数据行 + foreach($results as $row) { + fputcsv($output, $row); + } + + fclose($output); + exit; + } + + /** + * 新增 - 添加实名认证信息 + */ + public function add_real_name_info($data) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + // 加密敏感信息 + if(!empty($data['id_number'])) { + $data['id_number'] = $this->encrypt_data($data['id_number']); + } + + $result = $wpdb->insert( + $table_name, + array( + 'entity_type' => $data['entity_type'], + 'entity_name' => $data['entity_name'], + 'id_type' => $data['id_type'], + 'id_number' => $data['id_number'], + 'contact_phone' => $data['contact_phone'], + 'contact_email' => $data['contact_email'], + 'domain' => $data['domain'], + 'server_location' => $data['server_location'], + 'verification_status' => $data['verification_status'], + 'verification_method' => $data['verification_method'] + ) + ); + + return $result !== false ? $wpdb->insert_id : false; + } + + /** + * 新增 - 更新实名认证信息 + */ + public function update_real_name_info($id, $data) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + // 如果ID号码已更改,则重新加密 + if(!empty($data['id_number']) && strpos($data['id_number'], '$P$') !== 0) { + $data['id_number'] = $this->encrypt_data($data['id_number']); + } + + $result = $wpdb->update( + $table_name, + $data, + array('id' => $id) + ); + + return $result !== false; + } + + /** + * 新增 - 获取实名认证信息 + */ + public function get_real_name_info($id) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + $result = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $table_name WHERE id = %d", + $id + )); + + return $result; + } + + /** + * 新增 - 获取实名认证信息(通过域名) + */ + public function get_real_name_info_by_domain($domain) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + $result = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $table_name WHERE domain = %s", + $domain + )); + + return $result; + } + + /** + * 新增 - 获取所有实名认证信息 + */ + public function get_all_real_name_info() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + $results = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC"); + + return $results; + } + + /** + * 新增 - 删除实名认证信息 + */ + public function delete_real_name_info($id) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + $result = $wpdb->delete( + $table_name, + array('id' => $id) + ); + + return $result !== false; + } + + /** + * 新增 - 验证实名认证信息 + */ + public function verify_real_name_info($id, $verification_method, $verification_status, $verification_proof = '') { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_real_name_info'; + + $data = array( + 'verification_status' => $verification_status, + 'verification_method' => $verification_method, + 'verification_date' => current_time('mysql'), + 'verification_proof' => $verification_proof + ); + + $result = $wpdb->update( + $table_name, + $data, + array('id' => $id) + ); + + return $result !== false; + } + + /** + * 新增 - 调用第三方API验证实名信息 + */ + public function verify_identity_with_api($name, $id_type, $id_number) { + $options = get_option('wpicp_options'); + $api_key = isset($options['verification_api_key']) ? $options['verification_api_key'] : ''; + $api_provider = isset($options['verification_api_provider']) ? $options['verification_api_provider'] : ''; + + if(empty($api_key) || empty($api_provider)) { + return array( + 'success' => false, + 'message' => __('API密钥或提供商未配置', 'wpicp') + ); + } + + // 从缓存中获取结果 + $cache_key = 'wpicp_identity_verify_' . md5($name . $id_type . $id_number); + $cached_result = get_transient($cache_key); + + if($cached_result !== false) { + return $cached_result; + } + + // 这里应该是实际的API调用,根据不同的服务提供商调用不同的接口 + // 这里使用模拟数据演示 + switch($api_provider) { + case 'aliyun': + $result = $this->call_aliyun_verify_api($name, $id_type, $id_number, $api_key); + break; + case 'tencent': + $result = $this->call_tencent_verify_api($name, $id_type, $id_number, $api_key); + break; + default: + $result = array( + 'success' => false, + 'message' => __('不支持的API提供商', 'wpicp') + ); + } + + // 缓存结果30天,避免频繁调用API + set_transient($cache_key, $result, 30 * DAY_IN_SECONDS); + + return $result; + } + + /** + * 新增 - 调用阿里云实名认证API(模拟) + */ + private function call_aliyun_verify_api($name, $id_type, $id_number, $api_key) { + // 实际应用中,应该使用阿里云SDK调用实名认证API + // 这里返回模拟数据 + $test_id_number = '123456789012345678'; // 模拟ID号码用于测试 + + if($id_number == $test_id_number) { + return array( + 'success' => true, + 'message' => __('身份验证成功', 'wpicp'), + 'data' => array( + 'verified' => true, + 'score' => 98 + ) + ); + } else { + return array( + 'success' => true, + 'message' => __('身份验证失败,信息不匹配', 'wpicp'), + 'data' => array( + 'verified' => false, + 'score' => 30 + ) + ); + } + } + + /** + * 新增 - 调用腾讯云实名认证API(模拟) + */ + private function call_tencent_verify_api($name, $id_type, $id_number, $api_key) { + // 实际应用中,应该使用腾讯云SDK调用实名认证API + // 这里返回模拟数据 + $test_id_number = '123456789012345678'; // 模拟ID号码用于测试 + + if($id_number == $test_id_number) { + return array( + 'success' => true, + 'message' => __('身份验证成功', 'wpicp'), + 'data' => array( + 'verified' => true, + 'similarity' => 95 + ) + ); + } else { + return array( + 'success' => true, + 'message' => __('身份验证失败,信息不匹配', 'wpicp'), + 'data' => array( + 'verified' => false, + 'similarity' => 40 + ) + ); + } + } + + /** + * 新增 - 检查域名备案状态 + */ + public function check_domain_icp_status($domain) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_status'; + + // 从缓存/数据库获取上次检查结果 + $status = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $table_name WHERE domain = %s", + $domain + )); + + $now = current_time('mysql'); + $last_check_time = $status ? strtotime($status->last_check) : 0; + $check_interval = 24 * 60 * 60; // 24小时 + + // 如果没有记录或者上次检查时间超过24小时,重新检查 + if(!$status || (time() - $last_check_time) > $check_interval) { + $options = get_option('wpicp_options'); + $api_key = isset($options['beian_query_api_key']) ? $options['beian_query_api_key'] : ''; + + if(!empty($api_key)) { + // 实际应用中,应该调用备案状态查询API + // 这里使用模拟数据 + $check_result = $this->query_icp_status_with_api($domain, $api_key); + $icp_status = isset($check_result['icp_status']) ? $check_result['icp_status'] : 'unknown'; + $police_status = isset($check_result['police_status']) ? $check_result['police_status'] : 'unknown'; + } else { + // 手动设置的状态 + $manual_status = get_option('wpicp_manual_status_' . md5($domain), array()); + $icp_status = isset($manual_status['icp_status']) ? $manual_status['icp_status'] : 'unknown'; + $police_status = isset($manual_status['police_status']) ? $manual_status['police_status'] : 'unknown'; + $check_result = $manual_status; + } + + // 更新或插入状态记录 + if($status) { + $wpdb->update( + $table_name, + array( + 'icp_status' => $icp_status, + 'police_status' => $police_status, + 'last_check' => $now, + 'check_result' => maybe_serialize($check_result), + 'updated_at' => $now + ), + array('id' => $status->id) + ); + } else { + $wpdb->insert( + $table_name, + array( + 'domain' => $domain, + 'icp_status' => $icp_status, + 'police_status' => $police_status, + 'last_check' => $now, + 'check_result' => maybe_serialize($check_result), + 'created_at' => $now, + 'updated_at' => $now + ) + ); + } + + // 获取最新记录 + $status = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM $table_name WHERE domain = %s", + $domain + )); + } + + return $status; + } + + /** + * 新增 - API查询ICP备案状态(模拟) + */ + private function query_icp_status_with_api($domain, $api_key) { + // 这里应该是实际的API调用,使用第三方服务查询备案状态 + // 这里使用模拟数据演示 + $test_domains = array( + 'example.com' => array( + 'icp_status' => 'registered', + 'icp_number' => '京ICP备12345678号-1', + 'entity_name' => '示例科技有限公司', + 'approval_date' => '2021-01-15', + 'police_status' => 'registered', + 'police_number' => '京公网安备11010802030294号' + ), + 'example.org' => array( + 'icp_status' => 'not_registered', + 'police_status' => 'not_registered' + ), + 'example.net' => array( + 'icp_status' => 'registered', + 'icp_number' => '沪ICP备87654321号-1', + 'entity_name' => '网络科技有限公司', + 'approval_date' => '2020-11-20', + 'police_status' => 'not_registered' + ) + ); + + // 如果是测试域名之一,返回预设数据 + if(isset($test_domains[$domain])) { + return $test_domains[$domain]; + } + + // 对于其他域名,返回随机状态 + $random = rand(1, 100); + if($random > 70) { + return array( + 'icp_status' => 'registered', + 'icp_number' => '粤ICP备' . rand(10000000, 99999999) . '号-1', + 'entity_name' => '随机公司名称' . rand(1, 100), + 'approval_date' => date('Y-m-d', strtotime('-' . rand(30, 600) . ' days')), + 'police_status' => ($random > 85) ? 'registered' : 'not_registered', + 'police_number' => ($random > 85) ? '粤公网安备' . rand(1000000000, 9999999999) . '号' : '' + ); + } else { + return array( + 'icp_status' => 'not_registered', + 'police_status' => 'not_registered' + ); + } + } + + /** + * 新增 - 手动设置备案状态 + */ + public function set_manual_status($domain, $icp_status, $police_status, $icp_number = '', $police_number = '') { + $status_data = array( + 'icp_status' => $icp_status, + 'police_status' => $police_status, + 'icp_number' => $icp_number, + 'police_number' => $police_number, + 'last_updated' => current_time('mysql') + ); + + update_option('wpicp_manual_status_' . md5($domain), $status_data); + + // 更新状态表 + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_status'; + + $existing = $wpdb->get_row($wpdb->prepare( + "SELECT id FROM $table_name WHERE domain = %s", + $domain + )); + + $now = current_time('mysql'); + + if($existing) { + $wpdb->update( + $table_name, + array( + 'icp_status' => $icp_status, + 'police_status' => $police_status, + 'last_check' => $now, + 'check_result' => maybe_serialize($status_data), + 'updated_at' => $now + ), + array('id' => $existing->id) + ); + } else { + $wpdb->insert( + $table_name, + array( + 'domain' => $domain, + 'icp_status' => $icp_status, + 'police_status' => $police_status, + 'last_check' => $now, + 'check_result' => maybe_serialize($status_data), + 'created_at' => $now, + 'updated_at' => $now + ) + ); + } + + return true; + } + + /** + * 新增 - 获取备案状态提示消息 + */ + public function get_status_message($domain = '') { + if(empty($domain)) { + $domain = parse_url(get_site_url(), PHP_URL_HOST); + } + + $status = $this->check_domain_icp_status($domain); + + if(!$status) { + return array( + 'type' => 'warning', + 'message' => sprintf(__('未找到域名 %s 的备案信息,请尽快进行ICP备案。', 'wpicp'), $domain), + 'icp_status' => 'unknown', + 'police_status' => 'unknown' + ); + } + + $check_result = maybe_unserialize($status->check_result); + $icp_number = isset($check_result['icp_number']) ? $check_result['icp_number'] : ''; + $police_number = isset($check_result['police_number']) ? $check_result['police_number'] : ''; + + // 备案状态提示 + if($status->icp_status == 'registered' && $status->police_status == 'registered') { + return array( + 'type' => 'success', + 'message' => sprintf(__('域名 %s 已完成ICP备案和公安备案。', 'wpicp'), $domain), + 'icp_status' => 'registered', + 'police_status' => 'registered', + 'icp_number' => $icp_number, + 'police_number' => $police_number + ); + } elseif($status->icp_status == 'registered') { + return array( + 'type' => 'info', + 'message' => sprintf(__('域名 %s 已完成ICP备案,但尚未完成公安备案。', 'wpicp'), $domain), + 'icp_status' => 'registered', + 'police_status' => 'not_registered', + 'icp_number' => $icp_number + ); + } else { + return array( + 'type' => 'error', + 'message' => sprintf(__('域名 %s 尚未完成ICP备案,请尽快办理。', 'wpicp'), $domain), + 'icp_status' => 'not_registered', + 'police_status' => 'not_registered' + ); + } + } + + /** + * 新增 - 添加备案记录历史 + */ + private function add_record_history($record_id, $action, $data) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_record_history'; + + $user_id = get_current_user_id(); + + $result = $wpdb->insert( + $table_name, + array( + 'record_id' => $record_id, + 'action' => $action, + 'data' => json_encode($data), + 'user_id' => $user_id + ) + ); + + return $result !== false; + } + + /** + * 新增 - 获取备案记录历史 + */ + public function get_record_history($record_id) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_record_history'; + + $results = $wpdb->get_results($wpdb->prepare( + "SELECT h.*, u.display_name as user_name + FROM $table_name h + LEFT JOIN {$wpdb->users} u ON h.user_id = u.ID + WHERE h.record_id = %d + ORDER BY h.created_at DESC", + $record_id + )); + + foreach($results as &$item) { + $item->data = json_decode($item->data, true); + } + + return $results; + } + + /** + * 验证ICP状态 + */ + public function verify_icp_status() { + $options = get_option('wpicp_options'); + + if(empty($options['icp_number']) || empty($options['api_key']) || $options['verification_method'] != 'api') { + return false; + } + + // 获取缓存的验证结果 + $verification_result = get_transient('wpicp_verification_result'); + + if($verification_result === false) { + // 这里应该是实际的API调用,这里使用模拟数据 + // 实际应用中,应该使用工信部API或第三方服务验证 + $icp_number = $options['icp_number']; + $api_key = $options['api_key']; + $site_url = get_site_url(); + + // 模拟API调用 + $response = array( + 'status' => 'valid', + 'message' => '备案信息有效', + 'verified' => true + ); + + // 保存到缓存,缓存一周 + set_transient('wpicp_verification_result', $response, WEEK_IN_SECONDS); + + return $response; + } + + return $verification_result; + } + + /** + * 检查网站合规性 + */ + public function check_site_compliance() { + $options = get_option('wpicp_options'); + + if(!isset($options['enable_sensitive_check']) || $options['enable_sensitive_check'] != 'yes') { + return false; + } + + $issues = array(); + $total_checked = 0; + + // 检查文章内容 + if(isset($_POST['check_posts']) && $_POST['check_posts'] == '1') { + $posts = get_posts(array( + 'post_type' => 'post', + 'posts_per_page' => 100, + 'post_status' => 'publish' + )); + + $total_checked += count($posts); + + foreach($posts as $post) { + $content_issues = $this->check_content_for_sensitive_words($post->post_title . ' ' . $post->post_content); + + if(!empty($content_issues)) { + foreach($content_issues as $issue) { + $issues[] = array( + 'type' => __('敏感内容', 'wpicp'), + 'location' => sprintf(__('文章: %s (ID: %d)', 'wpicp'), $post->post_title, $post->ID), + 'details' => sprintf(__('发现敏感词: %s (类别: %s)', 'wpicp'), $issue['word'], $issue['category']), + 'suggestion' => __('请检查并修改相关内容', 'wpicp') + ); + } + } + } + } + + // 检查页面内容 + if(isset($_POST['check_pages']) && $_POST['check_pages'] == '1') { + $pages = get_posts(array( + 'post_type' => 'page', + 'posts_per_page' => 50, + 'post_status' => 'publish' + )); + + $total_checked += count($pages); + + foreach($pages as $page) { + $content_issues = $this->check_content_for_sensitive_words($page->post_title . ' ' . $page->post_content); + + if(!empty($content_issues)) { + foreach($content_issues as $issue) { + $issues[] = array( + 'type' => __('敏感内容', 'wpicp'), + 'location' => sprintf(__('页面: %s (ID: %d)', 'wpicp'), $page->post_title, $page->ID), + 'details' => sprintf(__('发现敏感词: %s (类别: %s)', 'wpicp'), $issue['word'], $issue['category']), + 'suggestion' => __('请检查并修改相关内容', 'wpicp') + ); + } + } + } + } + + // 检查评论内容 + if(isset($_POST['check_comments']) && $_POST['check_comments'] == '1') { + $comments = get_comments(array( + 'status' => 'approve', + 'number' => 100 + )); + + $total_checked += count($comments); + + foreach($comments as $comment) { + $content_issues = $this->check_content_for_sensitive_words($comment->comment_content); + + if(!empty($content_issues)) { + foreach($content_issues as $issue) { + $issues[] = array( + 'type' => __('敏感评论', 'wpicp'), + 'location' => sprintf(__('评论ID: %d, 作者: %s', 'wpicp'), $comment->comment_ID, $comment->comment_author), + 'details' => sprintf(__('发现敏感词: %s (类别: %s)', 'wpicp'), $issue['word'], $issue['category']), + 'suggestion' => __('请检查并修改或删除相关评论', 'wpicp') + ); + } + } + } + } + + // 检查外部链接 + if(isset($_POST['check_links']) && $_POST['check_links'] == '1') { + $posts = get_posts(array( + 'post_type' => array('post', 'page'), + 'posts_per_page' => 50, + 'post_status' => 'publish' + )); + + $external_links = array(); + + foreach($posts as $post) { + // 提取所有链接 + preg_match_all('/]*href=([\'"])(.+?)\1[^>]*>/i', $post->post_content, $matches); + + if(!empty($matches[2])) { + foreach($matches[2] as $url) { + if(!empty($url) && strpos($url, get_site_url()) === false && strpos($url, 'http') === 0) { + $external_links[] = array( + 'url' => $url, + 'post_id' => $post->ID, + 'post_title' => $post->post_title + ); + } + } + } + } + + $total_checked += count($external_links); + + // 检查外部链接(实际应用中应该调用API检查链接安全性) + foreach($external_links as $link) { + // 这里使用简单的模拟检查,实际应该使用安全API + $unsafe_domains = array('example.com', 'unsafe-site.com', 'malware-site.net'); + + $domain = parse_url($link['url'], PHP_URL_HOST); + + if(in_array($domain, $unsafe_domains)) { + $issues[] = array( + 'type' => __('不安全链接', 'wpicp'), + 'location' => sprintf(__('文章: %s (ID: %d)', 'wpicp'), $link['post_title'], $link['post_id']), + 'details' => sprintf(__('发现不安全链接: %s', 'wpicp'), $link['url']), + 'suggestion' => __('请检查并移除或替换此链接', 'wpicp') + ); + } + } + } + + // 新增 - 检查备案信息 + if(isset($_POST['check_beian_info']) && $_POST['check_beian_info'] == '1') { + $domain = parse_url(get_site_url(), PHP_URL_HOST); + $status = $this->check_domain_icp_status($domain); + + $total_checked++; + + if(!$status || $status->icp_status != 'registered') { + $issues[] = array( + 'type' => __('备案合规', 'wpicp'), + 'location' => sprintf(__('域名: %s', 'wpicp'), $domain), + 'details' => __('网站尚未完成ICP备案', 'wpicp'), + 'suggestion' => __('请尽快完成ICP备案,以符合中国法律法规要求', 'wpicp') + ); + } + + if(!$status || $status->police_status != 'registered') { + $issues[] = array( + 'type' => __('备案合规', 'wpicp'), + 'location' => sprintf(__('域名: %s', 'wpicp'), $domain), + 'details' => __('网站尚未完成公安备案', 'wpicp'), + 'suggestion' => __('请尽快完成公安备案,以符合中国法律法规要求', 'wpicp') + ); + } + + // 新增 - 检查实名认证情况 + $real_name_info = $this->get_real_name_info_by_domain($domain); + + if(!$real_name_info) { + $issues[] = array( + 'type' => __('实名认证', 'wpicp'), + 'location' => sprintf(__('域名: %s', 'wpicp'), $domain), + 'details' => __('尚未提交实名认证信息', 'wpicp'), + 'suggestion' => __('请提交网站实名认证信息,以便备案使用', 'wpicp') + ); + } elseif($real_name_info->verification_status != 'verified') { + $issues[] = array( + 'type' => __('实名认证', 'wpicp'), + 'location' => sprintf(__('域名: %s', 'wpicp'), $domain), + 'details' => __('实名认证尚未完成或验证失败', 'wpicp'), + 'suggestion' => __('请完成实名认证流程,确保信息准确无误', 'wpicp') + ); + } + } + + return array( + 'issues' => $issues, + 'total_checked' => $total_checked + ); + } + + /** + * 检查内容是否包含敏感词 + */ + private function check_content_for_sensitive_words($content) { + $issues = array(); + + foreach($this->sensitive_words as $word_data) { + $word = $word_data['word']; + + if(mb_stripos($content, $word) !== false) { + $issues[] = array( + 'word' => $word, + 'category' => $word_data['category'], + 'level' => $word_data['level'] + ); + } + } + + return $issues; + } + + /** + * 数据加密 + */ + public function encrypt_data($data) { + if(empty($data)) { + return ''; + } + + // 使用WordPress的加密函数 + return wp_hash_password($data); + } + + /** + * 数据解密验证 + */ + public function verify_encrypted_data($original_data, $encrypted_data) { + return wp_check_password($original_data, $encrypted_data); + } + + /** + * 字符串数据净化 + */ + public function sanitize_data($data) { + return sanitize_text_field($data); + } + + /** + * 新增 - 导入敏感词 + */ + public function import_sensitive_words($words_array) { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_sensitive_words'; + + $count = 0; + + foreach($words_array as $word_data) { + if(empty($word_data['word'])) { + continue; + } + + $word = $this->sanitize_data($word_data['word']); + $category = isset($word_data['category']) ? $this->sanitize_data($word_data['category']) : 'general'; + $level = isset($word_data['level']) ? intval($word_data['level']) : 1; + + // 检查是否已存在 + $exists = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM $table_name WHERE word = %s", + $word + )); + + if($exists) { + // 更新 + $wpdb->update( + $table_name, + array( + 'category' => $category, + 'level' => $level + ), + array('word' => $word) + ); + } else { + // 插入 + $wpdb->insert( + $table_name, + array( + 'word' => $word, + 'category' => $category, + 'level' => $level + ) + ); + + if($wpdb->insert_id) { + $count++; + } + } + } + + // 清除缓存 + delete_transient('wpicp_sensitive_words'); + + // 重新加载 + $this->load_sensitive_words(); + + return $count; + } + + /** + * 新增 - 导出敏感词 + */ + public function export_sensitive_words() { + global $wpdb; + $table_name = $wpdb->prefix . 'wpicp_sensitive_words'; + + $words = $wpdb->get_results("SELECT word, category, level FROM $table_name ORDER BY category, word", ARRAY_A); + + if(!$words) { + wp_die(__('没有敏感词可供导出', 'wpicp')); + } + + $filename = 'wpicp_sensitive_words_' . date('Y-m-d') . '.csv'; + + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=' . $filename); + + $output = fopen('php://output', 'w'); + + // 输出CSV标头 + fputcsv($output, array('敏感词', '类别', '级别')); + + // 输出数据行 + foreach($words as $row) { + fputcsv($output, $row); + } + + fclose($output); + exit; + } + + /** + * 新增 - 获取备案指南数据 + */ + public function get_beian_guide_data($province = '') { + // 这里应该从配置或数据库中加载不同省份的备案指南 + // 这里使用静态数据演示 + + $general_guide = array( + 'title' => __('ICP备案和公安备案指南', 'wpicp'), + 'description' => __('根据《中华人民共和国网络安全法》和工信部相关规定,在中国境内提供网站服务需要进行ICP备案和公安备案。', 'wpicp'), + 'steps' => array( + array( + 'title' => __('第一步:准备资料', 'wpicp'), + 'content' => __('1. 域名证书:确保域名在有效期内,且实名认证信息与备案主体一致。
2. 主体证件:个人需提供身份证正反面,企业需提供营业执照副本。
3. 网站负责人证件:身份证正反面、手持身份证照片。
4. 真实有效的联系方式:手机号码和电子邮箱。', 'wpicp') + ), + array( + 'title' => __('第二步:选择服务接入商', 'wpicp'), + 'content' => __('通过您的云服务提供商(如阿里云、腾讯云等)提交备案申请,他们会提供备案系统和相关支持。', 'wpicp') + ), + array( + 'title' => __('第三步:填写资料', 'wpicp'), + 'content' => __('1. 登录服务商备案系统,填写备案信息。
2. 上传所需证件照片。
3. 进行网站负责人视频核验或者提交幕布照片。', 'wpicp') + ), + array( + 'title' => __('第四步:初审和提交管局审核', 'wpicp'), + 'content' => __('1. 接入商初审:1-3个工作日。
2. 管局审核:一般为5-20个工作日,具体时间因各省管局而异。', 'wpicp') + ), + array( + 'title' => __('第五步:获得备案号', 'wpicp'), + 'content' => __('备案通过后,您将获得ICP备案号,格式如"京ICP备12345678号-1"。', 'wpicp') + ), + array( + 'title' => __('第六步:公安备案', 'wpicp'), + 'content' => __('1. 在获得ICP备案号后,前往当地公安机关网站进行公安备案。
2. 全国公安机关互联网站安全管理平台:http://www.beian.gov.cn', 'wpicp') + ), + array( + 'title' => __('第七步:设置备案信息', 'wpicp'), + 'content' => __('备案完成后,在网站底部添加备案号及链接(使用本插件可轻松完成)。', 'wpicp') + ) + ), + 'important_notes' => array( + __('备案信息必须真实、准确,不得提供虚假资料。', 'wpicp'), + __('网站内容必须符合国家法律法规,不得含有违法违规信息。', 'wpicp'), + __('备案成功后,若备案信息发生变更,需及时变更备案。', 'wpicp'), + __('若网站内容与备案信息不符,可能导致网站被关闭。', 'wpicp') + ), + 'useful_links' => array( + array( + 'title' => __('工信部备案管理系统', 'wpicp'), + 'url' => 'https://beian.miit.gov.cn/' + ), + array( + 'title' => __('全国公安机关互联网站安全管理平台', 'wpicp'), + 'url' => 'http://www.beian.gov.cn/' + ) + ) + ); + + // 特定省份的指南 + $province_guides = array( + 'beijing' => array( + 'title' => __('北京地区ICP备案指南', 'wpicp'), + 'authority' => __('北京市通信管理局', 'wpicp'), + 'address' => __('北京市西城区闹市口大街1号院5号楼', 'wpicp'), + 'phone' => '010-12345678', + 'website' => 'http://bjca.miit.gov.cn/', + 'special_requirements' => array( + __('北京地区要求备案照片必须使用纯白色背景。', 'wpicp'), + __('企业备案需要提供最新的企业营业执照(副本)复印件并加盖公章。', 'wpicp') + ), + 'processing_time' => __('约7-10个工作日', 'wpicp') + ), + 'shanghai' => array( + 'title' => __('上海地区ICP备案指南', 'wpicp'), + 'authority' => __('上海市通信管理局', 'wpicp'), + 'address' => __('上海市静安区万航渡路2451号', 'wpicp'), + 'phone' => '021-12345678', + 'website' => 'http://shca.miit.gov.cn/', + 'special_requirements' => array( + __('上海地区企业备案需要提供上海市企业营业执照并加盖公章。', 'wpicp'), + __('外地企业在沪备案需要提供上海分公司证件。', 'wpicp') + ), + 'processing_time' => __('约5-8个工作日', 'wpicp') + ) + // 可以添加更多省份的指南 + ); + + // 返回通用指南和特定省份指南(如果有) + if(!empty($province) && isset($province_guides[$province])) { + return array( + 'general' => $general_guide, + 'province' => $province_guides[$province] + ); + } + + return array( + 'general' => $general_guide, + 'provinces' => array_keys($province_guides) + ); + } + + /** + * 新增 - 获取常见问题 + */ + public function get_faq_data() { + return array( + array( + 'question' => __('什么是ICP备案?', 'wpicp'), + 'answer' => __('ICP备案是指在中国大陆境内提供非经营性互联网信息服务,应当办理备案。备案成功后会获得工信部颁发的备案号,例如"京ICP备12345678号"。', 'wpicp') + ), + array( + 'question' => __('ICP备案和公安备案有什么区别?', 'wpicp'), + 'answer' => __('ICP备案是向工信部门申请,公安备案是向公安部门申请。两者针对不同法规要求,都是必须完成的。ICP备案完成后才能进行公安备案。', 'wpicp') + ), + array( + 'question' => __('个人网站需要备案吗?', 'wpicp'), + 'answer' => __('是的,无论是个人网站还是企业网站,只要服务器在中国大陆并向公众提供服务,都需要进行ICP备案和公安备案。', 'wpicp') + ), + array( + 'question' => __('备案大约需要多长时间?', 'wpicp'), + 'answer' => __('从提交资料到获得备案号,一般需要2-4周时间,具体取决于各省管局的审核速度。在此期间,您的网站可能无法访问。', 'wpicp') + ), + array( + 'question' => __('如何查询我的网站是否已备案?', 'wpicp'), + 'answer' => __('可以通过工信部备案管理系统(https://beian.miit.gov.cn/)输入域名进行查询。', 'wpicp') + ), + array( + 'question' => __('备案信息需要变更怎么办?', 'wpicp'), + 'answer' => __('如果备案主体、网站负责人、联系方式等信息发生变化,需要及时进行备案信息变更。变更流程与新备案类似,但审核时间通常会短一些。', 'wpicp') + ), + array( + 'question' => __('一个备案号可以用于多个网站吗?', 'wpicp'), + 'answer' => __('一个备案号下可以备案多个网站,每个网站会有不同的序号,如"京ICP备12345678号-1"、"京ICP备12345678号-2"。', 'wpicp') + ), + array( + 'question' => __('不进行备案会有什么后果?', 'wpicp'), + 'answer' => __('根据相关法规,未备案的网站将被关闭,情节严重的还可能面临罚款等处罚。', 'wpicp') + ), + array( + 'question' => __('使用香港、国外服务器需要备案吗?', 'wpicp'), + 'answer' => __('如果您的服务器在中国大陆境外(如香港、美国等),原则上不需要进行ICP备案,但网站内容仍需遵守中国法律法规。', 'wpicp') + ), + array( + 'question' => __('本插件如何帮助我进行备案?', 'wpicp'), + 'answer' => __('本插件提供备案信息的收集、验证、显示和管理功能,并提供备案指南和合规检查,但实际备案申请需要您通过接入服务商或直接向相关部门提交。', 'wpicp') + ) + ); + } +} diff --git a/public/class-wpicp-public.php b/public/class-wpicp-public.php new file mode 100644 index 0000000..e9ac205 --- /dev/null +++ b/public/class-wpicp-public.php @@ -0,0 +1,311 @@ + __('显示ICP备案信息', 'wpicp')) + ); + } + + /** + * 前端显示小工具 + */ + public function widget($args, $instance) { + $options = get_option('wpicp_options'); + + if(empty($options['icp_number'])) { + return; + } + + $title = !empty($instance['title']) ? apply_filters('widget_title', $instance['title']) : __('ICP备案信息', 'wpicp'); + $icp_number = esc_html($options['icp_number']); + $custom_link = !empty($options['custom_link']) ? esc_url($options['custom_link']) : 'https://beian.miit.gov.cn/'; + $style_class = !empty($options['display_style']) ? 'wpicp-style-' . esc_attr($options['display_style']) : 'wpicp-style-default'; + + // 显示公安备案信息 + $police_number = isset($options['police_number']) ? esc_html($options['police_number']) : ''; + $police_link = isset($options['police_link']) ? esc_url($options['police_link']) : 'http://www.beian.gov.cn/'; + + echo $args['before_widget']; + + if(!empty($title)) { + echo $args['before_title'] . $title . $args['after_title']; + } + + echo '
'; + echo '' . $icp_number . ''; + + // 如果有公安备案号,也显示 + if(!empty($police_number)) { + echo '
'; + echo '' . $police_number . ''; + } + + echo '
'; + + echo $args['after_widget']; + } + + /** + * 后台显示表单 + */ + public function form($instance) { + $title = !empty($instance['title']) ? $instance['title'] : __('ICP备案信息', 'wpicp'); + ?> +

+ + +

+

+ '; + echo '' . $icp_number . ''; + + // 如果有公安备案号,也显示 + if(!empty($police_number)) { + echo ' | ' . $police_number . ''; + } + + echo '
'; + } + + /** + * 注册ICP信息小工具 + */ + public function register_icp_widget() { + register_widget('WPICP_Widget'); + } + + /** + * ICP信息短代码 + */ + public function icp_info_shortcode($atts) { + $options = get_option('wpicp_options'); + + if(empty($options['icp_number'])) { + return ''; + } + + $atts = shortcode_atts( + array( + 'style' => isset($options['display_style']) ? $options['display_style'] : 'default', + ), + $atts, + 'wpicp_info' + ); + + $icp_number = esc_html($options['icp_number']); + $custom_link = !empty($options['custom_link']) ? esc_url($options['custom_link']) : 'https://beian.miit.gov.cn/'; + $style_class = 'wpicp-style-' . esc_attr($atts['style']); + + // 显示公安备案信息 + $police_number = isset($options['police_number']) ? esc_html($options['police_number']) : ''; + $police_link = isset($options['police_link']) ? esc_url($options['police_link']) : 'http://www.beian.gov.cn/'; + + $output = '
'; + $output .= '' . $icp_number . ''; + + // 如果有公安备案号,也显示 + if(!empty($police_number)) { + $output .= ' | ' . $police_number . ''; + } + + $output .= '
'; + + return $output; + } + + /** + * 检查ICP备案状态 + */ + public function check_icp_status() { + $options = get_option('wpicp_options'); + + // 如果已启用状态通知 + if(isset($options['status_notification']) && $options['status_notification'] == 'yes') { + $domain = parse_url(get_site_url(), PHP_URL_HOST); + + require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; + $core = new WPICP_Core(); + $status_message = $core->get_status_message($domain); + + // 如果未备案并且是管理员,显示前台提醒 + if(current_user_can('manage_options') && + ($status_message['icp_status'] == 'not_registered' || $status_message['icp_status'] == 'unknown')) { + + if(!isset($_COOKIE['wpicp_notice_dismissed'])) { + ?> +
+

+ +
+ + + '; + + if(!isset($_COOKIE['wpicp_notice_dismissed'])) { + ?> +
+

+ +
+ + + verify_icp_status(); + } + } +} diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..e833a9a --- /dev/null +++ b/readme.txt @@ -0,0 +1,236 @@ +=== wpban Pro === +Contributors: wpban +Tags: security, firewall, ban, geo-blocking, rate-limiting, crawler-blocking, brute-force, ip-blocking +Requires at least: 6.7.2 +Tested up to: 6.7.2 +Stable tag: 5.0 +Requires PHP: 7.4 +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html + +Advanced WordPress security plugin with geo-blocking, rate limiting, AI crawler blocking, and intelligent threat detection. + +== Description == + +wpban Pro is a comprehensive security solution for WordPress that protects your site from various threats including malicious bots, brute force attacks, content scrapers, and unauthorized access attempts. + += Key Features = + +**🛡️ IP Management** +* Ban IPs with wildcard support (e.g., 192.168.*.*) +* IP range blocking (CIDR and range notation) +* Whitelist trusted IPs +* Automatic reverse proxy detection + +**🌍 Geographic Blocking** +* Block or allow specific countries +* Real-time IP geolocation +* Cached country lookups for performance +* Whitelist/blacklist modes + +**⚡ Rate Limiting** +* Protect against DDoS and flood attacks +* Separate limits for general requests, login attempts, and API calls +* Automatic temporary bans for violators +* Customizable thresholds + +**🤖 Crawler Control** +* Block 40+ AI crawlers (GPTBot, ClaudeBot, etc.) +* Control SEO crawler access +* Protect content from AI training datasets +* robots.txt integration + +**📊 Advanced Logging** +* Detailed security event logs +* Filter by date, action, IP, or country +* Export logs to CSV +* Automatic log rotation + +**📧 Email Notifications** +* Real-time security alerts +* Customizable alert thresholds +* Multiple event types +* Test email functionality + +**🚪 Login Protection** +* Restrict wp-login.php access by IP +* Brute force detection +* Failed login tracking +* Emergency bypass URL + +**🎯 Security Templates** +* Quick setup with pre-configured templates +* Basic, Strict, Content Protection, and Performance modes +* One-click application +* Customizable settings + +**🔧 Additional Features** +* Browser restrictions (block WeChat/QQ) +* User agent filtering +* Referer blocking +* Host-based banning +* Import/export settings +* Database optimization tools + += Performance Optimized = + +* Smart caching system +* Optimized database queries with indexes +* Minimal performance impact +* Lazy loading of features + += Emergency Access = + +Never get locked out! WPBan provides an emergency bypass URL that allows you to access your site even if your IP gets banned accidentally. + +== Installation == + +1. Upload the `wpban` folder to `/wp-content/plugins/` +2. Activate the plugin through the 'Plugins' menu in WordPress +3. Go to 'WPBan Security' in your admin menu +4. Choose a security template or configure settings manually +5. Save your emergency bypass URL in a safe place + += Minimum Requirements = + +* WordPress 6.7.2 or higher +* PHP 7.4 or higher +* MySQL 5.7 or higher + +== Frequently Asked Questions == + += Will this plugin slow down my website? = + +No. WPBan is designed with performance in mind. It uses intelligent caching, optimized database queries, and only loads features when needed. + += What happens if I accidentally ban myself? = + +Use the emergency bypass URL provided in the dashboard. This special URL allows you to access your site and disable the ban. Always save this URL in a secure location. + += Can I block entire countries? = + +Yes! WPBan includes geographic blocking that allows you to block or exclusively allow specific countries. The plugin uses free IP geolocation services for this feature. + += Will blocking SEO crawlers hurt my rankings? = + +Yes, blocking major search engine crawlers (Googlebot, Bingbot) will negatively impact your SEO. The plugin shows warnings for these critical crawlers. Only block SEO crawlers if you have a specific reason. + += How do I protect against AI content scraping? = + +Use the "Content Protection" template which blocks major AI crawlers, or manually select AI crawlers to block in the Crawlers settings. The plugin blocks access and adds robots.txt rules. + += Can I import/export settings? = + +Yes! Go to Tools > Import/Export to backup your settings or migrate them to another site. + += How long are logs kept? = + +Logs are automatically cleaned after 30 days to prevent database bloat. You can export logs before they're deleted or manually clear them at any time. + += Does it work with Cloudflare? = + +Yes! Enable the "Reverse Proxy" option in General settings to properly detect visitor IPs when using Cloudflare or other proxy services. + +== Screenshots == + +1. Dashboard - Overview of security statistics and quick actions +2. Security Templates - One-click security configurations +3. IP Rules - Manage banned IPs, ranges, and whitelists +4. Rate Limiting - Configure request limits +5. Geographic Blocking - Block or allow countries +6. Crawler Management - Control bot access +7. Security Logs - Detailed event tracking +8. Email Notifications - Real-time alerts + +== Changelog == + += 5.0 = +* Added geographic blocking with real-time IP geolocation +* Implemented advanced rate limiting system +* Added email notifications for security events +* Improved logging with country tracking and pagination +* Added import/export functionality +* Optimized database performance with indexes +* Added emergency bypass URL feature +* Improved UI with WordPress native design +* Added security templates for quick setup +* Fixed array structure issue in templates + += 4.0 = +* Complete rewrite with improved architecture +* Added caching system +* Enhanced performance +* Better code organization + += 3.3 = +* Initial public release +* Basic IP blocking functionality +* Crawler blocking +* Simple logging + +== Upgrade Notice == + += 5.0 = +Major update with geographic blocking, rate limiting, and email notifications. Backup your settings before upgrading. + +== Advanced Usage == + += Custom Templates = + +You can create custom security templates by hooking into the `wpban_templates` filter: + +` +add_filter('wpban_templates', function($templates) { + $templates['custom'] = [ + 'name' => 'My Custom Template', + 'description' => 'Custom security configuration', + 'settings' => [ + 'banned_ips' => ['1.2.3.4'], + 'rate_limits' => [ + 'requests_per_minute' => 45 + ] + ] + ]; + return $templates; +}); +` + += Custom Country Detection = + +Integrate with premium GeoIP services: + +` +add_filter('wpban_ip_country', function($country, $ip) { + // Your custom country detection logic + return $detected_country; +}, 10, 2); +` + += Whitelist Specific Pages = + +Exclude certain pages from security checks: + +` +add_filter('wpban_skip_checks', function($skip) { + if (is_page('special-page')) { + return true; + } + return $skip; +}); +` + +== Support == + +For support, feature requests, or bug reports, please visit our [support forum](https://wordpress.org/support/plugin/wpban/) or [GitHub repository](https://github.com/wpban/wpban). + +== Privacy Policy == + +This plugin stores: +* Security logs containing IP addresses, user agents, and geographic data +* Your security configuration settings + +This plugin may connect to external services: +* IP geolocation APIs (ip-api.com, ipinfo.io) for country detection +* These services only receive IP addresses for lookup + +All data is stored locally in your WordPress database and is not shared with third parties. \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..76cac26 --- /dev/null +++ b/style.css @@ -0,0 +1,341 @@ +/** + * WPICP - WordPress ICP备案插件样式 + */ + +/* 通用样式 */ +.wpicp-footer, +.wpicp-widget, +.wpicp-shortcode { + font-size: 12px; + line-height: 1.5; + margin: 10px 0; + text-align: center; + padding: 5px; +} + +.wpicp-footer a, +.wpicp-widget a, +.wpicp-shortcode a { + text-decoration: none; + color: #666; +} + +/* 默认样式 */ +.wpicp-style-default { + font-family: Arial, sans-serif; +} + +.wpicp-style-default .wpicp-icp a { + position: relative; + display: inline-block; + padding-left: 20px; +} + +.wpicp-style-default .wpicp-icp a:before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 16px; + height: 16px; + background-image: url('data:image/svg+xml;utf8,'); + background-size: contain; + background-repeat: no-repeat; +} + +.wpicp-style-default .wpicp-police a { + position: relative; + display: inline-block; + padding-left: 20px; +} + +.wpicp-style-default .wpicp-police a:before { + content: ""; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 16px; + height: 16px; + background-image: url('data:image/svg+xml;utf8,'); + background-size: contain; + background-repeat: no-repeat; +} + +/* 简洁样式 */ +.wpicp-style-simple { + border-top: 1px solid #eee; + padding-top: 10px; + color: #999; +} + +.wpicp-style-simple a { + color: #999; +} + +/* 深色样式 */ +.wpicp-style-dark { + background-color: #333; + color: #fff; + padding: 10px; +} + +.wpicp-style-dark a { + color: #fff; +} + +/* 管理页面样式 */ +.wpicp-admin-info { + background-color: #f9f9f9; + border-left: 4px solid #0073aa; + box-shadow: 0 1px 1px rgba(0,0,0,.04); + margin: 20px 0; + padding: 15px; +} + +.wpicp-admin-info h2 { + margin-top: 0; +} + +.wpicp-admin-form, +.wpicp-admin-records, +.wpicp-export-tools, +.wpicp-admin-tools, +.wpicp-check-results, +.wpicp-admin-history, +.wpicp-tool-box, +.wpicp-province-selection, +.wpicp-province-guide, +.wpicp-general-guide, +.wpicp-faq-list { + margin: 20px 0; + padding: 15px; + background-color: #fff; + border: 1px solid #ccd0d4; + box-shadow: 0 1px 1px rgba(0,0,0,.04); +} + +.wpicp-tool-box { + display: inline-block; + vertical-align: top; + margin-right: 20px; + min-width: 250px; +} + +.wpicp-export-tools { + margin-top: 20px; +} + +.wpicp-check-results { + margin-top: 20px; +} + +.wpicp-check-summary { + background-color: #f9f9f9; + padding: 15px; + margin-top: 20px; + border: 1px solid #ccd0d4; +} + +/* 新增 - 状态摘要样式 */ +.wpicp-status-summary { + padding: 15px; + border-radius: 3px; + margin: 20px 0; +} + +.wpicp-status-summary-success { + background-color: #d4edda; + border: 1px solid #c3e6cb; + color: #155724; +} + +.wpicp-status-summary-warning { + background-color: #fff3cd; + border: 1px solid #ffeeba; + color: #856404; +} + +.wpicp-status-summary-error { + background-color: #f8d7da; + border: 1px solid #f5c6cb; + color: #721c24; +} + +.wpicp-status-message { + font-size: 16px; + font-weight: 500; + margin-bottom: 15px; +} + +.wpicp-status-details { + width: 100%; + border-collapse: collapse; + margin-bottom: 15px; +} + +.wpicp-status-details th, +.wpicp-status-details td { + padding: 8px; + text-align: left; + border-bottom: 1px solid rgba(0,0,0,0.1); +} + +.wpicp-status-details th { + width: 30%; +} + +.wpicp-status-actions { + margin-top: 15px; +} + +/* 新增 - 状态指示器样式 */ +.wpicp-status { + display: inline-block; + padding: 3px 8px; + border-radius: 3px; + font-size: 12px; + font-weight: 600; +} + +.wpicp-status-success { + background-color: #d4edda; + color: #155724; +} + +.wpicp-status-error { + background-color: #f8d7da; + color: #721c24; +} + +.wpicp-status-warning { + background-color: #fff3cd; + color: #856404; +} + +.wpicp-status-pending { + background-color: #d1ecf1; + color: #0c5460; +} + +/* 新增 - 敏感词级别指示器 */ +.wpicp-level { + display: inline-block; + padding: 2px 6px; + border-radius: 3px; + font-size: 12px; + font-weight: 600; +} + +.wpicp-level-low { + background-color: #d4edda; + color: #155724; +} + +.wpicp-level-medium { + background-color: #fff3cd; + color: #856404; +} + +.wpicp-level-high { + background-color: #f8d7da; + color: #721c24; +} + +/* 新增 - 省份列表 */ +.wpicp-province-list { + display: flex; + flex-wrap: wrap; + list-style: none; + padding: 0; + margin: 0; +} + +.wpicp-province-list li { + margin: 5px; +} + +/* 新增 - 备案指南步骤 */ +.wpicp-guide-step { + margin-bottom: 20px; + padding: 15px; + background-color: #f9f9f9; + border-left: 4px solid #0073aa; +} + +.wpicp-guide-step h3 { + margin-top: 0; + color: #0073aa; +} + +.wpicp-guide-notes { + margin-top: 20px; + padding: 15px; + background-color: #fff3cd; + border-left: 4px solid #ffeeba; +} + +.wpicp-useful-links { + margin-top: 20px; +} + +/* 新增 - FAQ样式 */ +.wpicp-faq-item { + margin-bottom: 20px; + border-bottom: 1px solid #eee; + padding-bottom: 15px; +} + +.wpicp-faq-question { + background-color: #f9f9f9; + padding: 10px 15px; + cursor: pointer; + margin: 0; +} + +.wpicp-faq-question:before { + content: "Q: "; + font-weight: bold; + color: #0073aa; +} + +.wpicp-faq-answer { + padding: 15px; + background-color: #fff; +} + +.wpicp-faq-answer:before { + content: "A: "; + font-weight: bold; + color: #28a745; +} + +.wpicp-more-help { + margin-top: 30px; + padding: 15px; + background-color: #f9f9f9; +} + +/* 响应式样式 */ +@media screen and (max-width: 782px) { + .wpicp-admin-form, + .wpicp-admin-records, + .wpicp-export-tools, + .wpicp-admin-tools, + .wpicp-check-results, + .wpicp-tool-box { + padding: 10px; + } + + .wpicp-tool-box { + display: block; + width: 100%; + margin-right: 0; + margin-bottom: 15px; + } + + .wpicp-status-details th { + width: 40%; + } +} diff --git a/uninstall.php b/uninstall.php new file mode 100644 index 0000000..1123f89 --- /dev/null +++ b/uninstall.php @@ -0,0 +1,65 @@ +query("DELETE FROM $wpdb->options WHERE option_name LIKE 'wpicp_%'"); + +// 删除插件创建的表 +$tables = array( + 'wpicp_records', + 'wpicp_sensitive_words', + 'wpicp_real_name_info', + 'wpicp_record_history', + 'wpicp_status' +); + +foreach($tables as $table) { + $wpdb->query("DROP TABLE IF EXISTS " . $wpdb->prefix . $table); +} + +// 清除用户元数据 +$wpdb->query("DELETE FROM $wpdb->usermeta WHERE meta_key LIKE 'wpicp_%'"); + +// 清除评论元数据 +$wpdb->query("DELETE FROM $wpdb->commentmeta WHERE meta_key LIKE 'wpicp_%'"); + +// 清除已计划的事件 +wp_clear_scheduled_hook('wpicp_daily_verification'); +wp_clear_scheduled_hook('wpicp_daily_status_check'); + +// 删除上传的文件 +$upload_dir = wp_upload_dir(); +$verification_dir = $upload_dir['basedir'] . '/wpicp-verification/'; + +if(file_exists($verification_dir)) { + // 删除目录中的所有文件 + $files = glob($verification_dir . '*'); + foreach($files as $file) { + if(is_file($file)) { + unlink($file); + } + } + + // 删除目录 + rmdir($verification_dir); +} diff --git a/wpicp.php b/wpicp.php new file mode 100644 index 0000000..0507cd9 --- /dev/null +++ b/wpicp.php @@ -0,0 +1,106 @@ +create_database_tables(); + + // 添加默认选项 + $default_options = array( + 'icp_number' => '', + 'display_location' => 'footer', + 'display_style' => 'default', + 'verification_method' => 'manual', + 'api_key' => '', + 'custom_link' => 'https://beian.miit.gov.cn/', + 'enable_sensitive_check' => 'no', + // 新增选项 + 'police_number' => '', + 'police_link' => 'http://www.beian.gov.cn/', + 'status_notification' => 'yes', + 'verification_api_provider' => 'none', + 'verification_api_key' => '', + 'beian_query_method' => 'manual', + 'beian_query_api_key' => '', + 'check_on_publish' => 'no', + 'scheduled_check' => 'no' + ); + + add_option('wpicp_options', $default_options); +} +register_activation_hook(__FILE__, 'activate_wpicp'); + +/** + * 插件停用函数 + */ +function deactivate_wpicp() { + // 停用时的操作 + flush_rewrite_rules(); + + // 清除计划任务 + wp_clear_scheduled_hook('wpicp_daily_status_check'); + wp_clear_scheduled_hook('wpicp_weekly_compliance_check'); +} +register_deactivation_hook(__FILE__, 'deactivate_wpicp'); + +/** + * 加载插件文本域 + */ +function wpicp_load_textdomain() { + load_plugin_textdomain('wpicp', false, dirname(plugin_basename(__FILE__)) . '/languages/'); +} +add_action('plugins_loaded', 'wpicp_load_textdomain'); + +/** + * 加载插件组件 + */ +require_once WPICP_PLUGIN_DIR . 'includes/class-wpicp-core.php'; +require_once WPICP_PLUGIN_DIR . 'admin/class-wpicp-admin.php'; +require_once WPICP_PLUGIN_DIR . 'public/class-wpicp-public.php'; + +/** + * 加载样式 + */ +function wpicp_enqueue_styles() { + wp_enqueue_style('wpicp-style', WPICP_PLUGIN_URL . 'style.css', array(), WPICP_VERSION); +} +add_action('wp_enqueue_scripts', 'wpicp_enqueue_styles'); +add_action('admin_enqueue_scripts', 'wpicp_enqueue_styles'); + +/** + * 初始化插件组件 + */ +function run_wpicp() { + new WPICP_Admin(); + new WPICP_Public(); // 这里使用WPICP_Public类名 +} +add_action('plugins_loaded', 'run_wpicp');