PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | framework/db/class-mapper.php +83 -45 6.2.0 → 6.3.0 View file →
@@ -73,9 +73,9 @@
73 73
74 74 /**
75 75 * Set the repository class name.
76 76 *
77 - * @param mixed $class_name The class name to set for the repository.
77 + * @param mixed $class_name The class name to set for the repository.
78 78 *
79 79 * @return $this
80 80 */
81 81 public function get_repository( $class_name ) {
@@ -86,9 +86,9 @@
86 86
87 87 /**
88 88 * Set the columns to select in the SQL query.
89 89 *
90 - * @param mixed $select The columns to select.
90 + * @param mixed $select The columns to select.
91 91 *
92 92 * @return $this
93 93 */
94 94 public function select( $select ) {
@@ -103,9 +103,9 @@
103 103 * Supports multiple call signatures:
104 104 * - where($column, $value) - equals comparison
105 105 * - where($column, $operator, $value) - custom operator comparison
106 106 *
107 - * @param mixed ...$args The conditions to apply in the WHERE clause.
107 + * @param mixed ...$args The conditions to apply in the WHERE clause.
108 108 *
109 109 * @return $this
110 110 */
111 111 public function where( ...$args ) {
@@ -132,9 +132,9 @@
132 132
133 133 /**
134 134 * Prepare where arguments - handles both 2-arg and 3-arg signatures.
135 135 *
136 - * @param array $args The arguments passed to where().
136 + * @param array $args The arguments passed to where().
137 137 *
138 138 * @return array|null [$column, $operator, $value] or null if invalid argument count.
139 139 */
140 140 private function prepare_where_args( array $args ): ?array {
@@ -153,15 +153,19 @@
153 153
154 154 /**
155 155 * Compile a where clause into SQL.
156 156 *
157 - * @param string $column The column name.
158 - * @param string $operator The operator.
159 - * @param mixed $value The value to compare against.
157 + * @param string $column The column name.
158 + * @param string $operator The operator.
159 + * @param mixed $value The value to compare against.
160 160 *
161 161 * @return string|null The compiled SQL or null if invalid.
162 162 */
163 163 private function compile_where( string $column, string $operator, $value ): ?string {
164 + if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $column ) ) {
165 + return null;
166 + }
167 +
164 168 global $wpdb;
165 169
166 170 $op_lower = strtolower( $operator );
167 171
@@ -177,22 +181,26 @@
177 181
178 182 // Handle basic comparison operators.
179 183 $placeholder = $this->guess_var_type( $value );
180 184
181 - // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
182 - return $wpdb->prepare( "`$column` $operator $placeholder", $value );
185 + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
186 + return $wpdb->prepare( "%i $operator $placeholder", $column, $value );
183 187 }
184 188
185 189 /**
186 190 * Compile a WHERE IN / NOT IN clause.
187 191 *
188 - * @param string $column The column name.
189 - * @param string $operator The operator (IN or NOT IN).
190 - * @param mixed $values The values (should be array, invalid inputs skipped).
192 + * @param string $column The column name.
193 + * @param string $operator The operator (IN or NOT IN).
194 + * @param mixed $values The values (should be array, invalid inputs skipped).
191 195 *
192 196 * @return string|null The compiled SQL or null if empty values.
193 197 */
194 198 private function compile_where_in( string $column, string $operator, $values ): ?string {
199 + if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $column ) ) {
200 + return null;
201 + }
202 +
195 203 if ( ! is_array( $values ) || 0 === count( $values ) ) {
196 204 return null;
197 205 }
198 206
@@ -202,24 +210,28 @@
202 210 foreach ( $values as $val ) {
203 211 $placeholders[] = $this->guess_var_type( $val );
204 212 }
205 213
206 - $sql_template = "`$column` $operator (" . implode( ', ', $placeholders ) . ')';
214 + $sql_template = '%i ' . $operator . ' (' . implode( ', ', $placeholders ) . ')';
207 215
208 216 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
209 - return $wpdb->prepare( $sql_template, ...$values );
217 + return $wpdb->prepare( $sql_template, $column, ...$values );
210 218 }
211 219
212 220 /**
213 221 * Compile a WHERE BETWEEN clause.
214 222 *
215 - * @param string $column The column name.
216 - * @param string $operator The operator (BETWEEN).
217 - * @param mixed $values The values (should be array with min/max, invalid inputs skipped).
223 + * @param string $column The column name.
224 + * @param string $operator The operator (BETWEEN).
225 + * @param mixed $values The values (should be array with min/max, invalid inputs skipped).
218 226 *
219 227 * @return string|null The compiled SQL or null if invalid values.
220 228 */
221 229 private function compile_where_between( string $column, string $operator, $values ): ?string {
230 + if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $column ) ) {
231 + return null;
232 + }
233 +
222 234 if ( ! is_array( $values ) || count( $values ) < 2 ) {
223 235 return null;
224 236 }
225 237
@@ -227,10 +239,12 @@
227 239
228 240 $placeholder_min = $this->guess_var_type( $values[0] );
229 241 $placeholder_max = $this->guess_var_type( $values[1] );
230 242
243 + // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
231 244 return $wpdb->prepare(
232 - "`$column` $operator $placeholder_min AND $placeholder_max", // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
245 + "%i $operator $placeholder_min AND $placeholder_max", // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
246 + $column,
233 247 $values[0],
234 248 $values[1]
235 249 );
236 250 }
@@ -237,9 +251,9 @@
237 251
238 252 /**
239 253 * Guess the type of value for correcting placeholder.
240 254 *
241 - * @param mixed $value The value to guess.
255 + * @param mixed $value The value to guess.
242 256 *
243 257 * @return string
244 258 */
245 259 private function guess_var_type( $value ): string {
@@ -256,9 +270,9 @@
256 270
257 271 /**
258 272 * Find a record by its ID.
259 273 *
260 - * @param int $id The ID of the record.
274 + * @param int $id The ID of the record.
261 275 *
262 276 * @return $this
263 277 */
264 278 public function find_by_id( $id ) {
@@ -270,20 +284,33 @@
270 284
271 285 /**
272 286 * Set the group by clause for the SQL query based on the provided argument.
273 287 *
274 - * @param string $group_by The column to group by.
288 + * @param string $group_by The column to group by.
275 289 *
276 290 * @return $this
277 291 */
278 292 public function group_by( $group_by ) {
279 293 global $wpdb;
280 - $this->group = str_replace(
281 - "'",
282 - '',
283 - $wpdb->prepare( 'GROUP BY %s', $group_by )
284 - );
285 294
295 + if ( ! is_string( $group_by ) || '' === trim( $group_by ) ) {
296 + return $this;
297 + }
298 +
299 + $parts = array_map( 'trim', explode( ',', $group_by ) );
300 + $safe_parts = array();
301 + foreach ( $parts as $part ) {
302 + if ( preg_match( '/^[a-zA-Z0-9_]+$/', $part ) ) {
303 + $safe_parts[] = $wpdb->prepare( '%i', $part );
304 + }
305 + }
306 +
307 + if ( empty( $safe_parts ) ) {
308 + return $this;
309 + }
310 +
311 + $this->group = 'GROUP BY ' . implode( ', ', $safe_parts );
312 +
286 313 return $this;
287 314 }
288 315
289 316 /**
@@ -288,25 +315,36 @@
288 315
289 316 /**
290 317 * Set the order for the SQL query based on the provided arguments.
291 318 *
292 - * @param mixed $order_by The column to order by.
293 - * @param string $order The order direction, defaults to 'asc'.
319 + * @param mixed $order_by The column to order by.
320 + * @param string $order The order direction, defaults to 'asc'.
294 321 *
295 322 * @return $this
296 323 */
297 324 public function order_by( $order_by, $order = 'asc' ) {
298 325 global $wpdb;
299 - if ( ! in_array( $order, array( 'asc', 'desc' ), true ) ) {
300 - // Fall it back.
301 - $order = 'asc';
326 +
327 + $order = 'desc' === strtolower( (string) $order ) ? 'DESC' : 'ASC';
328 +
329 + if ( ! is_string( $order_by ) || '' === trim( $order_by ) ) {
330 + return $this;
302 331 }
303 - $this->order = str_replace(
304 - "'",
305 - '',
306 - $wpdb->prepare( 'ORDER BY %s %s', $order_by, $order )
307 - );
308 332
333 + $parts = array_map( 'trim', explode( ',', $order_by ) );
334 + $safe_parts = array();
335 + foreach ( $parts as $part ) {
336 + if ( preg_match( '/^[a-zA-Z0-9_]+$/', $part ) ) {
337 + $safe_parts[] = $wpdb->prepare( '%i', $part );
338 + }
339 + }
340 +
341 + if ( empty( $safe_parts ) ) {
342 + return $this;
343 + }
344 +
345 + $this->order = 'ORDER BY ' . implode( ', ', $safe_parts ) . ' ' . $order;
346 +
309 347 return $this;
310 348 }
311 349
312 350 /**
@@ -311,10 +349,10 @@
311 349
312 350 /**
313 351 * Set the limit for the SQL query based on the provided value.
314 352 *
315 - * @param int $limit The limit value.
316 - * @param int|null $offset The offset value.
353 + * @param int $limit The limit value.
354 + * @param int|null $offset The offset value.
317 355 *
318 356 * @return $this
319 357 */
320 358 public function limit( $limit, $offset = null ) {
@@ -388,9 +426,9 @@
388 426 /**
389 427 * Get records in array form.
390 428 *
391 429 * @return array
392 - * @since 2.7.0
430 + * @since 2.7.0
393 431 */
394 432 public function get_results() {
395 433 $sql = $this->query_build(); // SQL is prepared here.
396 434 $this->saved_queries = $sql;
@@ -420,9 +458,9 @@
420 458
421 459 /**
422 460 * Handle the insert/update of current model.
423 461 *
424 - * @param Model $model The model to save.
462 + * @param Model $model The model to save.
425 463 *
426 464 * @return int|bool The ID of current record OR false.
427 465 * @throws \ReflectionException If class is not defined.
428 466 */
@@ -466,9 +504,9 @@
466 504
467 505 /**
468 506 * Delete a record from the database table based on the provided conditions.
469 507 *
470 - * @param mixed $where The conditions to apply when deleting the record.
508 + * @param mixed $where The conditions to apply when deleting the record.
471 509 *
472 510 * @return int|false The number of rows affected or false on failure.
473 511 * @throws \ReflectionException If class is not defined.
474 512 */
@@ -544,10 +582,10 @@
544 582
545 583 /**
546 584 * It is used to retrieve the table name associated with a given model.
547 585 *
548 - * @param mixed $model (optional) The model object or class name. If not provided, it uses the "repository"
549 - * property of the class.
586 + * @param mixed $model (optional) The model object or class name. If not provided, it uses the "repository"
587 + * property of the class.
550 588 *
551 589 * @return string|false The table name with the WordPress database prefix, or false if the table property doesn't
552 590 * exist or an exception occurs.
553 591 * @throws \ReflectionException If the model class doesn't exist.
@@ -583,9 +621,9 @@
583 621 /**
584 622 * Join the stuff on the table to make a full query statement.
585 623 * SQL params e.g. WHERE, ORDER or LIMIT were escaped on separate methods.
586 624 *
587 - * @param string $select Columns to select.
625 + * @param string $select Columns to select.
588 626 *
589 627 * @return string
590 628 * @throws \ReflectionException If class is not defined.
591 629 */
@@ -612,9 +650,9 @@
612 650
613 651 /**
614 652 * Checks if the given operator is valid.
615 653 *
616 - * @param string $operator The operator to check.
654 + * @param string $operator The operator to check.
617 655 *
618 656 * @return bool True if the operator is valid, false otherwise.
619 657 */
620 658 private function valid_operator( $operator ) {