PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/user/user.php

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