Make WordPress Core

Changeset 61656


Ignore:
Timestamp:
02/17/2026 05:48:04 AM (6 months ago)
Author:
westonruter
Message:

Users: Ensure user data supplied to wp_insert_user() is normalized to an array.

This fixes an issue where PHPStan hangs when analyzing the containing users.php file.

Developed in https://github.com/WordPress/wordpress-develop/pull/10953

Follow-up to [60650].

Props westonruter, justlevine, peterwilsoncc.
See #64238, #61175.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/user.php

    r61644 r61656  
    22102210        } elseif ( $userdata instanceof WP_User ) {
    22112211                $userdata = $userdata->to_array();
     2212        } elseif ( $userdata instanceof Traversable ) {
     2213                $userdata = iterator_to_array( $userdata );
     2214        } elseif ( $userdata instanceof ArrayAccess ) {
     2215                $userdata_obj = $userdata;
     2216                $userdata     = array();
     2217                foreach (
     2218                        array(
     2219                                'ID',
     2220                                'user_pass',
     2221                                'user_login',
     2222                                'user_nicename',
     2223                                'user_url',
     2224                                'user_email',
     2225                                'display_name',
     2226                                'nickname',
     2227                                'first_name',
     2228                                'last_name',
     2229                                'description',
     2230                                'rich_editing',
     2231                                'syntax_highlighting',
     2232                                'comment_shortcuts',
     2233                                'admin_color',
     2234                                'use_ssl',
     2235                                'user_registered',
     2236                                'user_activation_key',
     2237                                'spam',
     2238                                'show_admin_bar_front',
     2239                                'role',
     2240                                'locale',
     2241                                'meta_input',
     2242                        ) as $key
     2243                ) {
     2244                        if ( isset( $userdata_obj[ $key ] ) ) {
     2245                                $userdata[ $key ] = $userdata_obj[ $key ];
     2246                        }
     2247                }
     2248        } else {
     2249                $userdata = (array) $userdata;
    22122250        }
    22132251
     
    22452283        }
    22462284
    2247         $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
     2285        $sanitized_user_login = sanitize_user( $userdata['user_login'] ?? '', true );
    22482286
    22492287        /**
  • trunk/tests/phpunit/tests/user.php

    r61210 r61656  
    984984
    985985        /**
     986         * @ticket 61175
     987         * @covers ::wp_insert_user
     988         */
     989        public function test_wp_insert_user_with_null() {
     990                // Note: $this->expectWarning() is deprecated and will be removed in PHPUnit 10.
     991                $warnings = array();
     992                set_error_handler(
     993                        static function ( int $errno, string $errstr ) use ( &$warnings ) {
     994                                $warnings[] = compact( 'errno', 'errstr' );
     995                                return true;
     996                        },
     997                        E_USER_WARNING
     998                );
     999                $user = wp_insert_user( null );
     1000                restore_error_handler();
     1001
     1002                $this->assertCount( 1, $warnings, 'Expected one warning.' );
     1003                $this->assertWPError( $user );
     1004                $this->assertSame( 'empty_user_login', $user->get_error_code() );
     1005        }
     1006
     1007        /**
     1008         * @ticket 61175
     1009         * @covers ::wp_insert_user
     1010         */
     1011        public function test_wp_insert_user_with_stdclass() {
     1012                $data    = array(
     1013                        'user_login' => 'new-admin',
     1014                        'user_pass'  => 'better-password',
     1015                );
     1016                $user_id = wp_insert_user( (object) $data );
     1017                $this->assertIsInt( $user_id, 'Expected user to be created.' );
     1018                $user = new WP_User( $user_id );
     1019                $this->assertSame( $data['user_login'], $user->user_login );
     1020        }
     1021
     1022        /**
     1023         * @ticket 61175
     1024         * @covers ::wp_insert_user
     1025         */
     1026        public function test_wp_insert_user_with_wp_user() {
     1027                $username         = 'new-admin';
     1028                $user             = new WP_User();
     1029                $user->user_login = $username;
     1030                $user->user_pass  = 'better-password';
     1031
     1032                $user_id = wp_insert_user( $user );
     1033                $this->assertIsInt( $user_id, 'Expected user to be created.' );
     1034                $user = new WP_User( $user_id );
     1035                $this->assertSame( $username, $user->user_login );
     1036        }
     1037
     1038        /**
     1039         * @ticket 61175
     1040         * @covers ::wp_insert_user
     1041         */
     1042        public function test_wp_insert_user_with_traversable() {
     1043                $internal_data = array(
     1044                        'user_login' => 'new-admin',
     1045                        'user_pass'  => 'better-password',
     1046                );
     1047
     1048                $array_access_user = new class( $internal_data ) implements ArrayAccess, IteratorAggregate {
     1049                        private array $data;
     1050
     1051                        public function __construct( array $data ) {
     1052                                $this->data = $data;
     1053                        }
     1054
     1055                        public function offsetExists( $offset ): bool {
     1056                                return isset( $this->data[ $offset ] );
     1057                        }
     1058
     1059                        #[\ReturnTypeWillChange]
     1060                        public function offsetGet( $offset ) {
     1061                                return $this->data[ $offset ];
     1062                        }
     1063
     1064                        public function offsetSet( $offset, $value ): void {
     1065                                $this->data[ $offset ] = $value;
     1066                        }
     1067
     1068                        public function offsetUnset( $offset ): void {
     1069                                unset( $this->data[ $offset ] );
     1070                        }
     1071
     1072                        public function getIterator(): ArrayIterator {
     1073                                return new ArrayIterator( $this->data );
     1074                        }
     1075                };
     1076
     1077                $user_id = wp_insert_user( $array_access_user );
     1078                $this->assertIsInt( $user_id, 'Expected user to be created.' );
     1079                $user = new WP_User( $user_id );
     1080                $this->assertSame( $internal_data['user_login'], $user->user_login );
     1081        }
     1082
     1083        /**
     1084         * @ticket 61175
     1085         * @covers ::wp_insert_user
     1086         */
     1087        public function test_wp_insert_user_with_only_array_access() {
     1088                $internal_data = array(
     1089                        'user_login' => 'new-admin',
     1090                        'user_pass'  => 'better-password',
     1091                );
     1092
     1093                $array_access_user = new class( $internal_data ) implements ArrayAccess  {
     1094                        private array $data;
     1095
     1096                        public function __construct( array $data ) {
     1097                                $this->data = $data;
     1098                        }
     1099
     1100                        public function offsetExists( $offset ): bool {
     1101                                return isset( $this->data[ $offset ] );
     1102                        }
     1103
     1104                        #[\ReturnTypeWillChange]
     1105                        public function offsetGet( $offset ) {
     1106                                return $this->data[ $offset ];
     1107                        }
     1108
     1109                        public function offsetSet( $offset, $value ): void {
     1110                                $this->data[ $offset ] = $value;
     1111                        }
     1112
     1113                        public function offsetUnset( $offset ): void {
     1114                                unset( $this->data[ $offset ] );
     1115                        }
     1116                };
     1117
     1118                $user_id = wp_insert_user( $array_access_user );
     1119                $this->assertIsInt( $user_id, 'Expected user to be created.' );
     1120                $user = new WP_User( $user_id );
     1121                $this->assertSame( $internal_data['user_login'], $user->user_login );
     1122        }
     1123
     1124        /**
    9861125         * @ticket 27317
    9871126         * @dataProvider data_illegal_user_logins
Note: See TracChangeset for help on using the changeset viewer.