[ Index ] |
PHP Cross Reference of BackPress |
[Summary view] [Print] [Text view]
1 <?php 2 3 class WP_Users { 4 var $db; 5 6 function WP_Users( &$db ) { 7 self::__construct( $db ); 8 // register_shutdown_function( array(&$this, '__destruct') ); 9 } 10 11 function __construct( &$db ) { 12 $this->db =& $db; 13 } 14 15 // function __destruct() { 16 // } 17 18 function _put_user( $args = null ) { 19 $defaults = array( 20 'ID' => false, 21 'user_login' => '', 22 'user_nicename' => '', 23 'user_email' => '', 24 'user_url' => '', 25 'user_pass' => false, 26 'user_registered' => time(), 27 'display_name' => '', 28 'user_status' => 0, 29 'strict_user_login' => true 30 ); 31 32 $fields = array_keys( wp_parse_args( $args ) ); 33 $args = wp_parse_args( $args, $defaults ); 34 unset($defaults['strict_user_login']); 35 36 if ( isset($args['ID']) && $args['ID'] ) { 37 unset($defaults['ID']); 38 $fields = array_intersect( $fields, array_keys( $defaults ) ); 39 } else { 40 $fields = array_keys( $defaults ); 41 } 42 43 extract( $args, EXTR_SKIP ); 44 45 $ID = (int) $ID; 46 47 if ( !$ID || in_array( 'user_login', $fields ) ) { 48 $user_login = $this->sanitize_user( $user_login, $strict_user_login ); 49 50 if ( !$user_login ) 51 return new WP_Error( 'user_login', __('Invalid login name') ); 52 if ( !$ID && $this->get_user( $user_login, array( 'by' => 'login' ) ) ) 53 return new WP_Error( 'user_login', __('Name already exists') ); 54 } 55 56 if ( !$ID || in_array( 'user_nicename', $fields ) ) { 57 if ( !$user_nicename = $this->sanitize_nicename( $user_nicename ? $user_nicename : $user_login ) ) 58 return new WP_Error( 'user_nicename', __('Invalid nicename') ); 59 if ( !$ID && $this->get_user( $user_nicename, array( 'by' => 'nicename' ) ) ) 60 return new WP_Error( 'user_nicename', __('Nicename already exists') ); 61 } 62 63 if ( !$ID || in_array( 'user_email', $fields ) ) { 64 if ( !$this->is_email( $user_email ) ) 65 return new WP_Error( 'user_email', __('Invalid email address') ); 66 67 if ( $already_email = $this->get_user( $user_email, array( 'by' => 'email' ) ) ) { 68 // if new user, or if multiple users with that email, or if only one user with that email, but it's not the user being updated 69 if ( !$ID || is_wp_error( $already_email ) || $already_email->ID != $ID ) 70 return new WP_Error( 'user_email', __('Email already exists') ); 71 } 72 } 73 74 if ( !$ID || in_array( 'user_url', $fields ) ) { 75 $user_url = esc_url( $user_url ); 76 } 77 78 if ( !$ID || in_array( 'user_pass', $fields ) ) { 79 if ( !$user_pass ) 80 $user_pass = WP_Pass::generate_password(); 81 $plain_pass = $user_pass; 82 $user_pass = WP_Pass::hash_password( $user_pass ); 83 } 84 85 if ( !$ID || in_array( 'user_registered', $fields ) ) { 86 if ( !is_numeric($user_registered) ) 87 $user_registered = backpress_gmt_strtotime( $user_registered ); 88 89 if ( !$user_registered || $user_registered < 0 ) 90 return new WP_Error( 'user_registered', __('Invalid registration time') ); 91 92 if ( !$user_registered = @gmdate('Y-m-d H:i:s', $user_registered) ) 93 return new WP_Error( 'user_registered', __('Invalid registration timestamp') ); 94 } 95 96 if ( !$ID || in_array( 'user_display', $fields ) ) { 97 if ( !$display_name ) 98 $display_name = $user_login; 99 } 100 101 $db_return = NULL; 102 if ( $ID ) { 103 $db_return = $this->db->update( $this->db->users, compact( $fields ), compact('ID') ); 104 } else { 105 $db_return = $this->db->insert( $this->db->users, compact( $fields ) ); 106 $ID = $this->db->insert_id; 107 } 108 109 if ( !$db_return ) 110 return new WP_Error( 'WP_Users::_put_user', __('Query failed') ); 111 112 // Cache the result 113 if ( $ID ) { 114 wp_cache_delete( $ID, 'users' ); 115 $this->get_user( $ID, array( 'from_cache' => false ) ); 116 } 117 118 $args = compact( array_keys($args) ); 119 $args['plain_pass'] = $plain_pass; 120 121 do_action( __CLASS__ . '::' . __FUNCTION__, $args ); 122 123 return $args; 124 } 125 126 function new_user( $args = null ) { 127 $args = wp_parse_args( $args ); 128 $args['ID'] = false; 129 130 $r = $this->_put_user( $args ); 131 132 if ( is_wp_error($r) ) 133 return $r; 134 135 do_action( __CLASS__ . '::' . __FUNCTION__, $r, $args ); 136 137 return $r; 138 } 139 140 function update_user( $ID, $args = null ) { 141 $args = wp_parse_args( $args ); 142 143 $args['output'] = OBJECT; 144 $user = $this->get_user( $ID, $args ); 145 if ( !$user || is_wp_error( $user ) ) 146 return $user; 147 148 $args['ID'] = $user->ID; 149 150 $r = $this->_put_user( $args ); 151 152 if ( is_wp_error($r) ) 153 return $r; 154 155 do_action( __CLASS__ . '::' . __FUNCTION__, $r, $args ); 156 157 return $r; 158 } 159 160 /** 161 * set_password() - Updates the user's password with a new encrypted one 162 * 163 * For integration with other applications, this function can be 164 * overwritten to instead use the other package password checking 165 * algorithm. 166 * 167 * @since 2.5 168 * @uses WP_Pass::hash_password() Used to encrypt the user's password before passing to the database 169 * 170 * @param string $password The plaintext new user password 171 * @param int $user_id User ID 172 */ 173 function set_password( $password, $user_id ) { 174 $user = $this->get_user( $user_id ); 175 if ( !$user || is_wp_error( $user ) ) 176 return $user; 177 178 $user_id = $user->ID; 179 $hash = WP_Pass::hash_password($password); 180 $this->update_user( $user->ID, array( 'user_pass' => $password ) ); 181 } 182 183 // $user_id can be user ID#, user_login, user_email (by specifying by = email) 184 function get_user( $user_id = 0, $args = null ) { 185 $defaults = array( 'output' => OBJECT, 'by' => false, 'from_cache' => true, 'append_meta' => true ); 186 $args = wp_parse_args( $args, $defaults ); 187 extract( $args, EXTR_SKIP ); 188 189 if ( !$user_id ) { 190 return false; 191 } 192 193 // Let's just deal with arrays 194 $user_ids = (array) $user_id; 195 196 if ( !count( $user_ids ) ) { 197 return false; 198 } 199 200 // Validate passed ids 201 $safe_user_ids = array(); 202 foreach ( $user_ids as $_user_id ) { 203 switch ( $by ) { 204 case 'login': 205 $safe_user_ids[] = $this->sanitize_user( $_user_id, true ); 206 break; 207 case 'email': 208 if ( $this->is_email( $_user_id ) ) { 209 $safe_user_ids[] = $_user_id; 210 } 211 break; 212 case 'nicename': 213 $safe_user_ids[] = $this->sanitize_nicename( $_user_id ); 214 break; 215 default: 216 if ( is_numeric( $_user_id ) ) { 217 $safe_user_ids[] = (int) $_user_id; 218 } else { // If one $_user_id is non-numerical, treat all $user_ids as user_logins 219 $safe_user_ids[] = $this->sanitize_user( $_user_id, true ); 220 $by = 'login'; 221 } 222 break; 223 } 224 } 225 226 // No soup for you! 227 if ( !count( $safe_user_ids ) ) { 228 return false; 229 } 230 231 // Name the cache storing non-existant ids and the SQL field to query by 232 switch ( $by ) { 233 case 'login': 234 $non_existant_cache = 'userlogins'; 235 $sql_field = 'user_login'; 236 break; 237 case 'email': 238 $non_existant_cache = 'useremail'; 239 $sql_field = 'user_email'; 240 break; 241 case 'nicename': 242 $non_existant_cache = 'usernicename'; 243 $sql_field = 'user_nicename'; 244 break; 245 default: 246 $non_existant_cache = 'users'; 247 $sql_field = 'ID'; 248 break; 249 } 250 251 // Check if the numeric user IDs exist from caches 252 $cached_users = array(); 253 if ( $from_cache ) { 254 $existant_user_ids = array(); 255 $maybe_existant_user_ids = array(); 256 257 switch ( $by ) { 258 case 'login': 259 case 'email': 260 case 'nicename': 261 foreach ( $safe_user_ids as $_safe_user_id ) { 262 $ID = wp_cache_get( $_safe_user_id, $non_existant_cache ); 263 if ( false === $ID ) { 264 $maybe_existant_user_ids[] = $_safe_user_id; 265 } elseif ( 0 !== $ID ) { 266 $existant_user_ids[] = $ID; 267 } 268 } 269 if ( count( $existant_user_ids ) ) { 270 // We need to run again using numeric ids 271 $args['by'] = false; 272 $cached_users = $this->get_user( $existant_user_ids, $args ); 273 } 274 break; 275 default: 276 foreach ( $safe_user_ids as $_safe_user_id ) { 277 $user = wp_cache_get( $_safe_user_id, 'users' ); 278 if ( false === $user ) { 279 $maybe_existant_user_ids[] = $_safe_user_id; 280 } elseif ( 0 !== $user ) { 281 $cached_users[] = $user; 282 } 283 } 284 break; 285 } 286 287 // No maybes? Then it's definite. 288 if ( !count( $maybe_existant_user_ids ) ) { 289 if ( !count( $cached_users ) ) { 290 // Nothing there sorry 291 return false; 292 } 293 294 // Deal with the case where one record was requested but multiple records are returned 295 if ( !is_array( $user_id ) && $user_id ) { 296 if ( 1 < count( $cached_users ) ) { 297 if ( 'user_email' == $sql_field ) { 298 $err = __( 'Multiple email matches. Log in with your username.' ); 299 } else { 300 $err = sprintf( __( 'Multiple %s matches' ), $sql_field ); 301 } 302 return new WP_Error( $sql_field, $err, $args + array( 'user_id' => $user_id, 'unique' => false ) ); 303 } 304 305 // If one item was requested, it expects a single user object back 306 $cached_users = array_shift( $cached_users ); 307 } 308 309 backpress_convert_object( $cached_users, $output ); 310 return $cached_users; 311 } 312 313 // If we get this far, there are some maybes so try and grab them 314 } else { 315 $maybe_existant_user_ids = $safe_user_ids; 316 } 317 318 // Escape the ids for the SQL query 319 $maybe_existant_user_ids = $this->db->escape_deep( $maybe_existant_user_ids ); 320 321 // Sort the ids so the MySQL will more consistently cache the query 322 sort( $maybe_existant_user_ids ); 323 324 // Get the users from the database 325 $sql = "SELECT * FROM `{$this->db->users}` WHERE `$sql_field` in ('" . join( "','", $maybe_existant_user_ids ) . "');"; 326 $db_users = $this->db->get_results( $sql ); 327 328 // Merge in the cached users if available 329 if ( count( $cached_users ) ) { 330 // Create a convenient array of database fetched user ids 331 $db_user_ids = array(); 332 foreach ( $db_users as $_db_user ) { 333 $db_user_ids[] = $_db_user->ID; 334 } 335 $users = array_merge( $cached_users, $db_users ); 336 } else { 337 $users = $db_users; 338 } 339 340 // Deal with the case where one record was requested but multiple records are returned 341 if ( !is_array( $user_id ) && $user_id ) { 342 if ( 1 < count( $users ) ) { 343 if ( 'user_email' == $sql_field ) { 344 $err = __( 'Multiple email matches. Log in with your username.' ); 345 } else { 346 $err = sprintf( __( 'Multiple %s matches' ), $sql_field ); 347 } 348 return new WP_Error( $sql_field, $err, $args + array( 'user_id' => $user_id, 'unique' => false ) ); 349 } 350 } 351 352 // Create a convenient array of final user ids 353 $final_user_ids = array(); 354 foreach ( $users as $_user ) { 355 $final_user_ids[] = $_user->$sql_field; 356 } 357 358 foreach ( $safe_user_ids as $_safe_user_id ) { 359 if ( !in_array( $_safe_user_id, $final_user_ids ) ) { 360 wp_cache_add( $_safe_user_id, 0, $non_existant_cache ); 361 } 362 } 363 364 if ( !count( $users ) ) { 365 return false; 366 } 367 368 // Add display names 369 $final_users = array(); 370 foreach ( $users as $_user ) { 371 // Make sure there is a display_name set 372 if ( !$_user->display_name ) { 373 $_user->display_name = $_user->user_login; 374 } 375 376 $final_users[] = $_user; 377 } 378 379 // append_meta() does the user object, useremail, userlogins caching 380 if ( $append_meta ) { 381 if ( count( $cached_users ) ) { 382 $db_final_users =array(); 383 $cached_final_users = array(); 384 foreach ( $final_users as $final_user ) { 385 if ( in_array( $final_user->ID, $db_user_ids ) ) { 386 $db_final_users[] = $final_user; 387 } else { 388 $cached_final_users[] = $final_user; 389 } 390 } 391 $db_final_users = $this->append_meta( $db_final_users ); 392 $final_users = array_merge( $cached_final_users, $db_final_users ); 393 } else { 394 $final_users = $this->append_meta( $final_users ); 395 } 396 } 397 398 // If one item was requested, it expects a single user object back 399 if ( !is_array( $user_id ) && $user_id ) { 400 $final_users = array_shift( $final_users ); 401 } 402 403 backpress_convert_object( $final_users, $output ); 404 return $final_users; 405 } 406 407 function delete_user( $user_id ) { 408 $user = $this->get_user( $user_id ); 409 410 if ( !$user || is_wp_error( $user ) ) 411 return $user; 412 413 do_action( 'pre_' . __CLASS__ . '::' . __FUNCTION__, $user->ID ); 414 415 $r = $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->users} WHERE ID = %d", $user->ID ) ); 416 $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->usermeta} WHERE user_id = %d", $user->ID ) ); 417 418 wp_cache_delete( $user->ID, 'users' ); 419 wp_cache_delete( $user->user_nicename, 'usernicename' ); 420 wp_cache_delete( $user->user_email, 'useremail' ); 421 wp_cache_delete( $user->user_login, 'userlogins' ); 422 423 do_action( __CLASS__ . '::' . __FUNCTION__, $user->ID ); 424 425 return $r; 426 } 427 428 // Used for user meta, but can be used for other meta data (such as bbPress' topic meta) 429 // Should this be in the class or should it be it's own special function? 430 function append_meta( $object, $args = null ) { 431 $defaults = array( 'meta_table' => 'usermeta', 'meta_field' => 'user_id', 'id_field' => 'ID', 'cache_group' => 'users' ); 432 $args = wp_parse_args( $args, $defaults ); 433 extract( $args, EXTR_SKIP ); 434 435 if ( is_array($object) ) { 436 $trans = array(); 437 foreach ( array_keys($object) as $i ) 438 $trans[$object[$i]->$id_field] =& $object[$i]; 439 $ids = join(',', array_keys($trans)); 440 if ( $ids && $metas = $this->db->get_results("SELECT $meta_field, meta_key, meta_value FROM {$this->db->$meta_table} WHERE $meta_field IN ($ids) /* WP_Users::append_meta */") ) { 441 usort( $metas, array(&$this, '_append_meta_sort') ); 442 foreach ( $metas as $meta ) { 443 if ( empty( $meta->meta_key ) ) 444 continue; 445 $trans[$meta->$meta_field]->{$meta->meta_key} = maybe_unserialize( $meta->meta_value ); 446 if ( strpos($meta->meta_key, $this->db->prefix) === 0 ) 447 $trans[$meta->$meta_field]->{substr($meta->meta_key, strlen($this->db->prefix))} = maybe_unserialize( $meta->meta_value ); 448 } 449 } 450 foreach ( array_keys($trans) as $i ) { 451 wp_cache_set( $i, $trans[$i], $cache_group ); 452 if ( 'users' == $cache_group ) { 453 wp_cache_set( $trans[$i]->user_login, $i, 'userlogins' ); 454 wp_cache_set( $trans[$i]->user_email, $i, 'useremail' ); 455 wp_cache_set( $trans[$i]->user_nicename, $i, 'usernicename' ); 456 } 457 } 458 return $object; 459 } elseif ( $object ) { 460 if ( $metas = $this->db->get_results("SELECT meta_key, meta_value FROM {$this->db->$meta_table} WHERE $meta_field = '{$object->$id_field}' /* WP_Users::append_meta */") ) { 461 usort( $metas, array(&$this, '_append_meta_sort') ); 462 foreach ( $metas as $meta ) { 463 if ( empty( $meta->meta_key ) ) 464 continue; 465 $object->{$meta->meta_key} = maybe_unserialize( $meta->meta_value ); 466 if ( strpos($meta->meta_key, $this->db->prefix) === 0 ) 467 $object->{substr($meta->meta_key, strlen($this->db->prefix))} = maybe_unserialize( $meta->meta_value ); 468 } 469 } 470 wp_cache_set( $object->$id_field, $object, $cache_group ); 471 if ( 'users' == $cache_group ) { 472 wp_cache_set($object->user_login, $object->ID, 'userlogins'); 473 wp_cache_set($object->user_email, $object->ID, 'useremail'); 474 wp_cache_set($object->user_nicename, $object->ID, 'usernicename'); 475 } 476 return $object; 477 } 478 } 479 480 /** 481 * _append_meta_sort() - sorts meta keys by length to ensure $appended_object->{$bbdb->prefix}key overwrites $appended_object->key as desired 482 * 483 * @internal 484 */ 485 function _append_meta_sort( $a, $b ) { 486 return strlen( $a->meta_key ) - strlen( $b->meta_key ); 487 } 488 489 function update_meta( $args = null ) { 490 $defaults = array( 'id' => 0, 'meta_key' => null, 'meta_value' => null, 'meta_table' => 'usermeta', 'meta_field' => 'user_id', 'cache_group' => 'users' ); 491 $args = wp_parse_args( $args, $defaults ); 492 extract( $args, EXTR_SKIP ); 493 494 $user = $this->get_user( $id ); 495 if ( !$user || is_wp_error($user) ) 496 return $user; 497 498 $id = (int) $user->ID; 499 500 if ( is_null($meta_key) || is_null($meta_value) ) 501 return false; 502 503 $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key); 504 if ( 'usermeta' == $meta_table && 'capabilities' == $meta_key ) 505 $meta_key = $this->db->prefix . 'capabilities'; 506 507 $meta_tuple = compact('id', 'meta_key', 'meta_value', 'meta_table'); 508 $meta_tuple = apply_filters( __CLASS__ . '::' . __FUNCTION__, $meta_tuple ); 509 extract($meta_tuple, EXTR_OVERWRITE); 510 511 $_meta_value = maybe_serialize( $meta_value ); 512 513 $cur = $this->db->get_row( $this->db->prepare( "SELECT * FROM {$this->db->$meta_table} WHERE $meta_field = %d AND meta_key = %s", $id, $meta_key ) ); 514 515 if ( !$cur ) { 516 $this->db->insert( $this->db->$meta_table, array( $meta_field => $id, 'meta_key' => $meta_key, 'meta_value' => $_meta_value ) ); 517 } elseif ( $cur->meta_value != $meta_value ) { 518 $this->db->update( $this->db->$meta_table, array( 'meta_value' => $_meta_value ), array( $meta_field => $id, 'meta_key' => $meta_key ) ); 519 } 520 521 522 wp_cache_delete( $id, $cache_group ); 523 524 return true; 525 } 526 527 function delete_meta( $args = null ) { 528 $defaults = array( 'id' => 0, 'meta_key' => null, 'meta_value' => null, 'meta_table' => 'usermeta', 'meta_field' => 'user_id', 'meta_id_field' => 'umeta_id', 'cache_group' => 'users' ); 529 $args = wp_parse_args( $args, $defaults ); 530 extract( $args, EXTR_SKIP ); 531 532 $user = $this->get_user( $id ); 533 if ( !$user || is_wp_error($user) ) 534 return $user; 535 536 $id = (int) $id; 537 538 if ( is_null($meta_key) ) 539 return false; 540 541 $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key); 542 543 $meta_tuple = compact('id', 'meta_key', 'meta_value', 'meta_table'); 544 $meta_tuple = apply_filters( __CLASS__ . '::' . __FUNCTION__, $meta_tuple ); 545 extract($meta_tuple, EXTR_OVERWRITE); 546 547 $_meta_value = is_null($meta_value) ? null : maybe_serialize( $meta_value ); 548 549 if ( is_null($_meta_value) ) 550 $meta_id = $this->db->get_var( $this->db->prepare( "SELECT $meta_id_field FROM {$this->db->$meta_table} WHERE $meta_field = %d AND meta_key = %s", $id, $meta_key ) ); 551 else 552 $meta_id = $this->db->get_var( $this->db->prepare( "SELECT $meta_id_field FROM {$this->db->$meta_table} WHERE $meta_field = %d AND meta_key = %s AND meta_value = %s", $id, $meta_key, $_meta_value ) ); 553 554 if ( !$meta_id ) 555 return false; 556 557 if ( is_null($_meta_value) ) 558 $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->$meta_table} WHERE $meta_field = %d AND meta_key = %s", $id, $meta_key ) ); 559 else 560 $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->$meta_table} WHERE $meta_id_field = %d", $meta_id ) ); 561 562 wp_cache_delete( $id, $cache_group ); 563 564 return true; 565 } 566 567 function sanitize_user( $user_login, $strict = false ) { 568 return sanitize_user( $user_login, $strict ); 569 } 570 571 function sanitize_nicename( $slug ) { 572 return sanitize_title( $slug ); 573 } 574 575 function is_email( $email ) { 576 return is_email( $email ); 577 } 578 579 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Nov 23 01:00:54 2024 | Cross-referenced by PHPXref 0.7.1 |