Mittwoch, 23. Juni 2010

Browsergame Tutorial - Part III

Browsergame Tutorial - Part III
User Management

A big difference between a browsergame and a tiny flashgame on a webpage is the opportunity for players to play against other players. This means real interaction between all players and not only different names in a highscore list. With this in mind, it's necessary to implement a user management to store a lot of user data in our database.
Let's start collecting information we want to store for each user:
  1. User ID. Each user should have a unique ID that will be our primary key in the user table of our database
  2. Unique user name. All players should be shown by name in the game
  3. Password. For the login, each user needs a password.
  4. E-Mail address. For the opportunity to contact the player, we need an E-Mail address.
  5. Date of registration. For statistics, it's nice to have a registration date stored in the database.
  6. Last login. To filter out dead accounts, we should add a field for the last login date.

Ok, enough information for now. We can add more fields we need to our user table later.

Now open your database administration tool and add your first table to the game database. I call my table players. The fieldnames/fieldtypes are:
  • userid (INT) - primary, autoincrement
  • username (varchar 64)
  • password (varchar 40)
  • email (varchar 255)
  • date_reg (INT)
  • date_login (INT)
Next we need a form for players to signup:

register.php
<?PHP

$content = "
    <form action=\"./register.php\" method=\"post\">
   
        <b>Registration</b><br><br>
   
           <table border=\"0\" cellspacing=\"0\" cellpadding=\"3\">
           <tr>
           <td width=\"40%\" valign=\"bottom\">Player name:</td>
           <td><input type=\"text\" name=\"playername\" class=\"form\" value=\"$name\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">Password:</td>
           <td><input type=\"password\" name=\"password1\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">Confirm Password:</td>
           <td><input type=\"password\" name=\"password2\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">E-Mail address:</td>
           <td><input type=\"text\" name=\"emailaddy\" value=\"$email\"></td>
           </tr>
           <tr>
           <td colspan=\"2\"><input type=\"submit\" value=\"register\"></td>
           </tr>
           </table>
     </form>
    ";
?>

Next we must extend this script to process the data. As you see, the form sends the data to the same script, so the whole registration will be handled by this script.
I used differend variable names for the POST variables and the local variables (ex. emailaddy and email). I recommend this for two reasons. On older php versions, local variables can be injected by GET variables and to prevent SQL injection, your variables should not give a hint how your database fields are named.

So, what to do? Any idea? Right. We must implement the following steps:

take the POST reguest
check information
write to database or generate error
forward the user to the game page

We should also think about, how the server should store the user data while the player is logged in. The php session management can be your solution. I'll store the playername as session variable.

This could be done like this:

register.php
<?PHP
session_start();

require"./template/settings.php";
require"./template/mysqlconnect.php";


//initialize other vars
$error = "";


// *** take the POST reguest ***
//check if playername is submitted
if( isset($_POST['playername']) ){
    //if so, fetch all POST var
    $name  = $_POST['playername'];
    $pw1   = $_POST['password'];
    $pw2   = $_POST['password2'];
    $email = $_POST['emailaddy'];


     // *** check information / generate error *** 
    if( empty($name) ){$error = "Please choose a player name";}
    elseif( empty($pw1) ){$error = "Please choose a password";}
    elseif( empty($pw2) ){$error = "Please confirm your password";}
    elseif( $pw1 != $pw2 ){$error = "Your passwords does not match";}
    elseif( empty($email) ){$error = "Please enter an E-Mail address";}
    else{
   
        //turn password into an MD5 string
        $pw1 = md5($pw1);
   
        //timestamp
        $timestamp = time();
   
        // *** write to database ***
        $query = "INSERT INTO players (username, password, email, date_reg,     date_login) VALUES ('$name', '$pw1', '$email', '$timestamp', '$timestamp')";
    mysql_query($query);
   
        //register session variable
        $_SESSION['name'] = $name;
   
        //forward to game
        header("Location: ./index.php");die;

}

 }else{
    //if not, initialize empty local vars
    $name  = "";
    $pw1   = "";
    $pw2   = "";
    $email = "";
}

$content = "

    $error
   
    <form action=\"./register.php\" method=\"post\">
  
        <b>Registration</b><br><br>
  
           <table border=\"0\" cellspacing=\"0\" cellpadding=\"3\">
           <tr>
           <td width=\"40%\" valign=\"bottom\">Player name:</td>
           <td><input type=\"text\" name=\"playername\" class=\"form\" value=\"$name\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">Password:</td>
           <td><input type=\"password\" name=\"
password1\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">Confirm Password:</td>
           <td><input type=\"password\" name=\"
