PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/smdoc/lib/class.user.php

#
PHP | 1190 lines | 678 code | 153 blank | 359 comment | 125 complexity | b8a59d04d59732979987b2e90fb6c7f1 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. <?php
  2. /*
  3. * Copyright (c) 2003-2004 The SquirrelMail Project Team
  4. * Licensed under the GNU GPL. For full terms see the file COPYING.
  5. *
  6. * This file is an addition/modification to the
  7. * Framework for Object Orientated Web Development (Foowd).
  8. *
  9. * $Id: class.user.php 8975 2005-03-09 19:56:14Z ebullient $
  10. */
  11. /**
  12. * Permission and constant definitions for the smdoc extended user class.
  13. *
  14. * @package smdoc
  15. * @subpackage user
  16. */
  17. /**
  18. * Set constants and meta information for the user class
  19. */
  20. setClassMeta('base_user', 'Base User');
  21. setConst('USER_CLASS_ID', META_BASE_USER_CLASS_ID);
  22. setConst('USER_CLASS_NAME', 'base_user');
  23. /**
  24. * @global array $USER_SOURCE
  25. */
  26. global $USER_SOURCE;
  27. $USER_SOURCE = array('table' => 'smdoc_user',
  28. 'table_create' => array(getClassname(USER_CLASS_ID),'makeTable'));
  29. setPermission('base_user', 'class','login', 'Everybody');
  30. setPermission('base_user', 'class','logout','Registered');
  31. setPermission('base_user', 'class','create','Everybody');
  32. setPermission('base_user', 'class','list', 'Everybody');
  33. setPermission('base_user', 'object', 'groups', 'Gods');
  34. setPermission('base_user', 'object', 'update', 'Author');
  35. setPermission('base_user', 'object', 'clone', 'Nobody');
  36. setPermission('base_user', 'object', 'admin', 'Nobody');
  37. setPermission('base_user', 'object', 'xml', 'Nobody');
  38. setPermission('base_user', 'object', 'permissions', 'Nobody');
  39. setPermission('base_user', 'object', 'history', 'Nobody');
  40. include_once(SM_DIR . 'class.anonuser.php');
  41. /**
  42. * The smdoc extended user class.
  43. *
  44. * Class for holding information about a user and providing methods for
  45. * manipulating and getting information on a user.
  46. *
  47. * This class is loosely based on the base user class in the Foowd
  48. * framework - but highly customized for smdoc (session-based auth).
  49. * The elements in smdoc.class.user.php are additional smdoc-specific
  50. * user attributes/etc.
  51. *
  52. * @author Paul James
  53. * @author Erin Schnabel
  54. * @package smdoc
  55. * @subpackage user
  56. */
  57. class base_user extends foowd_object
  58. {
  59. /**
  60. * Fetch User
  61. *
  62. * @param smdoc $foowd Reference to the foowd environment object.
  63. * @return retrieved foowd user or anonymous user instance
  64. */
  65. function &factory(&$foowd)
  66. {
  67. $foowd->track('base_user::factory');
  68. $user_info = array();
  69. $new_user = NULL;
  70. $user_info = base_user::getUserDetails($foowd);
  71. if ( isset($user_info['username']) )
  72. $new_user =& base_user::fetchUser($foowd, $user_info);
  73. // If loading the user is unsuccessful (or unattempted),
  74. // fetch an anonymous user
  75. if ( $new_user == NULL )
  76. $new_user =& base_user::fetchAnonymousUser($foowd);
  77. $foowd->track();
  78. return $new_user;
  79. }
  80. /**
  81. * Create Anonymous Foowd User
  82. *
  83. * @param smdoc $foowd Reference to the foowd environment object.
  84. * @return new instance of anonymous user class.
  85. */
  86. function &fetchAnonymousUser(&$foowd)
  87. {
  88. $anonUserClass = getConstOrDefault('ANONYMOUS_USER_CLASS', 'foowd_anonuser');
  89. if (class_exists($anonUserClass))
  90. return new $anonUserClass($foowd);
  91. else
  92. trigger_error('Could not find anonymous user class.', E_USER_ERROR);
  93. }
  94. /**
  95. * Fetch Foowd User
  96. *
  97. * @global array Specifies table information for user persistance.
  98. * @param smdoc $foowd Reference to the foowd environment object.
  99. * @param mixed userArray Array containing user information (userid, password).
  100. * @return retrieved foowd user or FALSE on failure.
  101. */
  102. function &fetchUser(&$foowd, $userArray = NULL)
  103. {
  104. global $USER_SOURCE;
  105. $foowd->track('base_user::fetchUser', $userArray);
  106. if ( isset($userArray['objectid']) )
  107. $where['objectid'] = $userArray['objectid'];
  108. elseif ( isset($userArray['username']) )
  109. $where['title'] = $userArray['username'];
  110. else
  111. return FALSE;
  112. $user =& $foowd->getObj($where, $USER_SOURCE, NULL, FALSE, FALSE);
  113. $foowd->track();
  114. return $user;
  115. }
  116. /**
  117. * Get user details from an external mechanism.
  118. *
  119. * If not already set, populate the user array with the user classid and
  120. * fetch the username and password of the current user from one of the input
  121. * mechanisms
  122. *
  123. * @param smdoc $foowd Reference to the foowd environment object.
  124. * @return array The resulting user array.
  125. */
  126. function getUserDetails(&$foowd)
  127. {
  128. $session_userinfo = new input_session('userinfo', NULL, NULL, TRUE);
  129. if ( !$session_userinfo->wasSet ||
  130. $session_userinfo->value == NULL )
  131. return FALSE;
  132. $user_info = $session_userinfo->value;
  133. $user = array();
  134. $user['username'] = $user_info['username'];
  135. $user['password'] = $user_info['password'];
  136. if ( isset($user_info['objectid']) )
  137. $user['objectid'] = $user_info['objectid'];
  138. return $user;
  139. }
  140. /**
  141. * Make a Foowd database table.
  142. *
  143. * When a database query fails due to a non-existant database table, this
  144. * method is envoked to create the missing table and execute the SQL
  145. * statement again.
  146. *
  147. * @global array Specifies table information for user persistance.
  148. * @param smdoc $foowd Reference to the foowd environment object.
  149. * @param string SQLString The original SQL string that failed to execute due to missing database table.
  150. * @return mixed The resulting database query resource or FALSE on failure.
  151. */
  152. function makeTable(&$foowd)
  153. {
  154. global $USER_SOURCE;
  155. $foowd->track('base_user->makeTable');
  156. $sql = 'CREATE TABLE `'.$USER_SOURCE['table'].'` (
  157. `objectid` int(11) NOT NULL default \'0\',
  158. `title` varchar(32) NOT NULL default \'\',
  159. `object` longblob,
  160. `updated` datetime NOT NULL default \'0000-00-00 00:00:00\',
  161. PRIMARY KEY (`objectid`),
  162. KEY `idxuser_updated` (`updated`),
  163. KEY `idxuser_title` (`title`)
  164. );';
  165. $result = $foowd->database->query($sql);
  166. $foowd->track();
  167. return $result;
  168. }
  169. /**
  170. * The users password.
  171. *
  172. * Stored as an MD5 hash to prevent snooping.
  173. *
  174. * @var string
  175. */
  176. var $password;
  177. /**
  178. * The users e-mail address.
  179. *
  180. * @var string
  181. */
  182. var $email;
  183. /**
  184. * The user groups the user is a member of.
  185. *
  186. * @var array
  187. */
  188. var $groups;
  189. /**
  190. * Constructs a new user.
  191. *
  192. * @global array Specifies table information for user persistance.
  193. * @param smdoc $foowd Reference to the foowd environment object.
  194. * @param string username The users name.
  195. * @param string password An MD5 hash of the users password.
  196. * @param string email The users e-mail address.
  197. * @param array groups The user groups the user belongs to.
  198. * @param string hostmask The users hostmask.
  199. */
  200. function base_user( &$foowd,
  201. $username = NULL,
  202. $password = NULL,
  203. $email = NULL,
  204. $objectid = NULL)
  205. {
  206. global $USER_SOURCE;
  207. $foowd->track('base_user->constructor');
  208. $this->foowd =& $foowd;
  209. // Don't use workspace id when looking for unique title
  210. if ( $objectid == NULL &&
  211. !$this->isTitleUnique($username, FALSE, $objectid, $USER_SOURCE) )
  212. {
  213. $this->objectid = 0;
  214. $foowd->track();
  215. return FALSE;
  216. }
  217. // init meta arrays
  218. $this->__wakeup();
  219. // Initialize variables
  220. $this->title = $username;
  221. $this->objectid = $objectid;
  222. $this->workspaceid = 0;
  223. $this->classid = USER_CLASS_ID;
  224. $this->creatorid = $this->objectid; // created by self
  225. $this->creatorName = $this->title; // created by self
  226. $this->created = time();
  227. $this->updatorid = $this->objectid; // updated by self
  228. $this->updatorName = $this->title; // updated by self
  229. $this->updated = time();
  230. $this->groups = array();
  231. $salt = $foowd->config_settings['user']['password_salt'];
  232. $this->password = md5($salt.$password);
  233. $this->email = $email;
  234. // set original access vars
  235. $this->foowd_original_access_vars['title'] = $this->title;
  236. $this->foowd_original_access_vars['objectid'] = $this->objectid;
  237. $this->foowd_original_access_vars['workspaceid'] = $this->workspaceid;
  238. // add to loaded object reference list
  239. $foowd->database->addToLoadedReference($this, $USER_SOURCE);
  240. // object created successfuly, queue for saving
  241. $this->foowd_changed = TRUE;
  242. $foowd->track();
  243. }
  244. /**
  245. * Serliaisation sleep method.
  246. * This is a VERY simple class.
  247. * Only include the objectid and title fields.
  248. *
  249. * @access private
  250. * @return array Array of the names of the member variables to keep when serialising.
  251. */
  252. function __sleep()
  253. {
  254. $returnArray = parent::__sleep();
  255. foreach ( $returnArray as $key => $value )
  256. {
  257. if ( $value == 'permissions' ||
  258. $value == 'version' ||
  259. $value == 'classid' )
  260. unset($returnArray[$key]);
  261. }
  262. return array_values($returnArray);
  263. }
  264. /**
  265. * Serialisation wakeup method.
  266. * @global array Specifies table information for user persistance.
  267. */
  268. function __wakeup()
  269. {
  270. parent::__wakeup();
  271. global $USER_SOURCE;
  272. $this->foowd_source = $USER_SOURCE;
  273. // add some regex verification
  274. unset($this->foowd_vars_meta['version']);
  275. $this->foowd_vars_meta['password'] = '/^[a-z0-9]{32}$/'; // this is not set to the password regex as it's stored as an md5
  276. $this->foowd_vars_meta['email'] = REGEX_EMAIL;
  277. $this->foowd_vars_meta['groups'] = REGEX_GROUP;
  278. $this->foowd_vars_meta['title'] = REGEX_TITLE;
  279. // re-arrange our indices
  280. unset($this->foowd_indexes['version']);
  281. unset($this->foowd_indexes['classid']);
  282. unset($this->foowd_indexes['workspaceid']);
  283. unset($this->foowd_indexes['permissions']);
  284. // Original access vars
  285. unset($this->foowd_original_access_vars['version']);
  286. $this->foowd_original_access_vars['classid'] = USER_CLASS_ID;
  287. $this->foowd_original_access_vars['title'] = $this->title;
  288. // Default primary key
  289. $this->foowd_primary_key = array('objectid');
  290. $this->permissions = array();
  291. $this->version = 1;
  292. $this->classid = USER_CLASS_ID;
  293. }
  294. /**
  295. * Whether a user is in a user group.
  296. *
  297. * @param string groupName Name of the group to check.
  298. * @param int creatorid The userid of the creator .
  299. * @return bool TRUE or FALSE.
  300. */
  301. function inGroup($groupName, $creatorid = NULL)
  302. {
  303. if ($groupName == 'Everybody') // group is everyone
  304. return TRUE;
  305. if ($groupName == 'Nobody') // group is nobody
  306. return FALSE;
  307. if ($groupName == 'Registered' ) // group is any registered user (not anonymous)
  308. return TRUE;
  309. if ( $groupName == 'Author' &&
  310. $creatorid != NULL && $this->objectid != NULL &&
  311. $this->objectid == $creatorid) // group is author and so is user
  312. return TRUE;
  313. if ( is_array($this->groups) )
  314. {
  315. if ( in_array($groupName, $this->groups) ) // user is in group
  316. return TRUE;
  317. if ( in_array('Gods', $this->groups) )
  318. return TRUE;
  319. }
  320. return FALSE;
  321. }
  322. /**
  323. * Check the string is the users password.
  324. *
  325. * @param string password The password to check.
  326. * @param bool plainText The password is in plain text rather than an md5 hash.
  327. * @return bool Returns TRUE if the passwords match.
  328. */
  329. function passwordCheck($password, $plainText = FALSE)
  330. {
  331. if ($plainText)
  332. {
  333. $salt = $this->foowd->config_settings['user']['password_salt'];
  334. $password = md5($salt.$password);
  335. }
  336. if ( $this->password === $password )
  337. return TRUE;
  338. return FALSE;
  339. }
  340. /**
  341. * Check if the user is the anonymous user.
  342. *
  343. * @return bool Returns TRUE if the user is of the anonymous user class.
  344. */
  345. function isAnonymous()
  346. {
  347. return FALSE;
  348. }
  349. /**
  350. * Log the user in.
  351. *
  352. * @static
  353. * @param smdoc $foowd Reference to the foowd environment object.
  354. * @param string username The username of the user to log in as.
  355. * @param string password The plain text password of the user to log in with.
  356. * @return int 0 = logged in successfully<br />
  357. * 1 = no user given<br />
  358. * 2 = unknown user<br />
  359. * 3 = bad password<br />
  360. * 4 = unknown authentication method<br />
  361. * 5 = user already logged in<br />
  362. * 6 = did not http auth correctly<br />
  363. * 7 = must have cookies enabled<br />
  364. * 8 = bad hostmask<br />
  365. */
  366. function login(&$foowd, $username = FALSE, $password = NULL)
  367. {
  368. if ( !$foowd->user->isAnonymous() )
  369. return 5; // user already logged in
  370. if ( !$username )
  371. return 1; // no user given
  372. $user_info['username'] = $username;
  373. $newuser =& base_user::fetchUser($foowd, $user_info);
  374. if ( !is_object($newuser) ||
  375. strtolower($newuser->title) != strtolower($username))
  376. return 2; // unknown user
  377. $salt = $foowd->config_settings['user']['password_salt'];
  378. if ( $newuser->password != md5($salt.$password) )
  379. return 3; // bad password
  380. $user_info['password'] = md5($salt.$password);
  381. $user_info['objectid'] = $newuser->objectid;
  382. // save user information
  383. $foowd->user = $newuser;
  384. $foowd->user->update();
  385. $session_userinfo = new input_session('userinfo', NULL, NULL, TRUE);
  386. $session_userinfo->set($user_info);
  387. return 0; // logged in successfully
  388. }
  389. /**
  390. * Log out the user.
  391. *
  392. * @static
  393. * @param smdoc $foowd Reference to the foowd environment object.
  394. * @param string authType The type of user authentication to use.
  395. * @return int 0 = cookie logged out successfully<br />
  396. * 1 = http logged out successfully<br />
  397. * 2 = ip auth, can not log out<br />
  398. * 3 = user already logged out<br />
  399. * 4 = http log out failed due to browser<br />
  400. */
  401. function logout(&$foowd)
  402. {
  403. if ( $foowd->user->isAnonymous() )
  404. return 3; // user already logged out
  405. $foowd->user = base_user::fetchAnonymousUser($foowd);
  406. $session_userinfo = new input_session('userinfo', NULL, NULL, true);
  407. $session_userinfo->set(NULL);
  408. return 0; // logged out successfully
  409. }
  410. /**
  411. * Create a new user.
  412. *
  413. * @static
  414. * @global array Specifies table information for user persistance.
  415. * @param smdoc $foowd Reference to the foowd environment object.
  416. * @param string username The name of the user to create.
  417. * @param string password The password of the user.
  418. * @param string email The e-mail address of the user.
  419. * @return int 0 = created ok<br />
  420. * 1 = created ok, ip auth so you can't log in<br />
  421. * 2 = need cookie, support not found<br />
  422. * 3 = eek, error creating user<br />
  423. * 4 = duplicate user name<br />
  424. */
  425. function create(&$foowd, $username, $password, $email)
  426. {
  427. global $USER_SOURCE;
  428. // no workspaceid, calculate new objectid.
  429. if ( !$foowd->database->isTitleUnique($username, FALSE, $objectid, $USER_SOURCE, TRUE) )
  430. return 4;
  431. $class = USER_CLASS_NAME;
  432. $object = new $class($foowd, $username, $password, $email, $objectid);
  433. if ( $object->objectid != 0 && $object->save() )
  434. return 0; // created ok
  435. return 3; // eek, error creating user.
  436. }
  437. /**
  438. * Get user a new password if it has been lost.
  439. *
  440. * @access private
  441. * @static
  442. * @param smdoc $foowd Reference to the foowd environment object.
  443. * @param string username The name of the user to fetch the password for.
  444. * @param string queryUsername Username given for stage 2 of the retrieval process.
  445. * @param string id The ID given for stage 2 of the process.
  446. * @return int 0 = nothing, display form<br />
  447. * 1 = password change request e-mail sent<br />
  448. * 2 = could not send e-mail due to technical problem<br />
  449. * 3 = user has no e-mail address<br />
  450. * 4 = user does not exist<br />
  451. * 5 = password changed and e-mail sent<br />
  452. * 6 = could not send e-mail due to technical problem<br />
  453. * 7 = id does not match<br />
  454. * 8 = user does not exist<br />
  455. */
  456. function fetchPassword(&$foowd, $username, $queryUsername = NULL, $id = NULL)
  457. {
  458. if ( $username == '' )
  459. return 0; // nothing, display form
  460. $user_info['username'] = $username;
  461. $lostuser =& base_user::fetchUser($foowd, $user_info);
  462. if ( !$lostuser || !isset($lostuser->title) ||
  463. strtolower($lostuser->title) != strtolower($username) )
  464. return 4; // user does not exist
  465. if ( !isset($lostuser->email) )
  466. return 3; // user has no e-mail address
  467. $site = $foowd->config_settings['site']['site_name'];
  468. // We have username only, send stage one email
  469. if ( $id == NULL && $queryUsername == NULL )
  470. {
  471. $foowd->template->assign('sitename', $site);
  472. $foowd->template->assign('username', $lostuser->title);
  473. $foowd->template->assign('hostname', $_SERVER['SERVER_NAME']);
  474. $foowd->template->assign('class', 'base_user');
  475. $foowd->template->assign('id', md5($user->updated.$user->title));
  476. $message = $foowd->template->fetch('fetchpwd_request.tpl');
  477. $result = email($foowd, $lostuser->email,
  478. sprintf(_("%s - Password Change Request"), $site),
  479. $message,
  480. 'From: '.$foowd->config_settings['site']['email_webmaster']
  481. .'\r\nReply-To: '.$foowd->config_settings['site']['email_noreply']);
  482. if ( $result )
  483. return 1; // password change request e-mail sent
  484. else
  485. return 2; // could not send e-mail due to technical problem
  486. }
  487. // We have id and query, change password and send confirmation
  488. else
  489. {
  490. if ( strtolower($lostuser->title) != strtolower($queryUsername) )
  491. return 8; // user does not exist
  492. if ($id != md5($lostuser->updated.$lostuser->title))
  493. return 7; // id does not match
  494. $newPassword = '';
  495. $foo_len = rand(6,12);
  496. srand(time());
  497. for($foo = 0; $foo < $foo_len; $foo++)
  498. $newPassword .= chr(rand(97, 122));
  499. $lostuser->set('password', md5($salt.$newPassword));
  500. $salt = $this->foowd->config_settings['user']['password_salt'];
  501. $foowd->template->assign('sitename', $site);
  502. $foowd->template->assign('username', $user->title);
  503. $foowd->template->assign('password', $newPassword);
  504. $foowd->template->assign('hostname', $_SERVER['SERVER_NAME']);
  505. $foowd->template->assign('class', 'base_user');
  506. $message = $foowd->template->fetch('fetchpwd_response.tpl');
  507. $result = email($foowd, $lostuser->email,
  508. sprintf(_("%s - Password Change Request"), $site),
  509. $message,
  510. 'From: '.$foowd->config_settings['site']['email_webmaster']
  511. .'\r\nReply-To: '.$foowd->config_settings['site']['email_noreply']);
  512. if ( $result )
  513. return 5; // password changed and e-mail sent
  514. else
  515. return 6; // could not send e-mail due to technical problem (or could not save new password)
  516. }
  517. return 0; // nothing, display form
  518. }
  519. /**
  520. * Create form elements for the update form from the objects member variables.
  521. *
  522. * @access protected
  523. * @global array Specifies table information for user persistance.
  524. * @param object form The form to add the form items to.
  525. * @param array error If error is encountered, add message to this array
  526. */
  527. function addUserItemsToForm(&$form, &$error)
  528. {
  529. global $USER_SOURCE;
  530. // Add regular elements to form
  531. include_once(INPUT_DIR.'input.textbox.php');
  532. include_once(INPUT_DIR.'input.dropdown.php');
  533. include_once(INPUT_DIR.'input.checkbox.php');
  534. $titleBox = new input_textbox('title', REGEX_TITLE, $this->title, 'Username', FALSE);
  535. $emailBox = new input_textbox('email', REGEX_EMAIL, $this->email, 'Email', FALSE);
  536. $showEmail = new input_checkbox('show_email', $form, $this->show_email, 'Share Email');
  537. if ( $form->submitted() )
  538. {
  539. if ( !empty($titleBox->value) && $titleBox->value != $this->title )
  540. {
  541. $unique = !$this->isTitleUnique($titleBox->value, FALSE, $objectid, $USER_SOURCE, FALSE) ;
  542. if ( $unique )
  543. $this->set('title', $titleBox->value);
  544. else
  545. {
  546. $titleBox->wasValid = FALSE;
  547. $error[] = _("User already exists, please choose a new name.");
  548. }
  549. }
  550. if ( !empty($emailBox->value) && $emailBox->value != $this->email )
  551. $this->set('email', $emailBox->value);
  552. if ( $showEmail->checked != $this->show_email )
  553. $this->set('show_email', $showEmail->checked);
  554. }
  555. $form->addObject($titleBox);
  556. $form->addObject($emailBox);
  557. $form->addObject($showEmail);
  558. $this->addPasswordItemsToForm($form, $error);
  559. // If something changed, update the
  560. // status of email as a public contact item based on
  561. // new values
  562. if ( $error == NULL && $form->submitted() && $this->foowd_changed )
  563. {
  564. if ( $this->show_email && $this->email )
  565. $this->IM_nicks['Email'] = $this->email;
  566. else
  567. unset($this->IM_nicks['Email']);
  568. }
  569. }
  570. /**
  571. * Create form elements for the update form from the objects member variables.
  572. *
  573. * @access protected
  574. * @param object form The form to add the form items to.
  575. * @param array error If error is encountered, add message to this array
  576. */
  577. function addPasswordItemsToForm(&$form, &$error)
  578. {
  579. include_once(INPUT_DIR.'input.textbox.php');
  580. $verify = new input_passwordbox('verify', REGEX_PASSWORD, NULL, 'Verify', FALSE);
  581. $password = new input_passwordbox('password', REGEX_PASSWORD, NULL, 'Password', FALSE);
  582. if ( $form->submitted() &&
  583. (!empty($password->value) || !empty($verify->value)) )
  584. {
  585. if ( $password->wasValid && !empty($password->value) &&
  586. $verify->wasValid && $password->value == $verify->value )
  587. {
  588. $salt = $this->foowd->config_settings['user']['password_salt'];
  589. $this->set('password', md5($salt.$password->value));
  590. }
  591. else
  592. {
  593. $password->wasValid = FALSE;
  594. $verify->wasValid = FALSE;
  595. $error[] = _("Passwords must be at least 4 characters, and must match.");
  596. }
  597. }
  598. $form->addObject($verify);
  599. $form->addObject($password);
  600. }
  601. /**
  602. * Update the groups the user belongs to - this is used for
  603. * adding or removing groups from an individual user.
  604. *
  605. * @access protected
  606. * @param array selectedGroups The groups selected for the user to be in.
  607. * @param array allGroups All the user groups in the system.
  608. * @see smdoc::getUserGroups()
  609. * @see smdoc_group::removeUser()
  610. * @see smdoc_group::addUser()
  611. */
  612. function addGroupsToForm(&$form, &$error)
  613. {
  614. include_once(INPUT_DIR.'input.dropdown.php');
  615. // Create array of groups
  616. $allGroups['None'] = 'None';
  617. $allGroups += $this->foowd->getUserGroups(FALSE);
  618. $groups = empty($this->groups) ? 'None' : $this->groups;
  619. $groupBox = new input_dropdown('groups', $groups, $allGroups, 'User Groups', TRUE);
  620. if ( $form->submitted() )
  621. {
  622. $new_groups = array();
  623. $grps = $groupBox->value;
  624. // If none selected, remove user from all groups
  625. if ( in_array('None', $grps) )
  626. $this->foowd->groups->removeUser($this->objectid, $this->groups);
  627. else
  628. {
  629. $remove_groups = array();
  630. $ok_groups = array();
  631. foreach ( $allGroups as $id => $name )
  632. {
  633. if ( in_array($id, $this->groups) )
  634. {
  635. if ( !in_array($id, $grps) )
  636. $remove_groups[] = $id;
  637. else
  638. $ok_groups[] = $id;
  639. }
  640. elseif ( in_array($id, $grps) )
  641. $new_groups[] = $id;
  642. }
  643. $this->foowd->groups->removeUser($this->objectid, $remove_groups);
  644. $this->foowd->groups->addUser($this->objectid, $new_groups);
  645. $new_groups = array_merge($new_groups, $ok_groups);
  646. }
  647. $this->set('groups', $new_groups);
  648. }
  649. $form->addObject($groupBox);
  650. }
  651. /**
  652. * Remove user from specified group
  653. *
  654. * @access protected
  655. * @param array selectedGroups The groups selected for the user to be in.
  656. * @param array allGroups All the user groups in the system.
  657. * @see smdoc::getUserGroups()
  658. * @see smdoc_group::removeUser()
  659. * @see smdoc_group::addUser()
  660. */
  661. function removeFromGroup($group)
  662. {
  663. $groups = $this->groups;
  664. foreach($groups as $i => $g)
  665. {
  666. if ( $g == $group )
  667. {
  668. unset($groups[$i]);
  669. break;
  670. }
  671. }
  672. $this->set('groups', $groups);
  673. }
  674. // ----------------------------- class methods --------------
  675. /**
  676. * Output an object creation form and process its input.
  677. *
  678. * @static
  679. * @param smdoc $foowd Reference to the foowd environment object.
  680. * @param string className The name of the class.
  681. */
  682. function class_create(&$foowd, $className)
  683. {
  684. $foowd->track('base_user->class_create');
  685. include_once(INPUT_DIR . 'input.textbox.php');
  686. include_once(INPUT_DIR . 'input.form.php');
  687. $queryTitle = new input_querystring('title', REGEX_TITLE, NULL);
  688. $createUsername = new input_textbox('createUsername', REGEX_TITLE, $queryTitle->value, 'Username');
  689. $verifyPassword = new input_passwordbox('verifyPassword', REGEX_PASSWORD, NULL, 'Verify');
  690. $createPassword = new input_passwordbox('createPassword', REGEX_PASSWORD, NULL, 'Password');
  691. $createEmail = new input_textbox('createEmail', REGEX_EMAIL, NULL, 'Email Address', FALSE);
  692. $createForm = new input_form('createForm', NULL, SQ_POST);
  693. if ( $createForm->submitted() &&
  694. $createUsername->wasSet && $createUsername->wasValid && $createUsername != '' )
  695. {
  696. if ( $createPassword->wasSet && $createPassword->wasValid &&
  697. $verifyPassword->wasSet && $verifyPassword->wasValid &&
  698. $createPassword->value != '' && $createPassword->value == $verifyPassword->value )
  699. {
  700. $result = call_user_func(array($className, 'create'),
  701. $foowd,
  702. $createUsername->value,
  703. $createPassword->value,
  704. $createEmail->value);
  705. }
  706. else
  707. $result = -1;
  708. }
  709. else
  710. $result = -2;
  711. switch ($result)
  712. {
  713. case 0:
  714. $_SESSION['ok'] = USER_CREATE_OK;
  715. $uri_arr['class'] = $className;
  716. $uri_arr['method'] = 'login';
  717. $uri_arr['username'] = htmlspecialchars($createUsername->value);
  718. $foowd->loc_forward(getURI($uri_arr, FALSE));
  719. exit;
  720. case -1:
  721. $foowd->template->assign('failure', _("Passwords must be at least 4 characters, and must match."));
  722. $verifyPassword->set(NULL);
  723. $createPassword->set(NULL);
  724. break;
  725. case -2:
  726. $foowd->template->assign('failure', FORM_FILL_FIELDS);
  727. break;
  728. case 3:
  729. $foowd->template->assign('failure', _("Could not create user."));
  730. break;
  731. case 4:
  732. $foowd->template->assign('failure', _("User already exists, please choose a new name."));
  733. break;
  734. }
  735. $createForm->addObject($createUsername);
  736. $createForm->addObject($createPassword);
  737. $createForm->addObject($verifyPassword);
  738. $createForm->addObject($createEmail);
  739. $foowd->template->assign_by_ref('form', $createForm);
  740. return;
  741. }
  742. /**
  743. * Output a login form and process its input.
  744. *
  745. * @static
  746. * @param smdoc $foowd Reference to the foowd environment object.
  747. * @param string className The name of the class.
  748. */
  749. function class_login(&$foowd, $className)
  750. {
  751. $foowd->track('base_user->class_login');
  752. include_once(INPUT_DIR . 'input.textbox.php');
  753. include_once(INPUT_DIR . 'input.form.php');
  754. $usernameQuery = new input_querystring('username', REGEX_TITLE, '');
  755. $loginUsername = new input_textbox('loginUsername', REGEX_TITLE, $usernameQuery->value, 'Username');
  756. $loginPassword = new input_passwordbox('loginPassword', REGEX_PASSWORD, NULL, 'Password');
  757. $loginForm = new input_form('loginForm', NULL, SQ_POST, _("Log In"), NULL);
  758. $loginForm->addObject($loginUsername);
  759. $loginForm->addObject($loginPassword);
  760. if ( $loginForm->submitted() )
  761. {
  762. $result = call_user_func( array($className, 'login'),
  763. $foowd,
  764. $loginUsername->value,
  765. $loginPassword->value );
  766. }
  767. else
  768. $result = -1;
  769. switch ($result)
  770. {
  771. case 0:
  772. case 5:
  773. $_SESSION['ok'] = ( $result == 0 ) ? USER_LOGIN_OK : USER_LOGIN_PREV;
  774. $uri_arr['objectid'] = $foowd->user->objectid;
  775. $uri_arr['classid'] = USER_CLASS_ID;
  776. $url = getURI($uri_arr, FALSE);
  777. $foowd->loc_forward($url);
  778. exit;
  779. case -1:
  780. $foowd->template->assign('failure', FORM_FILL_FIELDS);
  781. break;
  782. case 2:
  783. case 3:
  784. $foowd->template->assign('failure', _("User or password is incorrect."));
  785. break;
  786. }
  787. $foowd->template->assign_by_ref('form', $loginForm);
  788. $foowd->track();
  789. }
  790. /**
  791. * Log the user out and display a log out screen.
  792. *
  793. * @static
  794. * @param smdoc $foowd Reference to the foowd environment object.
  795. * @param string className The name of the class.
  796. */
  797. function class_logout(&$foowd, $className)
  798. {
  799. $result = call_user_func(array($className, 'logout'), $foowd);
  800. switch ($result)
  801. {
  802. case 0:
  803. case 3:
  804. $_SESSION['ok'] = USER_LOGOUT_OK;
  805. $uri_arr['class'] = getClassname(USER_CLASS_ID);
  806. $uri_arr['method'] = 'login';
  807. $foowd->loc_forward(getURI($uri_arr, FALSE));
  808. return NULL;
  809. }
  810. trigger_error('Unexpected response when logging out user: ' . $result, E_USER_ERROR);
  811. }
  812. /**
  813. * Output a fetch password form and process its input.
  814. *
  815. * @static
  816. * @param smdoc $foowd Reference to the foowd environment object.
  817. * @param string className The name of the class.
  818. */
  819. function class_lostPassword(&$foowd, $className)
  820. {
  821. $foowd->track('base_user->class_lostPassword');
  822. include_once(INPUT_DIR.'input.querystring.php');
  823. include_once(INPUT_DIR.'input.textbox.php');
  824. include_once(INPUT_DIR.'input.form.php');
  825. $usernameQuery = new input_querystring('username', REGEX_TITLE, NULL);
  826. $idQuery = new input_querystring('id', '/[a-z0-9]{32}/', NULL);
  827. $lostUsername = new input_textbox('lostUsername', REGEX_TITLE, $usernameQuery->value, _("Username").':');
  828. $lostForm = new input_form('lostForm', NULL, 'POST', _("Retrieve Password"), NULL);
  829. $result = call_user_func(array($className, 'fetchPassword'),
  830. &$foowd, $className,
  831. $lostUsername->value,
  832. $usernameQuery->value,
  833. $idQuery->value);
  834. switch ($result)
  835. {
  836. case 0: // done nothing, display form
  837. $lostForm->addObject($lostUsername);
  838. $foowd->template->assign_by_ref('form', $lostForm);
  839. break;
  840. case 1: // stage 1 complete
  841. $foowd->template->assign('stage1', TRUE);
  842. break;
  843. case 2: // could not send e-mail, technical problem
  844. $foowd->template->assign('failure', 2);
  845. $foowd->template->assign('webmaster', $foowd->webmaster_email);
  846. break;
  847. case 3: // could not send e-mail, user does not have an e-mail address listed
  848. $foowd->template->assign('failure', 3);
  849. $foowd->template->assign('username', htmlspecialchars($lostUsername->value));
  850. $foowd->template->assign('webmaster', $foowd->webmaster_email);
  851. break;
  852. case 4: // could not send e-mail, user does not exist
  853. $foowd->template->assign('failure', 4);
  854. $foowd->template->assign('username', htmlspecialchars($lostUsername->value));
  855. break;
  856. case 5: // stage 2 complete
  857. $foowd->template->assign('stage2', TRUE);
  858. $foowd->template->assign('class', $className);
  859. $foowd->template->assign('username', $lostUsername->value);
  860. break;
  861. case 6: // could not change password, technical problem
  862. $foowd->template->assign('failure', 6);
  863. $foowd->template->assign('webmaster', $foowd->webmaster_email);
  864. break;
  865. case 7: // could not change password, id does not match
  866. $foowd->template->assign('failure', 7);
  867. $foowd->template->assign('webmaster', $foowd->webmaster_email);
  868. $foowd->template->assign('class', $className);
  869. $foowd->template->assign('username', $usernameQuery->value);
  870. break;
  871. case 8: // could not change password, could not find user
  872. $foowd->template->assign('failure', 8);
  873. $foowd->template->assign('webmaster', $foowd->webmaster_email);
  874. break;
  875. }
  876. $foowd->track();
  877. }
  878. /**
  879. * Output a list of all registered users.
  880. *
  881. * Values set in template:
  882. * + userlist - below
  883. * + usercount - number of registered users
  884. *
  885. * Sample contents of $t['userlist']:
  886. * <pre>
  887. * array (
  888. * 0 => array (
  889. * 'title' => 'Username'
  890. * 'objectid' => 1287432
  891. * 'IRC' => ''
  892. * )
  893. * )
  894. * </pre>
  895. *
  896. * @static
  897. * @global array Specifies table information for user persistance.
  898. * @param smdoc $foowd Reference to the foowd environment object.
  899. * @param string className The name of the class.
  900. */
  901. function class_list(&$foowd, $className)
  902. {
  903. $foowd->track('base_user->class_list');
  904. global $USER_SOURCE;
  905. /*
  906. * No special indices, use user source, no special where clause,
  907. * order by title, no limit,
  908. * don't objects, and don't restrict to certain workspace
  909. */
  910. $indices = array('objectid','title','IRC');
  911. $objects =& $foowd->getObjList($indices, $USER_SOURCE, NULL,
  912. array('title'), NULL,
  913. FALSE, FALSE );
  914. $foowd->template->assign_by_ref('user_list', $objects);
  915. $num_users = $foowd->database->count($USER_SOURCE);
  916. $foowd->template->assign('user_count', $num_users);
  917. $foowd->track();
  918. }
  919. // -----------------------------object methods --------------
  920. /**
  921. * Output the object.
  922. *
  923. * @param smdoc $foowd Reference to the foowd environment object.
  924. */
  925. function method_view()
  926. {
  927. $this->foowd->track('base_user->method_view');
  928. $this->foowd->template->assign('created', date(DATETIME_FORMAT, $this->created));
  929. $this->foowd->template->assign('lastvisit', date(DATETIME_FORMAT, $this->updated));
  930. if ( $this->foowd->user->inGroup('Author', $this->creatorid) )
  931. $this->foowd->template->assign('update', TRUE);
  932. if ( $this->email )
  933. $this->foowd->template->assign('email', mungEmail($this->email));
  934. $this->foowd->track();
  935. }
  936. /**
  937. * Output the object administration form and handle its input.
  938. *
  939. * @access protected
  940. */
  941. function method_groups()
  942. {
  943. $this->foowd->track('base_user->method_groups');
  944. include_once(INPUT_DIR.'input.form.php');
  945. $groupsForm = new input_form('groupsForm', NULL, SQ_POST);
  946. $error = NULL;
  947. $this->addGroupsToForm($groupsForm, $error);
  948. if ( $error != NULL )
  949. $this->foowd->template->assign('failure', $error);
  950. elseif ( $groupsForm->submitted() && $this->foowd_changed)
  951. {
  952. if ( $this->save() )
  953. {
  954. $_SESSION['ok'] = USER_UPDATE_OK;
  955. $uri_arr['objectid'] = $this->objectid;
  956. $uri_arr['classid'] = USER_CLASS_ID;
  957. $this->foowd->loc_forward( getURI($uri_arr, FALSE));
  958. }
  959. else
  960. $this->foowd->template->assign('failure', OBJECT_UPDATE_FAILED);
  961. }
  962. $this->foowd->template->assign_by_ref('form', $groupsForm);
  963. $this->foowd->track();
  964. }
  965. /**
  966. * Output a user update form and process its input.
  967. *
  968. * @param smdoc $foowd Reference to the foowd environment object.
  969. */
  970. function method_update()
  971. {
  972. $this->foowd->track('base_user->method_update');
  973. include_once(INPUT_DIR . 'input.form.php');
  974. $updateForm = new input_form('updateForm', NULL, SQ_POST, _("Update Profile"));
  975. $error = NULL;
  976. $this->addUserItemsToForm($updateForm, $error);
  977. if ( $error != NULL )
  978. $this->foowd->template->assign('failure', $error);
  979. elseif ( $updateForm->submitted() && $this->foowd_changed )
  980. {
  981. if ( $this->save() )
  982. {
  983. $_SESSION['ok'] = USER_UPDATE_OK;
  984. $uri_arr['objectid'] = $this->objectid;
  985. $uri_arr['classid'] = USER_CLASS_ID;
  986. $this->foowd->loc_forward( getURI($uri_arr, FALSE));
  987. }
  988. else
  989. $this->foowd->template->assign('failure', OBJECT_UPDATE_FAILED);
  990. }
  991. $this->foowd->template->assign_by_ref('form', $updateForm);
  992. $this->foowd->track();
  993. }
  994. // ----------------------------- disabled methods --------------
  995. /**
  996. * Create a new version of this object. Set the objects version number to the
  997. * next available version number and queue the object for saving. This will
  998. * have the effect of creating a new object entry since the objects version
  999. * number has changed.
  1000. */
  1001. function newVersion()
  1002. {
  1003. trigger_error('newVersion not supported for base_user', E_USER_ERROR);
  1004. }
  1005. /**
  1006. * Clean up the archive versions of the object.
  1007. *
  1008. * @param smdoc $foowd Reference to the foowd environment object.
  1009. * @return bool Returns TRUE on success.
  1010. */
  1011. function tidyArchive()
  1012. {
  1013. trigger_error('tidyArchive does not apply to base_user' , E_USER_ERROR);
  1014. }
  1015. /**
  1016. * Clone the object.
  1017. *
  1018. * @param smdoc $foowd Reference to the foowd environment object.
  1019. * @param string title The title of the new object clone.
  1020. * @param string workspace The workspace to place the object clone in.
  1021. * @return bool Returns TRUE on success.
  1022. */
  1023. function clone($title, $workspace)
  1024. {
  1025. trigger_error('Can not clone users.' , E_USER_ERROR);
  1026. }
  1027. /**
  1028. * Convert variable list to XML.
  1029. *
  1030. * @param array vars The variables to convert.
  1031. * @param array goodVars List of variables to convert.
  1032. */
  1033. function vars2XML($vars, $goodVars)
  1034. {
  1035. trigger_error('vars2XML does not apply to base_user' , E_USER_ERROR);
  1036. }
  1037. }