| @@ -6,8 +6,10 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace Booktics\Abstracts; |
| 9 | 9 | |
| 10 | +if ( ! defined( 'ABSPATH' ) ) exit; | |
| 11 | + | |
| 10 | 12 | use JsonSerializable; |
| 11 | 13 | use WP_User_Query; |
| 12 | 14 | |
| 13 | 15 | abstract class User_Model implements JsonSerializable { |
| @@ -414,8 +416,9 @@ | ||
| 414 | 416 | $relation = 'OR'; |
| 415 | 417 | } |
| 416 | 418 | } |
| 417 | 419 | if ( ! empty( $meta_query ) ) { |
| 420 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering users by meta fields | |
| 418 | 421 | $args['meta_query'] = [ |
| 419 | 422 | 'relation' => $relation, |
| 420 | 423 | ...$meta_query |
| 421 | 424 | ]; |
| @@ -538,17 +541,17 @@ | ||
| 538 | 541 | } |
| 539 | 542 | |
| 540 | 543 | $value = $this->$key ?? $this->fillable[ $key ]; |
| 541 | 544 | |
| 542 | - // Unserialize if necessary | |
| 545 | + // Unserialize if necessary (object instantiation disallowed — see helper). | |
| 543 | 546 | if ( is_string( $value ) && $this->is_serialized( $value ) ) { |
| 544 | - $value = maybe_unserialize( $value ); | |
| 547 | + $value = \booktics_safe_maybe_unserialize( $value ); | |
| 545 | 548 | } |
| 546 | 549 | |
| 547 | 550 | // Normalize value to default type |
| 548 | 551 | if ( gettype( $value ) !== gettype( $default ) ) { |
| 549 | 552 | if ( gettype( $default ) === 'array' && is_string( $value ) && $this->is_serialized( $value ) ) { |
| 550 | - $value = maybe_unserialize( $value ); | |
| 553 | + $value = \booktics_safe_maybe_unserialize( $value ); | |
| 551 | 554 | } elseif ( gettype( $default ) === 'array' ) { |
| 552 | 555 | $value = $default; |
| 553 | 556 | } |
| 554 | 557 | } |
| @@ -553,9 +556,9 @@ | ||
| 553 | 556 | } |
| 554 | 557 | } |
| 555 | 558 | |
| 556 | 559 | // Cast specific keys to objects |
| 557 | - if ( $key == 'schedule' ) { | |
| 560 | + if ( 'schedule' == $key ) { | |
| 558 | 561 | $value = (object) $value; |
| 559 | 562 | } |
| 560 | 563 | |
| 561 | 564 | // Cast specific keys to boolean |
| @@ -566,9 +569,9 @@ | ||
| 566 | 569 | ] ) ) { |
| 567 | 570 | $value = filter_var( $value, FILTER_VALIDATE_BOOLEAN ); |
| 568 | 571 | } |
| 569 | 572 | |
| 570 | - if ( $key == 'user_registered' ) { | |
| 573 | + if ( 'user_registered' == $key ) { | |
| 571 | 574 | $value = $default; |
| 572 | 575 | } |
| 573 | 576 | |
| 574 | 577 | $data[ $key ] = $value ?? $default; |
| @@ -586,9 +589,11 @@ | ||
| 586 | 589 | * |
| 587 | 590 | * @return bool True if data is serialized, false otherwise |
| 588 | 591 | */ |
| 589 | 592 | function is_serialized( $data ) { |
| 590 | - return is_string( $data ) && @unserialize( $data ) !== false; | |
| 593 | + // Structural check only (WordPress core) — never calls unserialize(), so it | |
| 594 | + // cannot trigger PHP Object Injection on attacker-controlled user meta. | |
| 595 | + return is_string( $data ) && \is_serialized( $data ); | |
| 591 | 596 | } |
| 592 | 597 | |
| 593 | 598 | /** |
| 594 | 599 | * Specify data which should be serialized to JSON. |