PluginProbe ʕ •ᴥ•ʔ
Check & Log Email – Easy Email Testing & Mail logging / 2.0.12
Check & Log Email – Easy Email Testing & Mail logging v2.0.12
1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 2.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.13.1 2.0.13.2 2.0.14 2.0.2 2.0.3 2.0.4 2.0.5 2.0.5.1 2.0.6 2.0.7 2.0.8 2.0.9 trunk 0.5.7 0.6.0 0.6.1 0.6.2 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.12.1 1.0.13 1.0.13.1 1.0.2 1.0.3
check-email / include / Core / DB / Check_Email_Table_Manager.php
check-email / include / Core / DB Last commit date
Check_Email_Table_Manager.php 4 months ago
Check_Email_Table_Manager.php
884 lines
1 <?php namespace CheckEmail\Core\DB;
2
3 /**
4 * Handle installation and db table creation.
5 */
6 use CheckEmail\Core\Loadie;
7 use CheckEmail\Util;
8
9 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
10
11 /**
12 * Helper class to create table.
13 */
14 class Check_Email_Table_Manager implements Loadie {
15
16 /* Database table name */
17 const LOG_TABLE_NAME = 'check_email_log';
18 const ERROR_TRACKER_TABLE_NAME = 'check_email_error_logs';
19
20 /* Database option name */
21 const DB_OPTION_NAME = 'check_email-log-db';
22
23 /* Database version */
24 const DB_VERSION = '0.3';
25
26 /**
27 * Setup hooks.
28 */
29 public function load() {
30 add_action( 'wpmu_new_blog', array( $this, 'create_table_for_new_blog' ) );
31
32 add_filter( 'wpmu_drop_tables', array( $this, 'delete_table_from_deleted_blog' ) );
33
34 add_filter( 'admin_init', array( $this, 'add_backtrace_segment_field' ) );
35 add_filter( 'admin_init', array( $this, 'add_open_count_field' ) );
36
37 $option = get_option( 'check-email-log-core' );
38 if ((isset($option['is_retention_amount_enable']) && $option['is_retention_amount_enable']) || (isset($option['is_retention_period_enable']) && $option['is_retention_period_enable'])) {
39 add_action('admin_init', array( $this, 'ck_mail_cron_schedule' ));
40 add_action('check_mail_cron_hook', array( $this, 'ck_mail_cron_execute' ));
41 }
42
43 // Do any DB upgrades.
44 $this->update_table_if_needed();
45 }
46
47 public function on_activate( $network_wide ) {
48 if ( is_multisite() && $network_wide ) {
49 // Note: if there are more than 10,000 blogs or
50 // if `wp_is_large_network` filter is set, then this may fail.
51 $sites = get_sites();
52
53 foreach ( $sites as $site ) {
54 switch_to_blog( $site->blog_id );
55 $this->create_table_if_needed();
56 restore_current_blog();
57 if (function_exists('ck_mail_create_error_logs') ) {
58 ck_mail_create_error_logs();
59 }
60 if (function_exists('ck_mail_create_spam_analyzer_table') ) {
61 ck_mail_create_spam_analyzer_table();
62 }
63 }
64 } else {
65 $this->create_table_if_needed();
66 if (function_exists('ck_mail_create_error_logs') ) {
67 ck_mail_create_error_logs();
68 }
69 if (function_exists('ck_mail_create_spam_analyzer_table') ) {
70 ck_mail_create_spam_analyzer_table();
71 }
72 }
73 }
74
75 /**
76 * Create email log table when a new blog is created.
77 */
78 public function create_table_for_new_blog( $blog_id ) {
79 if ( is_plugin_active_for_network( 'check-email-log/check-email.php' ) ) {
80 switch_to_blog( $blog_id );
81 $this->create_table_if_needed();
82 restore_current_blog();
83 }
84 }
85
86 /**
87 * Add email log table to the list of tables deleted when a blog is deleted.
88 */
89 public function delete_table_from_deleted_blog( $tables ) {
90 $tables[] = $this->get_log_table_name();
91
92 return $tables;
93 }
94
95 /**
96 * Get email log table name.
97 */
98 public function get_log_table_name() {
99 global $wpdb;
100
101 return $wpdb->prefix . self::LOG_TABLE_NAME;
102 }
103 public function get_error_tracker_table_name() {
104 global $wpdb;
105
106 return $wpdb->prefix . self::ERROR_TRACKER_TABLE_NAME;
107 }
108
109 public function insert_log( $data ) {
110 global $wpdb;
111
112 $table_name = $this->get_log_table_name();
113 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: custom table on insert
114 $wpdb->insert( $table_name, $data );
115 }
116
117 public function delete_logs( $ids ) {
118 global $wpdb;
119
120 $table_name = $this->get_log_table_name();
121
122 $ids = esc_sql( $ids );
123 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: $table_name
124 $result = $wpdb->query( "DELETE FROM {$table_name} where id IN ( {$ids} )" );
125 $ids_array = array_map('intval', explode(',', $ids));
126 if ($result !== false) {
127 foreach ($ids_array as $id) {
128 wp_cache_delete($id, 'check_mail_log');
129 }
130 }
131 return $result;
132 }
133
134 public function delete_all_logs() {
135 global $wpdb;
136
137 $table_name = $this->get_log_table_name();
138 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: $table_name
139 $result = $wpdb->query( "DELETE FROM {$table_name}" );
140
141 if ($result !== false) {
142 wp_cache_delete('check_mail_log','check_mail_log');
143 }
144
145 return $result;
146 }
147
148 public function delete_error_tracker( $ids ) {
149 global $wpdb;
150
151 $table_name = $this->get_error_tracker_table_name();
152
153 $ids = esc_sql( $ids );
154 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: $table_name
155 $result = $wpdb->query( "DELETE FROM {$table_name} where id IN ( {$ids} )" );
156 $ids_array = array_map('intval', explode(',', $ids));
157 if ($result !== false) {
158 foreach ($ids_array as $id) {
159 wp_cache_delete($id, 'check_mail_log');
160 }
161 }
162 return $result;
163 }
164
165 public function delete_all_error_tracker() {
166 global $wpdb;
167
168 $table_name = $this->get_error_tracker_table_name();
169 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery -- Reason: $table_name
170 $result = $wpdb->query( "DELETE FROM {$table_name}" );
171
172 if ($result !== false) {
173 wp_cache_delete('check_mail_log','check_mail_log');
174 }
175
176 return $result;
177 }
178
179 public function delete_logs_older_than( $interval_in_days ) {
180 global $wpdb;
181 $table_name = $this->get_log_table_name();
182 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
183 $query = $wpdb->prepare( "DELETE FROM {$table_name} WHERE sent_date < DATE_SUB( CURDATE(), INTERVAL %d DAY )", $interval_in_days );
184 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- already prepare in query
185 $deleted_rows_count = $wpdb->query( $query );
186
187 return $deleted_rows_count;
188 }
189
190 public function fetch_log_items_by_id( $ids = array(), $additional_args = array() ) {
191 global $wpdb;
192 $table_name = $this->get_log_table_name();
193
194 $query = "SELECT * FROM {$table_name}";
195
196 $date_column_format_key = 'date_column_format';
197 if ( array_key_exists( $date_column_format_key, $additional_args ) && ! empty( $additional_args[ $date_column_format_key ] ) ) {
198 $query = "SELECT DATE_FORMAT(sent_date, \"{$additional_args[ $date_column_format_key ]}\") as sent_date_custom, el.* FROM {$table_name} as el";
199 }
200
201 if ( ! empty( $ids ) ) {
202 $ids = array_map( 'absint', $ids );
203
204 // Can't use wpdb->prepare for the below query.
205 $ids_list = esc_sql( implode( ',', $ids ) );
206
207 $query .= " where id IN ( {$ids_list} )";
208 }
209
210 return $wpdb->get_results( $query, 'ARRAY_A' ); //@codingStandardsIgnoreLine
211 }
212
213 public function fetch_log_items( $request, $per_page, $current_page_no ) {
214 global $wpdb;
215 $table_name = $this->get_log_table_name();
216
217 $query = 'SELECT * FROM ' . $table_name;
218 $count_query = 'SELECT count(*) FROM ' . $table_name;
219 $query_cond = '';
220
221 if ( isset( $request['s'] ) && is_string( $request['s'] ) && $request['s'] !== '' ) {
222 $search_term = trim( esc_sql( $request['s'] ) );
223
224 if ( Util\wp_chill_check_email_advanced_search_term( $search_term ) ) {
225 $predicates = Util\wp_chill_check_email_get_advanced_search_term_predicates( $search_term );
226
227 foreach ( $predicates as $column => $email ) {
228 switch ( $column ) {
229 case 'id':
230 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
231 $query_cond .= "id = '$email'";
232 break;
233 case 'to':
234 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
235 $query_cond .= "to_email LIKE '%$email%'";
236 break;
237 case 'email':
238 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
239 $query_cond .= ' ( '; /* Begin 1st */
240 $query_cond .= " ( to_email LIKE '%$email%' OR subject LIKE '%$email%' ) "; /* Begin 2nd & End 2nd */
241 $query_cond .= ' OR ';
242 $query_cond .= ' ( '; /* Begin 3rd */
243 $query_cond .= "headers <> ''";
244 $query_cond .= ' AND ';
245 $query_cond .= ' ( '; /* Begin 4th */
246 $query_cond .= "headers REGEXP '[F|f]rom:.*$email' OR ";
247 $query_cond .= "headers REGEXP '[CC|Cc|cc]:.*$email' OR ";
248 $query_cond .= "headers REGEXP '[BCC|Bcc|bcc]:.*$email' OR ";
249 $query_cond .= "headers REGEXP '[R|r]eply-[T|t]o:.*$email'";
250 $query_cond .= ' ) '; /* End 4th */
251 $query_cond .= ' ) '; /* End 3rd */
252 $query_cond .= ' ) '; /* End 1st */
253 break;
254 case 'cc':
255 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
256 $query_cond .= ' ( '; /* Begin 1st */
257 $query_cond .= "headers <> ''";
258 $query_cond .= ' AND ';
259 $query_cond .= ' ( '; /* Begin 2nd */
260 $query_cond .= "headers REGEXP '[CC|Cc|cc]:.*$email' ";
261 $query_cond .= ' ) '; /* End 2nd */
262 $query_cond .= ' ) '; /* End 1st */
263 break;
264 case 'bcc':
265 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
266 $query_cond .= ' ( '; /* Begin 1st */
267 $query_cond .= "headers <> ''";
268 $query_cond .= ' AND ';
269 $query_cond .= ' ( '; /* Begin 2nd */
270 $query_cond .= "headers REGEXP '[BCC|Bcc|bcc]:.*$email' ";
271 $query_cond .= ' ) '; /* End 2nd */
272 $query_cond .= ' ) '; /* End 1st */
273 break;
274 case 'reply-to':
275 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
276 $query_cond .= ' ( '; /* Begin 1st */
277 $query_cond .= "headers <> ''";
278 $query_cond .= ' AND ';
279 $query_cond .= ' ( '; /* Begin 2nd */
280 $query_cond .= "headers REGEXP '[R|r]eply-to:.*$email' ";
281 $query_cond .= ' ) '; /* End 2nd */
282 $query_cond .= ' ) '; /* End 1st */
283 break;
284 }
285 }
286 } else {
287 $query_cond .= " WHERE ( to_email LIKE '%$search_term%' OR subject LIKE '%$search_term%' OR message LIKE '%$search_term%' ) ";
288 }
289 }
290
291 if ( isset( $request['d'] ) && $request['d'] !== '' ) {
292 $search_date = trim( esc_sql( $request['d'] ) );
293 if ( '' === $query_cond ) {
294 $query_cond .= " WHERE sent_date BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
295 } else {
296 $query_cond .= " AND sent_date BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
297 }
298 }
299 if ( isset( $request['status'] ) && $request['status'] !== '' ) {
300 $status = trim( esc_sql( $request['status'] ) );
301 switch( $status ) {
302 case 'failed':
303 $query_cond .= " WHERE `result` IS NULL OR `result` = ''";
304 break;
305 case 'complete':
306 $query_cond .= " WHERE `result` IS NOT NULL AND `result` != ''";
307 break;
308 default:
309 break;
310 }
311 }
312
313 // Ordering parameters.
314 $orderby = ! empty( $request['orderby'] ) ? sanitize_sql_orderby( $request['orderby'] ) : 'sent_date';
315 if ( isset( $request['order'] ) ) {
316 $order = in_array( strtoupper($request['order']), array( 'DESC', 'ASC' ) ) ? esc_sql( $request['order'] ) : 'DESC';
317 }else{
318 $order = 'DESC';
319 }
320
321
322 if ( ! empty( $orderby ) & ! empty( $order ) ) {
323 $query_cond .= ' ORDER BY ' . $orderby . ' ' . $order;
324 }
325
326 // Find total number of items.
327 $count_query = $count_query . $query_cond;
328 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
329 $total_items = $wpdb->get_var( $count_query );
330
331 // Adjust the query to take pagination into account.
332 if ( ! empty( $current_page_no ) && ! empty( $per_page ) ) {
333 $offset = ( $current_page_no - 1 ) * $per_page;
334 $query_cond .= ' LIMIT ' . (int) $offset . ',' . (int) $per_page;
335 }
336
337 // Fetch the items.
338 $query = $query . $query_cond;
339 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Due to critical query not used prepare $table_name
340 $items = $wpdb->get_results( $query );
341
342 return array( $items, $total_items );
343 }
344
345 /*public function create_table_if_needed() {
346 global $wpdb;
347
348 $table_name = $this->get_log_table_name();
349 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
350 if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s",$wpdb->esc_like( $table_name ))) != $table_name ) {
351
352 $sql = $this->get_create_table_query();
353
354 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
355 dbDelta( $sql );
356
357 add_option( self::DB_OPTION_NAME, self::DB_VERSION );
358 }
359 }*/
360
361 public function create_table_if_needed() {
362 global $wpdb;
363
364 $table_name = $this->get_log_table_name();
365 $table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
366
367 // If the table does NOT exist...
368 if ( ! $table_exists ) {
369 $sql = $this->get_create_table_query();
370
371 if ( ! function_exists( 'dbDelta' ) ) {
372 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
373 }
374
375 $wpdb->query( $sql );
376 }
377
378 if ( ! function_exists( 'dbDelta' ) ) {
379 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
380 }
381
382 $sql = $this->get_create_table_query();
383 dbDelta( $sql );
384 }
385
386 public function get_logs_count() {
387 global $wpdb;
388 $table_name = $this->get_log_table_name();
389 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
390 // $query = $wpdb->prepare("SELECT count(*) FROM `$table_name`");
391 $query = "SELECT count(*) FROM `$table_name`";
392 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason:already used prepare
393 return $wpdb->get_var( $query );
394 }
395
396 public function fetch_log_id_by_data( $data ) {
397 if ( empty( $data ) || ! is_array( $data ) ) {
398 return 0;
399 }
400
401 global $wpdb;
402 $table_name = $this->get_log_table_name();
403
404 $query = "SELECT ID FROM {$table_name}";
405 $query_cond = '';
406 $where = array();
407
408 // Execute the following `if` conditions only when $data is array.
409 if ( array_key_exists( 'to', $data ) ) {
410 // Since the value is stored as CSV in DB, convert the values from error data to CSV to compare.
411 $to_email = Util\wp_chill_check_email_stringify( $data['to'] );
412
413 $to_email = trim( esc_sql( $to_email ) );
414 $where[] = $wpdb->prepare("to_email = %s",$to_email);
415 }
416
417 if ( array_key_exists( 'subject', $data ) ) {
418 $subject = trim( esc_sql( $data['subject'] ) );
419 $where[] = $wpdb->prepare("subject = %s",$subject);
420 }
421
422 if ( array_key_exists( 'attachments', $data ) ) {
423 if ( is_array( $data['attachments'] ) ) {
424 $attachments = count( $data['attachments'] ) > 0 ? 'true' : 'false';
425 } else {
426 $attachments = empty( $data['attachments'] ) ? 'false' : 'true';
427 }
428 $attachments = trim( esc_sql( $attachments ) );
429 $where[] = $wpdb->prepare("attachments = %s",$attachments);
430 }
431
432 foreach ( $where as $index => $value ) {
433 $query_cond .= 0 === $index ? ' WHERE ' : ' AND ';
434 $query_cond .= $value;
435 }
436
437 // Get only the latest logged item when multiple rows match.
438 $query_cond .= ' ORDER BY id DESC LIMIT 1';
439
440 $query = $query . $query_cond;
441 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
442 return absint( $wpdb->get_var( $query ) );
443 }
444
445 public function mark_log_as_failed( $log_item_id, $message ) {
446 global $wpdb;
447 $table_name = $this->get_log_table_name();
448 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
449 $wpdb->update(
450 $table_name,
451 array(
452 'result' => '0',
453 'error_message' => $message,
454 ),
455 array( 'ID' => $log_item_id ),
456 array(
457 '%d', // `result` format.
458 '%s', // `error_message` format.
459 ),
460 array(
461 '%d', // `ID` format.
462 )
463 );
464 }
465
466 private function update_table_if_needed() {
467 if ( get_option( self::DB_OPTION_NAME, false ) === self::DB_VERSION ) {
468 return;
469 }
470
471 $sql = $this->get_create_table_query();
472
473 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
474 dbDelta( $sql );
475
476 update_option( self::DB_OPTION_NAME, self::DB_VERSION );
477 }
478
479 private function get_create_table_query() {
480 global $wpdb;
481 $table_name = $this->get_log_table_name();
482 $charset_collate = $wpdb->get_charset_collate();
483
484 $sql = 'CREATE TABLE ' . $table_name . ' (
485 id mediumint(9) NOT NULL AUTO_INCREMENT,
486 to_email VARCHAR(500) NOT NULL,
487 subject VARCHAR(500) NOT NULL,
488 message TEXT NOT NULL,
489 backtrace_segment TEXT NOT NULL,
490 headers TEXT NOT NULL,
491 attachments TEXT NOT NULL,
492 sent_date timestamp NOT NULL,
493 attachment_name VARCHAR(1000),
494 ip_address VARCHAR(15),
495 result TINYINT(1),
496 error_message VARCHAR(1000),
497 PRIMARY KEY (id)
498 ) ' . $charset_collate . ';';
499
500 return $sql;
501 }
502
503 private function validate_columns( $column ) {
504 return in_array( $column, array( 'to' ), true );
505 }
506
507 public function query_log_items_by_column( $columns ) {
508 if ( ! is_array( $columns ) ) {
509 return;
510 }
511
512 $columns_keys = array_keys( $columns );
513 if ( ! array_filter( $columns_keys, array( $this, 'validate_columns' ) ) ) {
514 return;
515 }
516
517 global $wpdb;
518
519 $table_name = $this->get_log_table_name();
520 $query = "SELECT id, sent_date, to_email, subject FROM {$table_name}";
521 $query_cond = '';
522 $where = array();
523
524 // Execute the following `if` conditions only when $data is array.
525 if ( array_key_exists( 'to', $columns ) ) {
526 // Since the value is stored as CSV in DB, convert the values from error data to CSV to compare.
527 $to_email = Util\wp_chill_check_email_stringify( $columns['to'] );
528
529 $to_email = trim( esc_sql( $to_email ) );
530 $where[] = "to_email = '$to_email'";
531
532 foreach ( $where as $index => $value ) {
533 $query_cond .= 0 === $index ? ' WHERE ' : ' AND ';
534 $query_cond .= $value;
535 }
536
537 // Get only the latest logged item when multiple rows match.
538 $query_cond .= ' ORDER BY id DESC';
539
540 $query = $query . $query_cond;
541 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
542 return $wpdb->get_results( $query );
543 }
544 }
545
546 /**
547 * Add new backtrace_segment field to check_email_log table
548 * @since 1.0.12
549 * */
550 public function add_backtrace_segment_field(){
551 global $wpdb;
552 $table_name = $this->get_log_table_name();
553
554 // Field to check
555 $field_name = 'backtrace_segment';
556
557 // Query to check if the field exists in the table
558 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
559 $field_exists = $wpdb->get_results(
560 $wpdb->prepare(
561 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
562 "SHOW COLUMNS FROM $table_name LIKE %s",
563 $field_name
564 )
565 );
566
567 if(empty($field_exists)){
568 $query = "ALTER TABLE $table_name ADD backtrace_segment TEXT NULL DEFAULT NULL AFTER message";
569 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
570 $wpdb->query($query);
571 }
572 }
573 /**
574 * Add new open_count field to check_email_log table = will check email is opened count by user
575 * @since 1.0.12
576 * */
577 public function add_open_count_field(){
578 global $wpdb;
579 $table_name = $this->get_log_table_name();
580
581 // Field to check
582 $field_name = 'open_count';
583
584 // Query to check if the field exists in the table
585 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
586 $field_exists = $wpdb->get_results(
587 $wpdb->prepare(
588 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
589 "SHOW COLUMNS FROM $table_name LIKE %s",
590 $field_name
591 )
592 );
593
594 if(empty($field_exists)){
595 $query = "ALTER TABLE $table_name ADD open_tracking_id TEXT NULL DEFAULT NULL, ADD open_count TEXT NULL DEFAULT NULL AFTER message";
596 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
597 $wpdb->query($query);
598 }
599 }
600
601 public function fetch_log_count_by_status( $request, $per_page, $current_page_no,$status='all' ) {
602 global $wpdb;
603 $table_name = $this->get_log_table_name();
604
605
606 $count_query = 'SELECT count(*) FROM ' . $table_name;
607 $query_cond = '';
608
609 if ( isset( $request['s'] ) && is_string( $request['s'] ) && $request['s'] !== '' ) {
610 $search_term = trim( esc_sql( $request['s'] ) );
611
612 if ( Util\wp_chill_check_email_advanced_search_term( $search_term ) ) {
613 $predicates = Util\wp_chill_check_email_get_advanced_search_term_predicates( $search_term );
614
615 foreach ( $predicates as $column => $email ) {
616 switch ( $column ) {
617 case 'id':
618 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
619 $query_cond .= "id = '$email'";
620 break;
621 case 'to':
622 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
623 $query_cond .= "to_email LIKE '%$email%'";
624 break;
625 case 'email':
626 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
627 $query_cond .= ' ( '; /* Begin 1st */
628 $query_cond .= " ( to_email LIKE '%$email%' OR subject LIKE '%$email%' ) "; /* Begin 2nd & End 2nd */
629 $query_cond .= ' OR ';
630 $query_cond .= ' ( '; /* Begin 3rd */
631 $query_cond .= "headers <> ''";
632 $query_cond .= ' AND ';
633 $query_cond .= ' ( '; /* Begin 4th */
634 $query_cond .= "headers REGEXP '[F|f]rom:.*$email' OR ";
635 $query_cond .= "headers REGEXP '[CC|Cc|cc]:.*$email' OR ";
636 $query_cond .= "headers REGEXP '[BCC|Bcc|bcc]:.*$email' OR ";
637 $query_cond .= "headers REGEXP '[R|r]eply-[T|t]o:.*$email'";
638 $query_cond .= ' ) '; /* End 4th */
639 $query_cond .= ' ) '; /* End 3rd */
640 $query_cond .= ' ) '; /* End 1st */
641 break;
642 case 'cc':
643 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
644 $query_cond .= ' ( '; /* Begin 1st */
645 $query_cond .= "headers <> ''";
646 $query_cond .= ' AND ';
647 $query_cond .= ' ( '; /* Begin 2nd */
648 $query_cond .= "headers REGEXP '[CC|Cc|cc]:.*$email' ";
649 $query_cond .= ' ) '; /* End 2nd */
650 $query_cond .= ' ) '; /* End 1st */
651 break;
652 case 'bcc':
653 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
654 $query_cond .= ' ( '; /* Begin 1st */
655 $query_cond .= "headers <> ''";
656 $query_cond .= ' AND ';
657 $query_cond .= ' ( '; /* Begin 2nd */
658 $query_cond .= "headers REGEXP '[BCC|Bcc|bcc]:.*$email' ";
659 $query_cond .= ' ) '; /* End 2nd */
660 $query_cond .= ' ) '; /* End 1st */
661 break;
662 case 'reply-to':
663 $query_cond .= empty( $query_cond ) ? ' WHERE ' : ' AND ';
664 $query_cond .= ' ( '; /* Begin 1st */
665 $query_cond .= "headers <> ''";
666 $query_cond .= ' AND ';
667 $query_cond .= ' ( '; /* Begin 2nd */
668 $query_cond .= "headers REGEXP '[R|r]eply-to:.*$email' ";
669 $query_cond .= ' ) '; /* End 2nd */
670 $query_cond .= ' ) '; /* End 1st */
671 break;
672 }
673 }
674 } else {
675 $query_cond .= " WHERE ( to_email LIKE '%$search_term%' OR subject LIKE '%$search_term%' ) ";
676 }
677 }
678
679 if ( isset( $request['d'] ) && $request['d'] !== '' ) {
680 $search_date = trim( esc_sql( $request['d'] ) );
681 if ( '' === $query_cond ) {
682 $query_cond .= " WHERE sent_date BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
683 } else {
684 $query_cond .= " AND sent_date BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
685 }
686 }
687 if ( !empty($status) ) {
688 $status = trim( esc_sql( $status ) );
689 if ($status != 'all') {
690 if ( empty($request['d']) && empty($request['s']) ) {
691 $query_cond .= " WHERE ";
692 }else{
693 $query_cond .= " AND ";
694 }
695 }
696
697 // print_r($query_cond);die;
698
699 switch( $status ) {
700 case 'failed':
701 $query_cond .= " `result` = 0";
702 break;
703 case 'complete':
704 $query_cond .= " `result` != 0";
705 break;
706 default:
707 break;
708 }
709 }
710
711 // Ordering parameters.
712 $orderby = ! empty( $request['orderby'] ) ? sanitize_sql_orderby( $request['orderby'] ) : 'sent_date';
713 if ( isset( $request['order'] ) ) {
714 $order = in_array( strtoupper($request['order']), array( 'DESC', 'ASC' ) ) ? esc_sql( $request['order'] ) : 'DESC';
715 }else{
716 $order = 'DESC';
717 }
718
719 if ( ! empty( $orderby ) & ! empty( $order ) ) {
720 $query_cond .= ' ORDER BY ' . $orderby . ' ' . $order;
721 }
722
723 // Find total number of items.
724 $count_query = $count_query . $query_cond;
725 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason using critical conditions in query
726 $total_items = $wpdb->get_var( $count_query );
727 return $total_items;
728 }
729
730 public function delete_log_older_than($timeInterval = null)
731 {
732 global $wpdb;
733 $table_name = $this->get_log_table_name();
734 $option = get_option( 'check-email-log-core' );
735 if (isset($option['is_retention_amount_enable']) && isset($option['retention_amount']) && $option['is_retention_amount_enable']) {
736 $limit= intval($option['retention_amount']);
737 if(!empty($limit)){
738 $count_query = 'SELECT count(*) FROM ' . $table_name;
739 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
740 $total_items = $wpdb->get_var( $count_query );
741 if ($total_items > $limit) {
742 $data_to_delete = $total_items - $limit;
743 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
744 $old_posts = $wpdb->get_col( $wpdb->prepare(
745 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
746 "SELECT ID FROM $table_name
747 ORDER BY ID ASC
748 LIMIT %d",$data_to_delete) );
749
750 // Delete the logs
751 foreach ($old_posts as $column_value) {
752 $sql = $wpdb->prepare(
753 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
754 "DELETE FROM $table_name WHERE ID = %d",
755 $column_value
756 );
757 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
758 $wpdb->query($sql);
759 }
760 }
761
762 }
763 }
764 if (isset($option['is_retention_period_enable']) && $option['is_retention_period_enable']) {
765
766 if ($option['log_retention_period'] == 'custom_in_days') {
767 $custom_in_days = empty($option['log_retention_period_in_days']) ? 1 : intval($option['log_retention_period_in_days']);
768 $time_interval = strtotime('+' . $custom_in_days. ' days');
769 }else{
770 $periods = array( '1_day' =>86400,
771 '1_week' =>604800,
772 '1_month' =>2419200,
773 '6_month' =>15780000,
774 '1_year' =>31560000
775 );
776 $time_interval = $periods[$option['log_retention_period']];
777 }
778 $timestamp = time() - $time_interval;
779
780 $sql = "DELETE FROM " . $table_name . " WHERE Unix_timestamp(sent_date) <= %d";
781 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
782 $sql = $wpdb->prepare($sql, $timestamp);
783 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
784 $wpdb->query($sql);
785 }
786 }
787
788 function ck_mail_cron_schedule() {
789 if (!wp_next_scheduled('check_mail_cron_hook')) {
790 wp_schedule_event(time(), 'daily', 'check_mail_cron_hook');
791 }
792 }
793
794 function ck_mail_cron_execute() {
795 $this->delete_log_older_than();
796 // error_log('Cron job executed at' . gmdate('Y-m-d H:i:s'));
797 }
798
799 public function fetch_error_tracker_items( $request, $per_page, $current_page_no ) {
800 global $wpdb;
801 $table_name = $this->get_error_tracker_table_name();
802
803 $query = 'SELECT * FROM ' . $table_name;
804 $count_query = 'SELECT count(*) FROM ' . $table_name;
805 $query_cond = '';
806
807 if ( isset( $request['d'] ) && $request['d'] !== '' ) {
808 $search_date = trim( esc_sql( $request['d'] ) );
809 if ( '' === $query_cond ) {
810 $query_cond .= " WHERE created_at BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
811 } else {
812 $query_cond .= " AND created_at BETWEEN '$search_date 00:00:00' AND '$search_date 23:59:59' ";
813 }
814 }
815 if ( isset( $request['status'] ) && $request['status'] !== '' ) {
816 $status = trim( esc_sql( $request['status'] ) );
817 switch( $status ) {
818 case 'failed':
819 $query_cond .= " WHERE `event_type` IS NULL OR `event_type` = ''";
820 break;
821 case 'complete':
822 $query_cond .= " WHERE `event_type` IS NOT NULL AND `event_type` != ''";
823 break;
824 default:
825 break;
826 }
827 }
828
829 // Ordering parameters.
830 $orderby = ! empty( $request['orderby'] ) ? sanitize_sql_orderby( $request['orderby'] ) : 'created_at';
831 if ( isset( $request['order'] ) ) {
832 $order = in_array( strtoupper($request['order']), array( 'DESC', 'ASC' ) ) ? esc_sql( $request['order'] ) : 'DESC';
833 }else{
834 $order = 'DESC';
835 }
836
837
838 if ( ! empty( $orderby ) & ! empty( $order ) ) {
839 $query_cond .= ' ORDER BY ' . $orderby . ' ' . $order;
840 }
841
842 // Find total number of items.
843 $count_query = $count_query . $query_cond;
844 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
845 $total_items = $wpdb->get_var( $count_query );
846
847 // Adjust the query to take pagination into account.
848 if ( ! empty( $current_page_no ) && ! empty( $per_page ) ) {
849 $offset = ( $current_page_no - 1 ) * $per_page;
850 $query_cond .= ' LIMIT ' . (int) $offset . ',' . (int) $per_page;
851 }
852
853 // Fetch the items.
854 $query = $query . $query_cond;
855 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: Due to critical query not used prepare $table_name
856 $items = $wpdb->get_results( $query );
857
858 return array( $items, $total_items );
859 }
860
861 public function fetch_error_tracker_items_by_id( $ids = array(), $additional_args = array() ) {
862 global $wpdb;
863 $table_name = $this->get_error_tracker_table_name();
864
865 $query = "SELECT * FROM {$table_name}";
866
867 $date_column_format_key = 'date_column_format';
868 if ( array_key_exists( $date_column_format_key, $additional_args ) && ! empty( $additional_args[ $date_column_format_key ] ) ) {
869 $query = "SELECT DATE_FORMAT(created_at, \"{$additional_args[ $date_column_format_key ]}\") as sent_date_custom, el.* FROM {$table_name} as el";
870 }
871
872 if ( ! empty( $ids ) ) {
873 $ids = array_map( 'absint', $ids );
874
875 // Can't use wpdb->prepare for the below query.
876 $ids_list = esc_sql( implode( ',', $ids ) );
877
878 $query .= " where id IN ( {$ids_list} )";
879 }
880
881 return $wpdb->get_results( $query, 'ARRAY_A' ); //@codingStandardsIgnoreLine
882 }
883 }
884