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

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