I'm new to both PHP and OOP and would like some constructive feedback on a class I made.
I have a "main account" login system already setup and working; when the user logs in they're presented with a list of games. This code logs said user into a specific game.
I have a separate database for each game, plus one for the main account. Tables for the games include 'Players' 'Login History' and 'Player Inventory'
For security I choose to have both prepared statements and issue a unique token at login stored in the 'player' table; which will be checked anytime there is an interaction with the database.
Things I'm looking for:
Bad programming practices: I want to learn to do things the right way before my bad code becomes a bad habit.
Readability: Goes along with the bullet above; but the easier it is to read and maintain the better; and hints in this area are more than welcome.
Security: Being a game I want this as secure as possible. Any direction in this area is highly appreciated.
Better way of doing this: I often miss the obvious and with the amount of experience I have there could easily be a better way I haven't thought of.
<?php
namespace login;
error_reporting(E_ALL);
date_default_timezone_set('America/New_York');
session_start();
class Login
{
//database variables
protected $host;
protected $database;
protected $username;
protected $password;
//database connection
protected $db_connect;
//game variables
protected $game_id;
protected $game_name;
//player variables
protected $user_id;
protected $player_id;
protected $player_name;
protected $token;
protected $ip;
public function __construct($game,$user_id)
{
$this->game_name = $game;
$this->user_id = $user_id;
switch($game)
{
case 'game_001' :
//set up variables
$this->game_id = 001;
$this->host = 'host';
$this->database = 'game_001';
$this->username = 'dbUser';
$this->password = 'dbPassword';
break;
default :
die('No database exists.');
}
//delete this
echo 'Login started...</br>';
//login to game
$this->login();
}
public function __destruct()
{
//close database connection
$this->db_connect->close();
//delete this
echo 'Login has been closed.';
}
private function login()
{
//connect to database
$this->db_connect();
//get player id and name with user_id
$this->get_player();
//create token
$this->generate_token();
//get ip
$this->get_ip();
//record login
$this->record_login();
//log token in database
$this->set_token();
//log session variables
$this->set_session();
}
private function set_session()
{
//delete this
echo 'Setting session variables...</br>';
$_SESSION[$this->game_name.'-token'] = $this->token;
$_SESSION[$this->game_name.'-logged_in'] = true;
$_SESSION[$this->game_name.'-player_id'] = $this->player_id;
$_SESSION[$this->game_name.'-player_name'] = $this->player_name;
//delete this
echo 'Session has been set.</br>';
}
private function set_token()
{
//delete this
echo 'Setting token in database...</br>';
$db = $this->db_connect;
$sql = "UPDATE `players` SET `token` = ? WHERE `players`.`player_id` = ?";
//prepare the statement
if(!$stmt = $db->prepare($sql))
{
die("Prepare failed: (".$db->errno.")".$db->error);
}
//bind variables
if(!$stmt->bind_param("si",$this->token, $this->player_id))
{
die("Binding parameters failed: (".$db->errno.")".$db->error);
}
//execute the prepared statement
if(!$stmt->execute())
{
die("Execution failed: (".$db->errno.")".$db->error);
}
//delete this
echo 'Token set successfully.</br>';
}
private function get_player()
{
//delete this
echo 'Searching for player information...</br>';
$db = $this->db_connect;
$user_id = $this->user_id;
$sql = "SELECT player_id, player_name FROM players WHERE user_id = ?";
//prepare the statement
if(!$stmt = $db->prepare($sql)){
die("Prepare failed: (".$db->errno.")".$db->error);
}
//bind variables
if(!$stmt->bind_param("i",$user_id)){
die("Binding parameters failed: (".$db->errno.")".$db->error);
}
//execute the prepared statement
if(!$stmt->execute()){
die("Execution failed: (".$db->errno.")".$db->error);
}
//bind result
$stmt->bind_result($this->player_id,$this->player_name);
if(!$stmt->fetch()) {
die("Fetch result failed.");
}
//delete this
echo 'Player information found: (#' . $this->player_id . ') ' . $this->player_name . '</br>';
}
private function record_login()
{
//delete this
echo 'Recording log into database...</br>';
$type = 'login';
$note = '';
$time= date('Y-m-d H:i:s');
$player_id = $this->player_id;
$player_name = $this->player_name;
$db = $this->db_connect;
$sql = "INSERT INTO login_history (game_num, player_id, user_id, log_type, timestamp, ip) VALUES (?,?,?,?,?,?)";
//prepare the statement
if(!$stmt = $db->prepare($sql))
{
die("Prepare failed: (".$db->errno.")".$db->error);
}
//bind variables
if(!$stmt->bind_param("iiisss",$this->game_id, $this->player_id, $this->user_id, $type, $time, $this->ip))
{
die("Binding parameters failed: (".$db->errno.")".$db->error);
}
//execute the prepared statement
if(!$stmt->execute())
{
die("Execution failed: (".$db->errno.")".$db->error);
}
//delete this
echo 'Login recorded successfully.</br>';
}
private function generate_token()
{
//delete this
echo 'Generating token...</br>';
$this->token = md5(uniqid(rand(), TRUE));
//delete this
echo 'Token generated: ' . $this->token . '</br>';
}
private function get_ip()
{
//delete this
echo 'Retreiving player ip address...</br>';
$client = @$_SERVER['HTTP_CLIENT_IP'];
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if(filter_var($client, FILTER_VALIDATE_IP))
{
$ip = $client;
}
elseif(filter_var($forward, FILTER_VALIDATE_IP))
{
$ip = $forward;
}
else
{
$ip = $remote;
}
$this->ip = $ip;
//delete this
echo 'IP address found: ' . $this->ip . '</br>';
}
private function db_connect()
{
echo 'Establishing database connection...</br>';
//the actual db connection (\ is used because mysqli is a global class)
$db = new \mysqli($this->host,$this->username,$this->password,$this->database);
//error check and return is everything is good.
if(mysqli_connect_error())
{
exit();
}
else
{
//delete this
echo 'Database connection established.</br>';
$this->db_connect = $db;
}
}
}
?>