소스 검색

Profile page. Logout. Cookies and sessions. Profile edit page and functions.

Iñigo Valentin 6 년 전
부모
커밋
8287b7a27a

+ 64 - 22
application/Controller.php

@@ -26,7 +26,7 @@
          *
          * @param Array $params POST parameters of the request.
          */
-        public function __construct($uid, $params){
+        public function __construct($params){
 
             global $path;
             global $UID;
@@ -52,6 +52,11 @@
                         action($db);
                         return;
                         break;
+                    case "LOGOUT":
+                        require_once($path["action"] . "logout.php");
+                        action($db);
+                        return;
+                        break;
                     case "NEW_TEAM":
                         require_once($path["action"] . "new_team.php");
                         action($db);
@@ -62,6 +67,17 @@
                         action($db);
                         return;
                         break;
+                    case "EDIT_PROFILE":
+                        require_once($path["action"] . "edit_profile.php");
+                        $response = action($db);
+                        if (strlen($response) > 1){
+                            echo($response);
+                            return;
+                        }
+                        else{
+                            return;
+                        }
+                        break;
                     default:
                         require_once($path["page"] . "Error_Page.php");
                         $page = new Error_Page($db, 404);
@@ -69,33 +85,55 @@
                 }
             }
 
-            // TODO: Validate private/public user with cookie and redirect
-            $UID = $uid;
-            if (preg_match("/\d{7}/", $UID)){
-                $q = $db->query("SELECT count(uid) AS c FROM player WHERE uid = $UID;");
-                $r = $q->fetchArray(SQLITE3_ASSOC);
-                if ($r["c"] == 0){
-                    require_once($path["page"] . "Landing_Page.php");
-                    $page = new Landing_Page($db);
-                    require_once($page->view);
-                    return;
-                }
+            if (isset($_COOKIE["uid"]) && isset($_SESSION["uid"]) && $_COOKIE["uid"] != $_COOKIE["uid"]){
+                // Both cookie and session are set, but they are different. Delete them both.
+                setcookie("uid", "", time() - 3600);
+                $_SESSION["session"] = false;
+                $_SESSION["uid"] = "";
+                require_once($path["page"] . "Landing_Page.php");
+                $page = new Landing_Page($db);
+                require_once($page->view);
+                return;
+            }
+            elseif (isset($_COOKIE["uid"]) && !isset($_SESSION["uid"])){
+                $_SESSION["session"] = true;
+                $_SESSION["uid"] = $_COOKIE["uid"];
+            }
+            elseif (!isset($_COOKIE["uid"]) && isset($_SESSION["uid"])){
+                setcookie("uid", $_SESSION["uid"], time() + 5 * 24 * 60 * 60);
+            }
+
+            // Validate session
+            $UID = $_SESSION["uid"];
+            $q = $db->query("SELECT count(uid) AS c FROM player WHERE uid = '$UID';");
+            $r = $q->fetchArray(SQLITE3_ASSOC);
+            if ($r["c"] == 0){
+                require_once($path["page"] . "Landing_Page.php");
+                $page = new Landing_Page($db);
+                require_once($page->view);
+                return;
             }
             else{
-                if ($_SESSION['session'] == true && isset($_SESSION['uid'])){
-                    $UID = $_SESSION['uid'];
-                    header("Location: /$UID" . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));
-                    return;
-                }
-                else{
-                    require_once($path["page"] . "Landing_Page.php");
-                    $page = new Landing_Page($db);
-                    require_once($page->view);
-                    return;
+                // Reset cokie and renew session.
+                setcookie("uid", $_SESSION["uid"], time() + 5 * 24 * 60 * 60);
+                $_SESSION["session"] = true;
+                $_SESSION["uid"] = $UID;
+                // Recover username if lost
+                if (!isset($_SESSION["name"]) || strlen($_SESSION["name"]) == 0){
+                    $q = $db->query("SELECT name FROM player WHERE uid = '$UID';");
+                    $r = $q->fetchArray(SQLITE3_ASSOC);
+                    $_SESSION["name"] = $r["name"];
                 }
             }
 
+            // If UID not in URL, redirect and end.
+            if ($pars[0] != $UID){
+                header("Location: /$UID" . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));
+                return;
+            }
+
             // Select the model to load.
+            array_shift($pars); // Remove first one, should be UID
             if (sizeof($pars) == 0){
                 require_once($path["page"] . "Home_Page.php");
                 $page = new Home_Page($db);
@@ -121,6 +159,10 @@
                     require_once($path["page"] . "Teams_Page.php");
                     $page = new Teams_Page($db);
                 }
