Controller.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. /**
  3. * Controller file.
  4. *
  5. * Provides a class to handle all posible request.
  6. *
  7. * @author Iñigo Valentin <i@inigovalentin.com>
  8. * @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3
  9. * @package SWDB
  10. */
  11. /**
  12. * Include some required files.
  13. */
  14. require_once(__DIR__ . "/config.php");
  15. require_once(PATH::HELPER . "DB_Helper.php");
  16. require_once(PATH::HELPER . "TEXT_Helper.php");
  17. require_once(PATH::HELPER . "NET_Helper.php");
  18. require_once(PATH::HELPER . "HTML_Helper.php");
  19. require_once(PATH::HELPER . "APPLICATION_Helper.php");
  20. require_once(PATH::ENTITY . "User.php");
  21. require_once(PATH::ENTITY . "Player.php");
  22. require_once(__DIR__ . "/Constant.php");
  23. require_once(__DIR__ . "/Context.php");
  24. /**
  25. * Application controller.
  26. *
  27. * Handles every request, creating the required models and selecting the
  28. * view.
  29. *
  30. * @category Controller
  31. */
  32. class Controller extends Context{
  33. /**
  34. * @var string[] GET parameters received by the controller.
  35. */
  36. private $params = [];
  37. /**
  38. * @var Context Publicly available context.
  39. */
  40. private $context;
  41. /**
  42. * Retrieves the application context.
  43. *
  44. * @return Context The context.
  45. */
  46. public function get_context(){
  47. return $this->context;
  48. }
  49. /**
  50. * Controller constructor.
  51. *
  52. * Initializes a database connection and sets up the public context.
  53. */
  54. public function __construct(){
  55. $this->context = new Context();
  56. session_start();
  57. $this->db = DB::start();
  58. $this->context->set_db($this->db);
  59. }
  60. /**
  61. * Handles the request parameters.
  62. *
  63. * Receives the request params and gets itself ready. Authenticates the user (if needed)
  64. * and validates the URL.
  65. *
  66. * @param string[] $params GET parameters of the request.
  67. */
  68. public function prepare($params){
  69. // Parse parameters.
  70. foreach($params as $p){
  71. if (strlen($p) > 0){
  72. array_push($this->params, $p);
  73. }
  74. }
  75. if (
  76. count($this->params) > 1 &&
  77. (
  78. strtoupper($this->params[0]) == "ACTION"
  79. ) ||
  80. strtoupper($this->params[0]) == "API"
  81. ){
  82. // For API calls, or login action calls, skip authentication
  83. return;
  84. }
  85. // Authentication
  86. if (array_key_exists("user_token", $_COOKIE) && array_key_exists("user_id", $_COOKIE)){
  87. // Authenticated user, check token.
  88. $statement = $this->db->prepare("
  89. SELECT count(token) AS c
  90. FROM token
  91. WHERE
  92. user = :user AND
  93. token = :token AND
  94. strftime('%s', datetime(expiry, 'unixepoch', 'localtime')) > strftime('%s','now')
  95. ");
  96. $statement->bindValue(":user", $_COOKIE["user_id"], SQLITE3_INTEGER);
  97. $statement->bindValue(":token", hash('sha256', $_COOKIE["user_token"]), SQLITE3_TEXT);
  98. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  99. if ($r["c"] == 0){
  100. // Token is invalid, expired, clear cookies, session, and logout.
  101. require_once(PATH::ACTION . "logout.php");
  102. action();
  103. return;
  104. }
  105. else{
  106. // Token is valid, renew session, and assign user.
  107. $_SESSION["user_id"] = $_COOKIE["user_id"];
  108. $_SESSION["session"] = true;
  109. $this->user = new User($_COOKIE["user_id"]);
  110. $this->context->set_user($this->user);
  111. }
  112. }
  113. else{
  114. // Unauthenticated user. Continue
  115. }
  116. // Validate URL (check if it has the player ID).
  117. $this->player = null;
  118. if (sizeof($this->params) > 0 && preg_match("/^[0-9]{6,12}$/", $this->params[0]) == 1){
  119. // Player ID passed in URL. Check it in database
  120. $statement = $this->db->prepare("
  121. SELECT
  122. id,
  123. user,
  124. public
  125. FROM player
  126. WHERE id = :id
  127. ");
  128. $statement->bindValue(":id", $this->params[0], SQLITE3_TEXT);
  129. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  130. if ($r){
  131. // The player exists...
  132. if (null != $this->user && $r["user"] == $this->user->get_id()){
  133. // ... and it belongs to the user. Proceed.
  134. $this->player = new Player($r["id"]);
  135. $this->context->set_player($this->player);
  136. }
  137. elseif (null == $this->user || $r["user"] != $this->user->get_id()){
  138. // ... and it doesn't belong to the user...
  139. if ($r["public"] == 1){
  140. // ... and it belongs to a public profile. Proceed.
  141. $this->player = new Player($r["id"]);
  142. $this->context->set_player($this->player);
  143. }
  144. else{
  145. // ... and it belongs to a private profile. Deny access.
  146. // TODO
  147. }
  148. }
  149. }
  150. }
  151. else{
  152. // Player ID is not passed as URL...
  153. if (null == $this->user){
  154. // ... and no user logged in. Go to the landing page.
  155. require_once(PATH::PAGE . "Landing_Page.php");
  156. $page = new Landing_Page();
  157. require_once($page->view);
  158. return;
  159. }
  160. else{
  161. // ... and the user is logged in. Get last accessed account.
  162. $statement = $this->db->prepare("
  163. SELECT id
  164. FROM player
  165. WHERE user = :user
  166. ORDER BY last_access DESC
  167. ");
  168. $statement->bindValue(":user", $this->user->get_id(), SQLITE3_INTEGER);
  169. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  170. if ($r){
  171. header("Location: /" . $r["id"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));
  172. return;
  173. }
  174. else{
  175. require_once(PATH::PAGE . "Landing_Page.php");
  176. $page = new Landing_Page();
  177. require_once($page->view);
  178. return;
  179. }
  180. }
  181. }
  182. // Get game mode
  183. $statement = $this->db->prepare("SELECT mode FROM player WHERE id = :id;");
  184. $statement->bindValue(":id", $this->player->get_id(), SQLITE3_INTEGER);
  185. $r = $statement->execute()->fetchArray(SQLITE3_ASSOC);
  186. if ($r && $r["mode"] == GAME_MODE_ID::RTA){
  187. $this->mode = GAME_MODE_ID::RTA;
  188. }
  189. else{
  190. $this->mode = GAME_MODE_ID::NORMAL;
  191. }
  192. $this->context->set_game_mode($this->mode);
  193. }
  194. /**
  195. * Executes the required action.
  196. *
  197. * Must be called after {@see Controller::prepare()}.
  198. * @return void|number
  199. */
  200. public function action(){
  201. // API call: Use API controller
  202. if (count($this->params) > 0 && strtoupper($this->params[0]) == "API"){
  203. if (count($this->params) == 1){
  204. // TODO: API MAIN PAGE
  205. }
  206. else{
  207. $version = strtolower($this->params[1]);
  208. $api_params = $this->params;
  209. array_shift($api_params);
  210. array_shift($api_params);
  211. switch ($version){
  212. case "v1":
  213. require_once(__DIR__ . "/API/v1/API_Controller.php");
  214. new API_Controller($this->params);
  215. break;
  216. }
  217. }
  218. return;
  219. }
  220. // Special case: Actions.
  221. // Not redirecting to page, just execute a function
  222. // TODO: Secure actions
  223. elseif (count($this->params) > 1 && strtoupper($this->params[0]) == "ACTION"){
  224. switch (strtoupper($this->params[1])){
  225. case "CHANGE_GAME_MODE":
  226. require_once(PATH::ACTION . "change_game_mode.php");
  227. action();
  228. return;
  229. break;
  230. case "LOGIN":
  231. require_once(PATH::ACTION . "login.php");
  232. action();
  233. return;
  234. break;
  235. case "LOGOUT":
  236. require_once(PATH::ACTION . "logout.php");
  237. action();
  238. return;
  239. break;
  240. case "NEW_TEAM":
  241. require_once(PATH::ACTION . "new_team.php");
  242. action();
  243. return;
  244. break;
  245. case "DELETE_TEAM":
  246. require_once(PATH::ACTION . "delete_team.php");
  247. action();
  248. return;
  249. break;
  250. case "RATE_TEAM":
  251. require_once(PATH::ACTION . "rate_team.php");
  252. action();
  253. return;
  254. break;
  255. case "SAVE_RUN_TEAM":
  256. require_once(PATH::ACTION . "save_run_team.php");
  257. action();
  258. return;
  259. break;
  260. case "OPTIMIZE_GET_RUNE_LIST":
  261. require_once(PATH::ACTION . "optimize_get_rune_list.php");
  262. $response = action();
  263. if (strlen($response) > 1){
  264. echo($response);
  265. return;
  266. }
  267. else{
  268. return;
  269. }
  270. break;
  271. case "OPTIMIZE_GET_OPTIONS":
  272. require_once(PATH::ACTION . "optimize_get_options.php");
  273. $response = action();
  274. if (strlen($response) > 1){
  275. echo($response);
  276. return;
  277. }
  278. else{
  279. return;
  280. }
  281. break;
  282. case "EDIT_PROFILE":
  283. require_once(PATH::ACTION . "edit_profile.php");
  284. $response = action();
  285. if (strlen($response) > 1){
  286. echo($response);
  287. return;
  288. }
  289. else{
  290. return;
  291. }
  292. break;
  293. default:
  294. require_once(PATH::PAGE . "Error_Page.php");
  295. $page = new Error_Page(404);
  296. http_response_code(404);
  297. }
  298. }
  299. // Select the model to load.
  300. array_shift($this->params); // Remove first one, should be player_id
  301. if (sizeof($this->params) == 0){
  302. require_once(PATH::PAGE . "Home_Page.php");
  303. $page = new Home_Page();
  304. }
  305. else{
  306. if (strtoupper($this->params[0]) == "RUNES"){
  307. require_once(PATH::PAGE . "Runes_Page.php");
  308. $page = new Runes_Page();
  309. }
  310. elseif (strtoupper($this->params[0]) == "ENCHANTMENTS"){
  311. require_once(PATH::PAGE . "Enchantments_Page.php");
  312. $page = new Enchantments_Page();
  313. }
  314. elseif (strtoupper($this->params[0]) == "ARTIFACTS"){
  315. require_once(PATH::PAGE . "Artifacts_Page.php");
  316. $page = new Artifacts_Page();
  317. }
  318. elseif (strtoupper($this->params[0]) == "GUILD"){
  319. require_once(PATH::PAGE . "Guild_Page.php");
  320. $page = new Guild_Page();
  321. }
  322. elseif (strtoupper($this->params[0]) == "RUNS"){
  323. require_once(PATH::PAGE . "Runs_Page.php");
  324. $page = new Runs_Page();
  325. }
  326. elseif (strtoupper($this->params[0]) == "STATS"){
  327. require_once(PATH::PAGE . "Stats_Page.php");
  328. $page = new Stats_Page();
  329. }
  330. elseif (strtoupper($this->params[0]) == "TEAMS"){
  331. require_once(PATH::PAGE . "Teams_Page.php");
  332. $page = new Teams_Page();
  333. }
  334. elseif (strtoupper($this->params[0]) == "PROFILE"){
  335. require_once(PATH::PAGE . "Profile_Page.php");
  336. $page = new Profile_Page();
  337. }
  338. elseif (strtoupper($this->params[0]) == "UNITS"){
  339. if (count($this->params) == 1){
  340. require_once(PATH::PAGE . "Units_Page.php");
  341. $page = new Units_Page();
  342. }
  343. else{
  344. require_once(PATH::PAGE . "Unit_Page.php");
  345. $page = new Unit_Page($this->params[1]);
  346. }
  347. }
  348. elseif (strtoupper($this->params[0]) == "MONSTERS"){
  349. if (count($this->params) == 1){
  350. require_once(PATH::PAGE . "Monsters_Page.php");
  351. $page = new Monsters_Page();
  352. }
  353. else{
  354. require_once(PATH::PAGE . "Monster_Page.php");
  355. $page = new Monster_Page($this->params[1]);
  356. }
  357. }
  358. elseif (strtoupper($this->params[0]) == "REPORT"){
  359. if (count($this->params) == 1){
  360. require_once(PATH::PAGE . "Report_Page.php");
  361. $page = new Report_Page();
  362. }
  363. elseif (strtoupper($this->params[1]) == "SKILLUP"){
  364. require_once(PATH::PAGE . "Report_Skillup_Page.php");
  365. $page = new Report_Skillup_Page($this->params[1]);
  366. }
  367. elseif (strtoupper($this->params[1]) == "RUNE_ENCHANTMENT"){
  368. require_once(PATH::PAGE . "Report_Rune_Enchantment_Page.php");
  369. $page = new Report_Rune_Enchantment_Page($this->params[1]);
  370. }
  371. }
  372. elseif (strtoupper($this->params[0]) == "OPTIMIZER"){
  373. if (count($this->params) == 1){
  374. require_once(PATH::PAGE . "Optimizer_Page.php");
  375. $page = new Optimizer_Page();
  376. }
  377. else{
  378. require_once(PATH::PAGE . "Optimizer_Unit_Page.php");
  379. $page = new Optimizer_Unit_Page($this->params[1]);
  380. }
  381. }
  382. }
  383. // Load the view, or set an error code.
  384. if (isset($page)){
  385. require_once($page->view);
  386. return 200;
  387. }
  388. else{
  389. require_once(PATH::PAGE . "Error_Page.php");
  390. $page = new Error_Page(404);
  391. http_response_code(404);
  392. return 404;
  393. }
  394. }
  395. }