[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Table; 11 12 use Joomla\CMS\Factory; 13 use Joomla\CMS\Filter\InputFilter; 14 use Joomla\CMS\Language\Text; 15 use Joomla\CMS\Mail\MailHelper; 16 use Joomla\CMS\String\PunycodeHelper; 17 use Joomla\Database\DatabaseDriver; 18 use Joomla\Database\ParameterType; 19 use Joomla\Registry\Registry; 20 use Joomla\String\StringHelper; 21 use Joomla\Utilities\ArrayHelper; 22 23 // phpcs:disable PSR1.Files.SideEffects 24 \defined('JPATH_PLATFORM') or die; 25 // phpcs:enable PSR1.Files.SideEffects 26 27 /** 28 * Users table 29 * 30 * @since 1.7.0 31 */ 32 class User extends Table 33 { 34 /** 35 * Indicates that columns fully support the NULL value in the database 36 * 37 * @var boolean 38 * @since 4.0.0 39 */ 40 protected $_supportNullValue = true; 41 42 /** 43 * Associative array of group ids => group ids for the user 44 * 45 * @var array 46 * @since 1.7.0 47 */ 48 public $groups; 49 50 /** 51 * Constructor 52 * 53 * @param DatabaseDriver $db Database driver object. 54 * 55 * @since 1.7.0 56 */ 57 public function __construct(DatabaseDriver $db) 58 { 59 parent::__construct('#__users', 'id', $db); 60 61 // Initialise. 62 $this->id = 0; 63 $this->sendEmail = 0; 64 } 65 66 /** 67 * Method to load a user, user groups, and any other necessary data 68 * from the database so that it can be bound to the user object. 69 * 70 * @param integer $userId An optional user id. 71 * @param boolean $reset False if row not found or on error 72 * (internal error state set in that case). 73 * 74 * @return boolean True on success, false on failure. 75 * 76 * @since 1.7.0 77 */ 78 public function load($userId = null, $reset = true) 79 { 80 // Get the id to load. 81 if ($userId !== null) { 82 $this->id = $userId; 83 } else { 84 $userId = $this->id; 85 } 86 87 // Check for a valid id to load. 88 if ($userId === null) { 89 return false; 90 } 91 92 // Reset the table. 93 $this->reset(); 94 95 $userId = (int) $userId; 96 97 // Load the user data. 98 $query = $this->_db->getQuery(true) 99 ->select('*') 100 ->from($this->_db->quoteName('#__users')) 101 ->where($this->_db->quoteName('id') . ' = :userid') 102 ->bind(':userid', $userId, ParameterType::INTEGER); 103 $this->_db->setQuery($query); 104 $data = (array) $this->_db->loadAssoc(); 105 106 if (!\count($data)) { 107 return false; 108 } 109 110 // Convert email from punycode 111 $data['email'] = PunycodeHelper::emailToUTF8($data['email']); 112 113 // Bind the data to the table. 114 $return = $this->bind($data); 115 116 if ($return !== false) { 117 // Load the user groups. 118 $query->clear() 119 ->select($this->_db->quoteName('g.id')) 120 ->select($this->_db->quoteName('g.title')) 121 ->from($this->_db->quoteName('#__usergroups', 'g')) 122 ->join( 123 'INNER', 124 $this->_db->quoteName('#__user_usergroup_map', 'm'), 125 $this->_db->quoteName('m.group_id') . ' = ' . $this->_db->quoteName('g.id') 126 ) 127 ->where($this->_db->quoteName('m.user_id') . ' = :muserid') 128 ->bind(':muserid', $userId, ParameterType::INTEGER); 129 $this->_db->setQuery($query); 130 131 // Add the groups to the user data. 132 $this->groups = $this->_db->loadAssocList('id', 'id'); 133 } 134 135 return $return; 136 } 137 138 /** 139 * Method to bind the user, user groups, and any other necessary data. 140 * 141 * @param array $array The data to bind. 142 * @param mixed $ignore An array or space separated list of fields to ignore. 143 * 144 * @return boolean True on success, false on failure. 145 * 146 * @since 1.7.0 147 */ 148 public function bind($array, $ignore = '') 149 { 150 if (\array_key_exists('params', $array) && \is_array($array['params'])) { 151 $registry = new Registry($array['params']); 152 $array['params'] = (string) $registry; 153 } 154 155 // Attempt to bind the data. 156 $return = parent::bind($array, $ignore); 157 158 // Load the real group data based on the bound ids. 159 if ($return && !empty($this->groups)) { 160 // Set the group ids. 161 $this->groups = ArrayHelper::toInteger($this->groups); 162 163 // Get the titles for the user groups. 164 $query = $this->_db->getQuery(true) 165 ->select($this->_db->quoteName('id')) 166 ->select($this->_db->quoteName('title')) 167 ->from($this->_db->quoteName('#__usergroups')) 168 ->whereIn($this->_db->quoteName('id'), array_values($this->groups)); 169 $this->_db->setQuery($query); 170 171 // Set the titles for the user groups. 172 $this->groups = $this->_db->loadAssocList('id', 'id'); 173 } 174 175 return $return; 176 } 177 178 /** 179 * Validation and filtering 180 * 181 * @return boolean True if satisfactory 182 * 183 * @since 1.7.0 184 */ 185 public function check() 186 { 187 try { 188 parent::check(); 189 } catch (\Exception $e) { 190 $this->setError($e->getMessage()); 191 192 return false; 193 } 194 195 // Set user id to null instead of 0, if needed 196 if ($this->id === 0) { 197 $this->id = null; 198 } 199 200 $filterInput = InputFilter::getInstance(); 201 202 // Validate user information 203 if ($filterInput->clean($this->name, 'TRIM') == '') { 204 $this->setError(Text::_('JLIB_DATABASE_ERROR_PLEASE_ENTER_YOUR_NAME')); 205 206 return false; 207 } 208 209 if ($filterInput->clean($this->username, 'TRIM') == '') { 210 $this->setError(Text::_('JLIB_DATABASE_ERROR_PLEASE_ENTER_A_USER_NAME')); 211 212 return false; 213 } 214 215 if ( 216 preg_match('#[<>"\'%;()&\\\\]|\\.\\./#', $this->username) || StringHelper::strlen($this->username) < 2 217 || $filterInput->clean($this->username, 'TRIM') !== $this->username || StringHelper::strlen($this->username) > 150 218 ) { 219 $this->setError(Text::sprintf('JLIB_DATABASE_ERROR_VALID_AZ09', 2)); 220 221 return false; 222 } 223 224 if ( 225 ($filterInput->clean($this->email, 'TRIM') == '') || !MailHelper::isEmailAddress($this->email) 226 || StringHelper::strlen($this->email) > 100 227 ) { 228 $this->setError(Text::_('JLIB_DATABASE_ERROR_VALID_MAIL')); 229 230 return false; 231 } 232 233 // Convert email to punycode for storage 234 $this->email = PunycodeHelper::emailToPunycode($this->email); 235 236 // Set the registration timestamp 237 if (empty($this->registerDate)) { 238 $this->registerDate = Factory::getDate()->toSql(); 239 } 240 241 // Set the lastvisitDate timestamp 242 if (empty($this->lastvisitDate)) { 243 $this->lastvisitDate = null; 244 } 245 246 // Set the lastResetTime timestamp 247 if (empty($this->lastResetTime)) { 248 $this->lastResetTime = null; 249 } 250 251 $uid = (int) $this->id; 252 253 // Check for existing username 254 $query = $this->_db->getQuery(true) 255 ->select($this->_db->quoteName('id')) 256 ->from($this->_db->quoteName('#__users')) 257 ->where($this->_db->quoteName('username') . ' = :username') 258 ->where($this->_db->quoteName('id') . ' != :userid') 259 ->bind(':username', $this->username) 260 ->bind(':userid', $uid, ParameterType::INTEGER); 261 $this->_db->setQuery($query); 262 263 $xid = (int) $this->_db->loadResult(); 264 265 if ($xid && $xid != (int) $this->id) { 266 $this->setError(Text::_('JLIB_DATABASE_ERROR_USERNAME_INUSE')); 267 268 return false; 269 } 270 271 // Check for existing email 272 $query->clear() 273 ->select($this->_db->quoteName('id')) 274 ->from($this->_db->quoteName('#__users')) 275 ->where('LOWER(' . $this->_db->quoteName('email') . ') = LOWER(:mail)') 276 ->where($this->_db->quoteName('id') . ' != :muserid') 277 ->bind(':mail', $this->email) 278 ->bind(':muserid', $uid, ParameterType::INTEGER); 279 $this->_db->setQuery($query); 280 $xid = (int) $this->_db->loadResult(); 281 282 if ($xid && $xid != (int) $this->id) { 283 $this->setError(Text::_('JLIB_DATABASE_ERROR_EMAIL_INUSE')); 284 285 return false; 286 } 287 288 // Check for root_user != username 289 $rootUser = Factory::getApplication()->get('root_user'); 290 291 if (!is_numeric($rootUser)) { 292 $query->clear() 293 ->select($this->_db->quoteName('id')) 294 ->from($this->_db->quoteName('#__users')) 295 ->where($this->_db->quoteName('username') . ' = :username') 296 ->bind(':username', $rootUser); 297 $this->_db->setQuery($query); 298 $xid = (int) $this->_db->loadResult(); 299 300 if ( 301 $rootUser == $this->username && (!$xid || $xid && $xid != (int) $this->id) 302 || $xid && $xid == (int) $this->id && $rootUser != $this->username 303 ) { 304 $this->setError(Text::_('JLIB_DATABASE_ERROR_USERNAME_CANNOT_CHANGE')); 305 306 return false; 307 } 308 } 309 310 return true; 311 } 312 313 /** 314 * Method to store a row in the database from the Table instance properties. 315 * 316 * If a primary key value is set the row with that primary key value will be updated with the instance property values. 317 * If no primary key value is set a new row will be inserted into the database with the properties from the Table instance. 318 * 319 * @param boolean $updateNulls True to update fields even if they are null. 320 * 321 * @return boolean True on success. 322 * 323 * @since 1.7.0 324 */ 325 public function store($updateNulls = true) 326 { 327 // Get the table key and key value. 328 $k = $this->_tbl_key; 329 $key = $this->$k; 330 331 // @todo: This is a dumb way to handle the groups. 332 // Store groups locally so as to not update directly. 333 $groups = $this->groups; 334 unset($this->groups); 335 336 // Insert or update the object based on presence of a key value. 337 if ($key) { 338 // Already have a table key, update the row. 339 $this->_db->updateObject($this->_tbl, $this, $this->_tbl_key, $updateNulls); 340 } else { 341 // Don't have a table key, insert the row. 342 $this->_db->insertObject($this->_tbl, $this, $this->_tbl_key); 343 } 344 345 // Reset groups to the local object. 346 $this->groups = $groups; 347 348 $query = $this->_db->getQuery(true); 349 350 // Store the group data if the user data was saved. 351 if (\is_array($this->groups) && \count($this->groups)) { 352 $uid = (int) $this->id; 353 354 // Grab all usergroup entries for the user 355 $query->clear() 356 ->select($this->_db->quoteName('group_id')) 357 ->from($this->_db->quoteName('#__user_usergroup_map')) 358 ->where($this->_db->quoteName('user_id') . ' = :userid') 359 ->bind(':userid', $uid, ParameterType::INTEGER); 360 361 $this->_db->setQuery($query); 362 $result = $this->_db->loadObjectList(); 363 364 // Loop through them and check if database contains something $this->groups does not 365 if (\count($result)) { 366 $mapGroupId = []; 367 368 foreach ($result as $map) { 369 if (\array_key_exists($map->group_id, $this->groups)) { 370 // It already exists, no action required 371 unset($groups[$map->group_id]); 372 } else { 373 $mapGroupId[] = (int) $map->group_id; 374 } 375 } 376 377 if (\count($mapGroupId)) { 378 $query->clear() 379 ->delete($this->_db->quoteName('#__user_usergroup_map')) 380 ->where($this->_db->quoteName('user_id') . ' = :uid') 381 ->whereIn($this->_db->quoteName('group_id'), $mapGroupId) 382 ->bind(':uid', $uid, ParameterType::INTEGER); 383 384 $this->_db->setQuery($query); 385 $this->_db->execute(); 386 } 387 } 388 389 // If there is anything left in this->groups it needs to be inserted 390 if (\count($groups)) { 391 // Set the new user group maps. 392 $query->clear() 393 ->insert($this->_db->quoteName('#__user_usergroup_map')) 394 ->columns([$this->_db->quoteName('user_id'), $this->_db->quoteName('group_id')]); 395 396 foreach ($groups as $group) { 397 $query->values( 398 implode( 399 ',', 400 $query->bindArray( 401 [$this->id , $group], 402 [ParameterType::INTEGER, ParameterType::INTEGER] 403 ) 404 ) 405 ); 406 } 407 408 $this->_db->setQuery($query); 409 $this->_db->execute(); 410 } 411 412 unset($groups); 413 } 414 415 // If a user is blocked, delete the cookie login rows 416 if ($this->block == 1) { 417 $query->clear() 418 ->delete($this->_db->quoteName('#__user_keys')) 419 ->where($this->_db->quoteName('user_id') . ' = :user_id') 420 ->bind(':user_id', $this->username); 421 $this->_db->setQuery($query); 422 $this->_db->execute(); 423 } 424 425 return true; 426 } 427 428 /** 429 * Method to delete a user, user groups, and any other necessary data from the database. 430 * 431 * @param integer $userId An optional user id. 432 * 433 * @return boolean True on success, false on failure. 434 * 435 * @since 1.7.0 436 */ 437 public function delete($userId = null) 438 { 439 // Set the primary key to delete. 440 $k = $this->_tbl_key; 441 442 if ($userId) { 443 $this->$k = (int) $userId; 444 } 445 446 $key = (int) $this->$k; 447 448 // Delete the user. 449 $query = $this->_db->getQuery(true) 450 ->delete($this->_db->quoteName($this->_tbl)) 451 ->where($this->_db->quoteName($this->_tbl_key) . ' = :key') 452 ->bind(':key', $key, ParameterType::INTEGER); 453 $this->_db->setQuery($query); 454 $this->_db->execute(); 455 456 // Delete the user group maps. 457 $query->clear() 458 ->delete($this->_db->quoteName('#__user_usergroup_map')) 459 ->where($this->_db->quoteName('user_id') . ' = :key') 460 ->bind(':key', $key, ParameterType::INTEGER); 461 $this->_db->setQuery($query); 462 $this->_db->execute(); 463 464 /* 465 * Clean Up Related Data. 466 */ 467 468 $query->clear() 469 ->delete($this->_db->quoteName('#__messages_cfg')) 470 ->where($this->_db->quoteName('user_id') . ' = :key') 471 ->bind(':key', $key, ParameterType::INTEGER); 472 $this->_db->setQuery($query); 473 $this->_db->execute(); 474 475 $query->clear() 476 ->delete($this->_db->quoteName('#__messages')) 477 ->where($this->_db->quoteName('user_id_to') . ' = :key') 478 ->bind(':key', $key, ParameterType::INTEGER); 479 $this->_db->setQuery($query); 480 $this->_db->execute(); 481 482 $query->clear() 483 ->delete($this->_db->quoteName('#__user_keys')) 484 ->where($this->_db->quoteName('user_id') . ' = :username') 485 ->bind(':username', $this->username); 486 $this->_db->setQuery($query); 487 $this->_db->execute(); 488 489 return true; 490 } 491 492 /** 493 * Updates last visit time of user 494 * 495 * @param integer $timeStamp The timestamp, defaults to 'now'. 496 * @param integer $userId The user id (optional). 497 * 498 * @return boolean False if an error occurs 499 * 500 * @since 1.7.0 501 */ 502 public function setLastVisit($timeStamp = null, $userId = null) 503 { 504 // Check for User ID 505 if (\is_null($userId)) { 506 if (isset($this)) { 507 $userId = $this->id; 508 } else { 509 jexit('No userid in setLastVisit'); 510 } 511 } 512 513 // If no timestamp value is passed to function, then current time is used. 514 if ($timeStamp === null) { 515 $timeStamp = 'now'; 516 } 517 518 $date = Factory::getDate($timeStamp); 519 $userId = (int) $userId; 520 $lastVisit = $date->toSql(); 521 522 // Update the database row for the user. 523 $db = $this->_db; 524 $query = $db->getQuery(true) 525 ->update($db->quoteName($this->_tbl)) 526 ->set($db->quoteName('lastvisitDate') . ' = :lastvisitDate') 527 ->where($db->quoteName('id') . ' = :id') 528 ->bind(':lastvisitDate', $lastVisit) 529 ->bind(':id', $userId, ParameterType::INTEGER); 530 $db->setQuery($query); 531 $db->execute(); 532 533 return true; 534 } 535 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |