PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 All 507 releases
jetpack / jetpack_vendor / automattic / jetpack-sync / src / replicastore / class-table-checksum-usermeta.php

class-table-checksum-usermeta.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-sync/src/replicastore/class-table-checksum-usermeta.php

214 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Table Checksums Class.
4 *
5 * @package automattic/jetpack-sync
6 */
7
8 namespace Automattic\Jetpack\Sync\Replicastore;
9
10 use Automattic\Jetpack\Connection\Manager;
11 use Automattic\Jetpack\Sync;
12 use Automattic\Jetpack\Sync\Modules;
13 use WP_Error;
14 use WP_User_Query;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit( 0 );
18 }
19
20 /**
21 * Class to handle Table Checksums for the User Meta table.
22 */
23 class Table_Checksum_Usermeta extends Table_Checksum_Users {
24 /**
25 * Calculate the checksum based on provided range and filters.
26 *
27 * @param int|null $range_from The start of the range.
28 * @param int|null $range_to The end of the range.
29 * @param array|null $filter_values Additional filter values. Not used at the moment.
30 * @param bool $granular_result If the returned result should be granular or only the checksum.
31 * @param bool $simple_return_value If we want to use a simple return value for non-granular results (return only the checksum, without wrappers).
32 *
33 * @return array|mixed|object|WP_Error|null
34 */
35 public function calculate_checksum( $range_from = null, $range_to = null, $filter_values = null, $granular_result = false, $simple_return_value = true ) {
36
37 if ( ! Sync\Settings::is_checksum_enabled() ) {
38 return new WP_Error( 'checksum_disabled', 'Checksums are currently disabled.' );
39 }
40
41 /**
42 * First we need to fetch the user IDs for the users that we want to include in the range.
43 *
44 * To keep things a bit simple and avoid filtering issues, let's reuse the `build_filter_statement` that already
45 * exists. Unfortunately we don't
46 */
47 global $wpdb;
48
49 // This call depends on the `range_field` pointing to the `ID` field of the `users` table. Currently, "ID".
50 $range_filter_statement = $this->build_filter_statement( $range_from, $range_to );
51
52 $query = "
53 SELECT
54 DISTINCT {$this->table}.{$this->range_field}
55 FROM
56 {$this->table}
57 JOIN {$wpdb->usermeta} as um_table ON um_table.user_id = {$this->table}.ID
58 WHERE
59 {$range_filter_statement}
60 AND um_table.meta_key = '{$wpdb->prefix}user_level'
61 AND um_table.meta_value > 0
62 ";
63
64 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
65 $user_ids = $wpdb->get_col( $query );
66
67 // Chunk the array down to make sure we don't overload the database with queries that are too large.
68 $chunked_user_ids = array_chunk( $user_ids, 500 );
69
70 $checksum_entries = array();
71
72 foreach ( $chunked_user_ids as $user_ids_chunk ) {
73 $user_objects = $this->get_user_objects_by_ids( $user_ids_chunk );
74
75 foreach ( $user_objects as $user_object ) {
76 // expand and sanitize desired meta based on WP.com logic.
77 $user_object = $this->expand_and_sanitize_user_meta( $user_object );
78
79 // Generate checksum entry based on the serialized value if not empty.
80 $checksum_entry = 0;
81 if ( ! empty( $user_object->roles ) ) {
82 $checksum_entry = crc32( implode( '#', array( $this->salt, 'roles', maybe_serialize( $user_object->roles ) ) ) );
83 }
84
85 // Meta only persisted if user is connected to WP.com.
86 if ( ( new Manager( 'jetpack' ) )->is_user_connected( $user_object->ID ) ) {
87 if ( ! empty( $user_object->allcaps ) ) {
88 $checksum_entry += crc32(
89 implode(
90 '#',
91 array(
92 $this->salt,
93 'capabilities',
94 maybe_serialize( $user_object->allcaps ),
95 )
96 )
97 );
98 }
99 // Explicitly check that locale is not same as site locale.
100 if ( ! empty( $user_object->locale ) && get_locale() !== $user_object->locale ) {
101 $checksum_entry += crc32(
102 implode(
103 '#',
104 array(
105 $this->salt,
106 'locale',
107 maybe_serialize( $user_object->locale ),
108 )
109 )
110 );
111 }
112 if ( ! empty( $user_object->allowed_mime_types ) ) {
113 $checksum_entry += crc32(
114 implode(
115 '#',
116 array(
117 $this->salt,
118 'allowed_mime_types',
119 maybe_serialize( $user_object->allowed_mime_types ),
120 )
121 )
122 );
123 }
124 }
125
126 $checksum_entries[ $user_object->ID ] = '' . $checksum_entry;
127 }
128 }
129
130 // Non-granular results need only to sum the different entries.
131 if ( ! $granular_result ) {
132 $checksum_sum = 0;
133 foreach ( $checksum_entries as $entry ) {
134 $checksum_sum += intval( $entry );
135 }
136
137 if ( $simple_return_value ) {
138 return '' . $checksum_sum;
139 }
140
141 return array(
142 'range' => $range_from . '-' . $range_to,
143 'checksum' => '' . $checksum_sum,
144 );
145
146 }
147
148 // Granular results.
149 $response = $checksum_entries;
150
151 // Sort the return value for easier comparisons and code flows further down the line.
152 ksort( $response );
153
154 return $response;
155 }
156
157 /**
158 * Expand the User Object with additional meta santized by WP.com logic.
159 *
160 * @param mixed $user_object User Object from WP_User_Query.
161 *
162 * @return mixed $user_object expanded User Object.
163 */
164 protected function expand_and_sanitize_user_meta( $user_object ) {
165 $user_module = Modules::get_module( 'users' );
166 '@phan-var \Automattic\Jetpack\Sync\Modules\Users $user_module';
167 // Expand User Objects based on Sync logic.
168 $user_object = $user_module->expand_user( $user_object );
169
170 // Sanitize location.
171 if ( ! empty( $user_object->locale ) ) {
172 $user_object->locale = wp_strip_all_tags( $user_object->locale, true );
173 }
174
175 // Sanitize allcaps.
176 if ( ! empty( $user_object->allcaps ) ) {
177 $user_object->allcaps = array_map(
178 function ( $cap ) {
179 return (bool) $cap;
180 },
181 $user_object->allcaps
182 );
183 }
184
185 // Sanitize allowed_mime_types.
186 $allowed_mime_types = $user_object->allowed_mime_types;
187 foreach ( $allowed_mime_types as $allowed_mime_type_short => $allowed_mime_type_long ) {
188 $allowed_mime_type_short = wp_strip_all_tags( (string) $allowed_mime_type_short, true );
189 $allowed_mime_type_long = wp_strip_all_tags( (string) $allowed_mime_type_long, true );
190 $allowed_mime_types[ $allowed_mime_type_short ] = $allowed_mime_type_long;
191 }
192 $user_object->allowed_mime_types = $allowed_mime_types;
193
194 // Sanitize roles.
195 if ( is_array( $user_object->roles ) ) {
196 $user_object->roles = array_map( 'sanitize_text_field', $user_object->roles );
197 }
198 return $user_object;
199 }
200
201 /**
202 * Gets a list of `WP_User` objects by their IDs
203 *
204 * @param array $ids List of IDs to fetch.
205 *
206 * @return array
207 */
208 protected function get_user_objects_by_ids( $ids ) {
209 $user_query = new WP_User_Query( array( 'include' => $ids ) );
210
211 return $user_query->get_results();
212 }
213 }
214