Source for file user-classes.php

Documentation is available at user-classes.php

  1. <?php
  2. ////////////////////////////////////////////////////////////////////////////////
  3. // Copyright (C) ReloadCMS Development Team //
  4. // http://reloadcms.sf.net //
  5. // //
  6. // This program is distributed in the hope that it will be useful, //
  7. // but WITHOUT ANY WARRANTY, without even the implied warranty of //
  8. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
  9. // //
  10. // This product released under GNU General Public License v2 //
  11. ////////////////////////////////////////////////////////////////////////////////
  12.  
  13.  
  14.  
  15. class rcms_access
  16. {
  17. var $rights_database = array();
  18. var $rights = array();
  19. var $root = false;
  20. var $level = 0;
  21.  
  22.  
  23. function initialiseAccess($rights, $level){
  24. $this->rights = array();
  25. $this->root = false;
  26. if($rights !== '*') {
  27. preg_match_all('/\|(.*?)\|/', $rights, $rights_r);
  28. foreach ($rights_r[1] as $right){
  29. $this->rights[$right] = (empty($this->rights_database[$right])) ? ' ' : $this->rights_database[$right];
  30. }
  31. } else {
  32. $this->root = true;
  33. }
  34. $this->level = $level;
  35. return true;
  36. }
  37.  
  38. /**
  39. * @param string $right
  40. * @return boolean
  41. * @desc Check if user have specified right
  42. */
  43. function checkForRight($right = '-any-', $username = ''){
  44. if(empty($username)) {
  45. $rights = &$this->rights;
  46. $root = &$this->root;
  47. } else {
  48. if(!$this->getRightsForUser($username, $rights, $root, $level)) {
  49. return false;
  50. }
  51. }
  52. return $root || ($right == '-any-' && !empty($rights)) || !empty($rights[$right]);
  53. }
  54.  
  55. function getRightsForUser($username, &$rights, &$root, &$level){
  56. if (!($userdata = $this->getUserData($username))) return false;
  57. if(!empty($this->config['registered_accesslevel'])){
  58. $level = (int)$this->config['registered_accesslevel'];
  59. if(!isset($userdata['accesslevel']) || $level > $userdata['accesslevel']){
  60. $userdata['accesslevel'] = $level;
  61. }
  62. }
  63. $rights = array();
  64. $root = false;
  65. if($userdata['admin'] !== '*') {
  66. preg_match_all('/\|(.*?)\|/', $userdata['admin'], $rights_r);
  67. foreach ($rights_r[1] as $right){
  68. $rights[$right] = (empty($this->rights_database[$right])) ? ' ' : $this->rights_database[$right];
  69. }
  70. } else {
  71. $root = true;
  72. }
  73. $level = (int)@$userdata['accesslevel'];
  74. return true;
  75. }
  76.  
  77. function setRightsForUser($username, $rights, $root = false, $level = 0){
  78. if(empty($rights)) $rights = array();
  79. if(!empty($this->config['registered_accesslevel'])){
  80. $reg_level = (int)$this->config['registered_accesslevel'];
  81. if($level === ''){
  82. $userdata['accesslevel'] = $reg_level;
  83. }
  84. }
  85. if($root) {
  86. $rights_string = '*';
  87. } else {
  88. $rights_string = '';
  89. if(is_array($rights)){
  90. foreach ($rights as $right => $cond){
  91. if($cond) $rights_string .= '|' . $right . '|';
  92. }
  93. }
  94. }
  95. user_change_field($username, 'admin', $rights_string);
  96. user_change_field($username, 'accesslevel', $level);
  97. return true;
  98. }
  99. }
  100.  
  101. class rcms_user_cache{
  102. var $cache_filename = 'users.cache.dat';
  103. var $cache = array();
  104.  
  105. function rcms_user_cache(){
  106. if(!is_file(DATA_PATH . $this->cache_filename)) {
  107. $this->cache = array();
  108. } else {
  109. if(!($this->cache = @unserialize(@file_get_contents(DATA_PATH . 'users.cache.dat')))){
  110. $this->cache = array();
  111. }
  112. }
  113. }
  114.  
  115. function save(){
  116. file_write_contents(DATA_PATH . $this->cache_filename, serialize($this->cache));
  117. }
  118.  
  119. function registerUser($username, $usernick, $email){
  120. $this->cache['nicks'][$username] = $usernick;
  121. $this->cache['mails'][$username] = $email;
  122. $this->save();
  123. return true;
  124. }
  125.  
  126. function getUser($field, $value){
  127. return array_search($value, $this->cache[$field]);
  128. }
  129.  
  130. function removeUser($username){
  131. if(!empty($this->cache['nicks'][$username])) {
  132. $this->cache['nicks'][$username] = '';
  133. unset($this->cache['nicks'][$username]);
  134. }
  135. if(!empty($this->cache['mails'][$username])) {
  136. $this->cache['mails'][$username] = '';
  137. unset($this->cache['mails'][$username]);
  138. }
  139. $this->save();
  140. return true;
  141. }
  142.  
  143. function checkField($field, $value){
  144. if(empty($this->cache[$field])) return true;
  145. return !in_array_i($value, $this->cache[$field]);
  146. }
  147. }
  148.  
  149. define('USERS_ALLOW_CHANGE', 0);
  150. define('USERS_ALLOW_SET', 1);
  151. define('USERS_DISALLOW_CHANGE', 2);
  152. define('USERS_DISALLOW_CHANGE_ALL', 3);
  153.  
  154. class rcms_user extends rcms_access {
  155.  
  156. var $profile_fields = array();
  157. var $profile_defaults = array();
  158.  
  159. /**
  160. * This property indicates if user is registered or just a guest
  161. *
  162. * @access public
  163. * @var boolean
  164. */
  165. var $logged_in = false;
  166.  
  167. /**
  168. * This array contain data from user's profile
  169. *
  170. * @access public
  171. * @var array
  172. */
  173. var $user = array();
  174.  
  175. /**
  176. * Name for user cookie
  177. *
  178. * @access private
  179. * @var string
  180. */
  181. var $cookie_user = 'reloadcms_user';
  182.  
  183. var $users_cache = null;
  184.  
  185. /**
  186. * @return boolean
  187. * @param string $skipcheck Use this parameter to skip userdata checks
  188. * @desc This function is an internal private function for class rcms_system
  189. and must not be used externally. This function initialize user and
  190. load his profile to object.
  191. */
  192. function initializeUser($skipcheck = false){
  193. $this->users_cache = new rcms_user_cache();
  194.  
  195. $this->data['apf'] = parse_ini_file(CONFIG_PATH . 'users.fields.ini');
  196. // Enter access levels for fields here
  197. $this->profile_fields = array(
  198. 'hideemail' => USERS_ALLOW_CHANGE,
  199. 'admin' => USERS_DISALLOW_CHANGE_ALL,
  200. 'tz' => USERS_ALLOW_CHANGE,
  201. 'accesslevel' => USERS_DISALLOW_CHANGE_ALL,
  202. 'last_prr' => USERS_DISALLOW_CHANGE_ALL,
  203. 'blocked' => USERS_DISALLOW_CHANGE
  204. );
  205. foreach ($this->data['apf'] as $field => $desc) {
  206. $this->profile_fields[$field] = USERS_ALLOW_CHANGE;
  207. }
  208. $this->profile_defaults = array('hideemail' => 0, 'admin' => ' ', 'tz' => 0, 'accesslevel' => 0, 'blocked' => 0, 'last_prr' => 0);
  209.  
  210. // Load default guest userdata
  211. $this->user = array('nickname' => __('Guest'), 'username' => 'guest', 'admin' => '', 'tz' => (int)@$this->config['default_tz'], 'accesslevel' => 0);
  212. $this->initialiseAccess($this->user['admin'], (int)@$userdata['accesslevel']);
  213.  
  214. // Ability for guests to enter nick
  215. $_POST['gst_nick'] = substr(trim(@$_POST['gst_nick']), 0, 32);
  216. if(!empty($_POST['gst_nick']) && !$this->logged_in){
  217. $this->user['nickname'] = $_POST['gst_nick'];
  218. setcookie('reloadcms_nick', $this->user['nickname']);
  219. $_COOKIE['reloadcms_nick'] = $this->user['nickname'];
  220. } elseif(!$this->logged_in && !empty($_COOKIE['reloadcms_nick'])){
  221. $this->user['nickname'] = substr(trim($_COOKIE['reloadcms_nick']), 0, 32);
  222. }
  223. if(!$this->users_cache->checkField('nicks', $this->user['nickname'])) {
  224. $this->user['nickname'] = __('Guest');
  225. setcookie('reloadcms_nick', '', time() - 16000);
  226. unset($_COOKIE['reloadcms_nick']);
  227. }
  228. // Secure the nickname
  229. $this->user['nickname'] = htmlspecialchars($this->user['nickname']);
  230.  
  231. // If user cookie is not present we exiting without error
  232. if(empty($_COOKIE[$this->cookie_user])) {
  233. $this->logged_in = false;
  234. return true;
  235. }
  236. // So we have a cookie, let's extract data from it
  237. $cookie_data = explode(':', $_COOKIE[$this->cookie_user], 2);
  238. if(!$skipcheck){
  239. // If this cookie is invalid - we exiting destroying cookie and exiting with error
  240. if(sizeof($cookie_data) != 2){
  241. setcookie($this->cookie_user, null, time() - 3600);
  242. return false;
  243. }
  244. // Now we must validate user's data
  245. if(!$this->checkUserData($cookie_data[0], $cookie_data[1], 'user_init', true, $this->user)){
  246. setcookie($this->cookie_user, null, time() - 3600);
  247. $this->logged_in = false;
  248. return false;
  249. }
  250. }
  251.  
  252. $userdata = $this->getUserData($cookie_data[0]);
  253. if($userdata == false){
  254. setcookie($this->cookie_user, null, time() - 3600);
  255. $this->logged_in = false;
  256. return false;
  257. }
  258. $this->user = $userdata;
  259. $this->logged_in = true;
  260.  
  261. if(!empty($this->config['registered_accesslevel'])){
  262. $level = (int)$this->config['registered_accesslevel'];
  263. if(!isset($userdata['accesslevel'])){
  264. $this->user['accesslevel'] = $level;
  265. }
  266. }
  267. // Initialise access levels
  268. $this->initialiseAccess($this->user['admin'], (int)@$this->user['accesslevel']);
  269. // Secure the nickname
  270. $this->user['nickname'] = htmlspecialchars($this->user['nickname']);
  271. return true;
  272. }
  273.  
  274. /**
  275. * @return boolean
  276. * @param string $username
  277. * @param string $password
  278. * @param string $report_to
  279. * @param boolean $hash
  280. * @param link $userdata
  281. * @desc This function is an internal private function for class rcms_system
  282. and must not be used externally. This function check user's data and
  283. validate his data file.
  284. */
  285. function checkUserData($username, $password, $report_to, $hash, &$userdata){
  286. if(preg_replace("/[\d\w]+/i", "", $username) != ""){
  287. $this->results[$report_to] = __('Invalid username');
  288. return false;
  289. }
  290. // If login is not exists - we exiting with error
  291. if(!is_file(USERS_PATH . $username)){
  292. $this->results[$report_to] = __('There are no user with this username');
  293. return false;
  294. }
  295. // So all is ok. Let's load userdata
  296. $result = $this->getUserData($username);
  297. // If userdata is invalid we must exit with error
  298. if(empty($result)) return false;
  299. // If password is invalid - exit with error
  300. if((!$hash && md5($password) !== $result['password']) || ($hash && $password !== $result['password'])) {
  301. $this->results[$report_to] = __('Invalid password');
  302. return false;
  303. }
  304. // If user is blocked - exit with error
  305. if(@$result['blocked']) {
  306. $this->results[$report_to] = __('This account has been blocked by administrator');
  307. return false;
  308. }
  309. $userdata = $result;
  310. return true;
  311. }
  312.  
  313. /**
  314. * @return boolean
  315. * @param string $username
  316. * @param string $password
  317. * @param boolean $remember
  318. * @desc This function check user's data and log in him.
  319. */
  320. function logInUser($username, $password, $remember){
  321. $username = basename($username);
  322. if($username == 'guest') return false;
  323. if(!$this->logged_in && $this->checkUserData($username, $password, 'user_login', false, $userdata)){
  324. rcms_log_put('Notification', $this->user['username'], 'Logged in as ' . $username);
  325. // OK... Let's allow user to log in :)
  326. setcookie($this->cookie_user, $username . ':' . $userdata['password'], ($remember) ? time()+3600*24*365 : null);
  327. $_COOKIE[$this->cookie_user] = $username . ':' . $userdata['password'];
  328. $this->initializeUser(true);
  329. return true;
  330. } else {
  331. if(!$this->logged_in) {
  332. rcms_log_put('Notification', $this->user['username'], 'Attempted to log in as ' . $username);
  333. }
  334. return false;
  335. }
  336. }
  337.  
  338. /**
  339. * @return boolean
  340. * @desc This function log out user from system and destroys his cookie.
  341. */
  342. function logOutUser(){
  343. if($this->logged_in){
  344. rcms_log_put('Notification', $this->user['username'], 'Logged out');
  345. setcookie($this->cookie_user, '', time()-3600);
  346. $_COOKIE[$this->cookie_user] = '';
  347. $this->initializeUser(false);
  348. return true;
  349. }
  350. }
  351.  
  352.  
  353. function registerUser($username, $nickname, $password, $confirm, $email, $userdata){
  354. $username = basename($username);
  355. $nickname = empty($nickname) ? $username : substr(trim($nickname), 0, 32);
  356.  
  357. if(empty($username) || preg_replace("/[\d\w]+/i", '', $username) != '' || strlen($username) > 32 || $username == 'guest') {
  358. $this->results['registration'] = __('Invalid username');
  359. return false;
  360. }
  361.  
  362. if(is_file(USERS_PATH . $username)) {
  363. $this->results['registration'] = __('User with this username already exists');
  364. return false;
  365. }
  366.  
  367. if(!user_check_nick_in_cache($username, $nickname, $cache)) {
  368. $this->results['registration'] = __('User with this nickname already exists');
  369. return false;
  370. }
  371.  
  372. if(empty($email) || !rcms_is_valid_email($email)) {
  373. $this->results['registration'] = __('Invalid e-mail address');
  374. return false;
  375. }
  376.  
  377. if(!user_check_email_in_cache($username, $email, $cache)){
  378. $this->results['registration'] = __('This e-mail address already registered');
  379. return false;
  380. }
  381.  
  382. if(!empty($this->config['regconf'])) $password = $confirm = rcms_random_string(8);
  383. if(empty($password) || empty($confirm) || $password != $confirm) {
  384. $this->results['registration'] = __('Password doesnot match it\'s confirmation');
  385. return false;
  386. }
  387.  
  388. // If our user is first - we must set him an admin rights
  389. $_userdata['admin'] = (sizeof(rcms_scandir(USERS_PATH)) == 0) ? '*' : ' ';
  390.  
  391. // Also we must set a md5 hash of user's password to userdata
  392. $_userdata['password'] = md5($password);
  393. $_userdata['nickname'] = $nickname;
  394. $_userdata['username'] = $username;
  395. $_userdata['email'] = $email;
  396.  
  397. // Parse some system fields
  398. $userdata['hideemail'] = empty($userdata['hideemail']) ? '0' : '1';
  399. $userdata['tz'] = (float) @$userdata['tz'];
  400.  
  401. foreach ($this->profile_fields as $field => $acc){
  402. if($acc <= USERS_ALLOW_SET || $acc == USERS_ALLOW_CHANGE){
  403. if(!isset($userdata[$field])) {
  404. $userdata[$field] = $this->profile_defaults[$field];
  405. } else {
  406. $_userdata[$field] = strip_tags(trim($userdata[$field]));
  407. }
  408. }
  409. }
  410. foreach ($this->data['apf'] as $field => $desc) {
  411. $_userdata[$field] = strip_tags(trim($userdata[$field]));
  412. }
  413.  
  414. if(!file_write_contents(USERS_PATH . $username, serialize($_userdata))){
  415. $this->results['registration'] = __('Cannot save profile');
  416. return false;
  417. }
  418.  
  419. user_register_in_cache($username, $nickname, $email, $cache);
  420.  
  421. if(!empty($this->config['regconf'])) {
  422. $site_url = parse_url($this->url);
  423. rcms_send_mail($email, 'no_reply@' . $site_url['host'],
  424. __('Password'),
  425. $this->config['encoding'],
  426. __('Your password at') . ' ' . $site_url['host'],
  427. __('Your username at') . ' ' . $site_url['host'] . ': ' . $username . "\r\n" . __('Your password at') . ' ' . $site_url['host'] . ': ' . $password);
  428. }
  429.  
  430. $this->results['registration'] = __('Registration complete. You can now login with your username and password.');
  431. rcms_log_put('Notification', $this->user['username'], 'Registered account ' . $username);
  432. return true;
  433. }
  434.  
  435. function updateUser($username, $nickname, $password, $confirm, $email, $userdata, $admin = false){
  436. $username = basename($username);
  437. $nickname = empty($nickname) ? $username : substr(strip_tags($nickname), 0, 20);
  438.  
  439. if(empty($username) || preg_replace("/[\d\w]+/i", '', $username) != '') {
  440. $this->results['profileupdate'] = __('Invalid username');
  441. return false;
  442. }
  443. if($username == 'guest') return false;
  444.  
  445. if(!is_file(USERS_PATH . $username)) {
  446. $this->results['profileupdate'] = __('There is no user with this name');
  447. return false;
  448. }
  449.  
  450. user_remove_from_cache($username, $cache);
  451. if(!($_userdata = $this->getUserData($username))) {
  452. $this->results['profileupdate'] = __('Cannot open profile');
  453. return false;
  454. }
  455.  
  456. if(!user_check_nick_in_cache($username, $nickname, $cache)) {
  457. $this->results['profileupdate'] = __('User with this nickname already exists');
  458. return false;
  459. }
  460.  
  461. if(empty($email) || !rcms_is_valid_email($email)) {
  462. $this->results['profileupdate'] = __('Invalid e-mail address');
  463. return false;
  464. }
  465.  
  466. if(!user_check_email_in_cache($username, $email, $cache)){
  467. $this->results['profileupdate'] = __('This e-mail address already registered');
  468. return false;
  469. }
  470.  
  471. if(!empty($password) && !empty($confirm) && $password != $confirm) {
  472. $this->results['profileupdate'] = __('Password doesnot match it\'s confirmation');
  473. return false;
  474. }
  475.  
  476. // Also we must set a md5 hash of user's password to userdata
  477. $_userdata['password'] = (empty($password)) ? $_userdata['password'] : md5($password);
  478. $_userdata['nickname'] = $nickname;
  479. $_userdata['email'] = $email;
  480.  
  481. // Parse some system fields
  482. $userdata['hideemail'] = empty($userdata['hideemail']) ? '0' : '1';
  483. $userdata['tz'] = (float) $userdata['tz'];
  484. $userdata['accesslevel'] = (int) @$userdata['accesslevel'];
  485.  
  486. foreach ($this->profile_fields as $field => $acc){
  487. if(($admin && $acc < USERS_DISALLOW_CHANGE_ALL) || $acc <= USERS_ALLOW_SET || $acc == USERS_ALLOW_CHANGE){
  488. if(!isset($userdata[$field])) {
  489. $userdata[$field] = $this->profile_defaults[$field];
  490. } else {
  491. $_userdata[$field] = strip_tags(trim($userdata[$field]));
  492. }
  493. }
  494. }
  495. foreach ($this->data['apf'] as $field => $desc) {
  496. $_userdata[$field] = strip_tags(trim($userdata[$field]));
  497. }
  498.  
  499. if(!file_write_contents(USERS_PATH . $username, serialize($_userdata))){
  500. $this->results['profileupdate'] = __('Cannot save profile');
  501. return false;
  502. }
  503.  
  504. user_register_in_cache($username, $nickname, $email, $cache);
  505. $this->results['profileupdate'] = __('Profile updated');
  506. if($this->user['username'] == $username) {
  507. $this->user = $_userdata;
  508. }
  509. rcms_log_put('Notification', $this->user['username'], 'Updated userinfo for ' . $username);
  510. return true;
  511. }
  512.  
  513. function recoverPassword($username, $email){
  514. $username = basename($username);
  515. if(!($data = $this->getUserData($username))) {
  516. $this->results['passrec'] = __('Cannot open profile');
  517. return false;
  518. }
  519. if($email != $data['email']) {
  520. $this->results['passrec'] = __('Your e-mail doesn\'t match e-mail in profile');
  521. return false;
  522. }
  523. $new_password = rcms_random_string(8);
  524. $site_url = parse_url($this->url);
  525. $time = time();
  526. if(!empty($data['last_prr']) && !empty($this->config['pr_flood']) && (int)$time <= ((int)$data['last_prr'] + (int)$this->config['pr_flood'])){
  527. $this->results['passrec'] = __('Too many requests in limited period of time. Try later.');
  528. $data['last_prr'] = time();
  529. if(!file_write_contents(USERS_PATH . $username, serialize($data))) {
  530. $this->results['passrec'] .= '<br />' . __('Cannot save profile');
  531. }
  532. rcms_log_put('Notification', $this->user['username'], 'Attempted to recover password for ' . $username);
  533. return false;
  534. }
  535.  
  536. if(rcms_send_mail($email, 'no_reply@' . $site_url['host'], __('Password'), $this->config['encoding'], __('Your new password at') . ' ' . $site_url['host'],
  537. __('Your username at') . ' ' . $site_url['host'] . ': ' . $username . "\r\n" . __('Your new password at') . ' ' . $site_url['host'] . ': ' . $new_password)) {
  538. $data['password'] = md5($new_password);
  539. $data['last_prr'] = $time;
  540. if(!file_write_contents(USERS_PATH . $username, serialize($data))) {
  541. $this->results['passrec'] = __('Cannot save profile');
  542. return false;
  543. }
  544. $this->results['passrec'] = __('New password has been sent to your e-mail');
  545. rcms_log_put('Notification', $this->user['username'], 'Recovered password for ' . $username);
  546. return true;
  547. } else {
  548. rcms_log_put('Notification', $this->user['username'], 'Recovered password for ' . $username . '" (BUT E-MAIL WAS NOT SENT)');
  549. $this->results['passrec'] = __('Cannot send e-mail');
  550. return false;
  551. }
  552. }
  553.  
  554. function getUserData($username){
  555. $result = @unserialize(@file_get_contents(USERS_PATH . basename($username)));
  556. if(empty($result)) return false; else return $result;
  557. }
  558.  
  559. function getUserList($expr = '*', $id_field = ''){
  560. $return = array();
  561. $users = rcms_scandir(USERS_PATH, $expr);
  562. foreach ($users as $user){
  563. if($data = $this->getUserData($user)) {
  564. if(!empty($id_field) && !empty($data[$id_field])) {
  565. $return[$data[$id_field]] = $data;
  566. } else {
  567. $return[] = $data;
  568. }
  569. }
  570. }
  571. return $return;
  572. }
  573.  
  574. function changeProfileField($username, $field, $value){
  575. $username = basename($username);
  576. if (!($userdata = $this->getUserData($username))) return false;
  577. $userdata[$field] = $value;
  578. if(!file_write_contents(USERS_PATH . $username, serialize($userdata))) return false;
  579. return true;
  580. }
  581.  
  582. function deleteUser($username){
  583. $username = basename($username);
  584. if(!rcms_delete_files(USERS_PATH . $username)) return false;
  585. user_remove_from_cache($username, $cache);
  586. return true;
  587. }
  588.  
  589. function createLink($user, $nick, $target = ''){
  590. if(!empty($target)) $target = ' target="' . $target . '"';
  591. if($user != 'guest') {
  592. return '<a href="' . RCMS_ROOT_PATH . '?module=user.list&amp;user=' . $user . '"' . $target . '>' . strip_tags($nick) . '</a>';
  593. } elseif(!empty($nick)) {
  594. return $nick;
  595. } else {
  596. return __('Guest');
  597. }
  598. }
  599. }
  600. ?>

Documentation generated on Fri, 08 Jun 2007 12:21:38 +0300 by phpDocumentor 1.3.0RC3