+                elseif (strtoupper($pars[0]) == "PROFILE"){
+                    require_once($path["page"] . "Profile_Page.php");
+                    $page = new Profile_Page($db);
+                }
                 elseif (strtoupper($pars[0]) == "MONSTERS"){
                     if (count($pars) == 1){
                         require_once($path["page"] . "Monsters_Page.php");

+ 69 - 0
application/action/edit_profile.php

@@ -0,0 +1,69 @@
+<?php
+
+    function generateApi($length = 16) {
+        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+        $charactersLength = strlen($characters);
+        $randomString = '';
+        for ($i = 0; $i < $length; $i++) {
+            $randomString .= $characters[rand(0, $charactersLength - 1)];
+        }
+        return $randomString;
+    }
+
+    function action($db = null){
+        global $AREA_TYPE;
+        global $DIFFICULTY;
+        global $SCENARIO;
+        global $DUNGEON;
+        global $ELEMENTAL_RIFT_DUNGEON;
+        global $LABYRINTH_STAGES;
+        global $UID;
+
+        $response = null;
+
+        $player = filter_input(INPUT_POST, 'uid');
+
+        if (filter_input(INPUT_POST, "mail")){
+            $mail = filter_input(INPUT_POST, 'mail');
+            // TODO: Validate mail
+            $s = $db->prepare('UPDATE player SET mail = :mail WHERE uid = :uid;');
+error_log("UPDATE player SET mail = '$mail' WHERE uid = '$player';");
+            $s->bindValue(':uid', $player);
+            $s->bindValue(':mail', $mail);
+            if(!$s->execute()){
+                return -1;
+            }
+        }
+
+        if (filter_input(INPUT_POST, "pass")){
+            $pass = sha1(filter_input(INPUT_POST, 'pass'));
+            $currentPass = sha1(filter_input(INPUT_POST, 'currentPass'));
+            // TODO: Validate current
+            $s = $db->prepare('UPDATE player SET password = :pass WHERE uid = :uid AND password = :currentPass;');
+            $s->bindValue(':uid', $player);
+            $s->bindValue(':pass', $mail);
+            $s->bindValue(':currentPass', $currentPass);
+            if(!$s->execute()){
+                return -2;
+            }
+        }
+
+        if (filter_input(INPUT_POST, "api")){
+            $api = generateApi();
+            $s = $db->prepare('UPDATE player SET api_key = :api WHERE uid = :uid;');
+            $s->bindValue(':uid', $player);
+            $s->bindValue(':api', $api);
+            if(!$s->execute()){
+                return -3;
+            }
+            $response = $api;
+        }
+
+        if ($response == null){
+            return 0;
+        }
+        else{
+            return $response;
+        }
+    }
+?>

+ 1 - 0
application/action/login.php

@@ -18,6 +18,7 @@
             return -4;
         }
         $uid = $r["uid"];
+        setcookie("uid", $uid, time() + 5 * 24 * 60 * 60); // 5 Days
         session_regenerate_id();
         $_SESSION['session'] = true;
         $_SESSION['name'] = $uname;

+ 14 - 0
application/action/logout.php

@@ -0,0 +1,14 @@
+<?php
+    function action($db = null){
+        global $UID;
+        $UID = null;
+        setcookie("uid", null, time() - 3600);
+        session_regenerate_id();
+        $_SESSION['session'] = false;
+        $_SESSION['name'] = "";
+        $_SESSION['uid'] = "";
+        header("Location: /");
+        die();
+        return 0;
+    }
+?>

+ 48 - 0
application/page/Profile_Page.php

@@ -0,0 +1,48 @@
+ <?php
+
+    require_once($path["page"] . "Page.php");
+
+
+    /**
+     * User profile page.
+     */
+    class Profile_Page extends Page{
+
+        public $name;
+        public $mail;
+        public $api_key;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param SQLite3 $db Connection to the database.
+         */
+        public function __construct($db){
+            global $path;
+            global $root;
+            global $UID;
+            parent::__construct($db);
+            $this->view = $path["view"] . "profile.php";
+            $s = "
+              SELECT
+                name,
+                mail,
+                api_key
+              FROM player
+              WHERE uid = '$UID';
+            ";
+            $q = $this->db->query($s);
+            if ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                $this->name = $r["name"];
+                $this->mail = $r["mail"];
+                $this->api_key = $r["api_key"];
+            }
+            $this->title = $this->name ." - SWDB";
+            $this->description = $this->name . " user profile";
+            $this->canonical = $root . "profile/";
+        }
+
+    }
+?>

+ 279 - 0
application/view/profile.php

