PageRenderTime 54ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/user/helper.php

https://github.com/FullService/joomla
PHP | 527 lines | 298 code | 70 blank | 159 comment | 49 complexity | 9592e8f1e37cf5a069783a4684370b47 MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id:helper.php 6961 2007-03-15 16:06:53Z tcp $
  4. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  5. * @license GNU General Public License version 2 or later; see LICENSE.txt
  6. */
  7. // No direct access
  8. defined('JPATH_BASE') or die;
  9. /**
  10. * Authorization helper class, provides static methods to perform various tasks relevant
  11. * to the Joomla user and authorization classes
  12. *
  13. * This class has influences and some method logic from the Horde Auth package
  14. *
  15. * @static
  16. * @package Joomla.Framework
  17. * @subpackage User
  18. * @since 1.5
  19. */
  20. class JUserHelper
  21. {
  22. /**
  23. * Method to add a user to a group.
  24. *
  25. * @param integer $userId The id of the user.
  26. * @param integer $groupId The id of the group.
  27. * @return mixed Boolean true on success, JException on error.
  28. * @since 1.6
  29. */
  30. public static function addUserToGroup($userId, $groupId)
  31. {
  32. // Get the user object.
  33. $user = new JUser((int) $userId);
  34. // Add the user to the group if necessary.
  35. if (!array_key_exists($groupId, $user->groups))
  36. {
  37. // Get the title of the group.
  38. $db = JFactory::getDbo();
  39. $db->setQuery(
  40. 'SELECT `title`' .
  41. ' FROM `#__usergroups`' .
  42. ' WHERE `id` = '. (int) $groupId
  43. );
  44. $title = $db->loadResult();
  45. // Check for a database error.
  46. if ($db->getErrorNum()) {
  47. return new JException($db->getErrorMsg());
  48. }
  49. // If the group does not exist, return an exception.
  50. if (!$title) {
  51. return new JException(JText::_('JLIB_USER_EXCEPTION_ACCESS_USERGROUP_INVALID'));
  52. }
  53. // Add the group data to the user object.
  54. $user->groups[$groupId] = $title;
  55. // Store the user object.
  56. if (!$user->save()) {
  57. return new JException($user->getError());
  58. }
  59. }
  60. // Set the group data for any preloaded user objects.
  61. $temp = JFactory::getUser((int) $userId);
  62. $temp->groups = $user->groups;
  63. // Set the group data for the user object in the session.
  64. $temp = JFactory::getUser();
  65. if ($temp->id == $userId) {
  66. $temp->groups = $user->groups;
  67. }
  68. return true;
  69. }
  70. /**
  71. * Method to get a list of groups a user is in.
  72. *
  73. * @param integer $userId The id of the user.
  74. * @return mixed Array on success, JException on error.
  75. * @since 1.6
  76. */
  77. public static function getUserGroups($userId)
  78. {
  79. // Get the user object.
  80. $user = JUser::getInstance((int) $userId);
  81. return isset($user->groups) ? $user->groups : array();
  82. }
  83. /**
  84. * Method to remove a user from a group.
  85. *
  86. * @param integer $userId The id of the user.
  87. * @param integer $groupId The id of the group.
  88. * @return mixed Boolean true on success, JException on error.
  89. * @since 1.6
  90. */
  91. public static function removeUserFromGroup($userId, $groupId)
  92. {
  93. // Get the user object.
  94. $user = JUser::getInstance((int) $userId);
  95. // Remove the user from the group if necessary.
  96. if (array_key_exists($groupId, $user->groups))
  97. {
  98. // Remove the user from the group.
  99. unset($user->groups[$groupId]);
  100. // Store the user object.
  101. if (!$user->save()) {
  102. return new JException($user->getError());
  103. }
  104. }
  105. // Set the group data for any preloaded user objects.
  106. $temp = JFactory::getUser((int) $userId);
  107. $temp->groups = $user->groups;
  108. // Set the group data for the user object in the session.
  109. $temp = JFactory::getUser();
  110. if ($temp->id == $userId) {
  111. $temp->groups = $user->groups;
  112. }
  113. return true;
  114. }
  115. /**
  116. * Method to set the groups for a user.
  117. *
  118. * @access public
  119. * @param integer $userId The id of the user.
  120. * @param array $groups An array of group ids to put the user in.
  121. * @return mixed Boolean true on success, JException on error.
  122. * @since 1.6
  123. */
  124. public static function setUserGroups($userId, $groups)
  125. {
  126. // Get the user object.
  127. $user = JUser::getInstance((int) $userId);
  128. // Set the group ids.
  129. JArrayHelper::toInteger($groups);
  130. $user->groups = array_fill_keys(array_values($groups), null);
  131. // Get the titles for the user groups.
  132. $db = JFactory::getDbo();
  133. $db->setQuery(
  134. 'SELECT `id`, `title`' .
  135. ' FROM `#__usergroups`' .
  136. ' WHERE `id` = '.implode(' OR `id` = ', array_keys($user->groups))
  137. );
  138. $results = $db->loadObjectList();
  139. // Check for a database error.
  140. if ($db->getErrorNum()) {
  141. return new JException($db->getErrorMsg());
  142. }
  143. // Set the titles for the user groups.
  144. for ($i = 0, $n = count($results); $i < $n; $i++) {
  145. $user->groups[$results[$i]->id] = $results[$i]->title;
  146. }
  147. // Store the user object.
  148. if (!$user->save()) {
  149. return new JException($user->getError());
  150. }
  151. // Set the group data for any preloaded user objects.
  152. $temp = JFactory::getUser((int) $userId);
  153. $temp->groups = $user->groups;
  154. // Set the group data for the user object in the session.
  155. $temp = JFactory::getUser();
  156. if ($temp->id == $userId) {
  157. $temp->groups = $user->groups;
  158. }
  159. return true;
  160. }
  161. /**
  162. * Gets the user profile information
  163. */
  164. function getProfile($userId = 0)
  165. {
  166. if ($userId == 0) {
  167. $user = JFactory::getUser();
  168. $userId = $user->id;
  169. }
  170. else {
  171. $user = JFactory::getUser((int) $userId);
  172. }
  173. // Get the dispatcher and load the users plugins.
  174. $dispatcher = JDispatcher::getInstance();
  175. JPluginHelper::importPlugin('users');
  176. $data = new JObject;
  177. // Trigger the data preparation event.
  178. $results = $dispatcher->trigger('onPrepareUserProfileData', array($userId, &$data));
  179. return $data;
  180. }
  181. /**
  182. * Method to activate a user
  183. *
  184. * @param string $activation Activation string
  185. * @return boolean True on success
  186. * @since 1.5
  187. */
  188. public static function activateUser($activation)
  189. {
  190. // Initialize some variables.
  191. $db = JFactory::getDbo();
  192. // Lets get the id of the user we want to activate
  193. $query = 'SELECT id'
  194. . ' FROM #__users'
  195. . ' WHERE activation = '.$db->Quote($activation)
  196. . ' AND block = 1'
  197. . ' AND lastvisitDate = '.$db->Quote('0000-00-00 00:00:00');
  198. ;
  199. $db->setQuery($query);
  200. $id = intval($db->loadResult());
  201. // Is it a valid user to activate?
  202. if ($id)
  203. {
  204. $user = JUser::getInstance((int) $id);
  205. $user->set('block', '0');
  206. $user->set('activation', '');
  207. // Time to take care of business.... store the user.
  208. if (!$user->save())
  209. {
  210. JError::raiseWarning("SOME_ERROR_CODE", $user->getError());
  211. return false;
  212. }
  213. }
  214. else
  215. {
  216. JError::raiseWarning("SOME_ERROR_CODE", JText::_('JLIB_USER_ERROR_UNABLE_TO_FIND_USER'));
  217. return false;
  218. }
  219. return true;
  220. }
  221. /**
  222. * Returns userid if a user exists
  223. *
  224. * @param string The username to search on
  225. * @return int The user id or 0 if not found
  226. */
  227. public static function getUserId($username)
  228. {
  229. // Initialise some variables
  230. $db = JFactory::getDbo();
  231. $query = 'SELECT id FROM #__users WHERE username = ' . $db->Quote($username);
  232. $db->setQuery($query, 0, 1);
  233. return $db->loadResult();
  234. }
  235. /**
  236. * Formats a password using the current encryption.
  237. *
  238. * @access public
  239. * @param string $plaintext The plaintext password to encrypt.
  240. * @param string $salt The salt to use to encrypt the password. []
  241. * If not present, a new salt will be
  242. * generated.
  243. * @param string $encryption The kind of pasword encryption to use.
  244. * Defaults to md5-hex.
  245. * @param boolean $show_encrypt Some password systems prepend the kind of
  246. * encryption to the crypted password ({SHA},
  247. * etc). Defaults to false.
  248. *
  249. * @return string The encrypted password.
  250. */
  251. public static function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false)
  252. {
  253. // Get the salt to use.
  254. $salt = JUserHelper::getSalt($encryption, $salt, $plaintext);
  255. // Encrypt the password.
  256. switch ($encryption)
  257. {
  258. case 'plain' :
  259. return $plaintext;
  260. case 'sha' :
  261. $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext));
  262. return ($show_encrypt) ? '{SHA}'.$encrypted : $encrypted;
  263. case 'crypt' :
  264. case 'crypt-des' :
  265. case 'crypt-md5' :
  266. case 'crypt-blowfish' :
  267. return ($show_encrypt ? '{crypt}' : '').crypt($plaintext, $salt);
  268. case 'md5-base64' :
  269. $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext));
  270. return ($show_encrypt) ? '{MD5}'.$encrypted : $encrypted;
  271. case 'ssha' :
  272. $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext.$salt).$salt);
  273. return ($show_encrypt) ? '{SSHA}'.$encrypted : $encrypted;
  274. case 'smd5' :
  275. $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext.$salt).$salt);
  276. return ($show_encrypt) ? '{SMD5}'.$encrypted : $encrypted;
  277. case 'aprmd5' :
  278. $length = strlen($plaintext);
  279. $context = $plaintext.'$apr1$'.$salt;
  280. $binary = JUserHelper::_bin(md5($plaintext.$salt.$plaintext));
  281. for ($i = $length; $i > 0; $i -= 16) {
  282. $context .= substr($binary, 0, ($i > 16 ? 16 : $i));
  283. }
  284. for ($i = $length; $i > 0; $i >>= 1) {
  285. $context .= ($i & 1) ? chr(0) : $plaintext[0];
  286. }
  287. $binary = JUserHelper::_bin(md5($context));
  288. for ($i = 0; $i < 1000; $i ++) {
  289. $new = ($i & 1) ? $plaintext : substr($binary, 0, 16);
  290. if ($i % 3) {
  291. $new .= $salt;
  292. }
  293. if ($i % 7) {
  294. $new .= $plaintext;
  295. }
  296. $new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext;
  297. $binary = JUserHelper::_bin(md5($new));
  298. }
  299. $p = array ();
  300. for ($i = 0; $i < 5; $i ++) {
  301. $k = $i +6;
  302. $j = $i +12;
  303. if ($j == 16) {
  304. $j = 5;
  305. }
  306. $p[] = JUserHelper::_toAPRMD5((ord($binary[$i]) << 16) | (ord($binary[$k]) << 8) | (ord($binary[$j])), 5);
  307. }
  308. return '$apr1$'.$salt.'$'.implode('', $p).JUserHelper::_toAPRMD5(ord($binary[11]), 3);
  309. case 'md5-hex' :
  310. default :
  311. $encrypted = ($salt) ? md5($plaintext.$salt) : md5($plaintext);
  312. return ($show_encrypt) ? '{MD5}'.$encrypted : $encrypted;
  313. }
  314. }
  315. /**
  316. * Returns a salt for the appropriate kind of password encryption.
  317. * Optionally takes a seed and a plaintext password, to extract the seed
  318. * of an existing password, or for encryption types that use the plaintext
  319. * in the generation of the salt.
  320. *
  321. * @access public
  322. * @param string $encryption The kind of pasword encryption to use.
  323. * Defaults to md5-hex.
  324. * @param string $seed The seed to get the salt from (probably a
  325. * previously generated password). Defaults to
  326. * generating a new seed.
  327. * @param string $plaintext The plaintext password that we're generating
  328. * a salt for. Defaults to none.
  329. *
  330. * @return string The generated or extracted salt.
  331. */
  332. public static function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '')
  333. {
  334. // Encrypt the password.
  335. switch ($encryption)
  336. {
  337. case 'crypt' :
  338. case 'crypt-des' :
  339. if ($seed) {
  340. return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2);
  341. } else {
  342. return substr(md5(mt_rand()), 0, 2);
  343. }
  344. break;
  345. case 'crypt-md5' :
  346. if ($seed) {
  347. return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12);
  348. } else {
  349. return '$1$'.substr(md5(mt_rand()), 0, 8).'$';
  350. }
  351. break;
  352. case 'crypt-blowfish' :
  353. if ($seed) {
  354. return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 16);
  355. } else {
  356. return '$2$'.substr(md5(mt_rand()), 0, 12).'$';
  357. }
  358. break;
  359. case 'ssha' :
  360. if ($seed) {
  361. return substr(preg_replace('|^{SSHA}|', '', $seed), -20);
  362. } else {
  363. return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  364. }
  365. break;
  366. case 'smd5' :
  367. if ($seed) {
  368. return substr(preg_replace('|^{SMD5}|', '', $seed), -16);
  369. } else {
  370. return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  371. }
  372. break;
  373. case 'aprmd5' :
  374. /* 64 characters that are valid for APRMD5 passwords. */
  375. $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  376. if ($seed) {
  377. return substr(preg_replace('/^\$apr1\$(.{8}).*/', '\\1', $seed), 0, 8);
  378. } else {
  379. $salt = '';
  380. for ($i = 0; $i < 8; $i ++) {
  381. $salt .= $APRMD5 {
  382. rand(0, 63)
  383. };
  384. }
  385. return $salt;
  386. }
  387. break;
  388. default :
  389. $salt = '';
  390. if ($seed) {
  391. $salt = $seed;
  392. }
  393. return $salt;
  394. break;
  395. }
  396. }
  397. /**
  398. * Generate a random password
  399. *
  400. * @static
  401. * @param int $length Length of the password to generate
  402. * @return string Random Password
  403. * @since 1.5
  404. */
  405. public static function genRandomPassword($length = 8)
  406. {
  407. $salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  408. $len = strlen($salt);
  409. $makepass = '';
  410. $stat = @stat(__FILE__);
  411. if (empty($stat) || !is_array($stat)) $stat = array(php_uname());
  412. mt_srand(crc32(microtime() . implode('|', $stat)));
  413. for ($i = 0; $i < $length; $i ++) {
  414. $makepass .= $salt[mt_rand(0, $len -1)];
  415. }
  416. return $makepass;
  417. }
  418. /**
  419. * Converts to allowed 64 characters for APRMD5 passwords.
  420. *
  421. * @access private
  422. * @param string $value
  423. * @param integer $count
  424. * @return string $value converted to the 64 MD5 characters.
  425. * @since 1.5
  426. */
  427. private static function _toAPRMD5($value, $count)
  428. {
  429. /* 64 characters that are valid for APRMD5 passwords. */
  430. $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  431. $aprmd5 = '';
  432. $count = abs($count);
  433. while (-- $count) {
  434. $aprmd5 .= $APRMD5[$value & 0x3f];
  435. $value >>= 6;
  436. }
  437. return $aprmd5;
  438. }
  439. /**
  440. * Converts hexadecimal string to binary data.
  441. *
  442. * @access private
  443. * @param string $hex Hex data.
  444. * @return string Binary data.
  445. * @since 1.5
  446. */
  447. private static function _bin($hex)
  448. {
  449. $bin = '';
  450. $length = strlen($hex);
  451. for ($i = 0; $i < $length; $i += 2) {
  452. $tmp = sscanf(substr($hex, $i, 2), '%x');
  453. $bin .= chr(array_shift($tmp));
  454. }
  455. return $bin;
  456. }
  457. }