Controller.php 15 KB

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