Completed
Push — renovate/copy-webpack-plugin-5... ( 1645c2...f892fa )
by
unknown
233:24 queued 224:35
created

Replicastore::get_comment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Automattic\Jetpack\Sync;
4
5
/**
6
 * An implementation of Replicastore Interface which returns data stored in a WordPress.org DB.
7
 * This is useful to compare values in the local WP DB to values in the synced replica store
8
 */
9
class Replicastore implements Replicastore_Interface {
10
	
11
	public function reset() {
12
		global $wpdb;
13
14
		$wpdb->query( "DELETE FROM $wpdb->posts" );
15
		$wpdb->query( "DELETE FROM $wpdb->comments" );
16
17
		// also need to delete terms from cache
18
		$term_ids = $wpdb->get_col( "SELECT term_id FROM $wpdb->terms" );
19
		foreach ( $term_ids as $term_id ) {
20
			wp_cache_delete( $term_id, 'terms' );
21
		}
22
23
		$wpdb->query( "DELETE FROM $wpdb->terms" );
24
25
		$wpdb->query( "DELETE FROM $wpdb->term_taxonomy" );
26
		$wpdb->query( "DELETE FROM $wpdb->term_relationships" );
27
28
		// callables and constants
29
		$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'jetpack_%'" );
30
		$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key NOT LIKE '\_%'" );
31
	}
32
33
	function full_sync_start( $config ) {
34
		$this->reset();
35
	}
36
37
	function full_sync_end( $checksum ) {
38
		// noop right now
39
	}
40
41 View Code Duplication
	public function post_count( $status = null, $min_id = null, $max_id = null ) {
42
		global $wpdb;
43
44
		$where = '';
0 ignored issues
show
Unused Code introduced by
$where is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
45
46
		if ( $status ) {
47
			$where = "post_status = '" . esc_sql( $status ) . "'";
48
		} else {
49
			$where = '1=1';
50
		}
51
52
		if ( null != $min_id ) {
53
			$where .= ' AND ID >= ' . intval( $min_id );
54
		}
55
56
		if ( null != $max_id ) {
57
			$where .= ' AND ID <= ' . intval( $max_id );
58
		}
59
60
		return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE $where" );
61
	}
62
63
	// TODO: actually use max_id/min_id
64
	public function get_posts( $status = null, $min_id = null, $max_id = null ) {
65
		$args = array(
66
			'orderby'        => 'ID',
67
			'posts_per_page' => -1,
68
		);
69
70
		if ( $status ) {
71
			$args['post_status'] = $status;
72
		} else {
73
			$args['post_status'] = 'any';
74
		}
75
76
		return get_posts( $args );
77
	}
78
79
	public function get_post( $id ) {
80
		return get_post( $id );
81
	}
82
83
	public function upsert_post( $post, $silent = false ) {
84
		global $wpdb;
85
86
		// reject the post if it's not a WP_Post
87
		if ( ! $post instanceof \WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
88
			return;
89
		}
90
91
		$post = $post->to_array();
92
93
		// reject posts without an ID
94
		if ( ! isset( $post['ID'] ) ) {
95
			return;
96
		}
97
98
		$now     = current_time( 'mysql' );
99
		$now_gmt = get_gmt_from_date( $now );
100
101
		$defaults = array(
102
			'ID'                    => 0,
103
			'post_author'           => '0',
104
			'post_content'          => '',
105
			'post_content_filtered' => '',
106
			'post_title'            => '',
107
			'post_name'             => '',
108
			'post_excerpt'          => '',
109
			'post_status'           => 'draft',
110
			'post_type'             => 'post',
111
			'comment_status'        => 'closed',
112
			'comment_count'         => '0',
113
			'ping_status'           => '',
114
			'post_password'         => '',
115
			'to_ping'               => '',
116
			'pinged'                => '',
117
			'post_parent'           => 0,
118
			'menu_order'            => 0,
119
			'guid'                  => '',
120
			'post_date'             => $now,
121
			'post_date_gmt'         => $now_gmt,
122
			'post_modified'         => $now,
123
			'post_modified_gmt'     => $now_gmt,
124
		);
125
126
		$post = array_intersect_key( $post, $defaults );
127
128
		$post = sanitize_post( $post, 'db' );
129
130
		unset( $post['filter'] );
131
132
		$exists = $wpdb->get_var( $wpdb->prepare( "SELECT EXISTS( SELECT 1 FROM $wpdb->posts WHERE ID = %d )", $post['ID'] ) );
133
134
		if ( $exists ) {
135
			$wpdb->update( $wpdb->posts, $post, array( 'ID' => $post['ID'] ) );
136
		} else {
137
			$wpdb->insert( $wpdb->posts, $post );
138
		}
139
140
		clean_post_cache( $post['ID'] );
141
	}
142
143
	public function delete_post( $post_id ) {
144
		wp_delete_post( $post_id, true );
145
	}
146
147
	public function posts_checksum( $min_id = null, $max_id = null ) {
148
		global $wpdb;
149
		return $this->table_checksum( $wpdb->posts, Defaults::$default_post_checksum_columns, 'ID', Settings::get_blacklisted_post_types_sql(), $min_id, $max_id );
0 ignored issues
show
Bug introduced by
The property default_post_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
150
	}
151
152
	public function post_meta_checksum( $min_id = null, $max_id = null ) {
153
		global $wpdb;
154
		return $this->table_checksum( $wpdb->postmeta, Defaults::$default_post_meta_checksum_columns, 'meta_id', Settings::get_whitelisted_post_meta_sql(), $min_id, $max_id );
0 ignored issues
show
Bug introduced by
The property default_post_meta_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
155
	}
156
157 View Code Duplication
	public function comment_count( $status = null, $min_id = null, $max_id = null ) {
158
		global $wpdb;
159
160
		$comment_approved = $this->comment_status_to_approval_value( $status );
161
162
		if ( $comment_approved !== false ) {
163
			$where = "comment_approved = '" . esc_sql( $comment_approved ) . "'";
164
		} else {
165
			$where = '1=1';
166
		}
167
168
		if ( $min_id != null ) {
169
			$where .= ' AND comment_ID >= ' . intval( $min_id );
170
		}
171
172
		if ( $max_id != null ) {
173
			$where .= ' AND comment_ID <= ' . intval( $max_id );
174
		}
175
176
		return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments WHERE $where" );
177
	}
178
179
	private function comment_status_to_approval_value( $status ) {
180
		switch ( $status ) {
181
			case 'approve':
182
				return '1';
183
			case 'hold':
184
				return '0';
185
			case 'spam':
186
				return 'spam';
187
			case 'trash':
188
				return 'trash';
189
			case 'any':
190
				return false;
191
			case 'all':
192
				return false;
193
			default:
194
				return false;
195
		}
196
	}
197
198
	// TODO: actually use max_id/min_id
199
	public function get_comments( $status = null, $min_id = null, $max_id = null ) {
200
		$args = array(
201
			'orderby' => 'ID',
202
			'status'  => 'all',
203
		);
204
205
		if ( $status ) {
206
			$args['status'] = $status;
207
		}
208
209
		return get_comments( $args );
210
	}
211
212
	public function get_comment( $id ) {
213
		return \WP_Comment::get_instance( $id );
214
	}
215
216
	public function upsert_comment( $comment ) {
217
		global $wpdb;
218
219
		$comment = $comment->to_array();
220
221
		// filter by fields on comment table
222
		$comment_fields_whitelist = array(
223
			'comment_ID',
224
			'comment_post_ID',
225
			'comment_author',
226
			'comment_author_email',
227
			'comment_author_url',
228
			'comment_author_IP',
229
			'comment_date',
230
			'comment_date_gmt',
231
			'comment_content',
232
			'comment_karma',
233
			'comment_approved',
234
			'comment_agent',
235
			'comment_type',
236
			'comment_parent',
237
			'user_id',
238
		);
239
240
		foreach ( $comment as $key => $value ) {
241
			if ( ! in_array( $key, $comment_fields_whitelist ) ) {
242
				unset( $comment[ $key ] );
243
			}
244
		}
245
246
		$exists = $wpdb->get_var(
247
			$wpdb->prepare(
248
				"SELECT EXISTS( SELECT 1 FROM $wpdb->comments WHERE comment_ID = %d )",
249
				$comment['comment_ID']
250
			)
251
		);
252
253
		if ( $exists ) {
254
			$wpdb->update( $wpdb->comments, $comment, array( 'comment_ID' => $comment['comment_ID'] ) );
255
		} else {
256
			$wpdb->insert( $wpdb->comments, $comment );
257
		}
258
259
		wp_update_comment_count( $comment['comment_post_ID'] );
260
	}
261
262
	public function trash_comment( $comment_id ) {
263
		wp_delete_comment( $comment_id );
264
	}
265
266
	public function delete_comment( $comment_id ) {
267
		wp_delete_comment( $comment_id, true );
268
	}
269
270
	public function spam_comment( $comment_id ) {
271
		wp_spam_comment( $comment_id );
272
	}
273
274
	public function trashed_post_comments( $post_id, $statuses ) {
275
		wp_trash_post_comments( $post_id );
276
	}
277
278
	public function untrashed_post_comments( $post_id ) {
279
		wp_untrash_post_comments( $post_id );
280
	}
281
282
	public function comments_checksum( $min_id = null, $max_id = null ) {
283
		global $wpdb;
284
		return $this->table_checksum( $wpdb->comments, Defaults::$default_comment_checksum_columns, 'comment_ID', Settings::get_comments_filter_sql(), $min_id, $max_id );
0 ignored issues
show
Bug introduced by
The property default_comment_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
285
	}
286
287
	public function comment_meta_checksum( $min_id = null, $max_id = null ) {
288
		global $wpdb;
289
		return $this->table_checksum( $wpdb->commentmeta, Defaults::$default_comment_meta_checksum_columns, 'meta_id', Settings::get_whitelisted_comment_meta_sql(), $min_id, $max_id );
0 ignored issues
show
Bug introduced by
The property default_comment_meta_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
290
	}
291
292
	public function options_checksum() {
293
		global $wpdb;
294
		$options_whitelist = "'" . implode( "', '", Defaults::$default_options_whitelist ) . "'";
0 ignored issues
show
Bug introduced by
The property default_options_whitelist cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
295
		$where_sql         = "option_name IN ( $options_whitelist )";
296
297
		return $this->table_checksum( $wpdb->options, Defaults::$default_option_checksum_columns, null, $where_sql, null, null );
0 ignored issues
show
Bug introduced by
The property default_option_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
298
	}
299
300
301
	public function update_option( $option, $value ) {
302
		return update_option( $option, $value );
303
	}
304
305
	public function get_option( $option, $default = false ) {
306
		return get_option( $option, $default );
307
	}
308
309
	public function delete_option( $option ) {
310
		return delete_option( $option );
311
	}
312
313
	public function set_theme_support( $theme_support ) {
314
		// noop
315
	}
316
317
	public function current_theme_supports( $feature ) {
318
		return current_theme_supports( $feature );
319
	}
320
321
	public function get_metadata( $type, $object_id, $meta_key = '', $single = false ) {
322
		return get_metadata( $type, $object_id, $meta_key, $single );
323
	}
324
325
	/**
326
	 *
327
	 * Stores remote meta key/values alongside an ID mapping key
328
	 *
329
	 * @param $type
330
	 * @param $object_id
331
	 * @param $meta_key
332
	 * @param $meta_value
333
	 * @param $meta_id
334
	 *
335
	 * @return bool
336
	 */
337
	public function upsert_metadata( $type, $object_id, $meta_key, $meta_value, $meta_id ) {
338
339
		$table = _get_meta_table( $type );
340
		if ( ! $table ) {
341
			return false;
342
		}
343
344
		global $wpdb;
345
346
		$exists = $wpdb->get_var(
347
			$wpdb->prepare(
348
				"SELECT EXISTS( SELECT 1 FROM $table WHERE meta_id = %d )",
349
				$meta_id
350
			)
351
		);
352
353
		if ( $exists ) {
354
			$wpdb->update(
355
				$table,
356
				array(
357
					'meta_key'   => $meta_key,
358
					'meta_value' => maybe_serialize( $meta_value ),
359
				),
360
				array( 'meta_id' => $meta_id )
361
			);
362
		} else {
363
			$object_id_field = $type . '_id';
364
			$wpdb->insert(
365
				$table,
366
				array(
367
					'meta_id'        => $meta_id,
368
					$object_id_field => $object_id,
369
					'meta_key'       => $meta_key,
370
					'meta_value'     => maybe_serialize( $meta_value ),
371
				)
372
			);
373
		}
374
375
		wp_cache_delete( $object_id, $type . '_meta' );
376
377
		return true;
378
	}
379
380
	public function delete_metadata( $type, $object_id, $meta_ids ) {
381
		global $wpdb;
382
383
		$table = _get_meta_table( $type );
384
		if ( ! $table ) {
385
			return false;
386
		}
387
388
		foreach ( $meta_ids as $meta_id ) {
389
			$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE meta_id = %d", $meta_id ) );
390
		}
391
392
		// if we don't have an object ID what do we do - invalidate ALL meta?
393
		if ( $object_id ) {
394
			wp_cache_delete( $object_id, $type . '_meta' );
395
		}
396
	}
397
398
	// todo: test this out to make sure it works as expected.
399
	public function delete_batch_metadata( $type, $object_ids, $meta_key ) {
400
		global $wpdb;
401
402
		$table = _get_meta_table( $type );
403
		if ( ! $table ) {
404
			return false;
405
		}
406
		$column = sanitize_key( $type . '_id' );
407
		$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE $column IN (%s) && meta_key = %s", implode( ',', $object_ids ), $meta_key ) );
408
409
		// if we don't have an object ID what do we do - invalidate ALL meta?
410
		foreach ( $object_ids as $object_id ) {
411
			wp_cache_delete( $object_id, $type . '_meta' );
412
		}
413
	}
414
415
	// constants
416
	public function get_constant( $constant ) {
417
		$value = get_option( 'jetpack_constant_' . $constant );
418
419
		if ( $value ) {
420
			return $value;
421
		}
422
423
		return null;
424
	}
425
426
	public function set_constant( $constant, $value ) {
427
		update_option( 'jetpack_constant_' . $constant, $value );
428
	}
429
430
	public function get_updates( $type ) {
431
		$all_updates = get_option( 'jetpack_updates', array() );
432
433
		if ( isset( $all_updates[ $type ] ) ) {
434
			return $all_updates[ $type ];
435
		} else {
436
			return null;
437
		}
438
	}
439
440
	public function set_updates( $type, $updates ) {
441
		$all_updates          = get_option( 'jetpack_updates', array() );
442
		$all_updates[ $type ] = $updates;
443
		update_option( 'jetpack_updates', $all_updates );
444
	}
445
446
	// functions
447
	public function get_callable( $name ) {
448
		$value = get_option( 'jetpack_' . $name );
449
450
		if ( $value ) {
451
			return $value;
452
		}
453
454
		return null;
455
	}
456
457
	public function set_callable( $name, $value ) {
458
		update_option( 'jetpack_' . $name, $value );
459
	}
460
461
	// network options
462
	public function get_site_option( $option ) {
463
		return get_option( 'jetpack_network_' . $option );
464
	}
465
466
	public function update_site_option( $option, $value ) {
467
		return update_option( 'jetpack_network_' . $option, $value );
468
	}
469
470
	public function delete_site_option( $option ) {
471
		return delete_option( 'jetpack_network_' . $option );
472
	}
473
474
	// terms
475
	// terms
476
	public function get_terms( $taxonomy ) {
477
		return get_terms( $taxonomy );
478
	}
479
480
	public function get_term( $taxonomy, $term_id, $is_term_id = true ) {
481
		$t = $this->ensure_taxonomy( $taxonomy );
482
		if ( ! $t || is_wp_error( $t ) ) {
483
			return $t;
484
		}
485
486
		return get_term( $term_id, $taxonomy );
487
	}
488
489
	private function ensure_taxonomy( $taxonomy ) {
490
		if ( ! taxonomy_exists( $taxonomy ) ) {
491
			// try re-registering synced taxonomies
492
			$taxonomies = $this->get_callable( 'taxonomies' );
493
			if ( ! isset( $taxonomies[ $taxonomy ] ) ) {
494
				// doesn't exist, or somehow hasn't been synced
495
				return new \WP_Error( 'invalid_taxonomy', "The taxonomy '$taxonomy' doesn't exist" );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_taxonomy'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
496
			}
497
			$t = $taxonomies[ $taxonomy ];
498
499
			return register_taxonomy(
500
				$taxonomy,
501
				$t->object_type,
502
				(array) $t
503
			);
504
		}
505
506
		return true;
507
	}
508
509
	public function get_the_terms( $object_id, $taxonomy ) {
510
		return get_the_terms( $object_id, $taxonomy );
511
	}
512
513
	public function update_term( $term_object ) {
514
		$taxonomy = $term_object->taxonomy;
515
		global $wpdb;
516
		$exists = $wpdb->get_var(
517
			$wpdb->prepare(
518
				"SELECT EXISTS( SELECT 1 FROM $wpdb->terms WHERE term_id = %d )",
519
				$term_object->term_id
520
			)
521
		);
522
		if ( ! $exists ) {
523
			$term_object   = sanitize_term( clone( $term_object ), $taxonomy, 'db' );
524
			$term          = array(
525
				'term_id'    => $term_object->term_id,
526
				'name'       => $term_object->name,
527
				'slug'       => $term_object->slug,
528
				'term_group' => $term_object->term_group,
529
			);
530
			$term_taxonomy = array(
531
				'term_taxonomy_id' => $term_object->term_taxonomy_id,
532
				'term_id'          => $term_object->term_id,
533
				'taxonomy'         => $term_object->taxonomy,
534
				'description'      => $term_object->description,
535
				'parent'           => (int) $term_object->parent,
536
				'count'            => (int) $term_object->count,
537
			);
538
			$wpdb->insert( $wpdb->terms, $term );
539
			$wpdb->insert( $wpdb->term_taxonomy, $term_taxonomy );
540
541
			return true;
542
		}
543
544
		return wp_update_term( $term_object->term_id, $taxonomy, (array) $term_object );
545
	}
546
547
	public function delete_term( $term_id, $taxonomy ) {
548
		return wp_delete_term( $term_id, $taxonomy );
549
	}
550
551
	public function update_object_terms( $object_id, $taxonomy, $terms, $append ) {
552
		wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
553
	}
554
555
	public function delete_object_terms( $object_id, $tt_ids ) {
556
		global $wpdb;
557
558
		if ( is_array( $tt_ids ) && ! empty( $tt_ids ) ) {
559
			// escape
560
			$tt_ids_sanitized = array_map( 'intval', $tt_ids );
561
562
			$taxonomies = array();
563
			foreach ( $tt_ids_sanitized as $tt_id ) {
564
				$term                            = get_term_by( 'term_taxonomy_id', $tt_id );
565
				$taxonomies[ $term->taxonomy ][] = $tt_id;
566
			}
567
			$in_tt_ids = implode( ', ', $tt_ids_sanitized );
568
569
			/**
570
			 * Fires immediately before an object-term relationship is deleted.
571
			 *
572
			 * @since 2.9.0
573
			 *
574
			 * @param int $object_id Object ID.
575
			 * @param array $tt_ids An array of term taxonomy IDs.
576
			 */
577
			do_action( 'delete_term_relationships', $object_id, $tt_ids_sanitized );
578
			$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
579
			foreach ( $taxonomies as $taxonomy => $taxonomy_tt_ids ) {
580
				$this->ensure_taxonomy( $taxonomy );
581
				wp_cache_delete( $object_id, $taxonomy . '_relationships' );
582
				/**
583
				 * Fires immediately after an object-term relationship is deleted.
584
				 *
585
				 * @since 2.9.0
586
				 *
587
				 * @param int $object_id Object ID.
588
				 * @param array $tt_ids An array of term taxonomy IDs.
589
				 */
590
				do_action( 'deleted_term_relationships', $object_id, $taxonomy_tt_ids );
591
				wp_update_term_count( $taxonomy_tt_ids, $taxonomy );
592
			}
593
594
			return (bool) $deleted;
595
		}
596
597
		return false;
598
	}
599
600
	// users
601
	public function user_count() {
602
603
	}
604
605
	public function get_user( $user_id ) {
606
		return \WP_User::get_instance( $user_id );
607
	}
608
609
	public function upsert_user( $user ) {
610
		$this->invalid_call();
611
	}
612
613
	public function delete_user( $user_id ) {
614
		$this->invalid_call();
615
	}
616
617
	public function upsert_user_locale( $user_id, $local ) {
618
		$this->invalid_call();
619
	}
620
621
	public function delete_user_locale( $user_id ) {
622
		$this->invalid_call();
623
	}
624
625
	public function get_user_locale( $user_id ) {
626
		return get_user_locale( $user_id );
627
	}
628
629
	public function get_allowed_mime_types( $user_id ) {
630
631
	}
632
633
	public function checksum_all() {
634
		$post_meta_checksum    = $this->checksum_histogram( 'post_meta', 1 );
635
		$comment_meta_checksum = $this->checksum_histogram( 'comment_meta', 1 );
636
637
		return array(
638
			'posts'        => $this->posts_checksum(),
639
			'comments'     => $this->comments_checksum(),
640
			'post_meta'    => reset( $post_meta_checksum ),
641
			'comment_meta' => reset( $comment_meta_checksum ),
642
		);
643
	}
644
645
	function checksum_histogram( $object_type, $buckets, $start_id = null, $end_id = null, $columns = null, $strip_non_ascii = true, $salt = '' ) {
646
		global $wpdb;
647
648
		$wpdb->queries = array();
649
650
		switch ( $object_type ) {
651
			case 'posts':
652
				$object_count = $this->post_count( null, $start_id, $end_id );
653
				$object_table = $wpdb->posts;
654
				$id_field     = 'ID';
655
				$where_sql    = Settings::get_blacklisted_post_types_sql();
656
				if ( empty( $columns ) ) {
657
					$columns = Defaults::$default_post_checksum_columns;
0 ignored issues
show
Bug introduced by
The property default_post_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
658
				}
659
				break;
660 View Code Duplication
			case 'post_meta':
661
				$object_table = $wpdb->postmeta;
662
				$where_sql    = Settings::get_whitelisted_post_meta_sql();
663
				$object_count = $this->meta_count( $object_table, $where_sql, $start_id, $end_id );
664
				$id_field     = 'meta_id';
665
666
				if ( empty( $columns ) ) {
667
					$columns = Defaults::$default_post_meta_checksum_columns;
0 ignored issues
show
Bug introduced by
The property default_post_meta_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
668
				}
669
				break;
670
			case 'comments':
671
				$object_count = $this->comment_count( null, $start_id, $end_id );
672
				$object_table = $wpdb->comments;
673
				$id_field     = 'comment_ID';
674
				$where_sql    = Settings::get_comments_filter_sql();
675
				if ( empty( $columns ) ) {
676
					$columns = Defaults::$default_comment_checksum_columns;
0 ignored issues
show
Bug introduced by
The property default_comment_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
677
				}
678
				break;
679 View Code Duplication
			case 'comment_meta':
680
				$object_table = $wpdb->commentmeta;
681
				$where_sql    = Settings::get_whitelisted_comment_meta_sql();
682
				$object_count = $this->meta_count( $object_table, $where_sql, $start_id, $end_id );
683
				$id_field     = 'meta_id';
684
				if ( empty( $columns ) ) {
685
					$columns = Defaults::$default_post_meta_checksum_columns;
0 ignored issues
show
Bug introduced by
The property default_post_meta_checksum_columns cannot be accessed from this context as it is declared private in class Automattic\Jetpack\Sync\Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
686
				}
687
				break;
688
			default:
689
				return false;
690
		}
691
692
		$bucket_size     = intval( ceil( $object_count / $buckets ) );
693
		$previous_max_id = 0;
694
		$histogram       = array();
695
696
		$where = '1=1';
697
698
		if ( $start_id ) {
699
			$where .= " AND $id_field >= " . intval( $start_id );
700
		}
701
702
		if ( $end_id ) {
703
			$where .= " AND $id_field <= " . intval( $end_id );
704
		}
705
706
		do {
707
			list( $first_id, $last_id ) = $wpdb->get_row(
708
				"SELECT MIN($id_field) as min_id, MAX($id_field) as max_id FROM ( SELECT $id_field FROM $object_table WHERE $where AND $id_field > $previous_max_id ORDER BY $id_field ASC LIMIT $bucket_size ) as ids",
709
				ARRAY_N
710
			);
711
712
			if ( null === $first_id || null === $last_id ) {
713
				// Nothing to checksum here...
714
				break;
715
			}
716
717
			// get the checksum value
718
			$value = $this->table_checksum( $object_table, $columns, $id_field, $where_sql, $first_id, $last_id, $strip_non_ascii, $salt );
719
720
			if ( is_wp_error( $value ) ) {
721
				return $value;
722
			}
723
724
			if ( null === $first_id || null === $last_id ) {
725
				break;
726
			} elseif ( $first_id === $last_id ) {
727
				$histogram[ $first_id ] = $value;
728
			} else {
729
				$histogram[ "{$first_id}-{$last_id}" ] = $value;
730
			}
731
732
			$previous_max_id = $last_id;
733
		} while ( true );
734
735
		return $histogram;
736
	}
737
738
	private function table_checksum( $table, $columns, $id_column, $where_sql = '1=1', $min_id = null, $max_id = null, $strip_non_ascii = true, $salt = '' ) {
739
		global $wpdb;
740
741
		// sanitize to just valid MySQL column names
742
		$sanitized_columns = preg_grep( '/^[0-9,a-z,A-Z$_]+$/i', $columns );
743
744
		if ( $strip_non_ascii ) {
745
			$columns_sql = implode( ',', array_map( array( $this, 'strip_non_ascii_sql' ), $sanitized_columns ) );
746
		} else {
747
			$columns_sql = implode( ',', $sanitized_columns );
748
		}
749
750
		if ( null !== $min_id && null !== $max_id ) {
751
			if ( $min_id === $max_id ) {
752
				$min_id     = intval( $min_id );
753
				$where_sql .= " AND $id_column = $min_id LIMIT 1";
754
			} else {
755
				$min_id     = intval( $min_id );
756
				$max_id     = intval( $max_id );
757
				$size       = $max_id - $min_id;
758
				$where_sql .= " AND $id_column >= $min_id AND $id_column <= $max_id LIMIT $size";
759
			}
760
		} else {
761
			if ( null !== $min_id ) {
762
				$min_id     = intval( $min_id );
763
				$where_sql .= " AND $id_column >= $min_id";
764
			}
765
766
			if ( null !== $max_id ) {
767
				$max_id     = intval( $max_id );
768
				$where_sql .= " AND $id_column <= $max_id";
769
			}
770
		}
771
772
		$query  = <<<ENDSQL
773
			SELECT CAST( SUM( CRC32( CONCAT_WS( '#', '%s', {$columns_sql} ) ) ) AS UNSIGNED INT )
774
			FROM $table
775
			WHERE $where_sql;
776
ENDSQL;
777
		$result = $wpdb->get_var( $wpdb->prepare( $query, $salt ) );
778
		if ( $wpdb->last_error ) {
779
			return new \WP_Error( 'database_error', $wpdb->last_error );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'database_error'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
780
		}
781
782
		return $result;
783
	}
784
785
	public function get_checksum_type() {
786
		return 'sum';
787
	}
788
789
	private function meta_count( $table, $where_sql, $min_id, $max_id ) {
790
		global $wpdb;
791
792
		if ( $min_id != null ) {
793
			$where_sql .= ' AND meta_id >= ' . intval( $min_id );
794
		}
795
796
		if ( $max_id != null ) {
797
			$where_sql .= ' AND meta_id <= ' . intval( $max_id );
798
		}
799
800
		return $wpdb->get_var( "SELECT COUNT(*) FROM $table WHERE $where_sql" );
801
	}
802
803
	/**
804
	 * Wraps a column name in SQL which strips non-ASCII chars.
805
	 * This helps normalize data to avoid checksum differences caused by
806
	 * badly encoded data in the DB
807
	 */
808
	function strip_non_ascii_sql( $column_name ) {
809
		return "REPLACE( CONVERT( $column_name USING ascii ), '?', '' )";
810
	}
811
812
	private function invalid_call() {
813
		$backtrace = debug_backtrace();
814
		$caller    = $backtrace[1]['function'];
815
		throw new \Exception( "This function $caller is not supported on the WP Replicastore" );
816
	}
817
}
818