PageRenderTime 71ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/User.php

https://github.com/whale2/users
PHP | 2141 lines | 1845 code | 195 blank | 101 comment | 160 complexity | 4c3237ec2fbe9928208ec70942fc96e2 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * User class
  4. */
  5. require_once(dirname(__FILE__).'/config.php');
  6. require_once(dirname(__FILE__).'/Account.php');
  7. require_once(dirname(__FILE__).'/CookieStorage.php');
  8. require_once(dirname(__FILE__).'/CampaignTracker.php');
  9. class User
  10. {
  11. /*
  12. * Checks if user is logged in and returns use object or redirects to login page
  13. */
  14. public static function require_login($impersonate = true)
  15. {
  16. $user = self::get($impersonate);
  17. if (!is_null($user))
  18. {
  19. return $user;
  20. }
  21. else
  22. {
  23. User::redirectToLogin();
  24. }
  25. }
  26. /*
  27. * Checks if user is logged in and returns use object or null if user is not logged in
  28. * Disabled users are not allowed to login unless they are being impersonated
  29. */
  30. public static function get($impersonate = true)
  31. {
  32. $storage = new MrClay_CookieStorage(array(
  33. 'secret' => UserConfig::$SESSION_SECRET,
  34. 'mode' => MrClay_CookieStorage::MODE_ENCRYPT,
  35. 'path' => UserConfig::$SITEROOTURL,
  36. 'httponly' => true
  37. ));
  38. $userid = $storage->fetch(UserConfig::$session_userid_key);
  39. if (is_numeric($userid)) {
  40. $user = self::getUser($userid);
  41. if (is_null($user)) {
  42. return null;
  43. }
  44. // only forsing password reset on non-impersonated users
  45. if ($user->requiresPasswordReset() &&
  46. !UsernamePasswordAuthenticationModule::$IGNORE_PASSWORD_RESET)
  47. {
  48. User::redirectToPasswordReset();
  49. }
  50. // don't event try impersonating if not admin
  51. if (!$impersonate || !$user->isAdmin()) {
  52. if ($user->isDisabled()) {
  53. return null;
  54. }
  55. return $user;
  56. }
  57. // now, let's check impersonation
  58. $impersonated_userid = $storage->fetch(UserConfig::$impersonation_userid_key);
  59. $impersonated_user = self::getUser($impersonated_userid);
  60. // do not impersonate unknown user or the same user
  61. if (is_null($impersonated_user) || $user->isTheSameAs($impersonated_user)) {
  62. if ($user->isDisabled()) {
  63. return null;
  64. }
  65. return $user;
  66. }
  67. $impersonated_user->impersonator = $user;
  68. return $impersonated_user;
  69. } else {
  70. return null;
  71. }
  72. }
  73. public static function updateReturnActivity() {
  74. $storage = new MrClay_CookieStorage(array(
  75. 'secret' => UserConfig::$SESSION_SECRET,
  76. 'mode' => MrClay_CookieStorage::MODE_ENCRYPT,
  77. 'path' => UserConfig::$SITEROOTURL,
  78. 'httponly' => true
  79. ));
  80. $last = $storage->fetch(UserConfig::$last_login_key);
  81. if (!$storage->store(UserConfig::$last_login_key, time())) {
  82. throw new Exception(implode('; ', $storage->errors));
  83. }
  84. $user = self::get();
  85. if (!is_null($user) && $last > 0
  86. && $last < time() - UserConfig::$last_login_session_length * 60)
  87. {
  88. if ($last > time() - 86400) {
  89. $user->recordActivity(USERBASE_ACTIVITY_RETURN_DAILY);
  90. } else if ($last > time() - 7 * 86400) {
  91. $user->recordActivity(USERBASE_ACTIVITY_RETURN_WEEKLY);
  92. } else if ($last > time() - 30 * 86400) {
  93. $user->recordActivity(USERBASE_ACTIVITY_RETURN_MONTHLY);
  94. }
  95. }
  96. }
  97. private function setReferer() {
  98. $referer = CampaignTracker::getReferer();
  99. if (is_null($referer)) {
  100. return;
  101. }
  102. $db = UserConfig::getDB();
  103. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET referer = ? WHERE id = ?'))
  104. {
  105. if (!$stmt->bind_param('si', $referer, $this->userid))
  106. {
  107. throw new Exception("Can't bind parameter".$stmt->error);
  108. }
  109. if (!$stmt->execute())
  110. {
  111. throw new Exception("Can't execute statement: ".$stmt->error);
  112. }
  113. $stmt->close();
  114. }
  115. else
  116. {
  117. throw new Exception("Can't prepare statement: ".$db->error);
  118. }
  119. }
  120. public function getReferer() {
  121. $db = UserConfig::getDB();
  122. $referer = null;
  123. if ($stmt = $db->prepare('SELECT referer FROM '.UserConfig::$mysql_prefix.'users WHERE id = ?'))
  124. {
  125. if (!$stmt->bind_param('i', $this->userid))
  126. {
  127. throw new Exception("Can't bind parameter".$stmt->error);
  128. }
  129. if (!$stmt->bind_result($referer))
  130. {
  131. throw new Exception("Can't bind parameter".$stmt->error);
  132. }
  133. if (!$stmt->execute())
  134. {
  135. throw new Exception("Can't execute statement: ".$stmt->error);
  136. }
  137. $stmt->fetch();
  138. $stmt->close();
  139. }
  140. else
  141. {
  142. throw new Exception("Can't prepare statement: ".$db->error);
  143. }
  144. return $referer;
  145. }
  146. private function setRegCampaign() {
  147. $campaign = CampaignTracker::getCampaign();
  148. if (is_null($campaign) || !$campaign) {
  149. return;
  150. }
  151. $db = UserConfig::getDB();
  152. $cmp_source_id = null;
  153. if (array_key_exists('cmp_source', $campaign)) {
  154. $cmp_source_id = CampaignTracker::getCampaignSourceID($campaign['cmp_source']);
  155. }
  156. $cmp_medium_id = null;
  157. if (array_key_exists('cmp_medium', $campaign)) {
  158. $cmp_medium_id = CampaignTracker::getCampaignMediumID($campaign['cmp_medium']);
  159. }
  160. $cmp_keywords_id = null;
  161. if (array_key_exists('cmp_keywords', $campaign)) {
  162. $cmp_keywords_id = CampaignTracker::getCampaignKeywordsID($campaign['cmp_keywords']);
  163. }
  164. $cmp_content_id = null;
  165. if (array_key_exists('cmp_content', $campaign)) {
  166. $cmp_content_id = CampaignTracker::getCampaignContentID($campaign['cmp_content']);;
  167. }
  168. $cmp_name_id = null;
  169. if (array_key_exists('cmp_name', $campaign)) {
  170. $cmp_name_id = CampaignTracker::getCampaignNameID($campaign['cmp_name']);
  171. }
  172. // update user record with compaign IDs
  173. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET
  174. reg_cmp_source_id = ?,
  175. reg_cmp_medium_id = ?,
  176. reg_cmp_keywords_id = ?,
  177. reg_cmp_content_id = ?,
  178. reg_cmp_name_id = ?
  179. WHERE id = ?'))
  180. {
  181. if (!$stmt->bind_param('sssssi',
  182. $cmp_source_id,
  183. $cmp_medium_id,
  184. $cmp_keywords_id,
  185. $cmp_content_id,
  186. $cmp_name_id,
  187. $this->userid))
  188. {
  189. throw new Exception("Can't bind parameter".$stmt->error);
  190. }
  191. if (!$stmt->execute())
  192. {
  193. throw new Exception("Can't execute statement: ".$stmt->error);
  194. }
  195. $stmt->close();
  196. }
  197. else
  198. {
  199. throw new Exception("Can't prepare statement: ".$db->error);
  200. }
  201. }
  202. private function init()
  203. {
  204. $db = UserConfig::getDB();
  205. if (UserConfig::$useAccounts) {
  206. $userid = $this->getID();
  207. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix.'user_preferences (user_id) VALUES (?)'))
  208. {
  209. if (!$stmt->bind_param('i', $userid))
  210. {
  211. throw new Exception("Can't bind parameter");
  212. }
  213. if (!$stmt->execute())
  214. {
  215. throw new Exception("Can't update user preferences (set current account)");
  216. }
  217. $stmt->close();
  218. }
  219. else
  220. {
  221. throw new Exception("Can't update user preferences (set current account)");
  222. }
  223. $personal = Account::createAccount($this->getName(), UserConfig::$default_plan, NULL, $this, Account::ROLE_ADMIN, NULL);
  224. $personal->setAsCurrent($this);
  225. }
  226. if (!is_null(UserConfig::$onCreate))
  227. {
  228. call_user_func_array(UserConfig::$onCreate, array($this));
  229. }
  230. if (!is_null(UserConfig::$email_module)) {
  231. UserConfig::$email_module->registerSubscriber($this);
  232. }
  233. }
  234. /*
  235. * create new user based on Google Friend Connect info
  236. */
  237. public static function createNewGoogleFriendConnectUser($name, $googleid, $userpic)
  238. {
  239. $name = mb_convert_encoding($name, 'UTF-8');
  240. $db = UserConfig::getDB();
  241. $user = null;
  242. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix."users (name, regmodule) VALUES (?, 'google' )"))
  243. {
  244. if (!$stmt->bind_param('s', $name))
  245. {
  246. throw new Exception("Can't bind parameter".$stmt->error);
  247. }
  248. if (!$stmt->execute())
  249. {
  250. throw new Exception("Can't execute statement: ".$stmt->error);
  251. }
  252. $id = $stmt->insert_id;
  253. $stmt->close();
  254. }
  255. else
  256. {
  257. throw new Exception("Can't prepare statement: ".$db->error);
  258. }
  259. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix.'googlefriendconnect (user_id, google_id, userpic) VALUES (?, ?, ?)'))
  260. {
  261. if (!$stmt->bind_param('iss', $id, $googleid, $userpic))
  262. {
  263. throw new Exception("Can't bind parameter".$stmt->error);
  264. }
  265. if (!$stmt->execute())
  266. {
  267. throw new Exception("Can't execute statement: ".$stmt->error);
  268. }
  269. $stmt->close();
  270. }
  271. else
  272. {
  273. throw new Exception("Can't prepare statement: ".$db->error);
  274. }
  275. $user = self::getUser($id);
  276. $user->setReferer();
  277. $user->setRegCampaign();
  278. $user->init();
  279. return $user;
  280. }
  281. /*
  282. * create new user based on facebook info
  283. */
  284. public static function createNewFacebookUser($name, $fb_id, $me = null)
  285. {
  286. $name = mb_convert_encoding($name, 'UTF-8');
  287. $db = UserConfig::getDB();
  288. $email = null;
  289. if (array_key_exists('email', $me)) {
  290. $email = $me['email'];
  291. }
  292. $user = null;
  293. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix."users (name, regmodule, email, fb_id) VALUES (?, 'facebook', ?, ?)"))
  294. {
  295. if (!$stmt->bind_param('ssi', $name, $email, $fb_id))
  296. {
  297. throw new Exception("Can't bind parameter".$stmt->error);
  298. }
  299. if (!$stmt->execute())
  300. {
  301. throw new Exception("Can't execute statement: ".$stmt->error);
  302. }
  303. $id = $stmt->insert_id;
  304. $stmt->close();
  305. }
  306. else
  307. {
  308. throw new Exception("Can't prepare statement: ".$db->error);
  309. }
  310. $user = self::getUser($id);
  311. $user->setReferer();
  312. $user->setRegCampaign();
  313. $user->init();
  314. return $user;
  315. }
  316. /*
  317. * create new user without credentials
  318. */
  319. public static function createNewWithoutCredentials($name, $email = null)
  320. {
  321. $name = mb_convert_encoding($name, 'UTF-8');
  322. $db = UserConfig::getDB();
  323. $user = null;
  324. $email = filter_var($email, FILTER_VALIDATE_EMAIL);
  325. if ($email === FALSE) {
  326. $email = null;
  327. }
  328. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix.'users (name, email) VALUES (?, ?)'))
  329. {
  330. if (!$stmt->bind_param('ss', $name, $email))
  331. {
  332. throw new Exception("Can't bind parameter".$stmt->error);
  333. }
  334. if (!$stmt->execute())
  335. {
  336. throw new Exception("Can't execute statement: ".$stmt->error);
  337. }
  338. $id = $stmt->insert_id;
  339. $stmt->close();
  340. }
  341. else
  342. {
  343. throw new Exception("Can't prepare statement: ".$db->error);
  344. }
  345. $user = self::getUser($id);
  346. $user->setReferer();
  347. $user->setRegCampaign();
  348. $user->init();
  349. return $user;
  350. }
  351. /*
  352. * create new user
  353. */
  354. public static function createNew($name, $username, $email, $password)
  355. {
  356. $name = mb_convert_encoding($name, 'UTF-8');
  357. $username = mb_convert_encoding($username, 'UTF-8');
  358. $db = UserConfig::getDB();
  359. $user = null;
  360. $salt = uniqid();
  361. $pass = sha1($salt.$password);
  362. if ($stmt = $db->prepare('INSERT INTO '.UserConfig::$mysql_prefix."users (regmodule, name, username, email, pass, salt) VALUES ('userpass', ?, ?, ?, ?, ?)"))
  363. {
  364. if (!$stmt->bind_param('sssss', $name, $username, $email, $pass, $salt))
  365. {
  366. throw new Exception("Can't bind parameter".$stmt->error);
  367. }
  368. if (!$stmt->execute())
  369. {
  370. throw new Exception("Can't execute statement: ".$stmt->error);
  371. }
  372. $id = $stmt->insert_id;
  373. $stmt->close();
  374. }
  375. else
  376. {
  377. throw new Exception("Can't prepare statement: ".$db->error);
  378. }
  379. $user = self::getUser($id);
  380. $user->setReferer();
  381. $user->setRegCampaign();
  382. $user->init();
  383. return $user;
  384. }
  385. /*
  386. * delete this user
  387. */
  388. public function delete()
  389. {
  390. $username = mb_convert_encoding($this -> username, 'UTF-8');
  391. $db = UserConfig::getDB();
  392. if ($stmt = $db->prepare('DELETE FROM '.UserConfig::$mysql_prefix."users WHERE username = ?"))
  393. {
  394. if (!$stmt->bind_param('s', $username))
  395. {
  396. throw new Exception("Can't bind parameter".$stmt->error);
  397. }
  398. if (!$stmt->execute())
  399. {
  400. throw new Exception("Can't execute statement: ".$stmt->error);
  401. }
  402. $stmt->close();
  403. }
  404. else
  405. {
  406. throw new Exception("Can't prepare statement: ".$db->error);
  407. }
  408. }
  409. /*
  410. * Returns total number of users in the system
  411. */
  412. public static function getTotalUsers()
  413. {
  414. $db = UserConfig::getDB();
  415. $total = 0;
  416. if ($stmt = $db->prepare('SELECT COUNT(*) FROM '.UserConfig::$mysql_prefix.'users'))
  417. {
  418. if (!$stmt->execute())
  419. {
  420. throw new Exception("Can't execute statement: ".$stmt->error);
  421. }
  422. if (!$stmt->bind_result($total))
  423. {
  424. throw new Exception("Can't bind result: ".$stmt->error);
  425. }
  426. $stmt->fetch();
  427. $stmt->close();
  428. }
  429. else
  430. {
  431. throw new Exception("Can't prepare statement: ".$db->error);
  432. }
  433. return $total;
  434. }
  435. /*
  436. * Returns a number of active users (with activity after one day from registration)
  437. */
  438. public static function getActiveUsers($date = null)
  439. {
  440. $db = UserConfig::getDB();
  441. $total = 0;
  442. if (UserConfig::$adminActiveOnlyWithPoints) {
  443. $activities_with_points = array();
  444. foreach (UserConfig::$activities as $id => $activity) {
  445. if ($activity[1] > 0) {
  446. $activities_with_points[] = $id;
  447. }
  448. }
  449. // if there are no activities that can earn points, no users are active
  450. if (count($activities_with_points) == 0) {
  451. return 0;
  452. }
  453. $in = implode(', ', $activities_with_points);
  454. $query = 'SELECT count(*) AS total FROM (
  455. SELECT user_id, count(*)
  456. FROM '.UserConfig::$mysql_prefix.'activity a
  457. INNER JOIN '.UserConfig::$mysql_prefix.'users u
  458. ON a.user_id = u.id
  459. WHERE a.time > DATE_ADD(u.regtime, INTERVAL 1 DAY)
  460. AND a.time > DATE_SUB('.
  461. (is_null($date) ? 'NOW()' : '?').
  462. ', INTERVAL 30 DAY)'.
  463. (is_null($date) ? '' : ' AND a.time < ?').'
  464. AND a.activity_id IN ('.$in.')
  465. GROUP BY user_id
  466. ) AS active';
  467. } else {
  468. $query = 'SELECT count(*) AS total FROM (
  469. SELECT user_id, count(*)
  470. FROM '.UserConfig::$mysql_prefix.'activity a
  471. INNER JOIN '.UserConfig::$mysql_prefix.'users u
  472. ON a.user_id = u.id
  473. WHERE a.time > DATE_ADD(u.regtime, INTERVAL 1 DAY)
  474. AND a.time > DATE_SUB('.
  475. (is_null($date) ? 'NOW()' : '?').
  476. ', INTERVAL 30 DAY)'.
  477. (is_null($date) ? '' : ' AND a.time < ?').'
  478. GROUP BY user_id
  479. ) AS active';
  480. }
  481. if ($stmt = $db->prepare($query))
  482. {
  483. if (!is_null($date)) {
  484. if (!$stmt->bind_param('ss', $date, $date))
  485. {
  486. throw new Exception("Can't bind parameter".$stmt->error);
  487. }
  488. }
  489. if (!$stmt->execute())
  490. {
  491. throw new Exception("Can't execute statement: ".$stmt->error);
  492. }
  493. if (!$stmt->bind_result($total))
  494. {
  495. throw new Exception("Can't bind result: ".$stmt->error);
  496. }
  497. $stmt->fetch();
  498. $stmt->close();
  499. }
  500. else
  501. {
  502. throw new Exception("Can't prepare statement: ".$db->error);
  503. }
  504. return $total;
  505. }
  506. /*
  507. * retrieves daily active users based on algorythm defined in getActiveUsers($date)
  508. */
  509. public static function getDailyActiveUsers($lastndays = null)
  510. {
  511. $db = UserConfig::getDB();
  512. $daily_activity = array();
  513. $start_date = null;
  514. $start_day = null;
  515. $start_month = null;
  516. $start_year = null;
  517. // getting start date
  518. if ($stmt = $db->prepare('SELECT CAST(MIN(time) AS DATE) AS activity_date,
  519. DAYOFMONTH(MIN(time)) as day,
  520. MONTH(MIN(time)) as month,
  521. YEAR(MIN(time)) as year
  522. FROM '.UserConfig::$mysql_prefix.'activity'.
  523. ((!is_null($lastndays) && is_int($lastndays)) ?
  524. ' WHERE time > DATE_SUB(NOW(), INTERVAL '.$lastndays.' DAY)' : '')
  525. ))
  526. {
  527. if (!$stmt->execute())
  528. {
  529. throw new Exception("Can't execute statement: ".$stmt->error);
  530. }
  531. if (!$stmt->bind_result($start_date, $start_day, $start_month, $start_year))
  532. {
  533. throw new Exception("Can't bind result: ".$stmt->error);
  534. }
  535. $stmt->fetch();
  536. $stmt->close();
  537. }
  538. else
  539. {
  540. throw new Exception("Can't prepare statement: ".$db->error);
  541. }
  542. // no activities recorded yet
  543. if (is_null($start_date)) {
  544. return array();
  545. }
  546. // now getting all cached numbers
  547. if ($stmt = $db->prepare('SELECT day, active_users
  548. FROM '.UserConfig::$mysql_prefix.'admin_daily_stats_cache'.
  549. ((!is_null($lastndays) && is_int($lastndays)) ?
  550. ' WHERE day > DATE_SUB(NOW(), INTERVAL '.$lastndays.' DAY)' : '')))
  551. {
  552. if (!$stmt->execute())
  553. {
  554. throw new Exception("Can't execute statement: ".$stmt->error);
  555. }
  556. if (!$stmt->bind_result($date, $active_users))
  557. {
  558. throw new Exception("Can't bind result: ".$stmt->error);
  559. }
  560. while($stmt->fetch() === TRUE)
  561. {
  562. $daily_activity[$date] = $active_users;
  563. }
  564. $stmt->close();
  565. }
  566. else
  567. {
  568. throw new Exception("Can't prepare statement: ".$db->error);
  569. }
  570. $timestamp = mktime(0, 0, 1, $start_month, $start_day, $start_year);
  571. $current_timestamp = time();
  572. $updates = array();
  573. while($timestamp < $current_timestamp) {
  574. $date = date('Y-m-d', $timestamp);
  575. if (!array_key_exists($date, $daily_activity)) {
  576. $active_users = self::getActiveUsers($date);
  577. $daily_activity[$date] = $active_users;
  578. $updates[$date] = $active_users;
  579. }
  580. $timestamp = strtotime("+1 day", $timestamp);
  581. }
  582. // saving newly calculated values into cache
  583. $totalupdates = count($updates);
  584. if ($totalupdates > 0) {
  585. $query = 'REPLACE INTO '.UserConfig::$mysql_prefix.'admin_daily_stats_cache
  586. (day, active_users) VALUES';
  587. $first = true;
  588. foreach ($updates as $date => $active_users) {
  589. if (!$first) {
  590. $query .= ',';
  591. }
  592. $query .= " ('$date', $active_users)";
  593. $first = false;
  594. }
  595. if ($stmt = $db->prepare($query))
  596. {
  597. if (!$stmt->execute())
  598. {
  599. throw new Exception("Can't execute statement: ".$stmt->error);
  600. }
  601. $stmt->close();
  602. }
  603. else
  604. {
  605. throw new Exception("Can't prepare statement: ".$db->error);
  606. }
  607. }
  608. return $daily_activity;
  609. }
  610. /*
  611. * retrieves daily active users by activity
  612. */
  613. public static function getDailyPointsByActivity($activityid)
  614. {
  615. $db = UserConfig::getDB();
  616. $daily_activity = array();
  617. if ($stmt = $db->prepare('SELECT CAST(time AS DATE) AS activity_date, count(*) AS cnt FROM '.UserConfig::$mysql_prefix.'activity WHERE activity_id = ? GROUP BY activity_date'))
  618. {
  619. if (!$stmt->bind_param('i', $activityid))
  620. {
  621. throw new Exception("Can't bind parameter".$stmt->error);
  622. }
  623. if (!$stmt->execute())
  624. {
  625. throw new Exception("Can't execute statement: ".$stmt->error);
  626. }
  627. if (!$stmt->bind_result($date, $cnt))
  628. {
  629. throw new Exception("Can't bind result: ".$stmt->error);
  630. }
  631. while($stmt->fetch() === TRUE)
  632. {
  633. $daily_activity[$date] = $cnt;
  634. }
  635. $stmt->close();
  636. }
  637. else
  638. {
  639. throw new Exception("Can't prepare statement: ".$db->error);
  640. }
  641. return $daily_activity;
  642. }
  643. /*
  644. * retrieves aggregated activity points
  645. */
  646. public static function getDailyActivityPoints($user)
  647. {
  648. $db = UserConfig::getDB();
  649. $daily_activity = array();
  650. $where = '';
  651. if (!is_null($user)) {
  652. $where = ' WHERE user_id = '.$user->getID().' ';
  653. } else if (count(UserConfig::$dont_display_activity_for) > 0) {
  654. $where = ' WHERE user_id NOT IN('.join(', ', UserConfig::$dont_display_activity_for).') ';
  655. }
  656. if ($stmt = $db->prepare('SELECT CAST(time AS DATE) AS activity_date, activity_id, count(*) AS total FROM '.UserConfig::$mysql_prefix.'activity '.$where.'GROUP BY activity_date, activity_id'))
  657. {
  658. if (!$stmt->execute())
  659. {
  660. throw new Exception("Can't execute statement: ".$stmt->error);
  661. }
  662. if (!$stmt->bind_result($date, $id, $total))
  663. {
  664. throw new Exception("Can't bind result: ".$stmt->error);
  665. }
  666. while($stmt->fetch() === TRUE)
  667. {
  668. $daily_activity[] = array('date' => $date, 'activity' => $id, 'total' => $total);
  669. }
  670. $stmt->close();
  671. }
  672. else
  673. {
  674. throw new Exception("Can't prepare statement: ".$db->error);
  675. }
  676. return $daily_activity;
  677. }
  678. /*
  679. * retrieves aggregated registrations numbers
  680. */
  681. public static function getDailyRegistrations()
  682. {
  683. $db = UserConfig::getDB();
  684. $dailyregs = array();
  685. if ($stmt = $db->prepare('SELECT CAST(regtime AS DATE) AS regdate, count(*) AS regs FROM '.UserConfig::$mysql_prefix.'users GROUP BY regdate'))
  686. {
  687. if (!$stmt->execute())
  688. {
  689. throw new Exception("Can't execute statement: ".$stmt->error);
  690. }
  691. if (!$stmt->bind_result($regdate, $regs))
  692. {
  693. throw new Exception("Can't bind result: ".$stmt->error);
  694. }
  695. while($stmt->fetch() === TRUE)
  696. {
  697. $dailyregs[] = array('regdate' => $regdate, 'regs' => $regs);
  698. }
  699. $stmt->close();
  700. }
  701. else
  702. {
  703. throw new Exception("Can't prepare statement: ".$db->error);
  704. }
  705. return $dailyregs;
  706. }
  707. /*
  708. * retrieves aggregated registrations numbers by module
  709. */
  710. public static function getDailyRegistrationsByModule()
  711. {
  712. $db = UserConfig::getDB();
  713. $dailyregs = array();
  714. if ($stmt = $db->prepare('SELECT CAST(regtime AS DATE) AS regdate, regmodule, count(*) AS reg FROM '.UserConfig::$mysql_prefix.'users GROUP BY regdate, regmodule'))
  715. {
  716. if (!$stmt->execute())
  717. {
  718. throw new Exception("Can't execute statement: ".$stmt->error);
  719. }
  720. if (!$stmt->bind_result($date, $module, $regs))
  721. {
  722. throw new Exception("Can't bind result: ".$stmt->error);
  723. }
  724. while($stmt->fetch()) {
  725. $dailyregs[$date][$module] = $regs;
  726. }
  727. $stmt->close();
  728. }
  729. else
  730. {
  731. throw new Exception("Can't prepare statement: ".$db->error);
  732. }
  733. return $dailyregs;
  734. }
  735. /*
  736. * retrieves aggregated recent registrations numbers by module
  737. */
  738. public static function getRecentRegistrationsByModule()
  739. {
  740. $db = UserConfig::getDB();
  741. $regs = array();
  742. if ($stmt = $db->prepare('SELECT regmodule, count(*) AS reg FROM '.UserConfig::$mysql_prefix.'users u WHERE regtime > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY regmodule'))
  743. {
  744. if (!$stmt->execute())
  745. {
  746. throw new Exception("Can't execute statement: ".$stmt->error);
  747. }
  748. if (!$stmt->bind_result($module, $reg))
  749. {
  750. throw new Exception("Can't bind result: ".$stmt->error);
  751. }
  752. while($stmt->fetch()) {
  753. $regs[$module] = $reg;
  754. }
  755. $stmt->close();
  756. }
  757. else
  758. {
  759. throw new Exception("Can't prepare statement: ".$db->error);
  760. }
  761. return $regs;
  762. }
  763. /*
  764. * retrieves user credentials for all authentication modules
  765. */
  766. public function getUserCredentials($requested_module_id = null)
  767. {
  768. $credentials = array();
  769. foreach (UserConfig::$authentication_modules as $module) {
  770. if (is_null($requested_module_id)) {
  771. $credentials[$module][] = $module->getUserCredentials($this);
  772. } else {
  773. if ($requested_module_id == $module->getID()) {
  774. return $module->getUserCredentials($this);
  775. }
  776. }
  777. }
  778. return $credentials;
  779. }
  780. /*
  781. * retrieves paged list of users
  782. */
  783. public static function getUsers($pagenumber = 0, $perpage = 20, $sort = 'registration')
  784. {
  785. $db = UserConfig::getDB();
  786. $users = array();
  787. $first = $perpage * $pagenumber;
  788. $orderby = 'regtime';
  789. if ($sort == 'activity') {
  790. $orderby = 'points';
  791. }
  792. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users ORDER BY '.$orderby.' DESC LIMIT ?, ?'))
  793. {
  794. if (!$stmt->bind_param('ii', $first, $perpage))
  795. {
  796. throw new Exception("Can't bind parameter".$stmt->error);
  797. }
  798. if (!$stmt->execute())
  799. {
  800. throw new Exception("Can't execute statement: ".$stmt->error);
  801. }
  802. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points))
  803. {
  804. throw new Exception("Can't bind result: ".$stmt->error);
  805. }
  806. while($stmt->fetch() === TRUE)
  807. {
  808. $users[] = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  809. }
  810. $stmt->close();
  811. }
  812. else
  813. {
  814. throw new Exception("Can't prepare statement: ".$db->error);
  815. }
  816. return $users;
  817. }
  818. /*
  819. * searches for users matching the query
  820. */
  821. public static function searchUsers($search, $pagenumber = 0, $perpage = 20)
  822. {
  823. $db = UserConfig::getDB();
  824. $users = array();
  825. $first = $perpage * $pagenumber;
  826. // TODO Replace with real, fast and powerful full-text search
  827. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime) FROM '.UserConfig::$mysql_prefix.'users WHERE INSTR(name, ?) > 0 OR INSTR(username, ?) > 0 OR INSTR(email, ?) > 0 ORDER BY regtime DESC LIMIT ?, ?'))
  828. {
  829. if (!$stmt->bind_param('sssii', $search, $search, $search, $first, $perpage))
  830. {
  831. throw new Exception("Can't bind parameter".$stmt->error);
  832. }
  833. if (!$stmt->execute())
  834. {
  835. throw new Exception("Can't execute statement: ".$stmt->error);
  836. }
  837. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime))
  838. {
  839. throw new Exception("Can't bind result: ".$stmt->error);
  840. }
  841. while($stmt->fetch() === TRUE)
  842. {
  843. $users[] = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime);
  844. }
  845. $stmt->close();
  846. }
  847. else
  848. {
  849. throw new Exception("Can't prepare statement: ".$db->error);
  850. }
  851. return $users;
  852. }
  853. /*
  854. * retrieves a list of latest activities
  855. */
  856. public static function getUsersActivity($all, $pagenumber = 0, $perpage = 20)
  857. {
  858. $activities = array();
  859. $exclude = '';
  860. if (count(UserConfig::$dont_display_activity_for) > 0) {
  861. $exclude = ' user_id NOT IN('.join(', ', UserConfig::$dont_display_activity_for).') ';
  862. }
  863. if ($all) {
  864. $query = 'SELECT UNIX_TIMESTAMP(time) as time, user_id, activity_id FROM '.UserConfig::$mysql_prefix.'activity '.($exclude != '' ? 'WHERE '.$exclude : '').' ORDER BY time DESC LIMIT ?, ?';
  865. } else {
  866. $ids = array();
  867. foreach (UserConfig::$activities as $id => $activity) {
  868. if ($activity[1] > 0) {
  869. $ids[] = $id;
  870. }
  871. }
  872. if (count($ids) == 0) {
  873. return $activities; // no activities are configured to be worthy
  874. }
  875. $query = 'SELECT UNIX_TIMESTAMP(time) as time, user_id, activity_id FROM '.UserConfig::$mysql_prefix.'activity WHERE activity_id IN ('.implode(', ', $ids).') '.($exclude != '' ? 'AND '.$exclude : '').'ORDER BY time DESC LIMIT ?, ?';
  876. }
  877. $db = UserConfig::getDB();
  878. $first = $perpage * $pagenumber;
  879. if ($stmt = $db->prepare($query))
  880. {
  881. if (!$stmt->bind_param('ii', $first, $perpage))
  882. {
  883. throw new Exception("Can't bind parameter".$stmt->error);
  884. }
  885. if (!$stmt->execute())
  886. {
  887. throw new Exception("Can't execute statement: ".$stmt->error);
  888. }
  889. if (!$stmt->bind_result($time, $user_id, $activity_id))
  890. {
  891. throw new Exception("Can't bind result: ".$stmt->error);
  892. }
  893. while($stmt->fetch() === TRUE)
  894. {
  895. $activities[] = array('time' => $time, 'user_id' => $user_id, 'activity_id' => $activity_id);
  896. }
  897. $stmt->close();
  898. }
  899. else
  900. {
  901. throw new Exception("Can't prepare statement: ".$db->error);
  902. }
  903. return $activities;
  904. }
  905. /*
  906. * retrieves a list of users by activity
  907. */
  908. public static function getUsersByActivity($activityid, $pagenumber = 0, $perpage = 20)
  909. {
  910. $activities = array();
  911. $exclude = '';
  912. if (count(UserConfig::$dont_display_activity_for) > 0) {
  913. $exclude = ' AND user_id NOT IN('.join(', ', UserConfig::$dont_display_activity_for).') ';
  914. }
  915. $query = 'SELECT UNIX_TIMESTAMP(time) as time, user_id FROM '.UserConfig::$mysql_prefix.'activity WHERE activity_id = ? '.$exclude.' ORDER BY time DESC LIMIT ?, ?';
  916. $db = UserConfig::getDB();
  917. $first = $perpage * $pagenumber;
  918. if ($stmt = $db->prepare($query))
  919. {
  920. if (!$stmt->bind_param('iii', $activityid, $first, $perpage))
  921. {
  922. throw new Exception("Can't bind parameter".$stmt->error);
  923. }
  924. if (!$stmt->execute())
  925. {
  926. throw new Exception("Can't execute statement: ".$stmt->error);
  927. }
  928. if (!$stmt->bind_result($time, $user_id))
  929. {
  930. throw new Exception("Can't bind result: ".$stmt->error);
  931. }
  932. while($stmt->fetch() === TRUE)
  933. {
  934. $activities[] = array('time' => $time, 'user_id' => $user_id);
  935. }
  936. $stmt->close();
  937. }
  938. else
  939. {
  940. throw new Exception("Can't prepare statement: ".$db->error);
  941. }
  942. return $activities;
  943. }
  944. public static function getUsersByEmailOrUsername($nameoremail)
  945. {
  946. $db = UserConfig::getDB();
  947. $nameoremail = trim($nameoremail);
  948. $users = array();
  949. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users WHERE username = ? OR email = ?'))
  950. {
  951. if (!$stmt->bind_param('ss', $nameoremail, $nameoremail))
  952. {
  953. throw new Exception("Can't bind parameter".$stmt->error);
  954. }
  955. if (!$stmt->execute())
  956. {
  957. throw new Exception("Can't execute statement: ".$stmt->error);
  958. }
  959. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points))
  960. {
  961. throw new Exception("Can't bind result: ".$stmt->error);
  962. }
  963. while ($stmt->fetch() === TRUE)
  964. {
  965. $users[] = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  966. }
  967. $stmt->close();
  968. }
  969. else
  970. {
  971. throw new Exception("Can't prepare statement: ".$db->error);
  972. }
  973. return $users;
  974. }
  975. /*
  976. * retrieve activity statistics
  977. */
  978. public static function getActivityStatistics()
  979. {
  980. $stats = array();
  981. $where = '';
  982. if (count(UserConfig::$dont_display_activity_for) > 0) {
  983. $where = ' WHERE user_id NOT IN('.join(', ', UserConfig::$dont_display_activity_for).') ';
  984. }
  985. $query = 'SELECT activity_id, count(*) as cnt FROM '.UserConfig::$mysql_prefix."activity $where GROUP BY activity_id";
  986. $db = UserConfig::getDB();
  987. if ($stmt = $db->prepare($query))
  988. {
  989. if (!$stmt->execute())
  990. {
  991. throw new Exception("Can't execute statement: ".$stmt->error);
  992. }
  993. if (!$stmt->bind_result($activity_id, $cnt))
  994. {
  995. throw new Exception("Can't bind result: ".$stmt->error);
  996. }
  997. while($stmt->fetch() === TRUE)
  998. {
  999. $stats[$activity_id] = $cnt;
  1000. }
  1001. $stmt->close();
  1002. }
  1003. else
  1004. {
  1005. throw new Exception("Can't prepare statement: ".$db->error);
  1006. }
  1007. return $stats;
  1008. }
  1009. /*
  1010. * retrieves a list of latest activities
  1011. */
  1012. public function getActivity($all, $pagenumber = 0, $perpage = 20)
  1013. {
  1014. $activities = array();
  1015. if ($all) {
  1016. $query = 'SELECT UNIX_TIMESTAMP(time) as time, user_id, activity_id FROM '.UserConfig::$mysql_prefix.'activity WHERE user_id = ? ORDER BY time DESC LIMIT ?, ?';
  1017. } else {
  1018. $ids = array();
  1019. foreach (UserConfig::$activities as $id => $activity) {
  1020. if ($activity[1] > 0) {
  1021. $ids[] = $id;
  1022. }
  1023. }
  1024. if (count($ids) == 0) {
  1025. return $activities; // no activities are configured to be worthy
  1026. }
  1027. $query = 'SELECT UNIX_TIMESTAMP(time) as time, user_id, activity_id FROM '.UserConfig::$mysql_prefix.'activity WHERE user_id = ? AND activity_id IN ('.implode(', ', $ids).') ORDER BY time DESC LIMIT ?, ?';
  1028. }
  1029. $db = UserConfig::getDB();
  1030. $first = $perpage * $pagenumber;
  1031. if ($stmt = $db->prepare($query))
  1032. {
  1033. if (!$stmt->bind_param('iii', $this->userid, $first, $perpage))
  1034. {
  1035. throw new Exception("Can't bind parameter".$stmt->error);
  1036. }
  1037. if (!$stmt->execute())
  1038. {
  1039. throw new Exception("Can't execute statement: ".$stmt->error);
  1040. }
  1041. if (!$stmt->bind_result($time, $user_id, $activity_id))
  1042. {
  1043. throw new Exception("Can't bind result: ".$stmt->error);
  1044. }
  1045. while($stmt->fetch() === TRUE)
  1046. {
  1047. $activities[] = array('time' => $time, 'user_id' => $user_id, 'activity_id' => $activity_id);
  1048. }
  1049. $stmt->close();
  1050. }
  1051. else
  1052. {
  1053. throw new Exception("Can't prepare statement: ".$db->error);
  1054. }
  1055. return $activities;
  1056. }
  1057. /*
  1058. * Generates password recovery code and saves it to the database for later matching
  1059. */
  1060. public function generateTemporaryPassword()
  1061. {
  1062. $db = UserConfig::getDB();
  1063. $temppass = uniqid();
  1064. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET temppass = ?, temppasstime = now() WHERE id = ?'))
  1065. {
  1066. if (!$stmt->bind_param('si', $temppass, $this->userid))
  1067. {
  1068. throw new Exception("Can't bind parameter".$stmt->error);
  1069. }
  1070. if (!$stmt->execute())
  1071. {
  1072. throw new Exception("Can't execute statement: ".$stmt->error);
  1073. }
  1074. $stmt->close();
  1075. }
  1076. else
  1077. {
  1078. throw new Exception("Can't prepare statement: ".$db->error);
  1079. }
  1080. return $temppass;
  1081. }
  1082. /*
  1083. * Resets temporary password
  1084. */
  1085. public function resetTemporaryPassword()
  1086. {
  1087. $db = UserConfig::getDB();
  1088. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET temppass = null, temppasstime = null WHERE id = ?'))
  1089. {
  1090. if (!$stmt->bind_param('s', $this->userid))
  1091. {
  1092. throw new Exception("Can't bind parameter".$stmt->error);
  1093. }
  1094. if (!$stmt->execute())
  1095. {
  1096. throw new Exception("Can't execute statement: ".$stmt->error);
  1097. }
  1098. $stmt->close();
  1099. }
  1100. else
  1101. {
  1102. throw new Exception("Can't prepare statement: ".$db->error);
  1103. }
  1104. }
  1105. /*
  1106. * Records user registration module (should be used only once
  1107. */
  1108. public function setRegistrationModule($module)
  1109. {
  1110. $db = UserConfig::getDB();
  1111. $module_id = $module->getID();
  1112. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET regmodule = ? WHERE id = ?'))
  1113. {
  1114. if (!$stmt->bind_param('si', $module_id, $this->userid))
  1115. {
  1116. throw new Exception("Can't bind parameter".$stmt->error);
  1117. }
  1118. if (!$stmt->execute())
  1119. {
  1120. throw new Exception("Can't execute statement: ".$stmt->error);
  1121. }
  1122. $stmt->close();
  1123. }
  1124. else
  1125. {
  1126. throw new Exception("Can't prepare statement: ".$db->error);
  1127. }
  1128. }
  1129. /*
  1130. * retrieves user information by array of IDs
  1131. */
  1132. public static function getUsersByIDs($userids)
  1133. {
  1134. $db = UserConfig::getDB();
  1135. $users = array();
  1136. $ids = array();
  1137. foreach ($userids as $userid) {
  1138. if (is_int($userid)){
  1139. $ids[] = $userid;
  1140. }
  1141. }
  1142. $idlist = join(', ', $ids);
  1143. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users WHERE id IN ('.$idlist.')'))
  1144. {
  1145. if (!$stmt->execute())
  1146. {
  1147. throw new Exception("Can't execute statement: ".$stmt->error);
  1148. }
  1149. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points))
  1150. {
  1151. throw new Exception("Can't bind result: ".$stmt->error);
  1152. }
  1153. while ($stmt->fetch() === TRUE)
  1154. {
  1155. $users[] = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  1156. }
  1157. $stmt->close();
  1158. }
  1159. else
  1160. {
  1161. throw new Exception("Can't prepare statement: ".$db->error);
  1162. }
  1163. return $users;
  1164. }
  1165. public function removeGoogleFriendConnectAssociation($google_id)
  1166. {
  1167. $db = UserConfig::getDB();
  1168. if ($stmt = $db->prepare('DELETE FROM '.UserConfig::$mysql_prefix.'googlefriendconnect WHERE user_id = ? AND google_id = ?'))
  1169. {
  1170. if (!$stmt->bind_param('is', $this->userid, $google_id))
  1171. {
  1172. throw new Exception("Can't bind parameter".$stmt->error);
  1173. }
  1174. if (!$stmt->execute())
  1175. {
  1176. throw new Exception("Can't execute statement: ".$stmt->error);
  1177. }
  1178. $stmt->close();
  1179. }
  1180. else
  1181. {
  1182. throw new Exception("Can't prepare statement: ".$db->error);
  1183. }
  1184. $this->recordActivity(USERBASE_ACTIVITY_REMOVED_GFC);
  1185. }
  1186. public function addGoogleFriendConnectAssociation($google_id, $userpic)
  1187. {
  1188. $db = UserConfig::getDB();
  1189. if ($stmt = $db->prepare('INSERT IGNORE INTO '.UserConfig::$mysql_prefix.'googlefriendconnect (user_id, google_id, userpic) VALUES (?, ?, ?)'))
  1190. {
  1191. if (!$stmt->bind_param('iss', $this->userid, $google_id, $userpic))
  1192. {
  1193. throw new Exception("Can't bind parameter".$stmt->error);
  1194. }
  1195. if (!$stmt->execute())
  1196. {
  1197. throw new Exception("Can't execute statement: ".$stmt->error);
  1198. }
  1199. $stmt->close();
  1200. }
  1201. else
  1202. {
  1203. throw new Exception("Can't prepare statement: ".$db->error);
  1204. }
  1205. $this->recordActivity(USERBASE_ACTIVITY_ADDED_GFC);
  1206. }
  1207. public function getGoogleFriendsConnectAssociations()
  1208. {
  1209. $db = UserConfig::getDB();
  1210. $associations = array();
  1211. if ($stmt = $db->prepare('SELECT google_id, userpic FROM '.UserConfig::$mysql_prefix.'users u INNER JOIN '.UserConfig::$mysql_prefix.'googlefriendconnect g ON u.id = g.user_id WHERE u.id = ?'))
  1212. {
  1213. if (!$stmt->bind_param('i', $this->userid))
  1214. {
  1215. throw new Exception("Can't bind parameter".$stmt->error);
  1216. }
  1217. if (!$stmt->execute())
  1218. {
  1219. throw new Exception("Can't execute statement: ".$stmt->error);
  1220. }
  1221. if (!$stmt->bind_result($google_id, $userpic))
  1222. {
  1223. throw new Exception("Can't bind result: ".$stmt->error);
  1224. }
  1225. while ($stmt->fetch() === TRUE)
  1226. {
  1227. $associations[] = array('google_id' => $google_id, 'userpic' => $userpic);
  1228. }
  1229. $stmt->close();
  1230. }
  1231. else
  1232. {
  1233. throw new Exception("Can't prepare statement: ".$db->error);
  1234. }
  1235. return $associations;
  1236. }
  1237. /*
  1238. * retrieves user information by username
  1239. */
  1240. public static function getUserByUsernamePassword($entered_username, $entered_password)
  1241. {
  1242. $db = UserConfig::getDB();
  1243. $user = null;
  1244. if ($stmt = $db->prepare('SELECT id, status, name, username, email, pass, salt, temppass, requirespassreset, fb_id FROM '.UserConfig::$mysql_prefix.'users WHERE username = ?'))
  1245. {
  1246. if (!$stmt->bind_param('s', $entered_username))
  1247. {
  1248. throw new Exception("Can't bind parameter".$stmt->error);
  1249. }
  1250. if (!$stmt->execute())
  1251. {
  1252. throw new Exception("Can't execute statement: ".$stmt->error);
  1253. }
  1254. if (!$stmt->bind_result($id, $status, $name, $username, $email, $pass, $salt, $temppass, $requirespassreset, $fb_id))
  1255. {
  1256. throw new Exception("Can't bind result: ".$stmt->error);
  1257. }
  1258. if ($stmt->fetch() === TRUE)
  1259. {
  1260. if (sha1($salt.$entered_password) == $pass)
  1261. {
  1262. $user = new self($id, $status, $name, $username, $email, $requirespassreset, $fb_id);
  1263. }
  1264. }
  1265. $stmt->close();
  1266. // if user used password recovery and remembered his old password
  1267. // then clean temporary password and password reset flag
  1268. // (don't reset the flag if was was set for some other reasons)
  1269. if (!is_null($user) && !$user->isDisabled() && !is_null($temppass) && $user->requiresPasswordReset())
  1270. {
  1271. $user->setRequiresPasswordReset(false);
  1272. $user->save();
  1273. $user->resetTemporaryPassword();
  1274. }
  1275. }
  1276. else
  1277. {
  1278. throw new Exception("Can't prepare statement: ".$db->error);
  1279. }
  1280. if (is_null($user))
  1281. {
  1282. if ($stmt = $db->prepare('SELECT id, status, name, username, email, fb_id FROM '.UserConfig::$mysql_prefix.'users WHERE username = ? AND temppass = ? AND temppasstime > DATE_SUB(NOW(), INTERVAL 1 DAY)'))
  1283. {
  1284. if (!$stmt->bind_param('ss', $entered_username, $entered_password))
  1285. {
  1286. throw new Exception("Can't bind parameter".$stmt->error);
  1287. }
  1288. if (!$stmt->execute())
  1289. {
  1290. throw new Exception("Can't execute statement: ".$stmt->error);
  1291. }
  1292. if (!$stmt->bind_result($id, $status, $name, $username, $email, $fb_id))
  1293. {
  1294. throw new Exception("Can't bind result: ".$stmt->error);
  1295. }
  1296. if ($stmt->fetch() === TRUE)
  1297. {
  1298. $user = new self($id, $status, $name, $username, $email, null, $fb_id);
  1299. }
  1300. $stmt->close();
  1301. if (!is_null($user))
  1302. {
  1303. $user->setRequiresPasswordReset(true);
  1304. $user->save();
  1305. }
  1306. }
  1307. else
  1308. {
  1309. throw new Exception("Can't prepare statement: ".$db->error);
  1310. }
  1311. }
  1312. else
  1313. {
  1314. $user->resetTemporaryPassword();
  1315. }
  1316. if (!is_null($user) && $user->isDisabled()) {
  1317. return null;
  1318. }
  1319. return $user;
  1320. }
  1321. /*
  1322. * retrieves user information by Google Friend Connect ID
  1323. */
  1324. public static function getUserByGoogleFriendConnectID($googleid)
  1325. {
  1326. $db = UserConfig::getDB();
  1327. $user = null;
  1328. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users u INNER JOIN '.UserConfig::$mysql_prefix.'googlefriendconnect g ON u.id = g.user_id WHERE g.google_id = ?'))
  1329. {
  1330. if (!$stmt->bind_param('s', $googleid))
  1331. {
  1332. throw new Exception("Can't bind parameter".$stmt->error);
  1333. }
  1334. if (!$stmt->execute())
  1335. {
  1336. throw new Exception("Can't execute statement: ".$stmt->error);
  1337. }
  1338. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points))
  1339. {
  1340. throw new Exception("Can't bind result: ".$stmt->error);
  1341. }
  1342. if ($stmt->fetch() === TRUE)
  1343. {
  1344. $user = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  1345. }
  1346. $stmt->close();
  1347. }
  1348. else
  1349. {
  1350. throw new Exception("Can't prepare statement: ".$db->error);
  1351. }
  1352. return $user;
  1353. }
  1354. /*
  1355. * retrieves user information by Facebook ID
  1356. */
  1357. public static function getUserByFacebookID($fb_id)
  1358. {
  1359. $db = UserConfig::getDB();
  1360. $user = null;
  1361. if ($stmt = $db->prepare('SELECT id, status, name, username, email, requirespassreset, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users WHERE fb_id = ?'))
  1362. {
  1363. if (!$stmt->bind_param('i', $fb_id))
  1364. {
  1365. throw new Exception("Can't bind parameter".$stmt->error);
  1366. }
  1367. if (!$stmt->execute())
  1368. {
  1369. throw new Exception("Can't execute statement: ".$stmt->error);
  1370. }
  1371. if (!$stmt->bind_result($userid, $status, $name, $username, $email, $requirespassreset, $regtime, $points))
  1372. {
  1373. throw new Exception("Can't bind result: ".$stmt->error);
  1374. }
  1375. if ($stmt->fetch() === TRUE)
  1376. {
  1377. $user = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  1378. }
  1379. $stmt->close();
  1380. }
  1381. else
  1382. {
  1383. throw new Exception("Can't prepare statement: ".$db->error);
  1384. }
  1385. return $user;
  1386. }
  1387. /*
  1388. * retrieves user information from database and constructs
  1389. */
  1390. public static function getUser($userid)
  1391. {
  1392. $db = UserConfig::getDB();
  1393. $user = null;
  1394. if ($stmt = $db->prepare('SELECT status, name, username, email, requirespassreset, fb_id, UNIX_TIMESTAMP(regtime), points FROM '.UserConfig::$mysql_prefix.'users WHERE id = ?'))
  1395. {
  1396. if (!$stmt->bind_param('i', $userid))
  1397. {
  1398. throw new Exception("Can't bind parameter".$stmt->error);
  1399. }
  1400. if (!$stmt->execute())
  1401. {
  1402. throw new Exception("Can't execute statement: ".$stmt->error);
  1403. }
  1404. if (!$stmt->bind_result($status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points))
  1405. {
  1406. throw new Exception("Can't bind result: ".$stmt->error);
  1407. }
  1408. if ($stmt->fetch() === TRUE)
  1409. {
  1410. $user = new self($userid, $status, $name, $username, $email, $requirespassreset, $fb_id, $regtime, $points);
  1411. }
  1412. $stmt->close();
  1413. }
  1414. else
  1415. {
  1416. throw new Exception("Can't prepare statement: ".$db->error);
  1417. }
  1418. return $user;
  1419. }
  1420. private static function setReturn($return)
  1421. {
  1422. $storage = new MrClay_CookieStorage(array(
  1423. 'secret' => UserConfig::$SESSION_SECRET,
  1424. 'path' => UserConfig::$SITEROOTURL,
  1425. 'expire' => 0,
  1426. 'httponly' => true
  1427. ));
  1428. if (!$storage->store(UserConfig::$session_return_key, $return)) {
  1429. throw new Exception(implode('; ', $storage->errors));
  1430. }
  1431. }
  1432. public static function getReturn()
  1433. {
  1434. $storage = new MrClay_CookieStorage(array(
  1435. 'secret' => UserConfig::$SESSION_SECRET,
  1436. 'path' => UserConfig::$SITEROOTURL,
  1437. 'httponly' => true
  1438. ));
  1439. $return = $storage->fetch(UserConfig::$session_return_key);
  1440. if (is_string($return)) {
  1441. return $return;
  1442. } else {
  1443. return null;
  1444. }
  1445. }
  1446. public static function clearReturn()
  1447. {
  1448. $storage = new MrClay_CookieStorage(array(
  1449. 'secret' => UserConfig::$SESSION_SECRET,
  1450. 'path' => UserConfig::$SITEROOTURL,
  1451. 'httponly' => true
  1452. ));
  1453. $storage->delete(UserConfig::$session_return_key);
  1454. }
  1455. public static function redirectToLogin()
  1456. {
  1457. self::setReturn($_SERVER['REQUEST_URI']);
  1458. header('Location: '.UserConfig::$USERSROOTURL.'/login.php');
  1459. exit;
  1460. }
  1461. private static function redirectToPasswordReset()
  1462. {
  1463. self::setReturn($_SERVER['REQUEST_URI']);
  1464. header('Location: '.UserConfig::$USERSROOTURL.'/modules/usernamepass/passwordreset.php');
  1465. exit;
  1466. }
  1467. // statics are over - things below are for objects.
  1468. private $userid;
  1469. private $status;
  1470. private $name;
  1471. private $username;
  1472. private $email;
  1473. private $requirespassreset;
  1474. private $fbid;
  1475. private $regtime;
  1476. private $points;
  1477. private $impersonator;
  1478. function __construct($userid, $status = 1, $name, $username = null, $email = null, $requirespassreset = false, $fbid = null, $regtime = null, $points = 0)
  1479. {
  1480. $this->userid = $userid;
  1481. $this->status = $status;
  1482. $this->name = $name;
  1483. $this->username = $username;
  1484. $this->email = $email;
  1485. $this->requirespassreset = $requirespassreset ? true : false;
  1486. $this->fbid = $fbid;
  1487. $this->regtime = $regtime;
  1488. $this->points = $points;
  1489. }
  1490. public function requiresPasswordReset()
  1491. {
  1492. return $this->requirespassreset;
  1493. }
  1494. public function setRequiresPasswordReset($requires)
  1495. {
  1496. $this->requirespassreset = $requires;
  1497. }
  1498. public function getID()
  1499. {
  1500. return $this->userid;
  1501. }
  1502. public function getName()
  1503. {
  1504. return $this->name;
  1505. }
  1506. public function setName($name)
  1507. {
  1508. $this->name = $name;
  1509. }
  1510. public function getUsername()
  1511. {
  1512. return $this->username;
  1513. }
  1514. public function setUsername($username)
  1515. {
  1516. if (is_null($this->username))
  1517. {
  1518. $this->username = $username;
  1519. } else {
  1520. throw new Exception('This user already has username set.');
  1521. }
  1522. }
  1523. public function getEmail()
  1524. {
  1525. return $this->email;
  1526. }
  1527. public function setEmail($email)
  1528. {
  1529. $this->email = $email;
  1530. }
  1531. public function getFacebookID()
  1532. {
  1533. return $this->fbid;
  1534. }
  1535. public function setFacebookID($fbid)
  1536. {
  1537. $this->fbid = $fbid;
  1538. }
  1539. public function setStatus($status) {
  1540. $this->status = $status ? 1 : 0;
  1541. }
  1542. public function getRegTime()
  1543. {
  1544. return $this->regtime;
  1545. }
  1546. public function getPoints()
  1547. {
  1548. return $this->points;
  1549. }
  1550. public function isTheSameAs($user)
  1551. {
  1552. return $this->getID() == $user->getID();
  1553. }
  1554. public function isDisabled()
  1555. {
  1556. return ($this->status == 0 ? true : false);
  1557. }
  1558. public function checkPass($password)
  1559. {
  1560. $db = UserConfig::getDB();
  1561. if ($stmt = $db->prepare('SELECT pass, salt FROM '.UserConfig::$mysql_prefix.'users WHERE id = ?'))
  1562. {
  1563. if (!$stmt->bind_param('i', $this->userid))
  1564. {
  1565. throw new Exception("Can't bind parameter".$stmt->error);
  1566. }
  1567. if (!$stmt->execute())
  1568. {
  1569. throw new Exception("Can't execute statement: ".$stmt->error);
  1570. }
  1571. if (!$stmt->bind_result($pass, $salt))
  1572. {
  1573. throw new Exception("Can't bind result: ".$stmt->error);
  1574. }
  1575. if ($stmt->fetch() === TRUE)
  1576. {
  1577. return ($pass == sha1($salt.$password));
  1578. }
  1579. $stmt->close();
  1580. }
  1581. else
  1582. {
  1583. throw new Exception("Can't prepare statement: ".$db->error);
  1584. }
  1585. return false;
  1586. }
  1587. public function setPass($password)
  1588. {
  1589. $db = UserConfig::getDB();
  1590. $salt = uniqid();
  1591. $pass = sha1($salt.$password);
  1592. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET pass = ?, salt = ? WHERE id = ?'))
  1593. {
  1594. if (!$stmt->bind_param('ssi', $pass, $salt, $this->userid))
  1595. {
  1596. throw new Exception("Can't bind parameter".$stmt->error);
  1597. }
  1598. if (!$stmt->execute())
  1599. {
  1600. throw new Exception("Can't execute statement: ".$stmt->error);
  1601. }
  1602. $stmt->close();
  1603. }
  1604. else
  1605. {
  1606. throw new Exception("Can't prepare statement: ".$db->error);
  1607. }
  1608. return;
  1609. }
  1610. public function save()
  1611. {
  1612. $db = UserConfig::getDB();
  1613. $passresetnum = $this->requirespassreset ? 1 : 0;
  1614. $status = $this->status == 0 ? 0 : 1;
  1615. if (!is_null(UserConfig::$email_module)) {
  1616. // !WARNING! it's not safe to do anything with this user except reading it's built-in
  1617. // properties
  1618. // TODO implement some protection from reading or writing to DB based on this user's info,
  1619. // just reading object properties.
  1620. // creating a copy of the user in case we need to update their email subscription
  1621. $old_user = User::getUser($this->getID());
  1622. }
  1623. $username = is_null($this->username) || $this->username == '' ? null
  1624. : mb_convert_encoding($this->username, 'UTF-8');
  1625. $name = is_null($this->name) || $this->name == '' ? null
  1626. : mb_convert_encoding($this->name, 'UTF-8');
  1627. $email = is_null($this->email) || $this->email == '' ? null
  1628. : mb_convert_encoding($this->email, 'UTF-8');
  1629. if ($stmt = $db->prepare('UPDATE '.UserConfig::$mysql_prefix.'users SET status = ?, username = ?, name = ?, email = ?, requirespassreset = ?, fb_id = ? WHERE id = ?'))
  1630. {
  1631. if (!$stmt->bind_param('isssiii', $status, $username, $name, $email, $passresetnum, $this->fbid, $this->userid))
  1632. {
  1633. throw new Exception("Can't bind parameter".$stmt->error);
  1634. }
  1635. if (!$stmt->execute())
  1636. {
  1637. throw new Exception("Can't execute statement: ".$stmt->error);
  1638. }
  1639. $stmt->close();
  1640. }
  1641. else
  1642. {
  1643. throw new Exception("Can't prepare statement: ".$db->error);
  1644. }
  1645. if (!is_null(UserConfig::$email_module)) {
  1646. // it's up to email module to decide what to do
  1647. UserConfig::$email_module->userChanged($old_user, $this);
  1648. }
  1649. return;
  1650. }
  1651. public function setSession($remember)
  1652. {
  1653. $storage = new MrClay_CookieStorage(array(
  1654. 'secret' => UserConfig::$SESSION_SECRET,
  1655. 'mode' => MrClay_CookieStorage::MODE_ENCRYPT,
  1656. 'path' => UserConfig::$SITEROOTURL,
  1657. 'expire' => UserConfig::$allowRememberMe && $remember
  1658. ? time() + UserConfig::$rememberMeTime : 0,
  1659. 'httponly' => true
  1660. ));
  1661. if (!$storage->store(UserConfig::$session_userid_key, $this->userid)) {
  1662. throw new Exception(implode('; ', $storage->errors));
  1663. }
  1664. }
  1665. public static function clearSession()
  1666. {
  1667. self::stopImpersonation();
  1668. $storage = new MrClay_CookieStorage(array(
  1669. 'secret' => UserConfig::$SESSION_SECRET,
  1670. 'mode' => MrClay_CookieStorage::MODE_ENCRYPT,
  1671. 'path' => UserConfig::$SITEROOTURL
  1672. ));
  1673. $storage->delete(UserConfig::$session_userid_key);
  1674. }
  1675. /**
  1676. * This method turns on impersonation of particular user (instead of just becoming one)
  1677. */
  1678. public function impersonate($user)
  1679. {
  1680. if (is_null($user) || $user->isTheSameAs($this)) {
  1681. return null;
  1682. }
  1683. $storage = new MrClay_CookieStorage(array(
  1684. 'secret' => UserConfig::$SESSION_SECRET,
  1685. 'mode' => MrClay_CookieStorage::MODE_ENCRYPT,
  1686. 'path' => UserConfig::$SITEROOTURL,
  1687. 'httponly' => true
  1688. ));
  1689. if (!$this->isAdmin()) {
  1690. throw new Exception('Not admin (userid: '.$this->userid.') is trying to impersonate another user (userid: '.$user->userid.')');
  1691. }
  1692. if (!$storage->store(UserConfig::$impersonation_userid_key, $user->userid)) {
  1693. throw new Exception(implode('; ', $storage->errors));
  1694. }
  1695. $user->impersonator = $this;
  1696. return $user;
  1697. }
  1698. /**
  1699. * Stops impersonation
  1700. */
  1701. public static function stopImpersonation()
  1702. {
  1703. $storage = new MrClay_Cookie

Large files files are truncated, but you can click here to view the full file