@@ -0,0 +1,279 @@
+<!DOCTYPE html>
+<html lang='en'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$path["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$path["css"]?>profile.css'/>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='en'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+        <script>
+
+            /**
+             * Redirects to the logout action.
+             */
+            function logout(){
+                window.location = '/action/logout/';
+            }
+
+            /**
+             * Shows an error window.
+             *
+             * @param msg Error message
+             */
+            function showError(msg){
+                document.getElementById('error_window').style.display = 'block';
+                document.getElementById('error_msg').innerHTML = msg;
+            }
+
+            /**
+             * Closes the error window.
+             */
+            function closeError(){
+                document.getElementById('error_window').style.display = 'none';
+                document.getElementById('error_msg').innerHTML = ' ';
+            }
+
+            /**
+             * Shows the mail change form.
+             */
+            function changeMail(){
+                document.getElementById('static_mail').style.display = 'none';
+                document.getElementById('change_mail').style.display = 'none';
+                document.getElementById('edit_mail').style.display = 'block';
+                document.getElementById('save_mail').style.display = 'block';
+            }
+
+            /**
+             * Saves an email change.
+             * 
+             * Validates the new email format and makes an AJAX request. If
+             * succesfull, hides the email change form.
+             */
+            function saveMail(){
+                var http = new XMLHttpRequest();
+                var mail = document.getElementById('edit_mail').value;
+                if (mail.length < 1){
+                    showError('Please enter a new email.');
+                    return;
+                }
+                if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(mail) == false){
+                    showError('Invalid email');
+                    return;
+                }
+                http.open('POST', '/action/edit_profile', true);
+                http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+                http.onreadystatechange = function(){
+                    if (this.readyState == 4){
+                        if (this.status == 200 || this.status == 204){
+                            document.getElementById('static_mail').innerHTML = mail;
+                            document.getElementById('static_mail').style.display = 'block';
+                            document.getElementById('change_mail').style.display = 'block';
+                            document.getElementById('edit_mail').style.display = 'none';
+                            document.getElementById('save_mail').style.display = 'none';
+                        }
+                        else{
+                            showError('An error ocurred: ' + this.responseText + ' (' + this.status + ').');
+                        }
+                    }
+                }
+                http.send('uid=<?=$UID?>&mail=' + mail);
+            }
+
+            /**
+             * Shows the password change form.
+             */
+            function changePass(){
+                document.getElementById('static_pass').style.display = 'none';
+                document.getElementById('change_pass').style.display = 'none';
+                document.getElementById('edit_pass_current').value = '';
+                document.getElementById('edit_pass_current').value = '';
+                document.getElementById('edit_pass_new').value = '';
+                document.getElementById('edit_pass_repeat').style.display = 'block';
+                document.getElementById('edit_pass_new').style.display = 'block';
+                document.getElementById('edit_pass_repeat').style.display = 'block';
+                document.getElementById('save_pass').style.display = 'block';
+            }
+
+            /**
+             * Saves a password change.
+             * 
+             * Validates the new password and makes an AJAX request. If
+             * succesfull, hides the password change form.
+             */
+            function savePass(){
+                var http = new XMLHttpRequest();
+                var pass = document.getElementById('edit_pass_new').value;
+                var currentPass = document.getElementById('edit_pass_current').value;
+                var repeatPass = document.getElementById('edit_pass_repeat').value;
+                if (pass.length < 1){
+                    showError('Please enter a new password.');
+                    return;
+                }
+                if (mail.length < 6){
+                    showError('Minimum password length is 6 characters.');
+                    return;
+                }
+                if (currentPass.length < 1){
+                    showError('Please enter your current password.');
+                    return;
+                }
+                if (pass != repeatPass){
+                    showError('Entered passwords do not match.');
+                    return;
+                }
+                http.open('POST', '/action/edit_profile', true);
+                http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+                http.onreadystatechange = function(){
+                    if (this.readyState == 4){
+                        if (this.status == 200 || this.status == 204){
+                            document.getElementById('static_pass').style.display = 'block';
+                            document.getElementById('change_pass').style.display = 'block';
+                            document.getElementById('edit_pass_current').style.display = 'none';
+                            document.getElementById('edit_pass_new').style.display = 'none';
+                            document.getElementById('edit_pass_repeat').style.display = 'none';
+                            document.getElementById('save_pass').style.display = 'none';
+                        }
+                        else{
+                            showError('An error ocurred: ' + this.responseText + ' (' + this.status + ').');
+                        }
+                    }
+                }
+                http.send('uid=<?=$UID?>&pass=' + pass + '&currentPass=' + currentPass);
+            }
+
+            /**
+             * Generates a new random API key.
+             *
+             * Makes a request. On success, updates the API in the UI.
+             */
+            function regenerateApi(){
+                var http = new XMLHttpRequest();
+                http.open('POST', '/action/edit_profile', true);
+                http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+                http.onreadystatechange = function(){
+                    if (this.readyState == 4){
+                        if (this.status == 200 || this.status == 204){
+                            document.getElementById('api_key').innerHTML = this.responseText;
+                        }
+                        else{
+                            showError('An error ocurred: ' + this.responseText + ' (' + this.status + ').');
+                        }
+                    }
+                }
+                http.send('uid=<?=$UID?>&api=1');
+            }
+        </script>
+    </head>
+    <body>
+<?php
+        include __DIR__ . "/inc/header.php";
+?>
+        <section id='monster' class='content'>
+            <h2>
+                <span>
+                    <?=$page->name?>
+                </span>
+            </h2>
+            <article>
+                <table id='profile'>
+                    <tr>
+                        <td class='title'>
+                            Username:
+                        </td>
+                        <td class='value'>
+                            <span>
+                                <?=$page->name?>
+                            </span>
+                        </td>
+                        <td class='action'>
+                            <input onclick='logout();' type='button' value='Logout'/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            eMail:
+                        </td>
+                        <td class='value'>
+                            <span id='static_mail'>
+                                <?=$page->mail?>
+                            </span>
+                            <input id='edit_mail' type='text' value='<?=$page->mail?>'/>
+                        </td>
+                        <td class='action'>
+                            <input id='change_mail' onclick='changeMail();' type='button' value='Change'/>
+                            <input id='save_mail' onclick='saveMail();' type='button' value='Save'/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            API key:
+                        </td>
+                        <td class='value'>
+                            <span id='api_key'>
+                                <?=$page->api_key?>
+                            </span>
+                        </td>
+                        <td class='action'>
+                            <input id='regenerate_api' onclick='regenerateApi();' type='button' value='Regenerate'/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td class='title'>
+                            Password:
+                        </td>
+                        <td class='value'>
+                            <span id='static_pass'>
+                                ********
+                            </span>
+                            <input id='edit_pass_current' type='password' placeholder='Currrent password'/>
+                            <input id='edit_pass_new' type='password' placeholder='New password'/>
+                            <input id='edit_pass_repeat' type='password' placeholder='Repeat password'/>
+                        </td>
+                        <td class='action'>
+                            <input id='change_pass' onclick='changePass();' type='button' value='Change'/>
+                            <input id='save_pass' onclick='savePass();' type='button' value='Save'/>
+                        </td>
+                    </tr>
+                </table>
+            </article>
+        </section> <!-- runes -->
+        <div id='error_window'>
+            <section class='content'>
+                <h2>
+                    <span>
+                        Error
+                    </span>
+                </h2>
+                <article>
+                    <p id='error_msg'>
+                    </p>
+                    <input type='button' value='Close' onclick='closeError();'/>
+                </article>
+            </section>
+        </div>
+
+<?php
+        include __DIR__ . "/inc/footer.php";
+?>
+    </body>
+</html>

