diff options
Diffstat (limited to 'plugins/jetpack/jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php')
-rw-r--r-- | plugins/jetpack/jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php b/plugins/jetpack/jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php new file mode 100644 index 00000000..20f686a6 --- /dev/null +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php @@ -0,0 +1,208 @@ +<?php +/** + * Table Checksums Class. + * + * @package automattic/jetpack-sync + */ + +namespace Automattic\Jetpack\Sync\Replicastore; + +use Automattic\Jetpack\Connection\Manager; +use Automattic\Jetpack\Sync; +use Automattic\Jetpack\Sync\Modules; +use WP_Error; +use WP_User_Query; + +/** + * Class to handle Table Checksums for the User Meta table. + */ +class Table_Checksum_Usermeta extends Table_Checksum_Users { + /** + * Calculate the checksum based on provided range and filters. + * + * @param int|null $range_from The start of the range. + * @param int|null $range_to The end of the range. + * @param array|null $filter_values Additional filter values. Not used at the moment. + * @param bool $granular_result If the returned result should be granular or only the checksum. + * @param bool $simple_return_value If we want to use a simple return value for non-granular results (return only the checksum, without wrappers). + * + * @return array|mixed|object|WP_Error|null + */ + public function calculate_checksum( $range_from = null, $range_to = null, $filter_values = null, $granular_result = false, $simple_return_value = true ) { + + if ( ! Sync\Settings::is_checksum_enabled() ) { + return new WP_Error( 'checksum_disabled', 'Checksums are currently disabled.' ); + } + + /** + * First we need to fetch the user IDs for the users that we want to include in the range. + * + * To keep things a bit simple and avoid filtering issues, let's reuse the `build_filter_statement` that already + * exists. Unfortunately we don't + */ + global $wpdb; + + // This call depends on the `range_field` pointing to the `ID` field of the `users` table. Currently, "ID". + $range_filter_statement = $this->build_filter_statement( $range_from, $range_to ); + + $query = " + SELECT + DISTINCT {$this->table}.{$this->range_field} + FROM + {$this->table} + JOIN {$wpdb->usermeta} as um_table ON um_table.user_id = {$this->table}.ID + WHERE + {$range_filter_statement} + AND um_table.meta_key = '{$wpdb->prefix}user_level' + AND um_table.meta_value > 0 + "; + + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $user_ids = $wpdb->get_col( $query ); + + // Chunk the array down to make sure we don't overload the database with queries that are too large. + $chunked_user_ids = array_chunk( $user_ids, 500 ); + + $checksum_entries = array(); + + foreach ( $chunked_user_ids as $user_ids_chunk ) { + $user_objects = $this->get_user_objects_by_ids( $user_ids_chunk ); + + foreach ( $user_objects as $user_object ) { + // expand and sanitize desired meta based on WP.com logic. + $user_object = $this->expand_and_sanitize_user_meta( $user_object ); + + // Generate checksum entry based on the serialized value if not empty. + $checksum_entry = 0; + if ( ! empty( $user_object->roles ) ) { + $checksum_entry = crc32( implode( '#', array( $this->salt, 'roles', maybe_serialize( $user_object->roles ) ) ) ); + } + + // Meta only persisted if user is connected to WP.com. + if ( ( new Manager( 'jetpack' ) )->is_user_connected( $user_object->ID ) ) { + if ( ! empty( $user_object->allcaps ) ) { + $checksum_entry += crc32( + implode( + '#', + array( + $this->salt, + 'capabilities', + maybe_serialize( $user_object->allcaps ), + ) + ) + ); + } + // Explicitly check that locale is not same as site locale. + if ( ! empty( $user_object->locale ) && get_locale() !== $user_object->locale ) { + $checksum_entry += crc32( + implode( + '#', + array( + $this->salt, + 'locale', + maybe_serialize( $user_object->locale ), + ) + ) + ); + } + if ( ! empty( $user_object->allowed_mime_types ) ) { + $checksum_entry += crc32( + implode( + '#', + array( + $this->salt, + 'allowed_mime_types', + maybe_serialize( $user_object->allowed_mime_types ), + ) + ) + ); + } + } + + $checksum_entries[ $user_object->ID ] = '' . $checksum_entry; + } + } + + // Non-granular results need only to sum the different entries. + if ( ! $granular_result ) { + $checksum_sum = 0; + foreach ( $checksum_entries as $entry ) { + $checksum_sum += intval( $entry ); + } + + if ( $simple_return_value ) { + return '' . $checksum_sum; + } + + return array( + 'range' => $range_from . '-' . $range_to, + 'checksum' => '' . $checksum_sum, + ); + + } + + // Granular results. + $response = $checksum_entries; + + // Sort the return value for easier comparisons and code flows further down the line. + ksort( $response ); + + return $response; + } + + /** + * Expand the User Object with additional meta santized by WP.com logic. + * + * @param mixed $user_object User Object from WP_User_Query. + * + * @return mixed $user_object expanded User Object. + */ + protected function expand_and_sanitize_user_meta( $user_object ) { + $user_module = Modules::get_module( 'users' ); + // Expand User Objects based on Sync logic. + $user_object = $user_module->expand_user( $user_object ); + + // Sanitize location. + if ( ! empty( $user_object->locale ) ) { + $user_object->locale = wp_strip_all_tags( $user_object->locale, true ); + } + + // Sanitize allcaps. + if ( ! empty( $user_object->allcaps ) ) { + $user_object->allcaps = array_map( + function ( $cap ) { + return (bool) $cap; + }, + $user_object->allcaps + ); + } + + // Sanitize allowed_mime_types. + $allowed_mime_types = $user_object->allowed_mime_types; + foreach ( $allowed_mime_types as $allowed_mime_type_short => $allowed_mime_type_long ) { + $allowed_mime_type_short = wp_strip_all_tags( (string) $allowed_mime_type_short, true ); + $allowed_mime_type_long = wp_strip_all_tags( (string) $allowed_mime_type_long, true ); + $allowed_mime_types[ $allowed_mime_type_short ] = $allowed_mime_type_long; + } + $user_object->allowed_mime_types = $allowed_mime_types; + + // Sanitize roles. + if ( is_array( $user_object->roles ) ) { + $user_object->roles = array_map( 'sanitize_text_field', $user_object->roles ); + } + return $user_object; + } + + /** + * Gets a list of `WP_User` objects by their IDs + * + * @param array $ids List of IDs to fetch. + * + * @return array + */ + protected function get_user_objects_by_ids( $ids ) { + $user_query = new WP_User_Query( array( 'include' => $ids ) ); + + return $user_query->get_results(); + } +} |