PageRenderTime 58ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/saf/lib/Session/Source/Database.php

https://github.com/wokkie/sitellite
PHP | 665 lines | 348 code | 63 blank | 254 comment | 50 complexity | 74af5598d7fdb939dae1792492880e1f MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | Sitellite - Content Management System |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2007 Simian Systems |
  7. // +----------------------------------------------------------------------+
  8. // | This software is released under the GNU General Public License (GPL) |
  9. // | Please see the accompanying file docs/LICENSE for licensing details. |
  10. // | |
  11. // | You should have received a copy of the GPL Software License along |
  12. // | with this program; if not, write to Simian Systems, 242 Lindsay, |
  13. // | Winnipeg, MB, R3N 1H1, CANADA. The License is also available at |
  14. // | the following web site address: |
  15. // | <http://www.sitellite.org/index/license> |
  16. // +----------------------------------------------------------------------+
  17. // | Authors: John Luxford <lux@simian.ca> |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // This is the Database source driver package for saf.Session.
  21. //
  22. /**
  23. * This is the Database source driver package for saf.Session.
  24. *
  25. * New in 1.2:
  26. * - Added the getRole(), getTeam(), and isDisabled() methods.
  27. * - Added an $encryptionMethod property that allows the method of password
  28. * encryption to be changed.
  29. * - Added the $rolecolumn, $teamcolumn, and $disabledcolumn properties.
  30. *
  31. * <code>
  32. * <?php
  33. *
  34. * $s = new SessionSource_Database;
  35. *
  36. * $s->setProperties (array (
  37. * 'foo' => 'bar',
  38. * ));
  39. *
  40. * if ($s->authorize ($user, $pass, $id)) {
  41. * // in
  42. * } else {
  43. * // out
  44. * }
  45. *
  46. * ? >
  47. * </code>
  48. *
  49. * @package Session
  50. * @author John Luxford <lux@simian.ca>
  51. * @copyright Copyright (C) 2001-2003, Simian Systems Inc.
  52. * @license http://www.sitellite.org/index/license Simian Open Software License
  53. * @version 1.2, 2003-04-23, $Id: Database.php,v 1.4 2007/10/06 00:06:30 lux Exp $
  54. * @access public
  55. *
  56. */
  57. $GLOBALS['loader']->import ('saf.Session.Source');
  58. class SessionSource_Database extends SessionSource {
  59. /**
  60. * The name of the database table that contains the users.
  61. * Defaults to 'sitellite_user'.
  62. *
  63. * @access public
  64. *
  65. */
  66. var $tablename = 'sitellite_user';
  67. /**
  68. * The name of the username column in the database.
  69. * Defaults to 'username'.
  70. *
  71. * @access public
  72. *
  73. */
  74. var $usernamecolumn = 'username';
  75. /**
  76. * The name of the password column in the database.
  77. * Defaults to 'password'.
  78. *
  79. * @access public
  80. *
  81. */
  82. var $passwordcolumn = 'password';
  83. /**
  84. * The name of the session id column in the database.
  85. * Defaults to 'session_id'.
  86. *
  87. * @access public
  88. *
  89. */
  90. var $sessionidcolumn = 'session_id';
  91. /**
  92. * The name of the timeout column in the database.
  93. * Defaults to 'expires'.
  94. *
  95. * @access public
  96. *
  97. */
  98. var $timeoutcolumn = 'expires';
  99. /**
  100. * The name of the role column in the database.
  101. * Defaults to 'role'.
  102. *
  103. * @access public
  104. *
  105. */
  106. var $rolecolumn = 'role';
  107. /**
  108. * The name of the team column in the database.
  109. * Defaults to 'team'.
  110. *
  111. * @access public
  112. *
  113. */
  114. var $teamcolumn = 'team';
  115. /**
  116. * The name of the teams column in the database.
  117. * Defaults to 'team'.
  118. *
  119. * @access public
  120. *
  121. */
  122. var $teamscolumn = 'teams';
  123. /**
  124. * The name of the disabled column in the database.
  125. * Defaults to 'disabled'.
  126. *
  127. * @access public
  128. *
  129. */
  130. var $disabledcolumn = 'disabled';
  131. /**
  132. * The name of the public column in the database.
  133. * Defaults to 'public'.
  134. *
  135. * @access public
  136. *
  137. */
  138. var $publiccolumn = 'public';
  139. /**
  140. * The method to use to compare the password to the
  141. * encrypted copy from the source. Defaults to
  142. * 'better_crypt_compare', which uses a modification of the
  143. * crypt() function. $encryptionMethod must be any valid
  144. * value that can be passed as a first parameter to the
  145. * call_user_func() PHP function. The specified function
  146. * must accept the challenging password as a first parameter,
  147. * and the source password as a second. This makes it easy
  148. * to write alternate encryption methods, such as MD5.
  149. *
  150. * @access public
  151. *
  152. */
  153. var $encryptionMethod = 'better_crypt_compare';
  154. /**
  155. * Authorizes the user against the database.
  156. *
  157. * @access public
  158. * @param string $username
  159. * @param string $password
  160. * @param string $id
  161. * @return boolean
  162. *
  163. */
  164. function authorize ($username, $password, $id) {
  165. if (! empty ($username) && ! empty ($password)) {
  166. // retrieve old password and compare
  167. if ($this->sessObj->useID) {
  168. $res = db_fetch (
  169. sprintf ('select * from %s where %s = ? and (%s IS NULL or %s NOT LIKE "PENDING:%%")',
  170. $this->tablename,
  171. $this->usernamecolumn,
  172. $this->sessionidcolumn,
  173. $this->sessionidcolumn
  174. ),
  175. $username
  176. );
  177. } else {
  178. $res = db_fetch (
  179. sprintf ('select * from %s where %s = ?',
  180. $this->tablename,
  181. $this->usernamecolumn
  182. ),
  183. $username
  184. );
  185. }
  186. if (! is_object ($res)) {
  187. $this->error = db_error ();
  188. return false;
  189. }
  190. $this->resultObj =& $res;
  191. if (call_user_func ($this->encryptionMethod, $password, $res->{$this->passwordcolumn})) {
  192. // good
  193. if ($this->sessObj->useID) {
  194. $id = md5 (uniqid(mt_rand(),1));
  195. while (! db_execute (
  196. sprintf (
  197. 'update %s set %s = ?, %s = ? where %s = ?',
  198. $this->tablename,
  199. $this->sessionidcolumn,
  200. $this->timeoutcolumn,
  201. $this->usernamecolumn
  202. ),
  203. $id,
  204. date ('Y-m-d H:i:s', time() + $this->sessObj->timeout),
  205. $username
  206. )) {
  207. $id = md5 (uniqid (mt_rand (), 1));
  208. }
  209. return $id;
  210. } else {
  211. return true;
  212. }
  213. } else {
  214. return false;
  215. }
  216. } elseif ($this->sessObj->useID && ! empty ($id)) {
  217. // retrieve by session identifier
  218. if ($this->sessObj->timeout > 0) {
  219. $res = db_fetch (
  220. sprintf (
  221. 'select * from %s where %s = ? and %s > now() and (%s IS NULL or %s NOT LIKE "PENDING:%%")',
  222. $this->tablename,
  223. $this->sessionidcolumn,
  224. $this->timeoutcolumn,
  225. $this->sessionidcolumn,
  226. $this->sessionidcolumn
  227. ),
  228. $id
  229. );
  230. } else {
  231. $res = db_fetch (
  232. sprintf (
  233. 'select * from %s where %s = ? and (%s IS NULL or %s NOT LIKE "PENDING:%%")',
  234. $this->tablename,
  235. $this->sessionidcolumn,
  236. $this->sessionidcolumn,
  237. $this->sessionidcolumn
  238. ),
  239. $id
  240. );
  241. }
  242. if (! is_object ($res)) {
  243. $this->error = db_error ();
  244. return false;
  245. }
  246. $this->resultObj =& $res;
  247. $this->sessObj->username = $res->{$this->usernamecolumn};
  248. if ($this->sessObj->timeout > 0) {
  249. // reset server-side timeout
  250. // this is an "if" so as to allow for automatic logins
  251. $r = db_execute (
  252. sprintf (
  253. 'update %s set %s = ? where %s = ?',
  254. $this->tablename,
  255. $this->timeoutcolumn,
  256. $this->sessionidcolumn
  257. ),
  258. date ('Y-m-d H:i:s', time() + $this->sessObj->timeout),
  259. $id
  260. );
  261. }
  262. return $this->resultObj->{$this->usernamecolumn};
  263. } else {
  264. return false;
  265. }
  266. }
  267. /**
  268. * Closes the session with the source. In this case, explicitly
  269. * removes the user's session info from the database.
  270. *
  271. * @access public
  272. *
  273. */
  274. function close () {
  275. if ($this->sessObj->timeout > 0) {
  276. return db_execute (
  277. sprintf (
  278. 'update %s set %s = NULL, %s = ? where %s = ?',
  279. $this->tablename,
  280. $this->sessionidcolumn,
  281. $this->timeoutcolumn,
  282. $this->usernamecolumn
  283. ),
  284. "00000000000000",
  285. $this->sessObj->username
  286. );
  287. } else {
  288. return db_execute (
  289. sprintf (
  290. 'update %s set %s = NULL where %s = ?',
  291. $this->tablename,
  292. $this->sessionidcolumn,
  293. $this->usernamecolumn
  294. ),
  295. $this->sessObj->username
  296. );
  297. }
  298. }
  299. /**
  300. * Returns the role of the current user.
  301. *
  302. * @access public
  303. *
  304. */
  305. function getRole () {
  306. $res = $this->resultObj->{$this->rolecolumn};
  307. if (! $res) {
  308. return 'anonymous';
  309. }
  310. return $res;
  311. }
  312. /**
  313. * Returns the team of the current user.
  314. *
  315. * @access public
  316. *
  317. */
  318. function getTeam () {
  319. $res = $this->resultObj->{$this->teamcolumn};
  320. if (! $res) {
  321. return 'core';
  322. }
  323. return $res;
  324. }
  325. /**
  326. * Returns the list of teams whose documents are accessible by the
  327. * current user.
  328. *
  329. * @access public
  330. *
  331. */
  332. function getTeams () {
  333. $res = $this->resultObj->{$this->teamscolumn};
  334. if (! $res) {
  335. return array ();
  336. }
  337. return unserialize ($res);
  338. }
  339. /**
  340. * Returns the whether or not the current user account
  341. * is disabled.
  342. *
  343. * @access public
  344. *
  345. */
  346. function isDisabled () {
  347. $res = $this->resultObj->{$this->disabledcolumn};
  348. if (! $res) {
  349. return false;
  350. } elseif ($res === true || $res == 'yes') {
  351. return true;
  352. }
  353. return false;
  354. }
  355. /**
  356. * Retrieves a user by their username.
  357. *
  358. * @access public
  359. *
  360. */
  361. function getUser ($user) {
  362. return db_single ('select * from ' . $this->tablename . ' where ' . $this->usernamecolumn . ' = ?', $user);
  363. }
  364. /**
  365. * Retrieves a user by their email address.
  366. *
  367. * @access public
  368. *
  369. */
  370. function getUserByEmail ($email) {
  371. return db_shift ('select ' . $this->usernamecolumn . ' from ' . $this->tablename . ' where email = ?', $email);
  372. }
  373. /**
  374. * Determines whether the specified verification key is valid.
  375. *
  376. * @access public
  377. *
  378. */
  379. function isValidKey ($user, $key) {
  380. return db_shift (
  381. sprintf (
  382. 'select count(*) from %s where %s = ? and %s = ?',
  383. $this->tablename,
  384. $this->usernamecolumn,
  385. $this->sessionidcolumn
  386. ),
  387. $user,
  388. $key
  389. );
  390. }
  391. /**
  392. * Adds a new user.
  393. *
  394. * @access public
  395. *
  396. */
  397. function add ($data) {
  398. list ($one, $two, $bind) = $this->_add ($data);
  399. $res = db_execute (
  400. sprintf (
  401. 'insert into %s (%s) values (%s)',
  402. $this->tablename,
  403. $one,
  404. $two
  405. ),
  406. $bind
  407. );
  408. if (! $res) {
  409. $this->error = db_error ();
  410. return false;
  411. }
  412. return true;
  413. }
  414. /**
  415. * Joins the list of data into a piece of SQL.
  416. *
  417. * @access private
  418. *
  419. */
  420. function _add ($data) {
  421. $one = '';
  422. $two = '';
  423. $bind = array ();
  424. $join = '';
  425. foreach ($data as $key => $value) {
  426. if ($key == $this->teamscolumn) {
  427. $value = serialize ($value);
  428. }
  429. $one .= $join . $key;
  430. $two .= $join . '?';
  431. $bind[] = $value;
  432. $join = ', ';
  433. }
  434. return array ($one, $two, $bind);
  435. }
  436. /**
  437. * Updates the data of the specified user.
  438. *
  439. * @access public
  440. *
  441. */
  442. function update ($data, $user) {
  443. $res = db_execute (
  444. sprintf (
  445. 'update %s set %s where %s = ?',
  446. $this->tablename,
  447. $this->_update ($data),
  448. $this->usernamecolumn
  449. ),
  450. $user
  451. );
  452. if (! $res) {
  453. $this->error = db_error ();
  454. return false;
  455. }
  456. return true;
  457. }
  458. /**
  459. * Joins the list of data into a piece of SQL.
  460. *
  461. * @access private
  462. *
  463. */
  464. function _update ($data) {
  465. $out = '';
  466. $op = '';
  467. foreach ($data as $key => $value) {
  468. if ($key == $this->teamscolumn) {
  469. $value = serialize ($value);
  470. }
  471. $out .= $op . $key . ' = ' . db_quote ($value);
  472. $op = ', ';
  473. }
  474. return $out;
  475. }
  476. /**
  477. * Removes the specified user.
  478. *
  479. * @access public
  480. *
  481. */
  482. function delete ($user) {
  483. $res = db_execute (
  484. sprintf (
  485. 'delete from %s where %s = ?',
  486. $this->tablename,
  487. $this->usernamecolumn
  488. ),
  489. $user
  490. );
  491. if (! $res) {
  492. $this->error = db_error ();
  493. return false;
  494. }
  495. return true;
  496. }
  497. /**
  498. * Retrieves the total number of users. $role and $team allow you to
  499. * retrieve a total for specific roles and teams.
  500. *
  501. * @access public
  502. *
  503. */
  504. function getTotal ($role, $team, $public) {
  505. $sql = 'select count(*) from ' . $this->tablename;
  506. $bind = array ();
  507. $pre = ' where ';
  508. if ($role) {
  509. $sql .= $pre . $this->rolecolumn . ' = ?';
  510. $bind[] = $role;
  511. $pre = ' and ';
  512. }
  513. if ($team) {
  514. $sql .= $pre . $this->teamcolumn . ' = ?';
  515. $bind[] = $team;
  516. $pre = ' and ';
  517. }
  518. if ($public) {
  519. $sql .= $pre . $this->publiccolumn . ' = ?';
  520. $bind[] = 'yes';
  521. }
  522. return db_shift ($sql, $bind);
  523. }
  524. /**
  525. * Retrieves the total number of active (ie. currently logged in) users.
  526. *
  527. * @access public
  528. *
  529. */
  530. function getActive () {
  531. $sql = 'select count(*) from ' . $this->tablename . ' where ' . $this->sessionidcolumn . ' is not null and ' . $this->timeoutcolumn . ' >= ?';
  532. $bind = array (date ('Y-m-d H:i:s', time() - $this->sessObj->timeout));
  533. return db_shift ($sql, $bind);
  534. }
  535. /**
  536. * Retrieves a list of users.
  537. *
  538. * @access public
  539. *
  540. */
  541. function getList ($offset, $limit, $order, $ascdesc, $role, $team, $name, $disabled, $public, $teams) {
  542. $sql = 'select * from ' . $this->tablename;
  543. $bind = array ();
  544. $pre = ' where ';
  545. if ($role) {
  546. $sql .= $pre . $this->rolecolumn . ' = ?';
  547. $bind[] = $role;
  548. $pre = ' and ';
  549. }
  550. if ($team) {
  551. $sql .= $pre . $this->teamcolumn . ' = ?';
  552. $bind[] = $team;
  553. $pre = ' and ';
  554. }
  555. if ($name) {
  556. $sql .= $pre . '(lastname like ? or firstname like ? or username like ?)';
  557. $bind[] = '%' . $name . '%';
  558. $bind[] = '%' . $name . '%';
  559. $bind[] = '%' . $name . '%';
  560. $pre = ' and ';
  561. }
  562. if ($disabled) {
  563. $sql .= $pre . 'disabled = ?';
  564. $bind[] = $disabled;
  565. $pre = ' and ';
  566. }
  567. if ($public) {
  568. $sql .= $pre . 'public = ?';
  569. $bind[] = $public;
  570. $pre = ' and ';
  571. }
  572. if ($teams) {
  573. $sql .= $pre . '(teams like ' . db_quote ('%' . $teams . '%') . ' or teams = ?)';
  574. $bind[] = 'a:1:{s:3:"all";s:2:"rw";}';
  575. $pre = ' and ';
  576. }
  577. if ($order) {
  578. $sql .= ' order by ' . $order;
  579. if ($ascdesc) {
  580. $sql .= ' ' . $ascdesc;
  581. }
  582. }
  583. $q = db_query ($sql);
  584. if ($q->execute ($bind)) {
  585. $this->total = $q->rows ();
  586. if ($offset == false && $limit == false) {
  587. $res = array ();
  588. while ($row = $q->fetch ()) {
  589. $res[] = $row;
  590. }
  591. } else {
  592. $res = $q->fetch ($offset, $limit);
  593. }
  594. $q->free ();
  595. return $res;
  596. } else {
  597. $this->error = $q->error ();
  598. return false;
  599. }
  600. }
  601. }
  602. ?>