[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Table/ -> User.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer