PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Flux/SessionData.php

https://github.com/chokoleytdesignoper/fluxcp_choko
PHP | 418 lines | 255 code | 51 blank | 112 comment | 70 complexity | df5d849e2cc64e282c2b09a354395d11 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, BSD-3-Clause
  1. <?php
  2. require_once 'Flux/DataObject.php';
  3. require_once 'Flux/ItemShop/Cart.php';
  4. require_once 'Flux/LoginError.php';
  5. /**
  6. * Contains all of Flux's session data.
  7. */
  8. class Flux_SessionData {
  9. /**
  10. * Actual session data array.
  11. *
  12. * @access private
  13. * @var array
  14. */
  15. private $sessionData;
  16. /**
  17. * Session data filters.
  18. *
  19. * @access private
  20. * @var array
  21. */
  22. private $dataFilters = array();
  23. /**
  24. * Selected login server group.
  25. *
  26. * @access public
  27. * @var Flux_LoginAthenaGroup
  28. */
  29. public $loginAthenaGroup;
  30. /**
  31. * Selected login server.
  32. *
  33. * @access public
  34. * @var Flux_LoginServer
  35. */
  36. public $loginServer;
  37. /**
  38. * Account object.
  39. *
  40. * @access public
  41. * @var Flux_DataObject
  42. */
  43. public $account;
  44. /**
  45. * Create new SessionData instance.
  46. *
  47. * @param array $sessionData
  48. * @access public
  49. */
  50. public function __construct(array &$sessionData, $logout = false)
  51. {
  52. $this->sessionData = &$sessionData;
  53. if ($logout) {
  54. $this->logout();
  55. }
  56. else {
  57. $this->initialize();
  58. }
  59. }
  60. /**
  61. * Initialize session data.
  62. *
  63. * @param bool $force
  64. * @return bool
  65. * @access private
  66. */
  67. private function initialize($force = false)
  68. {
  69. $keysToInit = array('username', 'serverName', 'athenaServerName', 'securityCode');
  70. foreach ($keysToInit as $key) {
  71. if ($force || !$this->{$key}) {
  72. $method = ucfirst($key);
  73. $method = "set{$method}Data";
  74. $this->$method(null);
  75. }
  76. }
  77. $loggedIn = true;
  78. if (!$this->username) {
  79. $loggedIn = false;
  80. $cfgAthenaServerName = Flux::config('DefaultCharMapServer');
  81. $cfgLoginAthenaGroup = Flux::config('DefaultLoginGroup');
  82. if (Flux::getServerGroupByName($cfgLoginAthenaGroup)){
  83. $this->setServerNameData($cfgLoginAthenaGroup);
  84. }
  85. else {
  86. $defaultServerName = current(array_keys(Flux::$loginAthenaGroupRegistry));
  87. $this->setServerNameData($defaultServerName);
  88. }
  89. }
  90. if ($this->serverName && ($this->loginAthenaGroup = Flux::getServerGroupByName($this->serverName))) {
  91. $this->loginServer = $this->loginAthenaGroup->loginServer;
  92. if (!$loggedIn && $cfgAthenaServerName && $this->getAthenaServer($cfgAthenaServerName)) {
  93. $this->setAthenaServerNameData($cfgAthenaServerName);
  94. }
  95. if (!$this->athenaServerName || ((!$loggedIn && !$this->getAthenaServer($cfgAthenaServerName)) || !$this->getAthenaServer($this->athenaServerName))) {
  96. $this->setAthenaServerNameData(current($this->getAthenaServerNames()));
  97. }
  98. }
  99. // Get new account data every request.
  100. if ($this->loginAthenaGroup && $this->username && ($account = $this->getAccount($this->loginAthenaGroup, $this->username))) {
  101. $this->account = $account;
  102. // Automatically log out of account when detected as banned.
  103. $permBan = ($account->state == 5 && !Flux::config('AllowPermBanLogin'));
  104. $tempBan = (($account->unban_time > 0 && $account->unban_time < time()) && !Flux::config('AllowTempBanLogin'));
  105. if ($permBan || $tempBan) {
  106. $this->logout();
  107. }
  108. }
  109. else {
  110. $this->account = new Flux_DataObject(null, array('level' => AccountLevel::UNAUTH));
  111. }
  112. //if (!$this->isLoggedIn()) {
  113. // $this->setServerNameData(null);
  114. // $this->setAthenaServerNameData(null);
  115. //}
  116. if (!is_array($this->cart)) {
  117. $this->setCartData(array());
  118. }
  119. if ($this->account->account_id && $this->loginAthenaGroup) {
  120. if (!array_key_exists($this->loginAthenaGroup->serverName, $this->cart)) {
  121. $this->cart[$this->loginAthenaGroup->serverName] = array();
  122. }
  123. foreach ($this->getAthenaServerNames() as $athenaServerName) {
  124. $athenaServer = $this->getAthenaServer($athenaServerName);
  125. $cartArray = &$this->cart[$this->loginAthenaGroup->serverName];
  126. $accountID = $this->account->account_id;
  127. if (!array_key_exists($accountID, $cartArray)) {
  128. $cartArray[$accountID] = array();
  129. }
  130. if (!array_key_exists($athenaServerName, $cartArray[$accountID])) {
  131. $cartArray[$accountID][$athenaServerName] = new Flux_ItemShop_Cart();
  132. }
  133. $cartArray[$accountID][$athenaServerName]->setAccount($this->account);
  134. $athenaServer->setCart($cartArray[$accountID][$athenaServerName]);
  135. }
  136. }
  137. return true;
  138. }
  139. /**
  140. * Log current user out.
  141. *
  142. * @return bool
  143. * @access public
  144. */
  145. public function logout()
  146. {
  147. $this->loginAthenaGroup = null;
  148. $this->loginServer = null;
  149. return $this->initialize(true);
  150. }
  151. public function __call($method, $args)
  152. {
  153. if (count($args) && preg_match('/set(.+?)Data/', $method, $m)) {
  154. $arg = current($args);
  155. $meth = $m[1];
  156. $meth[0] = strtolower($meth[0]);
  157. if (array_key_exists($meth, $this->dataFilters)) {
  158. foreach ($this->dataFilters[$meth] as $callback) {
  159. $arg = call_user_func($callback, $arg);
  160. }
  161. }
  162. $this->sessionData[$meth] = $arg;
  163. }
  164. }
  165. public function &__get($prop)
  166. {
  167. $value = null;
  168. if (array_key_exists($prop, $this->sessionData)) {
  169. $value = &$this->sessionData[$prop];
  170. }
  171. return $value;
  172. }
  173. /**
  174. * Set session data.
  175. *
  176. * @param array $keys Session keys to be affected.
  177. * @param mixed $value Value to be assigned to all specified keys.
  178. * @return mixed whatever was set
  179. * @access public
  180. */
  181. public function setData(array $keys, $value)
  182. {
  183. foreach ($keys as $key) {
  184. $key = ucfirst($key);
  185. $this->{"set{$key}Data"}($value);
  186. }
  187. return $value;
  188. }
  189. /**
  190. * Add a session data setter filter.
  191. *
  192. * @param string $key Which session key
  193. * @param string $callback Function callback.
  194. * @return string Callback
  195. * @access public
  196. */
  197. public function addDataFilter($key, $callback)
  198. {
  199. if (!array_key_exists($key, $this->dataFilters)) {
  200. $this->dataFilters[$key] = array();
  201. }
  202. $this->dataFilters[$key][] = $callback;
  203. return $callback;
  204. }
  205. /**
  206. * Checks whether the current user is logged in.
  207. */
  208. public function isLoggedIn()
  209. {
  210. return $this->account->level >= AccountLevel::NORMAL;
  211. }
  212. /**
  213. * User login.
  214. *
  215. * @param string $server Server name
  216. * @param string $username
  217. * @param string $password
  218. * @throws Flux_LoginError
  219. * @access public
  220. */
  221. public function login($server, $username, $password, $securityCode = null)
  222. {
  223. $loginAthenaGroup = Flux::getServerGroupByName($server);
  224. if (!$loginAthenaGroup) {
  225. throw new Flux_LoginError('Invalid server.', Flux_LoginError::INVALID_SERVER);
  226. }
  227. if ($loginAthenaGroup->loginServer->isIpBanned() && !Flux::config('AllowIpBanLogin')) {
  228. throw new Flux_LoginError('IP address is banned', Flux_LoginError::IPBANNED);
  229. }
  230. if (!$loginAthenaGroup->isAuth($username, $password)) {
  231. throw new Flux_LoginError('Invalid login', Flux_LoginError::INVALID_LOGIN);
  232. }
  233. if ($securityCode !== false && Flux::config('UseLoginCaptcha')) {
  234. if (strtolower($securityCode) != strtolower($this->securityCode)) {
  235. throw new Flux_LoginError('Invalid security code', Flux_LoginError::INVALID_SECURITY_CODE);
  236. }
  237. elseif (Flux::config('EnableReCaptcha')) {
  238. require_once 'recaptcha/recaptchalib.php';
  239. $resp = recaptcha_check_answer(
  240. Flux::config('ReCaptchaPrivateKey'),
  241. $_SERVER['REMOTE_ADDR'],
  242. // Checks POST fields.
  243. $_POST['recaptcha_challenge_field'],
  244. $_POST['recaptcha_response_field']);
  245. if (!$resp->is_valid) {
  246. throw new Flux_LoginError('Invalid security code', Flux_LoginError::INVALID_SECURITY_CODE);
  247. }
  248. }
  249. }
  250. $creditsTable = Flux::config('FluxTables.CreditsTable');
  251. $creditColumns = 'credits.balance, credits.last_donation_date, credits.last_donation_amount';
  252. $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login ";
  253. $sql .= "LEFT OUTER JOIN {$creditsTable} AS credits ON login.account_id = credits.account_id ";
  254. $sql .= "WHERE login.sex != 'S' AND login.level >= 0 AND login.userid = ? LIMIT 1";
  255. $smt = $loginAthenaGroup->connection->getStatement($sql);
  256. $res = $smt->execute(array($username));
  257. if ($res && ($row = $smt->fetch())) {
  258. if ($row->unban_time > 0) {
  259. if (time() >= $row->unban_time) {
  260. $row->unban_time = 0;
  261. $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.login SET unban_time = 0 WHERE account_id = ?";
  262. $sth = $loginAthenaGroup->connection->getStatement($sql);
  263. $sth->execute(array($row->account_id));
  264. }
  265. elseif (!Flux::config('AllowTempBanLogin')) {
  266. throw new Flux_LoginError('Temporarily banned', Flux_LoginError::BANNED);
  267. }
  268. }
  269. if ($row->state == 5) {
  270. $createTable = Flux::config('FluxTables.AccountCreateTable');
  271. $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$createTable ";
  272. $sql .= "WHERE account_id = ? AND confirmed = 0";
  273. $sth = $loginAthenaGroup->connection->getStatement($sql);
  274. $sth->execute(array($row->account_id));
  275. $row2 = $sth->fetch();
  276. if ($row2 && $row2->id) {
  277. throw new Flux_LoginError('Pending confirmation', Flux_LoginError::PENDING_CONFIRMATION);
  278. }
  279. }
  280. if (!Flux::config('AllowPermBanLogin') && $row->state == 5) {
  281. throw new Flux_LoginError('Permanently banned', Flux_LoginError::PERMABANNED);
  282. }
  283. $this->setServerNameData($server);
  284. $this->setUsernameData($username);
  285. $this->initialize(false);
  286. }
  287. else {
  288. $message = "Unexpected error during login.\n";
  289. $message .= 'PDO error info, if any: '.print_r($smt->errorInfo(), true);
  290. throw new Flux_LoginError($message, Flux_LoginError::UNEXPECTED);
  291. }
  292. return true;
  293. }
  294. /**
  295. * Get account object for a particular user name.
  296. *
  297. * @param Flux_LoginAthenaGroup $loginAthenaGroup
  298. * @param string $username
  299. * @return mixed
  300. * @access private
  301. */
  302. private function getAccount(Flux_LoginAthenaGroup $loginAthenaGroup, $username)
  303. {
  304. $creditsTable = Flux::config('FluxTables.CreditsTable');
  305. $creditColumns = 'credits.balance, credits.last_donation_date, credits.last_donation_amount';
  306. $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login ";
  307. $sql .= "LEFT OUTER JOIN {$loginAthenaGroup->loginDatabase}.{$creditsTable} AS credits ON login.account_id = credits.account_id ";
  308. $sql .= "WHERE login.sex != 'S' AND login.level >= 0 AND login.userid = ? LIMIT 1";
  309. $smt = $loginAthenaGroup->connection->getStatement($sql);
  310. $res = $smt->execute(array($username));
  311. if ($res && ($row = $smt->fetch())) {
  312. return $row;
  313. }
  314. else {
  315. return false;
  316. }
  317. }
  318. /**
  319. * Get available server names.
  320. *
  321. * @access public
  322. */
  323. public function getAthenaServerNames()
  324. {
  325. if ($this->loginAthenaGroup) {
  326. $names = array();
  327. foreach ($this->loginAthenaGroup->athenaServers as $server) {
  328. $names[] = $server->serverName;
  329. }
  330. return $names;
  331. }
  332. else {
  333. return array();
  334. }
  335. }
  336. /**
  337. * Get a Flux_Athena instance by its name based on current server settings.
  338. *
  339. * @param string $name
  340. * @access public
  341. */
  342. public function getAthenaServer($name = null)
  343. {
  344. if (is_null($name) && $this->athenaServerName) {
  345. return $this->getAthenaServer($this->athenaServerName);
  346. }
  347. if ($this->loginAthenaGroup && ($server = Flux::getAthenaServerByName($this->serverName, $name))) {
  348. return $server;
  349. }
  350. else {
  351. return false;
  352. }
  353. }
  354. /**
  355. * Get flash message.
  356. *
  357. * @return string
  358. * @access public
  359. */
  360. public function getMessage()
  361. {
  362. $message = $this->message;
  363. $this->setMessageData(null);
  364. return $message;
  365. }
  366. }
  367. ?>