PageRenderTime 26ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/dms/user.class.php

https://github.com/goldfrapper/DMS
PHP | 403 lines | 322 code | 54 blank | 27 comment | 63 complexity | 6174ffc89c1faac9f85896509357c489 MD5 | raw file
  1. <?php
  2. /**
  3. * User, Group and Session administration
  4. * @author Tom Van de Putte
  5. * @date Friday 06 August 2010
  6. *
  7. */
  8. class DMS_User_Service
  9. {
  10. public static function login()
  11. {
  12. $code = DMS_System_Service::get('code','POST');
  13. $login = DMS_System_Service::get('login','POST');
  14. $pass = DMS_System_Service::get('pass','POST');
  15. if($login===null || $pass===null) {
  16. DMS_System_Service::redirect('?p=login&e=empty');
  17. }
  18. # Try to login user
  19. try {
  20. $user = new DMS_User_User();
  21. $user->login($login, $pass);
  22. }
  23. catch( DMS_Exceptions_InvalidUser $e) {
  24. DMS_System_Service::redirect('?p=login&e=invalid');
  25. }
  26. catch( Exception $e) {
  27. var_dump($e); die();
  28. }
  29. # Start session
  30. try {
  31. // Try to revert to a previous (open) session.
  32. $c = DMS_User_Session::getLastOpenSessionForUser($user);
  33. if($c!==false) {
  34. /**
  35. * FIXME: Something strange; When there is only one session for the user
  36. */
  37. if($c!=$code) DMS_User_Session::clearSession($code);
  38. $code = $c;
  39. }
  40. $sess = DMS_User_Factory::getSession($code);
  41. $sess->user = $user;
  42. $sess->login();
  43. } catch( Exception $e) {
  44. var_dump($e); die();
  45. }
  46. }
  47. public static function logout()
  48. {
  49. $code = DMS_System_Service::get('code');
  50. $sess = DMS_User_Factory::getSession($code);
  51. try {
  52. $sess->user->logout();
  53. $sess->logout();
  54. } catch( DMS_Exceptions_CannotUpdateSession $e) {
  55. echo 'failed to log out'; return;
  56. }
  57. echo 'logged out';
  58. }
  59. // Update sessions mdate
  60. public static function updateSessionTime($code)
  61. {
  62. $sess = DMS_User_Factory::getSession($code);
  63. $sess->updateSessionTime();
  64. }
  65. }
  66. class DMS_User_Factory
  67. {
  68. static private $sess;
  69. /**
  70. * Returns session object for given session code or creates a new session
  71. * then checks for send headers and sets cookie if not already set
  72. */
  73. public static function getSession($code=null)
  74. {
  75. if(isset(self::$sess) && self::$sess instanceof DMS_User_Session) {
  76. return self::$sess;
  77. }
  78. if(!isset($code) && isset($_COOKIE['DMS_SESS'])) {
  79. $code = $_COOKIE['DMS_SESS'];
  80. } elseif(empty($code)) $code = null;
  81. try {
  82. $sess = new DMS_User_Session($code);
  83. } catch(DMS_Exceptions_InvalidSessionCode $e) {
  84. $sess = new DMS_User_Session();
  85. } catch( DMS_Exceptions_LoggedOutSession $e) {
  86. $sess = self::getSession('');
  87. }
  88. self::$sess = $sess;
  89. $s = false;
  90. foreach(headers_list() as $h) {
  91. if(strpos($h,'Set-Cookie')===0) $s = true;
  92. }
  93. if(!$s) setcookie('DMS_SESS', $sess->code, 0, '/');
  94. return $sess;
  95. }
  96. }
  97. class DMS_User_Session implements DMS_Models_iModel
  98. {
  99. public $id;
  100. public $user;
  101. public $code;
  102. public $cdate;
  103. public $mdate;
  104. public $status;
  105. public function __construct($code=null)
  106. {
  107. $pdo = new DMS_DB_PDO();
  108. if(is_null($code)) {
  109. $this->code = md5(uniqid('dms_'));
  110. $r = $pdo->exec("INSERT INTO dms_sessions (code,mdate) VALUES('{$this->code}',NOW());");
  111. if(!$r) {
  112. throw new Exception();
  113. }
  114. } else $this->code = $code;
  115. $stat = $pdo->query("SELECT * FROM dms_sessions WHERE code='{$this->code}';");
  116. if(!$stat instanceOf PDOStatement) {
  117. throw new Exception();
  118. }
  119. $all = $stat->fetchAll(PDO::FETCH_ASSOC);
  120. if(!sizeof($all)) {
  121. throw new DMS_Exceptions_InvalidSessionCode();
  122. }
  123. $this->id = $all[0]['id'];
  124. $this->cdate = $all[0]['cdate'];
  125. $this->mdate = $all[0]['mdate'];
  126. $this->status = $all[0]['status'];
  127. if($this->status==0) {
  128. throw new DMS_Exceptions_LoggedOutSession();
  129. }
  130. $user_id = $all[0]['user_id'];
  131. if(is_numeric($user_id)) $this->user = new DMS_User_User($user_id);
  132. }
  133. public function login()
  134. {
  135. $pdo = new DMS_DB_PDO();
  136. $r = $pdo->exec("UPDATE dms_sessions SET user_id={$this->user->id} WHERE id={$this->id};");
  137. if($r===false) throw new DMS_Exceptions_CannotUpdateSession();
  138. }
  139. public function logout()
  140. {
  141. $pdo = new DMS_DB_PDO();
  142. $r = $pdo->exec("UPDATE dms_sessions SET status=0 WHERE id={$this->id};");
  143. if($r===false) throw new DMS_Exceptions_CannotUpdateSession();
  144. return true;
  145. }
  146. public function updateSessionTime()
  147. {
  148. $pdo = new DMS_DB_PDO();
  149. $r = $pdo->exec("UPDATE dms_sessions SET mdate=NOW() WHERE id={$this->id};");
  150. if($r===false) throw new DMS_Exceptions_CannotUpdateSession();
  151. }
  152. public static function getLastOpenSessionForUser(DMS_User_User $user)
  153. {
  154. $pdo = new DMS_DB_PDO();
  155. $sql = "SELECT code FROM dms_sessions WHERE user_id={$user->id} ORDER BY mdate DESC LIMIT 1;";
  156. $stat = $pdo->query($sql);
  157. if(!$stat instanceOf PDOStatement) throw new Exception();
  158. $all = $stat->fetchAll(PDO::FETCH_ASSOC);
  159. if(!sizeof($all)) return false;
  160. return $all[0]['code'];
  161. }
  162. public static function clearSession($code)
  163. {
  164. $pdo = new DMS_DB_PDO();
  165. $r = $pdo->exec("DELETE FROM dms_sessions WHERE code='$code';");
  166. if($r===false) throw new DMS_Exceptions_CannotUpdateSession();
  167. }
  168. }
  169. class DMS_User_User implements DMS_Models_iModel
  170. {
  171. const EMPTY_VALUES = -1;
  172. const BAD_USERNAME = -2;
  173. const BAD_EMAIL = -4;
  174. const USER_EXISTS = -8;
  175. const EMAIL_EXISTS = -16;
  176. const USER_ANOMYMOUS = -32;
  177. public $id = 0;
  178. public $name = 'anonymous';
  179. public $fname = 'Anonymous';
  180. public $email = 'anonymous@agx.eu';
  181. private $status = 0;
  182. private $groups = array();
  183. public function __construct($user_id=null)
  184. {
  185. if(is_numeric($user_id) & $user_id!=0) {
  186. $pdo = new DMS_DB_PDO();
  187. $stat = $pdo->query("SELECT * FROM dms_users WHERE id=$user_id;");
  188. $this->_setDataFromDB($stat);
  189. }
  190. }
  191. public function login($login, $pass)
  192. {
  193. $pdo = new DMS_DB_PDO();
  194. $email_login = DMS_System_Settings::getPublic('user_email_login');
  195. $col = ($email_login)? 'email':'name';
  196. $stat = $pdo->query("SELECT * FROM dms_users WHERE $col='$login' AND pass=SHA1('$pass');");
  197. $this->_setDataFromDB($stat);
  198. $r = $pdo->exec("UPDATE dms_users SET status=1 WHERE id={$this->id};");
  199. if($r===false) throw new Exception();
  200. $this->status = 1;
  201. return true;
  202. }
  203. public function validate()
  204. {
  205. # Empty values
  206. if( empty($this->name) && empty($this->email)) {
  207. return DMS_User_User::EMPTY_VALUES;
  208. }
  209. # If user is still anonymous
  210. if(!$this->id && $this->name=='anonymous') return self::USER_ANOMYMOUS;
  211. $o = 0;
  212. # Malformatted username?
  213. if(strlen($this->name>20) || !preg_match('/^[a-zA-Z0-9]+$/',$this->name)) {
  214. $o = self::BAD_USERNAME;
  215. }
  216. # Email is not an email address
  217. if(!preg_match('/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i',$this->email)) {
  218. $o += DMS_User_User::BAD_EMAIL;
  219. }
  220. if($o!=0) return $o;
  221. if(!$this->id) {
  222. # Does username exists?
  223. $pdo = new DMS_DB_PDO();
  224. $stat = $pdo->query("SELECT COUNT(*) FROM dms_users WHERE name='{$this->name}'");
  225. $all = $stat->fetchAll(PDO::FETCH_NUM);
  226. if($all===false || empty($all) || $all[0][0]!=0) $o = DMS_User_User::USER_EXISTS;
  227. # Does email address exists?
  228. $stat = $pdo->query("SELECT COUNT(*) FROM dms_users WHERE email='{$this->email}'");
  229. $all = $stat->fetchAll(PDO::FETCH_NUM);
  230. if($all===false || empty($all) || $all[0][0]!=0) $o += DMS_User_User::EMAIL_EXISTS;
  231. }
  232. if($o!=0) return $o;
  233. return true;
  234. }
  235. public function save( $pass = null )
  236. {
  237. if(!$this->validate()) throw new DMS_Exceptions_InvalidUserData();
  238. if($this->id!=0) {
  239. $sql = "UPDATE dms_users SET name='{$this->name}',fname='{$this->fname}',email='{$this->email}'";
  240. if($pass!==null) $sql.= ",pass=SHA1('$pass')";
  241. $sql.= " WHERE id={$this->id}";
  242. } else {
  243. if($pass!==null) {
  244. $sql = 'INSERT INTO dms_users (name,pass,fname,email) VALUES (';
  245. $sql.= "'{$this->name}',SHA1('$pass'),'{$this->fname}','{$this->email}') ";
  246. } else {
  247. $sql = 'INSERT INTO dms_users (name,fname,email) VALUES (';
  248. $sql.= "'{$this->name}','{$this->fname}','{$this->email}')";
  249. }
  250. }
  251. $pdo = new DMS_DB_PDO();
  252. $r = $pdo->exec($sql);
  253. if($r===false) throw new DMS_Exceptions_CannotUpdateUser();
  254. if(!$this->id) $this->id = $pdo->lastInsertId();
  255. }
  256. public function resetPass( $name = null, $email = null, $new_pass )
  257. {
  258. if($name===null && $email===null) return;
  259. $sql = "SELECT * FROM dms_users WHERE ";
  260. $sql .= ($name!==null && !empty($name))? "name='$name'" : "email='$email'";
  261. $pdo = new DMS_DB_PDO();
  262. $stat = $pdo->query($sql);
  263. try {
  264. $this->_setDataFromDB($stat);
  265. } catch(Exception $e) {
  266. throw new DMS_Exceptions_CannotResetUser();
  267. }
  268. /**
  269. * BUG: The status of the user should be altered and a reset password request mail
  270. * should be send. Only 1 mail should be send while status is unchanged.
  271. */
  272. $r = $pdo->exec("UPDATE dms_users SET pass=SHA1('$new_pass') WHERE id={$this->id}");
  273. if($r===false) throw new DMS_Exceptions_CannotResetUser();
  274. return true;
  275. }
  276. public function logout()
  277. {
  278. if(!$id) return;
  279. $pdo = new DMS_DB_PDO();
  280. $r = $pdo->exec("UPDATE dms_users SET status=0 WHERE id={$this->id};");
  281. if($r===false) throw new DMS_Exceptions_CannotLogoutUser();
  282. $this->status = 0;
  283. return true;
  284. }
  285. public function getGroupIterator()
  286. {
  287. $pdo = new DMS_DB_PDO();
  288. $stat = $pdo->query("SELECT group_id AS id FROM dms_usergroups WHERE user_id={$this->id};");
  289. return new DMS_User_GroupIterator($stat);
  290. }
  291. private function _setDataFromDB( PDOStatement $stat )
  292. {
  293. if($stat===false) return false;
  294. if($stat->rowCount()==0) {
  295. throw new DMS_Exceptions_InvalidUser();
  296. }
  297. $all = $stat->fetchAll(PDO::FETCH_ASSOC);
  298. if(!sizeof($all)) {
  299. throw new Exception();
  300. }
  301. $this->id = $all[0]['id'];
  302. $this->name = $all[0]['name'];
  303. $this->fname = $all[0]['fname'];
  304. $this->email = $all[0]['email'];
  305. $this->status = $all[0]['status'];
  306. }
  307. }
  308. class DMS_User_Group implements DMS_Models_iModel
  309. {
  310. public $id;
  311. public $name;
  312. private $appLinks = array();
  313. public function __construct($id)
  314. {
  315. if(!is_numeric($id)) {
  316. throw new Exception();
  317. }
  318. $this->id=$id;
  319. $pdo = new DMS_DB_PDO();
  320. $st = $pdo->query("SELECT appID FROM dms_groupperms WHERE group_id=$id;");
  321. while(($c = $st->fetch(PDO::FETCH_NUM))!==false) {
  322. $this->appLinks[] = $c[0];
  323. }
  324. }
  325. public function getName()
  326. {
  327. if(empty($this->name)) {
  328. $pdo = new DMS_DB_PDO();
  329. $st = $pdo->query("SELECT name FROM dms_groups WHERE id={$this->id};");
  330. if(($c = $st->fetchAll(PDO::FETCH_NUM))!==false && !empty($c[0])) {
  331. $this->name = $c[0][0];
  332. }
  333. }
  334. return $this->name;
  335. }
  336. public function hasPermission(DMS_Models_AppLink $appLink)
  337. {
  338. if(in_array($appLink->appID,$this->appLinks)) return true;
  339. return false;
  340. }
  341. }
  342. class DMS_User_GroupIterator extends DMS_DB_PDOIterator
  343. {
  344. public function current()
  345. {
  346. $c = parent::current();
  347. return new DMS_User_Group($c['id']);
  348. }
  349. }