PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/user/user.php

http://github.com/joomla/joomla-platform
PHP | 835 lines | 360 code | 116 blank | 359 comment | 52 complexity | dd44d12520d947c98f749d11c10d9c0b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage User
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * User class. Handles all application interaction with a user
  12. *
  13. * @package Joomla.Platform
  14. * @subpackage User
  15. * @since 11.1
  16. */
  17. class JUser extends JObject
  18. {
  19. /**
  20. * A cached switch for if this user has root access rights.
  21. *
  22. * @var boolean
  23. * @since 11.1
  24. */
  25. protected $isRoot = null;
  26. /**
  27. * Unique id
  28. *
  29. * @var integer
  30. * @since 11.1
  31. */
  32. public $id = null;
  33. /**
  34. * The user's real name (or nickname)
  35. * @var string
  36. * @since 11.1
  37. */
  38. public $name = null;
  39. /**
  40. * The login name
  41. *
  42. * @var string
  43. * @since 11.1
  44. */
  45. public $username = null;
  46. /**
  47. * The email
  48. *
  49. * @var string
  50. * @since 11.1
  51. */
  52. public $email = null;
  53. /**
  54. * MD5 encrypted password
  55. *
  56. * @var string
  57. * @since 11.1
  58. */
  59. public $password = null;
  60. /**
  61. * Clear password, only available when a new password is set for a user
  62. *
  63. * @var string
  64. * @since 11.1
  65. */
  66. public $password_clear = '';
  67. /**
  68. * Block status
  69. *
  70. * @var integer
  71. * @since 11.1
  72. */
  73. public $block = null;
  74. /**
  75. * Should this user receive system email
  76. *
  77. * @var integer
  78. * @since 11.1
  79. */
  80. public $sendEmail = null;
  81. /**
  82. * Date the user was registered
  83. *
  84. * @var datetime
  85. * @since 11.1
  86. */
  87. public $registerDate = null;
  88. /**
  89. * Date of last visit
  90. *
  91. * @var datetime
  92. * @since 11.1
  93. */
  94. public $lastvisitDate = null;
  95. /**
  96. * Activation hash
  97. *
  98. * @var string
  99. * @since 11.1
  100. */
  101. public $activation = null;
  102. /**
  103. * User parameters
  104. *
  105. * @var JRegistry
  106. * @since 11.1
  107. */
  108. public $params = null;
  109. /**
  110. * Associative array of user names => group ids
  111. *
  112. * @var array
  113. * @since 11.1
  114. */
  115. public $groups = array();
  116. /**
  117. * Guest status
  118. *
  119. * @var boolean
  120. * @since 11.1
  121. */
  122. public $guest = null;
  123. /**
  124. * Last Reset Time
  125. *
  126. * @var string
  127. * @since 12.2
  128. */
  129. public $lastResetTime = null;
  130. /**
  131. * Count since last Reset Time
  132. *
  133. * @var int
  134. * @since 12.2
  135. */
  136. public $resetCount = null;
  137. /**
  138. * User parameters
  139. * @var JRegistry
  140. * @since 11.1
  141. */
  142. protected $_params = null;
  143. /**
  144. * Authorised access groups
  145. *
  146. * @var array
  147. * @since 11.1
  148. */
  149. protected $_authGroups = null;
  150. /**
  151. * Authorised access levels
  152. *
  153. * @var array
  154. * @since 11.1
  155. */
  156. protected $_authLevels = null;
  157. /**
  158. * Authorised access actions
  159. *
  160. * @var array
  161. * @since 11.1
  162. */
  163. protected $_authActions = null;
  164. /**
  165. * Error message
  166. *
  167. * @var string
  168. * @since 11.1
  169. */
  170. protected $_errorMsg = null;
  171. /**
  172. * @var array JUser instances container.
  173. * @since 11.3
  174. */
  175. protected static $instances = array();
  176. /**
  177. * Constructor activating the default information of the language
  178. *
  179. * @param integer $identifier The primary key of the user to load (optional).
  180. *
  181. * @since 11.1
  182. */
  183. public function __construct($identifier = 0)
  184. {
  185. // Create the user parameters object
  186. $this->_params = new JRegistry;
  187. // Load the user if it exists
  188. if (!empty($identifier))
  189. {
  190. $this->load($identifier);
  191. }
  192. else
  193. {
  194. // Initialise
  195. $this->id = 0;
  196. $this->sendEmail = 0;
  197. $this->aid = 0;
  198. $this->guest = 1;
  199. }
  200. }
  201. /**
  202. * Returns the global User object, only creating it if it
  203. * doesn't already exist.
  204. *
  205. * @param integer $identifier The user to load - Can be an integer or string - If string, it is converted to ID automatically.
  206. *
  207. * @return JUser The User object.
  208. *
  209. * @since 11.1
  210. */
  211. public static function getInstance($identifier = 0)
  212. {
  213. // Find the user id
  214. if (!is_numeric($identifier))
  215. {
  216. if (!$id = JUserHelper::getUserId($identifier))
  217. {
  218. JLog::add(JText::sprintf('JLIB_USER_ERROR_ID_NOT_EXISTS', $identifier), JLog::WARNING, 'jerror');
  219. $retval = false;
  220. return $retval;
  221. }
  222. }
  223. else
  224. {
  225. $id = $identifier;
  226. }
  227. // If the $id is zero, just return an empty JUser.
  228. // Note: don't cache this user because it'll have a new ID on save!
  229. if ($id === 0)
  230. {
  231. return new JUser;
  232. }
  233. // Check if the user ID is already cached.
  234. if (empty(self::$instances[$id]))
  235. {
  236. $user = new JUser($id);
  237. self::$instances[$id] = $user;
  238. }
  239. return self::$instances[$id];
  240. }
  241. /**
  242. * Method to get a parameter value
  243. *
  244. * @param string $key Parameter key
  245. * @param mixed $default Parameter default value
  246. *
  247. * @return mixed The value or the default if it did not exist
  248. *
  249. * @since 11.1
  250. */
  251. public function getParam($key, $default = null)
  252. {
  253. return $this->_params->get($key, $default);
  254. }
  255. /**
  256. * Method to set a parameter
  257. *
  258. * @param string $key Parameter key
  259. * @param mixed $value Parameter value
  260. *
  261. * @return mixed Set parameter value
  262. *
  263. * @since 11.1
  264. */
  265. public function setParam($key, $value)
  266. {
  267. return $this->_params->set($key, $value);
  268. }
  269. /**
  270. * Method to set a default parameter if it does not exist
  271. *
  272. * @param string $key Parameter key
  273. * @param mixed $value Parameter value
  274. *
  275. * @return mixed Set parameter value
  276. *
  277. * @since 11.1
  278. */
  279. public function defParam($key, $value)
  280. {
  281. return $this->_params->def($key, $value);
  282. }
  283. /**
  284. * Method to check JUser object authorisation against an access control
  285. * object and optionally an access extension object
  286. *
  287. * @param string $action The name of the action to check for permission.
  288. * @param string $assetname The name of the asset on which to perform the action.
  289. *
  290. * @return boolean True if authorised
  291. *
  292. * @since 11.1
  293. */
  294. public function authorise($action, $assetname = null)
  295. {
  296. // Make sure we only check for core.admin once during the run.
  297. if ($this->isRoot === null)
  298. {
  299. $this->isRoot = false;
  300. // Check for the configuration file failsafe.
  301. $config = JFactory::getConfig();
  302. $rootUser = $config->get('root_user');
  303. // The root_user variable can be a numeric user ID or a username.
  304. if (is_numeric($rootUser) && $this->id > 0 && $this->id == $rootUser)
  305. {
  306. $this->isRoot = true;
  307. }
  308. elseif ($this->username && $this->username == $rootUser)
  309. {
  310. $this->isRoot = true;
  311. }
  312. else
  313. {
  314. // Get all groups against which the user is mapped.
  315. $identities = $this->getAuthorisedGroups();
  316. array_unshift($identities, $this->id * -1);
  317. if (JAccess::getAssetRules(1)->allow('core.admin', $identities))
  318. {
  319. $this->isRoot = true;
  320. return true;
  321. }
  322. }
  323. }
  324. return $this->isRoot ? true : JAccess::check($this->id, $action, $assetname);
  325. }
  326. /**
  327. * Method to return a list of all categories that a user has permission for a given action
  328. *
  329. * @param string $component The component from which to retrieve the categories
  330. * @param string $action The name of the section within the component from which to retrieve the actions.
  331. *
  332. * @return array List of categories that this group can do this action to (empty array if none). Categories must be published.
  333. *
  334. * @since 11.1
  335. */
  336. public function getAuthorisedCategories($component, $action)
  337. {
  338. // Brute force method: get all published category rows for the component and check each one
  339. // TODO: Modify the way permissions are stored in the db to allow for faster implementation and better scaling
  340. $db = JFactory::getDbo();
  341. $query = $db->getQuery(true)->select('c.id AS id, a.name AS asset_name')->from('#__categories AS c')
  342. ->innerJoin('#__assets AS a ON c.asset_id = a.id')->where('c.extension = ' . $db->quote($component))->where('c.published = 1');
  343. $db->setQuery($query);
  344. $allCategories = $db->loadObjectList('id');
  345. $allowedCategories = array();
  346. foreach ($allCategories as $category)
  347. {
  348. if ($this->authorise($action, $category->asset_name))
  349. {
  350. $allowedCategories[] = (int) $category->id;
  351. }
  352. }
  353. return $allowedCategories;
  354. }
  355. /**
  356. * Gets an array of the authorised access levels for the user
  357. *
  358. * @return array
  359. *
  360. * @since 11.1
  361. */
  362. public function getAuthorisedViewLevels()
  363. {
  364. if ($this->_authLevels === null)
  365. {
  366. $this->_authLevels = array();
  367. }
  368. if (empty($this->_authLevels))
  369. {
  370. $this->_authLevels = JAccess::getAuthorisedViewLevels($this->id);
  371. }
  372. return $this->_authLevels;
  373. }
  374. /**
  375. * Gets an array of the authorised user groups
  376. *
  377. * @return array
  378. *
  379. * @since 11.1
  380. */
  381. public function getAuthorisedGroups()
  382. {
  383. if ($this->_authGroups === null)
  384. {
  385. $this->_authGroups = array();
  386. }
  387. if (empty($this->_authGroups))
  388. {
  389. $this->_authGroups = JAccess::getGroupsByUser($this->id);
  390. }
  391. return $this->_authGroups;
  392. }
  393. /**
  394. * Pass through method to the table for setting the last visit date
  395. *
  396. * @param integer $timestamp The timestamp, defaults to 'now'.
  397. *
  398. * @return boolean True on success.
  399. *
  400. * @since 11.1
  401. */
  402. public function setLastVisit($timestamp = null)
  403. {
  404. // Create the user table object
  405. $table = $this->getTable();
  406. $table->load($this->id);
  407. return $table->setLastVisit($timestamp);
  408. }
  409. /**
  410. * Method to get the user parameters
  411. *
  412. * @param object $params The user parameters object
  413. *
  414. * @return void
  415. *
  416. * @since 11.1
  417. */
  418. public function setParameters($params)
  419. {
  420. $this->_params = $params;
  421. }
  422. /**
  423. * Method to get the user table object
  424. *
  425. * This function uses a static variable to store the table name of the user table to
  426. * instantiate. You can call this function statically to set the table name if
  427. * needed.
  428. *
  429. * @param string $type The user table name to be used
  430. * @param string $prefix The user table prefix to be used
  431. *
  432. * @return object The user table object
  433. *
  434. * @since 11.1
  435. */
  436. public static function getTable($type = null, $prefix = 'JTable')
  437. {
  438. static $tabletype;
  439. // Set the default tabletype;
  440. if (!isset($tabletype))
  441. {
  442. $tabletype['name'] = 'user';
  443. $tabletype['prefix'] = 'JTable';
  444. }
  445. // Set a custom table type is defined
  446. if (isset($type))
  447. {
  448. $tabletype['name'] = $type;
  449. $tabletype['prefix'] = $prefix;
  450. }
  451. // Create the user table object
  452. return JTable::getInstance($tabletype['name'], $tabletype['prefix']);
  453. }
  454. /**
  455. * Method to bind an associative array of data to a user object
  456. *
  457. * @param array &$array The associative array to bind to the object
  458. *
  459. * @return boolean True on success
  460. *
  461. * @since 11.1
  462. */
  463. public function bind(&$array)
  464. {
  465. // Let's check to see if the user is new or not
  466. if (empty($this->id))
  467. {
  468. // Check the password and create the crypted password
  469. if (empty($array['password']))
  470. {
  471. $array['password'] = JUserHelper::genRandomPassword();
  472. $array['password2'] = $array['password'];
  473. }
  474. // Not all controllers check the password, although they should.
  475. // Hence this code is required:
  476. if (isset($array['password2']) && $array['password'] != $array['password2'])
  477. {
  478. $this->setError(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'));
  479. return false;
  480. }
  481. $this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');
  482. $salt = JUserHelper::genRandomPassword(32);
  483. $crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
  484. $array['password'] = $crypt . ':' . $salt;
  485. // Set the registration timestamp
  486. $this->set('registerDate', JFactory::getDate()->toSql());
  487. }
  488. else
  489. {
  490. // Updating an existing user
  491. if (!empty($array['password']))
  492. {
  493. if ($array['password'] != $array['password2'])
  494. {
  495. $this->setError(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'));
  496. return false;
  497. }
  498. $this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');
  499. $salt = JUserHelper::genRandomPassword(32);
  500. $crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
  501. $array['password'] = $crypt . ':' . $salt;
  502. }
  503. else
  504. {
  505. $array['password'] = $this->password;
  506. }
  507. }
  508. if (array_key_exists('params', $array))
  509. {
  510. $params = '';
  511. $this->_params->loadArray($array['params']);
  512. if (is_array($array['params']))
  513. {
  514. $params = (string) $this->_params;
  515. }
  516. else
  517. {
  518. $params = $array['params'];
  519. }
  520. $this->params = $params;
  521. }
  522. // Bind the array
  523. if (!$this->setProperties($array))
  524. {
  525. $this->setError(JText::_('JLIB_USER_ERROR_BIND_ARRAY'));
  526. return false;
  527. }
  528. // Check that username is not greater than 150 characters
  529. $username = $this->get('username');
  530. if (strlen($username) > 150)
  531. {
  532. $username = substr($username, 0, 150);
  533. $this->set('username', $username);
  534. }
  535. // Check that password is not greater than 100 characters
  536. $password = $this->get('password');
  537. if (strlen($password) > 100)
  538. {
  539. $password = substr($password, 0, 100);
  540. $this->set('password', $password);
  541. }
  542. // Make sure its an integer
  543. $this->id = (int) $this->id;
  544. return true;
  545. }
  546. /**
  547. * Method to save the JUser object to the database
  548. *
  549. * @param boolean $updateOnly Save the object only if not a new user
  550. * Currently only used in the user reset password method.
  551. *
  552. * @return boolean True on success
  553. *
  554. * @since 11.1
  555. * @throws RuntimeException
  556. */
  557. public function save($updateOnly = false)
  558. {
  559. // Create the user table object
  560. $table = $this->getTable();
  561. $this->params = (string) $this->_params;
  562. $table->bind($this->getProperties());
  563. // Allow an exception to be thrown.
  564. try
  565. {
  566. // Check and store the object.
  567. if (!$table->check())
  568. {
  569. $this->setError($table->getError());
  570. return false;
  571. }
  572. // If user is made a Super Admin group and user is NOT a Super Admin
  573. // @todo ACL - this needs to be acl checked
  574. $my = JFactory::getUser();
  575. // Are we creating a new user
  576. $isNew = empty($this->id);
  577. // If we aren't allowed to create new users return
  578. if ($isNew && $updateOnly)
  579. {
  580. return true;
  581. }
  582. // Get the old user
  583. $oldUser = new JUser($this->id);
  584. // Access Checks
  585. // The only mandatory check is that only Super Admins can operate on other Super Admin accounts.
  586. // To add additional business rules, use a user plugin and throw an Exception with onUserBeforeSave.
  587. // Check if I am a Super Admin
  588. $iAmSuperAdmin = $my->authorise('core.admin');
  589. // We are only worried about edits to this account if I am not a Super Admin.
  590. if ($iAmSuperAdmin != true)
  591. {
  592. if ($isNew)
  593. {
  594. // Check if the new user is being put into a Super Admin group.
  595. foreach ($this->groups as $groupId)
  596. {
  597. if (JAccess::checkGroup($groupId, 'core.admin'))
  598. {
  599. throw new RuntimeException('User not Super Administrator');
  600. }
  601. }
  602. }
  603. else
  604. {
  605. // I am not a Super Admin, and this one is, so fail.
  606. if (JAccess::check($this->id, 'core.admin'))
  607. {
  608. throw new RuntimeException('User not Super Administrator');
  609. }
  610. if ($this->groups != null)
  611. {
  612. // I am not a Super Admin and I'm trying to make one.
  613. foreach ($this->groups as $groupId)
  614. {
  615. if (JAccess::checkGroup($groupId, 'core.admin'))
  616. {
  617. throw new RuntimeException('User not Super Administrator');
  618. }
  619. }
  620. }
  621. }
  622. }
  623. // Fire the onUserBeforeSave event.
  624. JPluginHelper::importPlugin('user');
  625. $dispatcher = JEventDispatcher::getInstance();
  626. $result = $dispatcher->trigger('onUserBeforeSave', array($oldUser->getProperties(), $isNew, $this->getProperties()));
  627. if (in_array(false, $result, true))
  628. {
  629. // Plugin will have to raise its own error or throw an exception.
  630. return false;
  631. }
  632. // Store the user data in the database
  633. $result = $table->store();
  634. // Set the id for the JUser object in case we created a new user.
  635. if (empty($this->id))
  636. {
  637. $this->id = $table->get('id');
  638. }
  639. if ($my->id == $table->id)
  640. {
  641. $registry = new JRegistry;
  642. $registry->loadString($table->params);
  643. $my->setParameters($registry);
  644. }
  645. // Fire the onUserAfterSave event
  646. $dispatcher->trigger('onUserAfterSave', array($this->getProperties(), $isNew, $result, $this->getError()));
  647. }
  648. catch (Exception $e)
  649. {
  650. $this->setError($e->getMessage());
  651. return false;
  652. }
  653. return $result;
  654. }
  655. /**
  656. * Method to delete the JUser object from the database
  657. *
  658. * @return boolean True on success
  659. *
  660. * @since 11.1
  661. */
  662. public function delete()
  663. {
  664. JPluginHelper::importPlugin('user');
  665. // Trigger the onUserBeforeDelete event
  666. $dispatcher = JEventDispatcher::getInstance();
  667. $dispatcher->trigger('onUserBeforeDelete', array($this->getProperties()));
  668. // Create the user table object
  669. $table = $this->getTable();
  670. $result = false;
  671. if (!$result = $table->delete($this->id))
  672. {
  673. $this->setError($table->getError());
  674. }
  675. // Trigger the onUserAfterDelete event
  676. $dispatcher->trigger('onUserAfterDelete', array($this->getProperties(), $result, $this->getError()));
  677. return $result;
  678. }
  679. /**
  680. * Method to load a JUser object by user id number
  681. *
  682. * @param mixed $id The user id of the user to load
  683. *
  684. * @return boolean True on success
  685. *
  686. * @since 11.1
  687. */
  688. public function load($id)
  689. {
  690. // Create the user table object
  691. $table = $this->getTable();
  692. // Load the JUserModel object based on the user id or throw a warning.
  693. if (!$table->load($id))
  694. {
  695. // Reset to guest user
  696. $this->guest = 1;
  697. JLog::add(JText::sprintf('JLIB_USER_ERROR_UNABLE_TO_LOAD_USER', $id), JLog::WARNING, 'jerror');
  698. return false;
  699. }
  700. /*
  701. * Set the user parameters using the default XML file. We might want to
  702. * extend this in the future to allow for the ability to have custom
  703. * user parameters, but for right now we'll leave it how it is.
  704. */
  705. $this->_params->loadString($table->params);
  706. // Assuming all is well at this point let's bind the data
  707. $this->setProperties($table->getProperties());
  708. // The user is no longer a guest
  709. if ($this->id != 0)
  710. {
  711. $this->guest = 0;
  712. }
  713. else
  714. {
  715. $this->guest = 1;
  716. }
  717. return true;
  718. }
  719. }