+ 69 - 0
public/css/profile.css

@@ -0,0 +1,69 @@
+table#profile{
+    margin: auto;
+    border-collapse: collapse;
+    border: 0.1em solid #000000;
+}
+
+table#profile td{
+    padding: 0.3em;
+    border-top: 0.1em solid #000000;
+    border-bottom: 0.1em solid #000000;
+}
+
+table#profile td.title{
+    text-align: right;
+    width: 6em;
+}
+
+table#profile td.value{
+    width: 10em;
+    text-align: left;
+}
+
+table#profile td.action{
+    width: 6em;
+    text-align: left;
+}
+
+table#profile td input, span{
+    width: 100%;
+}
+
+input#edit_mail,
+input#edit_pass_current,
+input#edit_pass_new,
+input#edit_pass_repeat,
+input#save_mail,
+input#save_pass{
+    display: none;
+}
+
+input#change_mail,
+span#static_mail,
+span#static_pass,
+span#api_key{
+    display: block;
+}
+
+div#error_window{
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: #00000088;
+    text-align: center;
+    display: none;
+}
+
+div#error_window h2{
+    text-align: left;
+}
+
+div#error_window section{
+    margin: 5em auto auto auto;
+    min-height: 6em;
+    width: 60%;
+    text-align: center;
+}
+

+ 1 - 9
public/index.php

@@ -2,15 +2,7 @@
     include __DIR__ . "/../application/config.php";
     include_once($path["controller"]);
 
-    //$request = $_SERVER['REQUEST_URI'];
     $request = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
     $params = explode('/', $request);
-    array_shift($params);
-    $uid = "";
-    if (count($params) > 0 && preg_match("/\d{7}/", $params[0])){
-        $uid = $params[0];
-        array_shift($params);
-    }
-
-    $controller = new Controller($uid, $params);
+    $controller = new Controller($params);
 ?>