password2\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">E-Mail address:</td>
           <td><input type=\"text\" name=\"emailaddy\" value=\"$email\"></td>
           </tr>
           <tr>
           <td colspan=\"2\"><input type=\"submit\" value=\"register\"></td>
           </tr>
           </table>
     </form>
    ";
  
require"./template/template.php";
mysql_close($link);

?>

As you see, this is a real smal solution for a signup script. Maybe you want to add a little more. You should think about some importent functions:
  • a way of making your SQL statement injection save
  • check if the entered E-Mail is a valid address
  • exclude playernames like "F*cker", "Bitch" or "Hitler"
  • exclude trashmail addresses
  • send a mail to inform you for new signups
  • let the player agree terms and conditions or a disclaimer
  • add a confirmation script for closed-loop authentication
  • prevent session hijacking 
  • maybe you want to use https for submitting the data
But even if you add all this stuff, the best registration form is useless, if the player has no opportunity to login after registration.
Sounds evident...

So we must add a login page.
Oh oh, lot of work. We are already in part three of this tutorial and still not a single line of code for our game functions. Anyone likes to give up? Maybe you with your bored face? No? Ok, let's finish this part with the missing login page.

We need another form to submit the username and password. If you bought a certificate for https, you should use the save connection to submit the user data. In my example, I'll use a normal http connection.
When username and password are send, we must check our database if the password fits to the user. If everything is ok, we can register the session:

login.php
<?PHP
session_start();

require"./template/settings.php";
require"./template/mysqlconnect.php";

// *** take the POST reguest ***
//check if playername is submitted
if( isset($_POST['playername']) AND isset($_POST['password']) ){
    //if so, fetch all POST var
    $name  = $_POST['playername'];
    $pw    = $_POST['password'];

    $pw = md5($pw);
    
    //check User-Password combination in database
    $userid = 0;
    $query  = "SELECT * FROM players WHERE username='$name' AND password='$pw'";
    $result = mysql_query($query);
    $row    = mysql_fetch_array($result);
    $userid   = $row['userid'];    
    $username = $row['username'];    
    if( $userid > 0 ){
        
        //register session variables
        $_SESSION['userid'] = $userid;
        $_SESSION['username'] = $username;
        
        //Update last Login
        $ts = time();
        $query = "UPDATE players SET date_login='$ts' WHERE userid='$userid'";
        mysql_query($query);
        
        //forward to game
        header("Location: ./index.php");die;
        
    }

}

//initialize other vars
$error = "";
    
$content = "

    
    
    <form action=\"./login.php\" method=\"post\">
   
        <b>Login</b><br><br>
           $error
           <br><br>
           <table border=\"0\" cellspacing=\"0\" cellpadding=\"3\">
           <tr>
           <td width=\"40%\" valign=\"bottom\">Player name:</td>
           <td><input type=\"text\" name=\"playername\" class=\"form\"></td>
           </tr>
           <tr>
           <td width=\"40%\" valign=\"bottom\">Password:</td>
           <td><input type=\"password\" name=\"password\"></td>
           </tr>
           <tr>
           <td colspan=\"2\"><input type=\"submit\" value=\"login\"></td>
           </tr>
           </table>
     </form>
    ";
   
require"./template/template.php";
mysql_close($link);

?>

My Blog screwed up the formatting a little bit, but I guess you'll be able to fix it or you'll make your own formatting.
Well, so far, everything is fine.
When you shake your head while reading this, you found out that not everything is fine ;-)
Two important parts are missing. First, we need to add a logout page, but this could be done very simple. The more important missing part is a check if a username is already registered. Right now, every player can register with the username "Zapp". Each Zapp will have a unique User-ID, but it looks very stupid in the highscore with double and triple usernames.
We need to add a query in the register.php, between 

//check if playername is submitted
and

// *** check information / generate error ***


    $userid = 0;
    $query  = "SELECT
userid FROM players WHERE username='$name'";
    $result = mysql_query($query);
    $row    = mysql_fetch_array($result);
    $
userid    = $row['userid'];   

Now we need to add a fifth elseif line in the // *** check information / generate error *** section, between the first and second line (check for username and password):
elseif( $userid > 0 ){$error = "Player name already registered";}

Now we are nearly finish with part 3 of our tutorial. Last script is our logout page:



logout.php
<?PHP
session_start();

// LOGOUT
unset($_SESSION['userid']);
unset($_SESSION['name']);
session_unset();
session_destroy();

header("Location: ./index.php");

?>

When you finish your work, it should look like this:


Register Page
Login Page
Logout Page

Keine Kommentare:

Kommentar veröffentlichen