* @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3 * @package SWDB */ require_once(__DIR__ . "/config.php"); require_once(PATH::HELPER . "DB_Helper.php"); require_once(PATH::HELPER . "TEXT_Helper.php"); require_once(PATH::HELPER . "NET_Helper.php"); require_once(PATH::HELPER . "HTML_Helper.php"); require_once(PATH::HELPER . "APPLICATION_Helper.php"); require_once(PATH::ENTITY . "User.php"); require_once(PATH::ENTITY . "Player.php"); require_once(__DIR__ . "/Constant.php"); require_once(__DIR__ . "/Context.php"); /** * Application controller. * * Handles every request, creating the required models and selecting the * view. * * @category Controller */ class Controller extends Context{ /** * @var string[] GET parameters received by the controller. */ private $params = []; /** * @var Context Publicly available context. */ private $context; /** * Retrieves the application context. * * @return Context The context. */ public function get_context(){ return $this->context; } /** * Controller constructor. * * Initializes a database connection and sets up the public context. */ public function __construct(){ $this->context = new Context(); session_start(); $this->db = DB::start(); $this->context->set_db($this->db); } /** * Handles the request parameters. * * Receives the request params and gets itself ready. Authenticates the user (if needed) * and validates the URL. * * @param string[] $params GET parameters of the request. */ public function prepare($params){ // Parse parameters. foreach($params as $p){ if (strlen($p) > 0){ array_push($this->params, $p); } } if ( count($this->params) > 1 && strtoupper($this->params[0]) == "API" ){ // For API calls, skip authentication and end here. return; } // Authentication if (array_key_exists("user_token", $_COOKIE) && array_key_exists("user_id", $_COOKIE)){ // Authenticated user, check token. $statement = $this->db->prepare(" SELECT count(token) AS c FROM token WHERE user = :user AND token = :token AND strftime('%s', datetime(expiry, 'unixepoch', 'localtime')) > strftime('%s','now') "); $statement->bindValue(":user", $_COOKIE["user_id"], SQLITE3_INTEGER); $statement->bindValue(":token", hash('sha256', $_COOKIE["user_token"]), SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r["c"] == 0){ // Token is invalid, expired, clear cookies, session, and logout. require_once(PATH::ACTION . "logout.php"); action(); return; } else{ // Token is valid, renew session, and assign user. $_SESSION["user_id"] = $_COOKIE["user_id"]; $_SESSION["session"] = true; $this->user = new User($_COOKIE["user_id"]); $this->context->set_user($this->user); } } else{ // Unauthenticated user. Continue } if ( count($this->params) > 1 && strtoupper($this->params[0]) == "ACTION" ){ // For ACTION calls, skip user detection and end here. return; } // Validate URL (check if it has the player ID). $this->player = null; if (sizeof($this->params) > 0 && preg_match("/^[0-9]{6,12}$/", $this->params[0]) == 1){ // Player ID passed in URL. Check it in database $statement = $this->db->prepare(" SELECT id, user, public FROM player WHERE id = :id "); $statement->bindValue(":id", $this->params[0], SQLITE3_TEXT); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ // The player exists... if (null != $this->user && $r["user"] == $this->user->get_id()){ // ... and it belongs to the user. Proceed. $this->player = new Player($r["id"]); $this->context->set_player($this->player); } elseif (null == $this->user || $r["user"] != $this->user->get_id()){ // ... and it doesn't belong to the user... if ($r["public"] == 1){ // ... and it belongs to a public profile. Proceed. $this->player = new Player($r["id"]); $this->context->set_player($this->player); } else{ // ... and it belongs to a private profile. Deny access. // TODO } } } } else{ // Player ID is not passed as URL... if (null == $this->user){ // ... and no user logged in. Go to the landing page. require_once(PATH::PAGE . "Landing_Page.php"); $page = new Landing_Page(); require_once($page->get_view()); return; } else{ // ... and the user is logged in. Get last accessed account. $statement = $this->db->prepare(" SELECT id FROM player WHERE user = :user ORDER BY last_access DESC "); $statement->bindValue(":user", $this->user->get_id(), SQLITE3_INTEGER); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r){ header("Location: /" . $r["id"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH)); return; } else{ require_once(PATH::PAGE . "Landing_Page.php"); $page = new Landing_Page(); require_once($page->get_view()); return; } } } // Get game mode $statement = $this->db->prepare("SELECT mode FROM player WHERE id = :id;"); $statement->bindValue(":id", $this->player->get_id(), SQLITE3_INTEGER); $r = $statement->execute()->fetchArray(SQLITE3_ASSOC); if ($r && $r["mode"] == GAME_MODE_ID::RTA){ $this->mode = GAME_MODE_ID::RTA; } else{ $this->mode = GAME_MODE_ID::NORMAL; } $this->context->set_game_mode($this->mode); } /** * Executes the required action. * * Must be called after {@see Controller::prepare()}. * @return void|number */ public function action(){ // API call: Use API controller if (count($this->params) > 0 && strtoupper($this->params[0]) == "API"){ if (count($this->params) == 1){ // TODO: API MAIN PAGE } else{ $version = strtolower($this->params[1]); $api_params = $this->params; array_shift($api_params); array_shift($api_params); switch ($version){ case "v1": require_once(__DIR__ . "/API/v1/API_Controller.php"); new API_Controller($this->params); break; } } return; } // Special case: Actions. // Not redirecting to page, just execute a function // TODO: Secure actions elseif (count($this->params) > 1 && strtoupper($this->params[0]) == "ACTION"){ switch (strtoupper($this->params[1])){ case "CHANGE_GAME_MODE": require_once(PATH::ACTION . "change_game_mode.php"); action(); return; break; case "LOGIN": require_once(PATH::ACTION . "login.php"); action(); return; break; case "LOGOUT": require_once(PATH::ACTION . "logout.php"); action(); return; break; case "NEW_TEAM": require_once(PATH::ACTION . "new_team.php"); action(); return; break; case "DELETE_TEAM": require_once(PATH::ACTION . "delete_team.php"); action(); return; break; case "RATE_TEAM": require_once(PATH::ACTION . "rate_team.php"); action(); return; break; case "SAVE_RUN_TEAM": require_once(PATH::ACTION . "save_run_team.php"); action(); return; break; case "OPTIMIZE_GET_RUNE_LIST": require_once(PATH::ACTION . "optimize_get_rune_list.php"); $response = action(); if (strlen($response) > 1){ echo($response); return; } else{ return; } break; case "OPTIMIZE_GET_OPTIONS": require_once(PATH::ACTION . "optimize_get_options.php"); $response = action(); if (strlen($response) > 1){ echo($response); return; } else{ return; } break; case "EDIT_PROFILE": require_once(PATH::ACTION . "edit_profile.php"); $response = action(); if (strlen($response) > 1){ echo($response); return; } else{ return; } break; default: require_once(PATH::PAGE . "Error_Page.php"); $page = new Error_Page(404); http_response_code(404); } } // Select the model to load. array_shift($this->params); // Remove first one, should be player_id if (sizeof($this->params) == 0){ require_once(PATH::PAGE . "Home_Page.php"); $page = new Home_Page(); } else{ if (strtoupper($this->params[0]) == "RUNES"){ require_once(PATH::PAGE . "Runes_Page.php"); $page = new Runes_Page(); } elseif (strtoupper($this->params[0]) == "ENCHANTMENTS"){ require_once(PATH::PAGE . "Enchantments_Page.php"); $page = new Enchantments_Page(); } elseif (strtoupper($this->params[0]) == "ARTIFACTS"){ require_once(PATH::PAGE . "Artifacts_Page.php"); $page = new Artifacts_Page(); } elseif (strtoupper($this->params[0]) == "GUILD"){ require_once(PATH::PAGE . "Guild_Page.php"); $page = new Guild_Page(); } elseif (strtoupper($this->params[0]) == "RUNS"){ require_once(PATH::PAGE . "Runs_Page.php"); $page = new Runs_Page(); } elseif (strtoupper($this->params[0]) == "STATS"){ require_once(PATH::PAGE . "Stats_Page.php"); $page = new Stats_Page(); } elseif (strtoupper($this->params[0]) == "TEAMS"){ require_once(PATH::PAGE . "Teams_Page.php"); $page = new Teams_Page(); } elseif (strtoupper($this->params[0]) == "PROFILE"){ require_once(PATH::PAGE . "Profile_Page.php"); $page = new Profile_Page(); } elseif (strtoupper($this->params[0]) == "UNITS"){ if (count($this->params) == 1){ require_once(PATH::PAGE . "Units_Page.php"); $page = new Units_Page(); } else{ require_once(PATH::PAGE . "Unit_Page.php"); $page = new Unit_Page($this->params[1]); } } elseif (strtoupper($this->params[0]) == "MONSTERS"){ if (count($this->params) == 1){ require_once(PATH::PAGE . "Monsters_Page.php"); $page = new Monsters_Page(); } else{ require_once(PATH::PAGE . "Monster_Page.php"); $page = new Monster_Page($this->params[1]); } } elseif (strtoupper($this->params[0]) == "REPORT"){ if (count($this->params) == 1){ require_once(PATH::PAGE . "Report_Page.php"); $page = new Report_Page(); } elseif (strtoupper($this->params[1]) == "SKILLUP"){ require_once(PATH::PAGE . "Report_Skillup_Page.php"); $page = new Report_Skillup_Page($this->params[1]); } elseif (strtoupper($this->params[1]) == "RUNE_ENCHANTMENT"){ require_once(PATH::PAGE . "Report_Rune_Enchantment_Page.php"); $page = new Report_Rune_Enchantment_Page($this->params[1]); } } elseif (strtoupper($this->params[0]) == "OPTIMIZER"){ if (count($this->params) == 1){ require_once(PATH::PAGE . "Optimizer_Page.php"); $page = new Optimizer_Page(); } else{ require_once(PATH::PAGE . "Optimizer_Unit_Page.php"); $page = new Optimizer_Unit_Page($this->params[1]); } } } // Load the view, or set an error code. if (isset($page)){ require_once($page->get_view()); return 200; } else{ require_once(PATH::PAGE . "Error_Page.php"); $page = new Error_Page(404); require_once($page->get_view()); http_response_code(404); return 404; } } }