PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.11
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.11
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / includes / Admin / Scanner / Scanner.php

Scanner.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.11, at includes/Admin/Scanner/Scanner.php

309 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace NotificationX\Admin\Scanner;
3
4 use NotificationX\Admin\Entries;
5 use NotificationX\Core\Database;
6 use NotificationX\Core\Helper;
7 use NotificationX\Core\Limiter;
8 use NotificationX\Core\PostType;
9 use NotificationX\GetInstance;
10 use NotificationX\NotificationX;
11 use WP_REST_Server;
12 use WP_REST_Request;
13 use WP_REST_Response;
14
15 class Scanner
16 {
17 use GetInstance;
18 private static $_namespace = 'notificationx';
19 private static $_version = 1;
20 private static $_apiBase = "";
21 private static $is_pro = false;
22 public function __construct()
23 {
24 add_action('rest_api_init', [$this, 'rest_init']);
25 if( NotificationX::is_pro() ) {
26 self::$is_pro = true;
27 }
28 self::$_apiBase = (defined('NX_DEBUG') && NX_DEBUG)
29 ? 'https://notificationx-api.test/cookie-scanner/v1'
30 : 'https://api.notificationx.com/cookie-scanner/v1';
31 }
32
33 public static function _namespace()
34 {
35 return self::$_namespace . '/v' . self::$_version;
36 }
37
38 /**
39 * Registers custom REST API endpoints for scan initiation, scan status, and scan history.
40 *
41 * - /scan: Initiates a new scan based on the provided URL.
42 * - /scan/status: Retrieves the status of a scan using the provided scan ID.
43 * - /scan/history: Fetches the scan history based on the notification ID (nx_id).
44 *
45 * @return void
46 */
47 public function rest_init()
48 {
49 $namespace = self::_namespace();
50
51 // Register the scan initiation endpoint
52 register_rest_route($namespace, '/scan', array(
53 'methods' => WP_REST_Server::CREATABLE,
54 'callback' => array($this, 'initiate_scan'),
55 'permission_callback' => '__return_true',
56 ));
57
58 // Register the scan status endpoint
59 register_rest_route($namespace, '/scan/status', array(
60 'methods' => WP_REST_Server::EDITABLE,
61 'callback' => array($this, 'check_scan_status'),
62 'permission_callback' => '__return_true',
63 ));
64
65 }
66
67 /**
68 * Initiates a scan process for the provided URL.
69 *
70 * Validates the URL parameter and triggers the scan if it's valid.
71 * Responds with the scan status.
72 *
73 * @param WP_REST_Request $request The REST request object containing the URL.
74 *
75 * @return WP_REST_Response The response indicating the status of the scan initiation.
76 */
77 public function initiate_scan(WP_REST_Request $request)
78 {
79 $url = $request->get_param('url');
80
81 // Check if the URL parameter is provided
82 if (empty($url)) {
83 return new WP_REST_Response(['error' => 'URL parameter is required'], 200);
84 }
85
86 // Trigger the scan process (implement this function as needed)
87 $this->trigger_scan($url);
88
89 return new WP_REST_Response(['status' => 'Scan started.'], 200);
90 }
91
92 /**
93 * Retrieves the current status of a scan based on the provided scan ID.
94 *
95 * Queries the status from an external service and returns the results.
96 * If the scan is completed, it processes the result and inserts cookie and stats entries into the database.
97 *
98 * @param WP_REST_Request $request The REST request object containing the scan ID.
99 *
100 * @return WP_REST_Response The response with the scan status or an error message.
101 */
102 public function check_scan_status(WP_REST_Request $request)
103 {
104 $scanId = $request->get_param('scan_id');
105 $nx_id = $request->get_param('nx_id');
106
107 // Retrieve the scan status from the database (implement this function as needed)
108 $status = $this->get_scan_status($scanId);
109
110 // Handle invalid scan ID
111 if ($status === null && empty( $scanId )) {
112 $data = [ 'status' => 'failed', 'message' => __('Invalid scan ID','notificationx') ];
113 return new WP_REST_Response(['data' => $data ], 404);
114 }
115
116 // Process the scan result if the status is 'completed'
117 if ( is_array($status) && !empty($status['status']) && $status['status'] === 'completed') {
118 // Update scan count to the options
119 $pre_count = get_option('nx_scan_count', 0);
120 update_option('nx_scan_count', $pre_count + 1);
121 update_option('nx_scan_date', Helper::nx_get_current_datetime() );
122
123 $cookies = $status['result']; // Extract scanned cookies
124 $stats = $status['stats']; // Extract scan statistics
125
126 // Use the helper function to categorize cookies and get the category count
127 $cookieData = $this->categorizeCookiesAndCount($cookies);
128 $categoryCount = $cookieData['category_count'];
129 $categorized = $cookieData['categorized'];
130 $data = [ 'last_scan_date' => Helper::nx_get_current_datetime(), 'status' => 'completed', 'stats' => $stats, 'cookies' => $cookies, 'category_count' => $categoryCount, 'categorized' => $categorized ];
131 return new WP_REST_Response(['data' => $data], 200);
132
133 // Prepare stats entry with the category count
134 if (!empty($stats) && is_array($stats)) {
135 $stats['category_count'] = $categoryCount;
136 }
137 if (!empty($stats) && is_array($stats)) {
138 $stats['categorized'] = $categorized;
139 }
140 if( empty( $nx_id ) ) {
141 return new WP_REST_Response(['data' => $status], 200);
142 }
143
144 // If cookies or stats exist, prepare them for database insertion
145 if ((!empty($cookies) && is_array($cookies)) || (!empty($stats) && is_array($stats))) {
146 $entriesToInsert = [];
147
148 // Prepare cookies entry
149 if (!empty($cookies) && is_array($cookies)) {
150 $entriesToInsert[] = [
151 'nx_id' => $nx_id,
152 'source' => 'gdpr_notification',
153 'entry_key' => $scanId . '_cookies',
154 'data' => $cookies,
155 'created_at' => date('Y-m-d H:i:s'),
156 ];
157 }
158
159 // Prepare stats entry
160 if (!empty($stats) && is_array($stats)) {
161 $entriesToInsert[] = [
162 'nx_id' => $nx_id,
163 'source' => 'gdpr_notification',
164 'entry_key' => $scanId . '_stats',
165 'data' => $stats,
166 'created_at' => date('Y-m-d H:i:s'),
167 ];
168 }
169
170 // Insert data into the database
171 foreach ($entriesToInsert as $entry) {
172 // Check if an entry already exists
173 $isExists = Database::get_instance()->get_posts(
174 Database::$table_entries, 'count(*)', [
175 'nx_id' => $nx_id,
176 'source' => 'gdpr_notification',
177 'entry_key' => $entry['entry_key'],
178 ]
179 );
180
181 if (empty($isExists[0]['count(*)'])) {
182 $post = PostType::get_instance()->get_post($nx_id);
183 $canEntry = apply_filters("nx_can_entry_gdpr_notification", true, $entry, $post);
184 if ($canEntry) {
185 Limiter::get_instance()->remove($nx_id, 1);
186 Entries::get_instance()->insert_entry($entry);
187 }
188 }
189 }
190 }
191 }
192
193 return new WP_REST_Response(['data' => $status], 200);
194 }
195
196 /**
197 * Triggers a scan process by making an HTTP GET request to an external API.
198 *
199 * Sends the provided URL to the external scan API and handles the response.
200 *
201 * @param string $url The URL to be scanned.
202 *
203 * @return WP_REST_Response The response containing the result of the scan.
204 */
205 private function trigger_scan($url)
206 {
207 // API endpoint that will process the scan
208 if( self::$is_pro ) {
209 $apiEndpoint = self::$_apiBase . "?nxpro=active&url=" . urlencode($url);
210 }else{
211 $apiEndpoint = self::$_apiBase . "?url=" . urlencode($url);
212 }
213
214 // Make an HTTP GET request
215 $response = wp_remote_get($apiEndpoint, [
216 'timeout' => 200, // Set timeout (adjust as needed)
217 'sslverify' => false, // Bypass SSL verification temporarily (for local dev)
218 ]);
219
220 // Check for errors in the response
221 if (is_wp_error($response)) {
222 return new WP_REST_Response(['error' => $response->get_error_message()], 500);
223 }
224
225 // Decode response body
226 $responseBody = json_decode(wp_remote_retrieve_body($response), true);
227
228 return wp_send_json_success($responseBody);
229 }
230
231 /**
232 * Retrieves the current status of a scan from the external scan API using the scan ID.
233 *
234 * Makes an HTTP GET request to the scan API to fetch the status of the scan.
235 *
236 * @param string $scanId The scan ID to check the status of.
237 *
238 * @return array The scan status data from the external API.
239 */
240 private function get_scan_status($scanId)
241 {
242 // API endpoint to check the scan status
243 $apiEndpoint = self::$_apiBase . "/status.php?scan_id=" . urlencode($scanId);
244
245 // Make an HTTP GET request
246 $response = wp_remote_get($apiEndpoint, [
247 'timeout' => 200, // Set timeout (adjust as needed)
248 'sslverify' => false, // Bypass SSL verification temporarily (for local dev)
249 ]);
250
251 // Check for errors in the response
252 if (is_wp_error($response)) {
253 return new WP_REST_Response(['error' => $response->get_error_message()], 500);
254 }
255
256 // Decode response body
257 $responseBody = json_decode(wp_remote_retrieve_body($response), true);
258 return $responseBody;
259 }
260
261
262 // Helper function to categorize cookies and calculate category count
263 public function categorizeCookiesAndCount($cookies) {
264 // Define cookie categories
265 $cookieCategoryPrefix = [
266 'necessary' => ['PHPSESSID', 'wordpress_logged_in', 'wp-settings', 'wp-settings-time', 'wpEmojiSettingsSupports', 'cookieyes-consent', 'elementor', 'csrftoken', 'auth', 'session', 'secure', 'cart', 'checkout', 'wp_woocommerce'],
267 'functional' => ['lang', 'preferences', 'remember_me', 'theme', 'consent', 'locale', 'user_settings', 'cookie_preference'],
268 'analytics' => ['_ga', '_gid', '_gat', 'fbp', 'utm', 'amplitude', 'mixpanel', 'hotjar', 'segment', 'ahoy', 'kissmetrics', 'analytics', 'visitor_id', 'sbjs_udata', 'sbjs_current', 'sbjs_first', 'sbjs_first_add', 'sbjs_current_add'],
269 'performance' => ['_hj', 'cf_use_ob', 'cf_clearance', 'AWSALB', 'load_balancer', 'page_speed', 'cdn_cache', 'pingdom', 'new_relic'],
270 'advertisement' => ['ads', '_fbp', '_gcl', '_dc_gtm', 'doubleclick', 'IDE', 'adroll', 'criteo', 'twitter_ads', 'bing_ads', 'remarketing', 'test_cookie'],
271 ];
272
273 // Initialize category counts
274 $categorized = [
275 'necessary' => 0,
276 'functional' => 0,
277 'analytics' => 0,
278 'performance' => 0,
279 'advertisement' => 0,
280 ];
281
282 // Categorize cookies based on partial matching of cookie names (prefixes)
283 if (!empty($cookies) && is_array($cookies)) {
284 foreach ($cookies as $cookie) {
285 foreach ($cookieCategoryPrefix as $category => $cookieNames) {
286 foreach ($cookieNames as $cookieName) {
287 if (isset($cookie['name']) && strpos($cookie['name'], $cookieName) !== false) { // Check if cookie contains the prefix
288 $categorized[$category]++;
289 break; // No need to check other prefixes for this cookie
290 }
291 }
292 }
293 }
294 }
295
296 // Calculate the category count (only categories with count > 0)
297 $categoryCount = count(array_filter($categorized, function($count) {
298 return $count > 0;
299 }));
300
301 return [
302 'category_count' => $categoryCount,
303 'categorized' => $categorized
304 ];
305 }
306
307 }
308 ?>
309