PluginProbe ʕ •ᴥ•ʔ
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin / 4.9.0
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin v4.9.0
4.9.0 0.9.6 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.2 1.7.0 1.7.1 1.8.0 1.8.1 1.9.0 2.0.0 2.0.1 2.1.1 2.2.1 2.3.1 2.4.0 2.5.0 2.5.1 2.6.0 2.7.0 2.8.0 2.9.0 3.0.1 3.0.2 3.0.3 3.1.0 3.10.0 3.11.0 3.11.1 3.2.0 3.2.1 3.3.0 3.4.0 3.5.0 3.5.1 3.5.2 3.6.1 3.7.0 3.8.0 3.8.2 3.9.0 4.0.1 4.1.0 4.1.1 4.2.0 4.3.0 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.8.0 trunk 0.10.0 0.10.1 0.11.1 0.11.2 0.3.1 0.3.2 0.4 0.4.1 0.4.2 0.5.0 0.5.1 0.5.2 0.6 0.7 0.8 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5
wp-mail-smtp / src / Tasks / Meta.php
wp-mail-smtp / src / Tasks Last commit date
Queue 6 days ago Reports 6 days ago DebugEventsCleanupTask.php 6 days ago Meta.php 6 days ago NotificationsUpdateTask.php 6 days ago Task.php 6 days ago Tasks.php 6 days ago
Meta.php
534 lines
1 <?php
2
3 namespace WPMailSMTP\Tasks;
4
5 /**
6 * Class Meta helps to manage the tasks meta information
7 * between Action Scheduler and WP Mail SMTP hooks arguments.
8 * We can't pass arguments longer than >191 chars in JSON to AS,
9 * so we need to store them somewhere (and clean from time to time).
10 *
11 * @since 2.1.0
12 */
13 class Meta {
14
15 /**
16 * Database table name.
17 *
18 * @since 2.1.0
19 *
20 * @var string
21 */
22 public $table_name;
23
24 /**
25 * Database version.
26 *
27 * @since 2.1.0
28 *
29 * @var string
30 */
31 public $version;
32
33 /**
34 * Primary key (unique field) for the database table.
35 *
36 * @since 2.1.0
37 *
38 * @var string
39 */
40 public $primary_key = 'id';
41
42 /**
43 * Database type identifier.
44 *
45 * @since 2.1.0
46 *
47 * @var string
48 */
49 public $type = 'tasks_meta';
50
51 /**
52 * Primary class constructor.
53 *
54 * @since 2.1.0
55 */
56 public function __construct() {
57
58 $this->table_name = self::get_table_name();
59 }
60
61 /**
62 * Get the DB table name.
63 *
64 * @since 2.1.0
65 *
66 * @return string
67 */
68 public static function get_table_name() {
69
70 global $wpdb;
71
72 return $wpdb->prefix . 'wpmailsmtp_tasks_meta';
73 }
74
75 /**
76 * Get table columns.
77 *
78 * @since 2.1.0
79 */
80 public function get_columns() {
81
82 return array(
83 'id' => '%d',
84 'action' => '%s',
85 'data' => '%s',
86 'date' => '%s',
87 );
88 }
89
90 /**
91 * Default column values.
92 *
93 * @since 2.1.0
94 *
95 * @return array
96 */
97 public function get_column_defaults() {
98
99 return array(
100 'action' => '',
101 'data' => '',
102 'date' => gmdate( 'Y-m-d H:i:s' ),
103 );
104 }
105
106 /**
107 * Retrieve a row from the database based on a given row ID.
108 *
109 * @since 2.1.0
110 *
111 * @param int $row_id Row ID.
112 *
113 * @return null|object
114 */
115 private function get_from_db( $row_id ) {
116
117 global $wpdb;
118
119 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
120 return $wpdb->get_row(
121 $wpdb->prepare(
122 "SELECT * FROM {$this->table_name} WHERE {$this->primary_key} = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
123 $row_id
124 )
125 );
126 }
127
128 /**
129 * Retrieve a row based on column and row ID.
130 *
131 * @since 2.1.0
132 *
133 * @param string $column Column name.
134 * @param int|string $row_id Row ID.
135 *
136 * @return object|null|bool Database query result, object or null on failure.
137 */
138 public function get_by( $column, $row_id ) {
139
140 global $wpdb;
141
142 if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
143 return false;
144 }
145
146 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
147 return $wpdb->get_row(
148 $wpdb->prepare(
149 "SELECT * FROM $this->table_name WHERE $column = '%s' LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder
150 $row_id
151 )
152 );
153 }
154
155 /**
156 * Retrieve a value based on column name and row ID.
157 *
158 * @since 2.1.0
159 *
160 * @param string $column Column name.
161 * @param int|string $row_id Row ID.
162 *
163 * @return string|null Database query result (as string), or null on failure.
164 */
165 public function get_column( $column, $row_id ) {
166
167 global $wpdb;
168
169 if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
170 return false;
171 }
172
173 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
174 return $wpdb->get_var(
175 $wpdb->prepare(
176 "SELECT $column FROM $this->table_name WHERE $this->primary_key = '%s' LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder
177 $row_id
178 )
179 );
180 }
181
182 /**
183 * Retrieve one column value based on another given column and matching value.
184 *
185 * @since 2.1.0
186 *
187 * @param string $column Column name.
188 * @param string $column_where Column to match against in the WHERE clause.
189 * @param string $column_value Value to match to the column in the WHERE clause.
190 *
191 * @return string|null Database query result (as string), or null on failure.
192 */
193 public function get_column_by( $column, $column_where, $column_value ) {
194
195 global $wpdb;
196
197 if ( empty( $column ) || empty( $column_where ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
198 return false;
199 }
200
201 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
202 return $wpdb->get_var(
203 $wpdb->prepare(
204 "SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
205 $column_value
206 )
207 );
208 }
209
210 /**
211 * Insert a new record into the database.
212 *
213 * @since 2.1.0
214 *
215 * @param array $data Column data.
216 * @param string $type Optional. Data type context.
217 *
218 * @return int ID for the newly inserted record. 0 otherwise.
219 */
220 private function add_to_db( $data, $type = '' ) {
221
222 global $wpdb;
223
224 // Set default values.
225 $data = wp_parse_args( $data, $this->get_column_defaults() );
226
227 do_action( 'wp_mail_smtp_pre_insert_' . $type, $data );
228
229 // Initialise column format array.
230 $column_formats = $this->get_columns();
231
232 // Force fields to lower case.
233 $data = array_change_key_case( $data );
234
235 // White list columns.
236 $data = array_intersect_key( $data, $column_formats );
237
238 // Reorder $column_formats to match the order of columns given in $data.
239 $data_keys = array_keys( $data );
240 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
241
242 $wpdb->insert( $this->table_name, $data, $column_formats );
243
244 do_action( 'wp_mail_smtp_post_insert_' . $type, $wpdb->insert_id, $data );
245
246 return $wpdb->insert_id;
247 }
248
249 /**
250 * Update an existing record in the database.
251 *
252 * @since 2.1.0
253 *
254 * @param int|string $row_id Row ID for the record being updated.
255 * @param array $data Optional. Array of columns and associated data to update. Default empty array.
256 * @param string $where Optional. Column to match against in the WHERE clause. If empty, $primary_key
257 * will be used. Default empty.
258 * @param string $type Optional. Data type context, e.g. 'affiliate', 'creative', etc. Default empty.
259 *
260 * @return bool False if the record could not be updated, true otherwise.
261 */
262 public function update( $row_id, $data = array(), $where = '', $type = '' ) {
263
264 global $wpdb;
265
266 // Row ID must be a positive integer.
267 $row_id = absint( $row_id );
268
269 if ( empty( $row_id ) ) {
270 return false;
271 }
272
273 if ( empty( $where ) ) {
274 $where = $this->primary_key;
275 }
276
277 do_action( 'wp_mail_smtp_pre_update_' . $type, $data );
278
279 // Initialise column format array.
280 $column_formats = $this->get_columns();
281
282 // Force fields to lower case.
283 $data = array_change_key_case( $data );
284
285 // White list columns.
286 $data = array_intersect_key( $data, $column_formats );
287
288 // Reorder $column_formats to match the order of columns given in $data.
289 $data_keys = array_keys( $data );
290 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
291
292 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
293 if ( false === $wpdb->update( $this->table_name, $data, array( $where => $row_id ), $column_formats ) ) {
294 return false;
295 }
296
297 do_action( 'wp_mail_smtp_post_update_' . $type, $data );
298
299 return true;
300 }
301
302 /**
303 * Delete a record from the database.
304 *
305 * @since 2.1.0
306 *
307 * @param int|string $row_id Row ID.
308 *
309 * @return bool False if the record could not be deleted, true otherwise.
310 */
311 public function delete( $row_id = 0 ) {
312
313 global $wpdb;
314
315 // Row ID must be positive integer.
316 $row_id = absint( $row_id );
317
318 if ( empty( $row_id ) ) {
319 return false;
320 }
321
322 do_action( 'wp_mail_smtp_pre_delete', $row_id );
323 do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $row_id );
324
325 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
326 if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE {$this->primary_key} = %d", $row_id ) ) ) {
327 return false;
328 }
329
330 do_action( 'wp_mail_smtp_post_delete', $row_id );
331 do_action( 'wp_mail_smtp_post_delete_' . $this->type, $row_id );
332
333 return true;
334 }
335
336 /**
337 * Delete a record from the database by column.
338 *
339 * @since 2.1.0
340 *
341 * @param string $column Column name.
342 * @param int|string $column_value Column value.
343 *
344 * @return bool False if the record could not be deleted, true otherwise.
345 */
346 public function delete_by( $column, $column_value ) {
347
348 global $wpdb;
349
350 if ( empty( $column ) || empty( $column_value ) || ! array_key_exists( $column, $this->get_columns() ) ) {
351 return false;
352 }
353
354 do_action( 'wp_mail_smtp_pre_delete', $column_value );
355 do_action( 'wp_mail_smtp_pre_delete_' . $this->type, $column_value );
356
357 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
358 if ( false === $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->table_name} WHERE $column = %s", $column_value ) ) ) {
359 return false;
360 }
361
362 do_action( 'wp_mail_smtp_post_delete', $column_value );
363 do_action( 'wp_mail_smtp_post_delete_' . $this->type, $column_value );
364
365 return true;
366 }
367
368 /**
369 * Check if the given table exists.
370 *
371 * @since 2.1.0
372 *
373 * @param string $table The table name. Defaults to the child class table name.
374 *
375 * @return string|null If the table name exists.
376 */
377 public function table_exists( $table = '' ) {
378
379 global $wpdb;
380
381 if ( ! empty( $table ) ) {
382 $table = sanitize_text_field( $table );
383 } else {
384 $table = $this->table_name;
385 }
386
387 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
388 $db_result = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
389
390 if ( is_null( $db_result ) ) {
391 return false;
392 }
393
394 return strtolower( $db_result ) === strtolower( $table );
395 }
396
397 /**
398 * Create custom entry meta database table.
399 * Used in migration.
400 *
401 * @since 2.1.0
402 */
403 public function create_table() {
404
405 global $wpdb;
406
407 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
408
409 $charset_collate = '';
410
411 if ( ! empty( $wpdb->charset ) ) {
412 $charset_collate .= "DEFAULT CHARACTER SET {$wpdb->charset}";
413 }
414 if ( ! empty( $wpdb->collate ) ) {
415 $charset_collate .= " COLLATE {$wpdb->collate}";
416 }
417
418 $sql = "CREATE TABLE {$this->table_name} (
419 id bigint(20) NOT NULL AUTO_INCREMENT,
420 action varchar(255) NOT NULL,
421 data longtext NOT NULL,
422 date datetime NOT NULL,
423 PRIMARY KEY (id)
424 ) {$charset_collate};";
425
426 dbDelta( $sql );
427 }
428
429 /**
430 * Remove queue records for a defined period of time in the past.
431 * Calling this method will remove queue records that are older than $period seconds.
432 *
433 * @since 2.1.0
434 *
435 * @param string $action Action that should be cleaned up.
436 * @param int $interval Number of seconds from now.
437 *
438 * @return int Number of removed tasks meta records.
439 */
440 public function clean_by( $action, $interval ) {
441
442 global $wpdb;
443
444 if ( empty( $action ) || empty( $interval ) ) {
445 return 0;
446 }
447
448 $table = self::get_table_name();
449 $action = sanitize_key( $action );
450 $date = gmdate( 'Y-m-d H:i:s', time() - (int) $interval );
451
452 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
453 return (int) $wpdb->query(
454 $wpdb->prepare(
455 "DELETE FROM `$table` WHERE action = %s AND date < %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
456 $action,
457 $date
458 )
459 );
460 }
461
462 /**
463 * Inserts a new record into the database.
464 *
465 * @since 2.1.0
466 *
467 * @param array $data Column data.
468 * @param string $type Optional. Data type context.
469 *
470 * @return int ID for the newly inserted record. 0 otherwise.
471 */
472 public function add( $data, $type = '' ) {
473
474 if ( empty( $data['action'] ) || ! is_string( $data['action'] ) ) {
475 return 0;
476 }
477
478 $data['action'] = sanitize_key( $data['action'] );
479
480 if ( isset( $data['data'] ) ) {
481 $string = wp_json_encode( $data['data'] );
482
483 if ( $string === false ) {
484 $string = '';
485 }
486
487 /*
488 * We are encoding the string representation of all the data
489 * to make sure that nothing can harm the database.
490 * This is not an encryption, and we need this data later as is,
491 * so we are using one of the fastest way to do that.
492 * This data is removed from DB on a daily basis.
493 */
494 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
495 $data['data'] = base64_encode( $string );
496 }
497
498 if ( empty( $type ) ) {
499 $type = $this->type;
500 }
501
502 return $this->add_to_db( $data, $type );
503 }
504
505 /**
506 * Retrieve a row from the database based on a given row ID.
507 *
508 * @since 2.1.0}
509 *
510 * @param int $meta_id Meta ID.
511 *
512 * @return null|object
513 */
514 public function get( $meta_id ) {
515
516 $meta = $this->get_from_db( $meta_id );
517
518 if ( empty( $meta ) || empty( $meta->data ) ) {
519 return $meta;
520 }
521
522 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
523 $decoded = base64_decode( $meta->data );
524
525 if ( $decoded === false || ! is_string( $decoded ) ) {
526 $meta->data = '';
527 } else {
528 $meta->data = json_decode( $decoded, true );
529 }
530
531 return $meta;
532 }
533 }
534