%PDF- %PDF-
Direktori : /home/t/r/a/tradesc/www/relax/wp-content/plugins/complianz-gdpr/cookie/ |
Current File : /home/t/r/a/tradesc/www/relax/wp-content/plugins/complianz-gdpr/cookie/class-scan.php |
<?php defined( 'ABSPATH' ) or die(); if ( ! class_exists( "cmplz_scan" ) ) { class cmplz_scan { private static $_this; function __construct() { if ( isset( self::$_this ) ) { wp_die( sprintf( '%s is a singleton class and you cannot create a second instance.', get_class( $this ) ) ); } self::$_this = $this; if ( cmplz_scan_in_progress() ) { add_action( 'wp_print_footer_scripts', array( $this, 'test_cookies' ), PHP_INT_MAX, 2 ); } add_action( 'cmplz_every_day_hook', array( $this, 'track_cookie_changes' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); add_action( 'admin_footer', array( $this, 'run_cookie_scan' ) ); add_filter( 'cmplz_do_action', array( $this, 'get_scan_progress' ), 10, 3 ); add_filter( 'cmplz_do_action', array( $this, 'reset_scan' ), 11, 3 ); } static function this() { return self::$_this; } /** * Check if there are any new cookies added */ public function track_cookie_changes() { if ( ! cmplz_user_can_manage() ) { return; } //only run if all pages are scanned. if ( ! $this->scan_complete() ) { return; } //check if anything was changed $new_cookies = COMPLIANZ::$banner_loader->get_cookies( array( 'new' => true ) ); if ( count( $new_cookies ) > 0 ) { $this->set_cookies_changed(); } } /** * Set the cookies as having been changed */ public function set_cookies_changed() { update_option( 'cmplz_changed_cookies', 1 , false); } /** * Check if cookies have been changed * * @return bool */ public function cookies_changed() { return ( get_option( 'cmplz_changed_cookies' ) == 1 ); } /** * Delete the transient that contains the pages list * * @param int $post_id * @param bool $post_after * @param bool $post_before */ public function clear_pages_list( int $post_id, $post_after = false, $post_before = false ) { delete_transient( 'cmplz_pages_list' ); } /** * Clean up duplicate cookie names * * @return void */ public function clear_double_cookienames() { if ( ! cmplz_user_can_manage() ) { return; } global $wpdb; $languages = COMPLIANZ::$banner_loader->get_supported_languages(); //first, delete all cookies with a language not in the $languages array $wpdb->query( "DELETE from {$wpdb->prefix}cmplz_cookies where language NOT IN ('" . implode( "','", $languages ) . "')" ); foreach ( $languages as $language ) { $settings = array( 'language' => $language, 'isMembersOnly' => 'all', ); $cookies = COMPLIANZ::$banner_loader->get_cookies( $settings ); foreach ( $cookies as $cookie ) { $same_name_cookies = $wpdb->get_results( $wpdb->prepare( "select * from {$wpdb->prefix}cmplz_cookies where name = %s and language = %s and serviceID = %s ", $cookie->name, $language, $cookie->serviceID ) ); if ( count( $same_name_cookies ) > 1 ) { array_shift( $same_name_cookies ); $IDS = wp_list_pluck( $same_name_cookies, 'ID' ); $sql = implode( ' OR ID =', $IDS ); $sql = "DELETE from {$wpdb->prefix}cmplz_cookies where ID=" . $sql; $wpdb->query( $sql ); } } $settings = array( 'language' => $language, ); $services = COMPLIANZ::$banner_loader->get_services( $settings ); foreach ( $services as $service ) { $same_name_services = $wpdb->get_results( $wpdb->prepare( "select * from {$wpdb->prefix}cmplz_services where name = %s and language = %s", $service->name, $language ) ); if ( count( $same_name_services ) > 1 ) { array_shift( $same_name_services ); $IDS = wp_list_pluck( $same_name_services, 'ID' ); $sql = implode( ' OR ID =', $IDS ); $sql = "DELETE from {$wpdb->prefix}cmplz_services where ID=" . $sql; $wpdb->query( $sql ); } } } } /** * Here we add scripts and styles for the wysywig editor on the backend * @param string $hook * * */ public function enqueue_admin_assets( $hook ) { if ( isset( $_GET['page'] ) && $_GET['page'] === 'complianz' ) { //script to check for ad blockers wp_enqueue_script( 'cmplz-ad-checker', cmplz_url . "assets/js/ads.js", array(), cmplz_version, true ); } } /** * Get all cookies, and post back to site with ajax. * This script is only inserted when a valid token is passed, so will never run for other visitors than the site admin * * */ public function test_cookies() { if ( $this->scan_complete() ) { return; } if (!isset($_GET['complianz_scan_token']) || !isset($_GET['complianz_id'])){ return; } $token = sanitize_title( $_GET['complianz_scan_token'] ); $id = sanitize_title( $_GET['complianz_id'] ); $admin_url = esc_url_raw( rest_url('complianz/v1/') ); $nonce = wp_create_nonce( 'wp_rest' ); $javascript = cmplz_get_template( 'test-cookies.js' ); $javascript = str_replace( array( '{admin_url}', '{token}', '{id}', '{nonce}' ), array( esc_url_raw( $admin_url ), esc_attr( $token ), esc_attr( $id ), $nonce ), $javascript ); ?> <script> <?php echo $javascript;?> </script> <?php } /** * * Get list of page id's that we want to process this set of scan requests, which weren't included in the scan before * * @return string $url * *@since 1.0 */ public function get_remote_scan_url() { if ( !cmplz_user_can_manage() ) { return false; } //homepage is not always a post. if ( !get_option('cmplz_remote_homepage_scanned') ) { update_option('cmplz_remote_homepage_scanned', true, false); return site_url(); } //from each post type, get one, for faster results. $post_types = $this->get_scannable_post_types(); $args = array( 'post_type' => $post_types, 'posts_per_page' => 1, 'meta_query' => array( array( 'key' => '_cmplz_remote_scanned_post', 'compare' => 'NOT EXISTS' ), ) ); $posts = get_posts( $args ); if ( count( $posts ) > 0 ) { $post = reset( $posts ); update_post_meta( $post->ID, '_cmplz_remote_scanned_post', true ); return get_permalink( $post->ID ); } //reset all posts, so we can start over. delete_post_meta_by_key( '_cmplz_remote_scanned_post' ); return site_url(); } /** * Insert an iframe to retrieve front-end cookies * * * */ public function run_cookie_scan(): void { if ( ! cmplz_admin_logged_in() ) { return; } if ( get_option('cmplz_activation_time') > strtotime('-30 minutes') ) { return; } if ( defined( 'CMPLZ_DO_NOT_SCAN' ) && CMPLZ_DO_NOT_SCAN ) { return; } if ( isset( $_GET['complianz_scan_token'] ) ) { return; } //if the last cookie scan date is more than a month ago, we re-scan. $last_scan_date = COMPLIANZ::$banner_loader->get_last_cookie_scan_date( true ); $scan_interval = apply_filters( 'cmplz_scan_interval', 3 ); $one_month_ago = strtotime( "-".$scan_interval." month" ); if ( ( $one_month_ago > $last_scan_date ) && $this->scan_complete() && !$this->automatic_cookiescan_disabled() ) { $this->reset_pages_list(); } if ( ! $this->scan_complete() ) { if ( ! get_option( 'cmplz_synced_cookiedatabase_once' ) ) { update_option( 'cmplz_sync_cookies_complete', false ); update_option( 'cmplz_sync_cookies_after_services_complete', false ); update_option( 'cmplz_sync_services_complete', false ); update_option( 'cmplz_synced_cookiedatabase_once', true ); } //store the date $timezone_offset = get_option( 'gmt_offset' ); $time = time() + ( 60 * 60 * $timezone_offset ); update_option( 'cmplz_last_cookie_scan', $time ); $url = $this->get_next_page_url(); if ( ! $url ) { return; } if ( $url === 'remote' ) { do_action('cmplz_remote_cookie_scan'); } else if ( strpos( $url, 'complianz_id' ) !== false ) { //get the html of this page. $response = wp_remote_get( $url ); if ( ! is_wp_error( $response ) ) { $html = $response['body']; $this->parse_html($html); } } //load in iframe so the scripts run. echo '<iframe id="cmplz_cookie_scan_frame" class="hidden" src="' . $url . '"></iframe>'; } } private function parse_html($html){ $stored_social_media = cmplz_scan_detected_social_media(); if ( ! $stored_social_media ) { $stored_social_media = array(); } $social_media = COMPLIANZ::$banner_loader->parse_for_social_media( $html ); $social_media = array_unique( array_merge( $stored_social_media, $social_media ), SORT_REGULAR ); update_option( 'cmplz_detected_social_media', $social_media ); $stored_thirdparty_services = cmplz_scan_detected_thirdparty_services(); if ( ! $stored_thirdparty_services ) { $stored_thirdparty_services = array(); } $thirdparty = $this->parse_for_thirdparty_services( $html ); $thirdparty = array_unique( array_merge( $stored_thirdparty_services, $thirdparty ), SORT_REGULAR ); update_option( 'cmplz_detected_thirdparty_services', $thirdparty ); //parse for google analytics and tagmanager, but only if the wizard wasn't completed before. //with this data we prefill the settings and give warnings when tracking is doubled if ( ! COMPLIANZ::$banner_loader->wizard_completed_once() ) { $this->parse_for_statistics_settings( $html ); } if ( preg_match_all( '/ga\.js/', $html ) > 1 || preg_match_all( '/analytics\.js/', $html ) > 1 || preg_match_all( '/googletagmanager\.com\/gtm\.js/', $html ) > 1 || preg_match_all( '/piwik\.js/', $html ) > 1 || preg_match_all( '/matomo\.js/', $html ) > 1 || preg_match_all( '/getclicky\.com\/js/', $html ) > 1 || preg_match_all( '/mc\.yandex\.ru\/metrika\/watch\.js/', $html ) > 1 ) { update_option( 'cmplz_double_stats', true ); } else { delete_option( 'cmplz_double_stats' ); } $stored_stats = cmplz_scan_detected_stats(); if ( ! $stored_stats ) { $stored_stats = array(); } $stats = $this->parse_for_stats( $html ); $stats = array_unique( array_merge( $stored_stats, $stats ), SORT_REGULAR ); update_option( 'cmplz_detected_stats', $stats ); } /** * Check a string for statistics * * @param string $html * @param bool $single_key //return a single string instead of array * * @return array|string $thirdparty * * */ public function parse_for_stats( $html, $single_key = false ) { $stats = array(); $stats_markers = COMPLIANZ::$config->stats_markers; foreach ( $stats_markers as $key => $markers ) { foreach ( $markers as $marker ) { if ( $single_key && strpos( $html, $marker ) !== false ) { return $key; } if ( strpos( $html, $marker ) !== false && ! in_array( $key, $stats ) ) { if ( $single_key ) { return $key; } $stats[] = $key; } } } if ( $single_key ) { return false; } return $stats; } /** * Run once to retrieve the settings for most used stats tools * * @param $html */ private function parse_for_statistics_settings( $html ) { if ( strpos( $html, 'gtm.js' ) !== false || strpos( $html, 'gtm.start' ) !== false ) { update_option( 'cmplz_detected_stats_type', true ); $pattern = '/(\'|")(GTM-[A-Z]{7})(\'|")/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[2] ) ) { cmplz_update_option_no_hooks('gtm_code', sanitize_text_field( $matches[2] ) ); update_option( 'cmplz_detected_stats_data', true ); cmplz_update_option('compile_statistics', 'google-tag-manager' ); } } if ( strpos( $html, 'analytics.js' ) !== false || strpos( $html, 'ga.js' ) !== false || strpos( $html, '_getTracker' ) !== false ) { update_option( 'cmplz_detected_stats_type', true ); $pattern = '/(\'|")(UA-[0-9]{8}-[0-9]{1})(\'|")/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[2] ) ) { cmplz_update_option('ua_code', sanitize_text_field( $matches[2] ) ); cmplz_update_option('compile_statistics', 'google-analytics' ); } //gtag $pattern = '/(\'|")(G-[0-9a-zA-Z]{10})(\'|")/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[2] ) ) { cmplz_update_option('ua_code', sanitize_text_field( $matches[2] ) ); cmplz_update_option('compile_statistics', 'google-analytics' ); } $pattern = '/\'anonymizeIp|anonymize_ip\'|:[ ]{0,1}true/i'; preg_match( $pattern, $html, $matches ); if ( $matches ) { $value = cmplz_get_option( 'compile_statistics_more_info' ); if ( ! is_array( $value ) ) { $value = array(); } if ( !in_array( 'ip-addresses-blocked', $value, true )) { $value[] = 'ip-addresses-blocked'; } cmplz_update_option('compile_statistics_more_info', $value ); } } if ( strpos( $html, 'piwik.js' ) !== false || strpos( $html, 'matomo.js' ) !== false ) { update_option( 'cmplz_detected_stats_type', true ); $pattern = '/(var u=")((https|http):\/\/.*?)"/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[2] ) ) { cmplz_update_option('matomo_url', sanitize_text_field( $matches[2] ) ); update_option( 'cmplz_detected_stats_data', true ); } $pattern = '/\[\'setSiteId\', \'([0-9]){1,3}\'\]\)/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[1] ) ) { cmplz_update_option('matomo_site_id', intval( $matches[1] ) ); update_option( 'cmplz_detected_stats_data', true ); } cmplz_update_option('compile_statistics', 'matomo' ); } if ( strpos( $html, 'static.getclicky.com/js' ) !== false ) { update_option( 'cmplz_detected_stats_type', true ); $pattern = '/clicky_site_ids\.push\(([0-9]{1,3})\)/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[1] ) ) { cmplz_update_option('clicky_site_id', intval( $matches[1] ) ); update_option( 'cmplz_detected_stats_data', true ); cmplz_update_option('compile_statistics', 'clicky' ); } } if ( strpos( $html, 'mc.yandex.ru/metrika/watch.js' ) !== false ) { update_option( 'cmplz_detected_stats_type', true ); $pattern = '/w.yaCounter([0-9]{1,10}) = new/i'; preg_match( $pattern, $html, $matches ); if ( $matches && isset( $matches[1] ) ) { cmplz_update_option('yandex_id', intval( $matches[1] ) ); update_option( 'cmplz_detected_stats_data', true ); cmplz_update_option('compile_statistics', 'yandex' ); } } } /** * Check a string for third party services * * @param string $html * @param bool $single_key //return a single string instead of array * * @return array|string $thirdparty * * */ public function parse_for_thirdparty_services( $html, $single_key = false ) { $thirdparty = array(); $thirdparty_markers = COMPLIANZ::$config->thirdparty_service_markers; foreach ( $thirdparty_markers as $key => $markers ) { foreach ( $markers as $marker ) { if ( $single_key && strpos( $html, $marker ) !== false ) { return $key; } if ( strpos( $html, $marker ) !== false && ! in_array( $key, $thirdparty ) ) { $thirdparty[] = $key; } } } if ( $single_key ) { return false; } return $thirdparty; } private function get_next_page_url() { if ( ! cmplz_user_can_manage() ) { return ''; } $token = wp_create_nonce( 'complianz_scan_token' ); $pages = array_filter($this->pages_to_process()); if ( count( $pages ) === 0 ) { return false; } $id_to_process = reset( $pages ); $this->set_page_as_processed( $id_to_process ); switch ( $id_to_process ) { case 'remote': return 'remote'; case 'home': $url = site_url(); break; case 'loginpage': $url = wp_login_url(); break; default: $url = get_permalink( $id_to_process ); } $url = add_query_arg( array( "complianz_scan_token" => $token, 'complianz_id' => $id_to_process ), $url ); if ( is_ssl() ) { $url = str_replace( "http://", "https://", $url ); } return apply_filters("cmplz_next_page_url", $url); } /** * Get the list of posttypes to process * @return array */ public function get_scannable_post_types(){ $args = array( 'public' => true, ); $post_types = get_post_types( $args ); unset( $post_types['elementor_font'], $post_types['attachment'], $post_types['revision'], $post_types['nav_menu_item'], $post_types['custom_css'], $post_types['customize_changeset'], $post_types['cmplz-dataleak'], $post_types['cmplz-processing'], $post_types['user_request'], $post_types['cookie'], $post_types['product'] ); return apply_filters('cmplz_cookiescan_post_types',$post_types ); } /** * * Get list of page id's that we want to process this set of scan requests, which weren't included in the scan before * * @return array $pages * *@since 1.0 */ public function get_pages_list_single_run() { if ( !cmplz_user_can_manage() ) { return []; } $posts = get_transient( 'cmplz_pages_list' ); if ( ! $posts ) { $posts = ['home', 'remote']; $all_types_posts = []; $post_types = $this->get_scannable_post_types(); //from each post type, get one, for faster results. foreach ( $post_types as $post_type ) { $args = array( 'post_type' => $post_type, 'posts_per_page' => 1, 'meta_query' => array( array( 'key' => '_cmplz_scanned_post', 'compare' => 'NOT EXISTS' ), ) ); $new_posts = get_posts( $args ); $all_types_posts = $all_types_posts + $new_posts; } $all_types_array = count($all_types_posts)>0 ? wp_list_pluck($all_types_posts, 'ID') : []; $posts = array_merge( $posts, $all_types_array ); foreach ( $post_types as $post_type ) { $args = array( 'post__not_in' => $all_types_array, 'post_type' => $post_type, 'posts_per_page' => 5, 'meta_query' => array( array( 'key' => '_cmplz_scanned_post', 'compare' => 'NOT EXISTS' ), ) ); $new_posts = get_posts( $args ); $new_posts_array = count($new_posts)>0 ? wp_list_pluck($new_posts, 'ID') : []; $posts = $posts + $new_posts_array; } if ( count( $posts ) === 0 && ! $this->automatic_cookiescan_disabled() ) { /* * If we didn't find any posts, we reset the post meta that tracks if all posts have been scanned. * This way we will find some posts on the next scan attempt * */ $this->reset_scanned_post_batches(); //now we need to reset the scanned pages list too $this->reset_pages_list(); } else { foreach ( $posts as $post_id ) { update_post_meta( $post_id, '_cmplz_scanned_post', true ); } } if ( cmplz_get_option( 'wp_admin_access_users' ) === 'yes' ) { $posts[] = 'loginpage'; } set_transient( 'cmplz_pages_list', $posts, MONTH_IN_SECONDS ); } return array_filter($posts); } /** * Reset the list of pages * * @param bool $delay * @param bool $manual //if it's manual, we always reset. If automatic scan is disabled, we do not reset. * * @return void * * @since 2.1.5 */ public function reset_pages_list( $delay = false, $manual = false ) { if ( ! $manual && $this->automatic_cookiescan_disabled() ) { return; } if ( $manual ) { $this->reset_scanned_post_batches(); } if ( $delay ) { $current_list = get_transient( 'cmplz_pages_list' ); $processed_pages = get_transient( 'cmplz_processed_pages_list' ); set_transient( 'cmplz_pages_list', $current_list, HOUR_IN_SECONDS ); set_transient( 'cmplz_processed_pages_list', $processed_pages, HOUR_IN_SECONDS ); } else { delete_transient( 'cmplz_pages_list' ); delete_transient( 'cmplz_processed_pages_list' ); } } /** * The scanned post meta is used to create batches of posts. A batch that is being processed is set to scanned. * This is only reset when all posts have been processed, or if user has disabled automatic scanning, and the manual scan is fired. * */ public function reset_scanned_post_batches() { if ( ! function_exists( 'delete_post_meta_by_key' ) ) { require_once ABSPATH . WPINC . '/post.php'; } delete_post_meta_by_key( '_cmplz_scanned_post' ); } /** * Check if the automatic scan is disabled * * @return bool */ public function automatic_cookiescan_disabled() { return cmplz_get_option( 'disable_automatic_cookiescan' ) == 1; } /** * Get list of pages that were processed before * * @return array $pages */ public function get_processed_pages_list() { $pages = get_transient( 'cmplz_processed_pages_list' ); if ( ! is_array( $pages ) ) { $pages = array(); } return array_filter($pages); } /** * Check if the scan is complete * * @param void * * @return bool * @since 1.0 * * */ public function scan_complete() { $pages = array_filter($this->pages_to_process()); return count( $pages ) === 0; } /** * * Get list of pages that still have to be processed * * @param void * * @return array $pagÄes * @since 1.0 */ private function pages_to_process(): array { $pages_list = $this->get_pages_list_single_run(); $processed_pages_list = $this->get_processed_pages_list(); return array_diff( $pages_list, $processed_pages_list ); } /** * Set a page as being processed * * @param $id * * @return void * @since 1.0 */ public function set_page_as_processed( $id ): void { if ( ! cmplz_user_can_manage() ) { return; } if ( $id !== 'home' && $id !== 'loginpage' && $id !== 'remote' && ! is_numeric( $id ) ) { return; } $pages = $this->get_processed_pages_list(); if ( ! in_array( $id, $pages, true ) ) { $pages[] = $id; $expiration = $this->automatic_cookiescan_disabled() ? 10 * YEAR_IN_SECONDS : MONTH_IN_SECONDS; set_transient( 'cmplz_processed_pages_list', $pages, $expiration ); } } /** * Update the cookie policy date */ public function update_cookie_policy_date() { update_option( 'cmplz_publish_date', time() ); //also reset the email notification, so it will get sent next year. update_option( 'cmplz_update_legal_documents_mail_sent', false ); } /** * Get progress of the current scan to output with ajax * * @param array $data * @param string $action * @param WP_REST_Request $request * * @return array */ public function get_scan_progress( array $data, string $action, WP_REST_Request $request): array { if (!cmplz_user_can_manage()) { return []; } if ( $action === 'get_scan_progress' ) { $timezone_offset = get_option( 'gmt_offset' ); $time = time() + ( 60 * 60 * $timezone_offset ); update_option( 'cmplz_last_cookie_scan', $time ); $next_url = $this->get_next_page_url(); if ($next_url==='remote') { do_action('cmplz_remote_cookie_scan'); $next_url = $this->get_next_page_url(); } else if ( strpos( $next_url, 'complianz_id' ) !== false ) { $response = wp_remote_get( $next_url ); if ( ! is_wp_error( $response ) ) { $html = $response['body']; $this->parse_html($html); } } $this->clear_double_cookienames(); $cookies = COMPLIANZ::$banner_loader->get_cookies(); $progress = $this->get_progress_count(); $total = count($cookies); $current = (int) ( $progress / 100 * $total ); $cookies = array_slice( $cookies, 0, $current); $cookies = count($cookies) > 0 ? wp_list_pluck( $cookies, 'name' ) : []; $data = [ "progress" => $progress, "next_page" => $next_url, 'cookies' => $cookies, 'token' => wp_create_nonce( 'complianz_scan_token' ), ]; } return $data; } /** * Rescan after a manual "rescan" command from the user */ public function reset_scan($data, $action, $request) { if ( !cmplz_user_can_manage() ) { return []; } if ( $action === 'scan' ) { $scan_type = sanitize_title($request->get_param('scan_action')); if ( $scan_type==='reset' ) { global $wpdb; $table_names = array( $wpdb->prefix . 'cmplz_cookies'); foreach ( $table_names as $table_name ) { if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name ) { $wpdb->query( "TRUNCATE TABLE $table_name" ); } } update_option( 'cmplz_detected_social_media', false ); update_option( 'cmplz_detected_thirdparty_services', false ); update_option( 'cmplz_detected_stats', false ); } if ( $scan_type==='reset' || $scan_type==='restart' ) { $this->reset_pages_list( false, true ); COMPLIANZ::$sync->resync(); } $data = []; } return $data; } /** * Get progress of the scan in percentage * * @return float */ public function get_progress_count() { $done = $this->get_processed_pages_list(); $total = $this->get_pages_list_single_run(); //prevent division by zero $total = count($total) === 0 ? count($done) : count($total); $progress = 100 * ( count( $done ) / $total); if ( $progress > 100 ) { $progress = 100; } return $progress; } } } //class closure