PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 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 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-sync/src/sync-queue/class-queue-storage-options.php +293 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,293 @@
1 +<?php
2 +/**
3 + * The class responsible for storing Queue events in the `wp_options` table.
4 + *
5 + * Used by class Queue.
6 + *
7 + * @see \Automattic\Jetpack\Sync\Queue
8 + *
9 + * @package automattic/jetpack-sync
10 + */
11 +
12 +namespace Automattic\Jetpack\Sync\Queue;
13 +
14 +/**
15 + * `wp_options` storage backend for the Queue.
16 + */
17 +class Queue_Storage_Options {
18 + /**
19 + * What queue is this instance responsible for.
20 + *
21 + * @var string
22 + */
23 + public $queue_id = '';
24 +
25 + /**
26 + * Class constructor.
27 + *
28 + * @param string $queue_id The queue name this instance will be responsible for.
29 + *
30 + * @throws \Exception If queue name was not provided.
31 + */
32 + public function __construct( $queue_id ) {
33 + if ( empty( $queue_id ) ) {
34 + // TODO what should we return here or throw an exception?
35 + throw new \Exception( 'Invalid queue_id provided' );
36 + }
37 +
38 + // TODO validate the value maybe?
39 + $this->queue_id = $queue_id;
40 + }
41 +
42 + /**
43 + * Insert an item in the queue.
44 + *
45 + * @param string $item_id The item ID.
46 + * @param string $item Serialized item data.
47 + *
48 + * @return bool If the item was added.
49 + */
50 + public function insert_item( $item_id, $item ) {
51 + global $wpdb;
52 +
53 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
54 + $rows_added = $wpdb->query(
55 + $wpdb->prepare(
56 + "INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES (%s, %s,%s)",
57 + $item_id,
58 + $item,
59 + 'no'
60 + )
61 + );
62 +
63 + return ( 0 !== $rows_added );
64 + }
65 +
66 + /**
67 + * Fetch items from the queue.
68 + *
69 + * @param int|null $item_count How many items to fetch from the queue.
70 + * Null for no limit.
71 + * @param string $order Sort direction for the items. Accepts 'ASC' or 'DESC'.
72 + * Any other value will be treated as 'ASC'.
73 + *
74 + * @return array|object|null Array of result objects on success, or null on failure.
75 + */
76 + public function fetch_items( $item_count, $order = 'ASC' ) {
77 + global $wpdb;
78 +
79 + $order = 'DESC' === $order ? 'DESC' : 'ASC';
80 +
81 + $sql_order = "ORDER BY option_name {$order}";
82 +
83 + $sql = "SELECT option_name AS id, option_value AS value
84 + FROM $wpdb->options
85 + WHERE option_name LIKE %s
86 + {$sql_order}";
87 +
88 + $params = array( "jpsq_{$this->queue_id}-%" );
89 +
90 + if ( $item_count ) {
91 + $sql .= ' LIMIT %d';
92 + $params[] = $item_count;
93 + }
94 +
95 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
96 + $items = $wpdb->get_results(
97 + $wpdb->prepare( $sql, $params ), // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
98 + OBJECT
99 + );
100 +
101 + return $items;
102 + }
103 +
104 + /**
105 + * Fetches items with specific IDs from the Queue.
106 + *
107 + * @param array $items_ids Items IDs to fetch from the queue.
108 + *
109 + * @return \stdClass[]|null
110 + */
111 + public function fetch_items_by_ids( $items_ids ) {
112 + global $wpdb;
113 +
114 + // return early if $items_ids is empty or not an array.
115 + if ( empty( $items_ids ) || ! is_array( $items_ids ) ) {
116 + return array();
117 + }
118 +
119 + $ids_placeholders = implode( ', ', array_fill( 0, count( $items_ids ), '%s' ) );
120 +
121 + $query_with_placeholders = "SELECT option_name AS id, option_value AS value
122 + FROM $wpdb->options
123 + WHERE option_name IN ( $ids_placeholders )";
124 +
125 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
126 + $items = $wpdb->get_results(
127 + $wpdb->prepare(
128 + $query_with_placeholders, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
129 + $items_ids
130 + ),
131 + OBJECT
132 + );
133 +
134 + return $items;
135 + }
136 +
137 + /**
138 + * Clear out the queue.
139 + *
140 + * @return bool|int|\mysqli_result|resource|null
141 + */
142 + public function clear_queue() {
143 + global $wpdb;
144 +
145 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
146 + return $wpdb->query(
147 + $wpdb->prepare(
148 + "DELETE FROM $wpdb->options WHERE option_name LIKE %s",
149 + "jpsq_{$this->queue_id}-%"
150 + )
151 + );
152 + }
153 +
154 + /**
155 + * Check how many items are in the queue.
156 + *
157 + * @return int
158 + */
159 + public function get_item_count() {
160 + global $wpdb;
161 +
162 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
163 + return (int) $wpdb->get_var(
164 + $wpdb->prepare(
165 + "SELECT count(*) FROM $wpdb->options WHERE option_name LIKE %s",
166 + "jpsq_{$this->queue_id}-%"
167 + )
168 + );
169 + }
170 +
171 + /**
172 + * Return the lag amount for the queue.
173 + *
174 + * @param float|int|null $now A timestamp to use as starting point when calculating the lag.
175 + *
176 + * @return float|int The lag amount.
177 + */
178 + public function get_lag( $now = null ) {
179 + global $wpdb;
180 +
181 + // TODO replace with peek and a flag to fetch only the name.
182 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
183 + $first_item_name = $wpdb->get_var(
184 + $wpdb->prepare(
185 + "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s ORDER BY option_name ASC LIMIT 1",
186 + "jpsq_{$this->queue_id}-%"
187 + )
188 + );
189 +
190 + if ( ! $first_item_name ) {
191 + return 0;
192 + }
193 +
194 + if ( null === $now ) {
195 + $now = microtime( true );
196 + }
197 +
198 + // Break apart the item name to get the timestamp.
199 + $matches = null;
200 + if ( preg_match( '/^jpsq_' . $this->queue_id . '-(\d+\.\d+)-/', $first_item_name, $matches ) ) {
201 + return $now - (float) $matches[1];
202 + } else {
203 + return 0;
204 + }
205 + }
206 +
207 + /**
208 + * Add multiple items to the queue at once.
209 + *
210 + * @param array $items Array of items to add.
211 + * @param string $id_prefix Prefix to use for all the items.
212 + *
213 + * @return bool|int|\mysqli_result|resource|null
214 + */
215 + public function add_all( $items, $id_prefix ) {
216 + global $wpdb;
217 +
218 + $query = "INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES ";
219 +
220 + $rows = array();
221 + $count_items = count( $items );
222 + for ( $i = 0; $i < $count_items; ++$i ) {
223 + // skip empty items.
224 + if ( empty( $items[ $i ] ) ) {
225 + continue;
226 + }
227 + try {
228 + $option_name = esc_sql( $id_prefix . '-' . $i );
229 + $option_value = esc_sql( serialize( $items[ $i ] ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
230 + $rows[] = "('$option_name', '$option_value', 'no')";
231 + } catch ( \Exception $e ) {
232 + // Item cannot be serialized so skip.
233 + continue;
234 + }
235 + }
236 +
237 + $rows_added = $wpdb->query( $query . implode( ',', $rows ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
238 +
239 + return $rows_added;
240 + }
241 +
242 + /**
243 + * Return $max_count items from the queue, including their value string length.
244 + *
245 + * @param int $max_count How many items to fetch from the queue.
246 + *
247 + * @return object[]|null
248 + */
249 + public function get_items_ids_with_size( $max_count ) {
250 + global $wpdb;
251 +
252 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
253 + return $wpdb->get_results(
254 + $wpdb->prepare(
255 + "SELECT option_name AS id, LENGTH(option_value) AS value_size FROM $wpdb->options WHERE option_name LIKE %s ORDER BY option_name ASC LIMIT %d",
256 + "jpsq_{$this->queue_id}-%",
257 + $max_count
258 + ),
259 + OBJECT
260 + );
261 + }
262 +
263 + /**
264 + * Delete items with specific IDs from the queue.
265 + *
266 + * @param array $ids IDs of the items to remove from the queue.
267 + *
268 + * @return bool|int|\mysqli_result|resource|null
269 + */
270 + public function delete_items_by_ids( $ids ) {
271 + global $wpdb;
272 +
273 + if ( ! is_array( $ids ) || empty( $ids ) ) {
274 + return false;
275 + }
276 +
277 + // TODO check if it's working properly - no need to delete all options in the table if the params are not right
278 + $ids_placeholders = implode( ', ', array_fill( 0, count( $ids ), '%s' ) );
279 +
280 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
281 + return $wpdb->query(
282 + $wpdb->prepare(
283 + /**
284 + * Ignoring the linting warning, as there's still no placeholder replacement for DB field name,
285 + * in this case this is `$ids_placeholders`, as we're preparing them above and are a dynamic count.
286 + */
287 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
288 + "DELETE FROM {$wpdb->options} WHERE option_name IN ( $ids_placeholders )",
289 + $ids
290 + )
291 + );
292 + }
293 +}