From 366eaece3bd878845047c4210c69873d02bb1391 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 10:48:25 +0200 Subject: [PATCH 01/33] Update Registration.php Rewrite by taking advantage of PHP filter functions --- 1-minimal/classes/Registration.php | 246 +++++++++++++---------------- 1 file changed, 113 insertions(+), 133 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 7e6ded54e..e75ac80f6 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -1,151 +1,131 @@ - * @version 1.0 - */ -class Registration { +* class Registration +* handles the user registration +* +* @author Panique +* @version 1.0 +*/ +class Registration +{ + private $db_connection; // database connection + private $is_registration_ok = false; + private $errors = array(); // collection of error messages + private $errorMessages = array( + 'user_name' => array( + 'missing' => 'Username is missing', + 'invalid' =>'Username does not fit the name sheme: only a-Z and numbers are allowed, 2 to 64 characters', + ), + 'user_email' => array( + 'missing' => 'Email missing', + 'invalid' =>'Invalid Email', + ), + 'user_password_new' => array( + 'missing' => 'Password missing', + 'invalid' =>'Password has a minimum length of 6 characters', + ), + 'user_password_repeat' => array( + 'missing' => 'Password missing', + 'invalid' =>'Password has a minimum length of 6 characters', + ), + ); + + public function __construct() + { + $this->$is_registration_ok = $this->registerNewUser(); + } - private $db_connection = null; // database connection - - private $user_name = ""; // user's name - private $user_email = ""; // user's email - private $user_password = ""; // user's password (what comes from POST) - private $user_password_hash = ""; // user's hashed and salted password - - public $registration_successful = false; + public function getErrors($name = null) + { + if (is_null($name)) { + return $this->errors; + } + if (isset($this->errors[$name])) { + return $this->errors[$name]; + } + return null; + } - public $errors = array(); // collection of error messages - public $messages = array(); // collection of success / neutral messages - - - /** - * the function "__construct()" automatically starts whenever an object of this class is created, - * you know, when you do "$login = new Login();" - */ - public function __construct() { - - if (isset($_POST["register"])) { - - $this->registerNewUser(); - - } + public function isRegistrationSuccessful() + { + return $this->is_registration_ok; } /** - * registerNewUser - * - * handles the entire registration process. checks all error possibilities, and creates a new user in the database if - * everything is fine - */ - private function registerNewUser() { - - if (empty($_POST['user_name'])) { - - $this->errors[] = "Empty Username"; - - } elseif (empty($_POST['user_password_new']) || empty($_POST['user_password_repeat'])) { - - $this->errors[] = "Empty Password"; - - } elseif ($_POST['user_password_new'] !== $_POST['user_password_repeat']) { - - $this->errors[] = "Password and password repeat are not the same"; - - } elseif (strlen($_POST['user_password_new']) < 6) { - - $this->errors[] = "Password has a minimum length of 6 characters"; - - } elseif (strlen($_POST['user_name']) > 64 || strlen($_POST['user_name']) < 2) { - - $this->errors[] = "Username cannot be shorter than 2 or longer than 64 characters"; - - } elseif (!preg_match('/^[a-z\d]{2,64}$/i', $_POST['user_name'])) { - - $this->errors[] = "Username does not fit the name sheme: only a-Z and numbers are allowed, 2 to 64 characters"; - - } elseif (empty($_POST['user_email'])) { - - $this->errors[] = "Email cannot be empty"; - - } elseif (strlen($_POST['user_email']) > 64) { - - $this->errors[] = "Email cannot be longer than 64 characters"; - - } elseif (!filter_var($_POST['user_email'], FILTER_VALIDATE_EMAIL)) { - - $this->errors[] = "Your email adress is not in a valid email format"; - - } elseif (!empty($_POST['user_name']) - && strlen($_POST['user_name']) <= 64 - && strlen($_POST['user_name']) >= 2 - && preg_match('/^[a-z\d]{2,64}$/i', $_POST['user_name']) - && !empty($_POST['user_email']) - && strlen($_POST['user_email']) <= 64 - && filter_var($_POST['user_email'], FILTER_VALIDATE_EMAIL) - && !empty($_POST['user_password_new']) - && !empty($_POST['user_password_repeat']) - && ($_POST['user_password_new'] === $_POST['user_password_repeat'])) { - - // TODO: the above check is redundant, but from a developer's perspective it makes clear - // what exactly we want to reach to go into this if-block - - // creating a database connection - $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - - // if no connection errors (= working database connection) - if (!$this->db_connection->connect_errno) { - - // escapin' this, additionally removing everything that could be (html/javascript-) code - $this->user_name = $this->db_connection->real_escape_string(htmlentities($_POST['user_name'], ENT_QUOTES)); - $this->user_email = $this->db_connection->real_escape_string(htmlentities($_POST['user_email'], ENT_QUOTES)); - - $this->user_password = $_POST['user_password_new']; - - // crypt the user's password with the PHP 5.5's password_hash() function, results in a 60 character hash string - // the PASSWORD_DEFAULT constant is defined by the PHP 5.5, or if you are using PHP 5.3/5.4, by the password hashing - // compatibility library - $this->user_password_hash = password_hash($this->user_password, PASSWORD_DEFAULT); - - // check if user already exists - $query_check_user_name = $this->db_connection->query("SELECT * FROM users WHERE user_name = '".$this->user_name."';"); - - if ($query_check_user_name->num_rows == 1) { - - $this->errors[] = "Sorry, that user name is already taken.
Please choose another one."; - - } else { - - // write new users data into database - $query_new_user_insert = $this->db_connection->query("INSERT INTO users (user_name, user_password_hash, user_email) VALUES('".$this->user_name."', '".$this->user_password_hash."', '".$this->user_email."');"); + * registerNewUser + * + * handles the entire registration process. checks all error possibilities, and creates a new user in the database if + * everything is fine + */ + private function registerNewUser() + { + $this->errors = array(); + $this->messages = array(); + if (filter_has_var(INPUT_POST, 'register')) { + return false; + } - if ($query_new_user_insert) { + //1 - Form filtering + $arguments = array( + 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), + 'user_email' => FILTER_VALIDATE_EMAIL, + 'user_password_new' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + 'user_password_repeat' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + ); + $params = filter_input_array(INPUT_POST, $arguments); + if (! $params) { + $this->errors['submission'] = 'Empty Submission'; + return false; + } - $this->messages[] = "Your account has been created successfully. You can now log in."; - $this->registration_successful = true; + foreach (array_keys($arguments) as $keys) { + $value = $params[$keys]; + if (is_null($value)) { + $this->errors[$keys] = $this->errorMessages[$keys]['missing']; + } elseif (! $value) { + $this->errors[$keys] = $this->errorMessages[$keys]['invalid']; + } + } + if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { + $this->errors['user_password'] = "Password and password repeat are not the same"; + } + if (count($this->errors)) { + return false; + } - } else { + //2 - DB Connection + $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); + if ($this->db_connection->connect_errno) { + $this->errors['connection'] = "Sorry, no database connection."; + return false; + } - $this->errors[] = "Sorry, your registration failed. Please go back and try again."; + //data prepare and sanitaze for db inclusion + $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); + unset($params['user_password_new'], $params['user_password_repeat']); + $params = array_map(array($this->db_connection, 'real_escape_string'), $params); - } - } + //3- check if user already exists + $res = $this->db_connection->query( + "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" + ); - } else { + if ($res->num_rows > 0) { + $this->errors['uniqueness'] = "Sorry, the user name OR the email is already taken.
Please choose another one."; + return false; + } - $this->errors[] = "Sorry, no database connection."; + // write new users data into database + $res = $this->db_connection->query( + "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" + ); - } - - } else { - - $this->errors[] = "An unknown error occured."; - + if (! $res) { + $this->errors['registration'] = "Sorry, your registration failed. Please go back and try again."; + return false; } - - } -} \ No newline at end of file + return true; + } +} From 41c4947c58b71e023e49b27f356ebcb91083fa32 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 10:50:10 +0200 Subject: [PATCH 02/33] Update Registration.php typo fix --- 1-minimal/classes/Registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index e75ac80f6..1099b7fb0 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -33,7 +33,7 @@ class Registration public function __construct() { - $this->$is_registration_ok = $this->registerNewUser(); + $this->is_registration_ok = $this->registerNewUser(); } public function getErrors($name = null) From a5abd2e9f84c567b7dbc153b24b1a1f3e12985fa Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 10:51:09 +0200 Subject: [PATCH 03/33] Update Registration.php --- 1-minimal/classes/Registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 1099b7fb0..5f4b8f732 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -62,7 +62,7 @@ private function registerNewUser() { $this->errors = array(); $this->messages = array(); - if (filter_has_var(INPUT_POST, 'register')) { + if (! filter_has_var(INPUT_POST, 'register')) { return false; } From fe42bc0ffc2fc4a17ee217ad023baec193c67b34 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 10:55:16 +0200 Subject: [PATCH 04/33] Update Registration.php added charset set up in DB connection parameters --- 1-minimal/classes/Registration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 5f4b8f732..03fa5721c 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -96,11 +96,12 @@ private function registerNewUser() //2 - DB Connection $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - if ($this->db_connection->connect_errno) { + if ($this->db_connection->connect_errno || ! $this->db_connection->set_charset(DB_CHARSET)) { $this->errors['connection'] = "Sorry, no database connection."; return false; } + //data prepare and sanitaze for db inclusion $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); unset($params['user_password_new'], $params['user_password_repeat']); From 51a721065829709fcb9cdc80bf3fd1bac4ef48ad Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 10:57:18 +0200 Subject: [PATCH 05/33] Update db.php added DB charset and using PHP 5.3+ const definition --- 1-minimal/config/db.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/1-minimal/config/db.php b/1-minimal/config/db.php index 428c78e44..c735dabc2 100644 --- a/1-minimal/config/db.php +++ b/1-minimal/config/db.php @@ -10,14 +10,17 @@ /** database host, usually it's "127.0.0.1" or "localhost", some servers also need port info, like "127.0.0.1:8080" */ -define("DB_HOST", "127.0.0.1"); +const "DB_HOST" = "127.0.0.1"; /** name of the database. please note: database and database table are not the same thing! */ -define("DB_NAME", "login"); +const "DB_NAME" = "login"; /** user for your database. the user needs to have rights for SELECT, UPDATE, DELETE and INSERT. /** By the way, it's bad style to use "root", but for development it will work */ -define("DB_USER", "root"); +const "DB_USER" = "root"; /** The password of the above user */ -define("DB_PASS", "mysql"); +const "DB_PASS" = "mysql"; + + +const 'DB_CHARSET' = 'utf8'; //connection charset From 9bbf08c0957eb7918dc0d0c3c17de305f0f81d21 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 11:56:11 +0200 Subject: [PATCH 06/33] Update Registration.php Updated Error message to better handle internationalisation move DB connection into the constructor method --- 1-minimal/classes/Registration.php | 67 ++++++++++++------------------ 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 03fa5721c..b8ff849d4 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -9,31 +9,24 @@ */ class Registration { - private $db_connection; // database connection + private $conn; // database connection private $is_registration_ok = false; private $errors = array(); // collection of error messages - private $errorMessages = array( - 'user_name' => array( - 'missing' => 'Username is missing', - 'invalid' =>'Username does not fit the name sheme: only a-Z and numbers are allowed, 2 to 64 characters', - ), - 'user_email' => array( - 'missing' => 'Email missing', - 'invalid' =>'Invalid Email', - ), - 'user_password_new' => array( - 'missing' => 'Password missing', - 'invalid' =>'Password has a minimum length of 6 characters', - ), - 'user_password_repeat' => array( - 'missing' => 'Password missing', - 'invalid' =>'Password has a minimum length of 6 characters', - ), - ); + + const DATA_MISSING = 1; + const DATA_INVALID = 2; + const DATA_MISMATCH = 3; + const REGISTRATION_FAILED = 1; + const USER_EXISTS = 1; public function __construct() { - $this->is_registration_ok = $this->registerNewUser(); + $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); + if ($this->conn->connect_errno || ! $this->conn->set_charset(DB_CHARSET)) { + die("Sorry, no database connection."); + } + + $this->$is_registration_ok = $this->registerNewUser(); } public function getErrors($name = null) @@ -62,7 +55,7 @@ private function registerNewUser() { $this->errors = array(); $this->messages = array(); - if (! filter_has_var(INPUT_POST, 'register')) { + if (filter_has_var(INPUT_POST, 'register')) { return false; } @@ -75,55 +68,47 @@ private function registerNewUser() ); $params = filter_input_array(INPUT_POST, $arguments); if (! $params) { - $this->errors['submission'] = 'Empty Submission'; + $this->errors['submission'] = self::DATA_MISSING; return false; } foreach (array_keys($arguments) as $keys) { $value = $params[$keys]; if (is_null($value)) { - $this->errors[$keys] = $this->errorMessages[$keys]['missing']; + $this->errors[$keys] = self::DATA_MISSING; } elseif (! $value) { - $this->errors[$keys] = $this->errorMessages[$keys]['invalid']; + $this->errors[$keys] = self::DATA_INVALID; } } if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { - $this->errors['user_password'] = "Password and password repeat are not the same"; + $this->errors['user_password'] = self::DATA_MISMATCH; } if (count($this->errors)) { return false; } - //2 - DB Connection - $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - if ($this->db_connection->connect_errno || ! $this->db_connection->set_charset(DB_CHARSET)) { - $this->errors['connection'] = "Sorry, no database connection."; - return false; - } - - - //data prepare and sanitaze for db inclusion + //2 - data prepared and sanitized for db inclusion $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); unset($params['user_password_new'], $params['user_password_repeat']); - $params = array_map(array($this->db_connection, 'real_escape_string'), $params); + $params = array_map(array($this->conn, 'real_escape_string'), $params); - //3- check if user already exists - $res = $this->db_connection->query( + //3 - check if user already in the table + $res = $this->conn->query( "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" ); if ($res->num_rows > 0) { - $this->errors['uniqueness'] = "Sorry, the user name OR the email is already taken.
Please choose another one."; + $this->errors['uniqueness'] = self::USER_EXISTS return false; } - // write new users data into database - $res = $this->db_connection->query( + //4 - write new users data into database + $res = $this->conn->query( "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" ); if (! $res) { - $this->errors['registration'] = "Sorry, your registration failed. Please go back and try again."; + $this->errors['registration'] = self::REGISTRATION_FAILED; return false; } From 11be25480804510e1ab86add72455694b983e27f Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 11:56:43 +0200 Subject: [PATCH 07/33] typo fix --- 1-minimal/classes/Registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index b8ff849d4..0c5792824 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -26,7 +26,7 @@ public function __construct() die("Sorry, no database connection."); } - $this->$is_registration_ok = $this->registerNewUser(); + $this->is_registration_ok = $this->registerNewUser(); } public function getErrors($name = null) From 5302c6fa900af9836145e905021ebdd0e1545d3d Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 12:16:46 +0200 Subject: [PATCH 08/33] Update Registration.php typo fix --- 1-minimal/classes/Registration.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 0c5792824..4a5651dd4 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -73,10 +73,9 @@ private function registerNewUser() } foreach (array_keys($arguments) as $keys) { - $value = $params[$keys]; - if (is_null($value)) { + if (is_null($params[$keys])) { $this->errors[$keys] = self::DATA_MISSING; - } elseif (! $value) { + } elseif (! $params[$keys]) { $this->errors[$keys] = self::DATA_INVALID; } } From 0c45054acb6521cd1e513e8f601a8e165749284e Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Sun, 30 Jun 2013 21:19:43 +0200 Subject: [PATCH 09/33] Update Registration.php --- 1-minimal/classes/Registration.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 4a5651dd4..b354cfa32 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -54,17 +54,25 @@ public function isRegistrationSuccessful() private function registerNewUser() { $this->errors = array(); - $this->messages = array(); if (filter_has_var(INPUT_POST, 'register')) { return false; } //1 - Form filtering $arguments = array( - 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), + 'user_name' => array( + 'filter' => FILTER_VALIDATE_REGEXP, + 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i') + ), 'user_email' => FILTER_VALIDATE_EMAIL, - 'user_password_new' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), - 'user_password_repeat' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + 'user_password_new' => array( + 'filter' => FILTER_VALIDATE_REGEXP, + 'options' => array('regexp' => '/^.{6,}$/') + ), + 'user_password_repeat' => array( + 'filter' => FILTER_VALIDATE_REGEXP, + 'options' => array('regexp' => '/^.{6,}$/') + ), ); $params = filter_input_array(INPUT_POST, $arguments); if (! $params) { @@ -97,7 +105,7 @@ private function registerNewUser() ); if ($res->num_rows > 0) { - $this->errors['uniqueness'] = self::USER_EXISTS + $this->errors['uniqueness'] = self::USER_EXISTS; return false; } From cdd481c7207d84164434ba422023c3b0b0d904c6 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 08:35:56 +0200 Subject: [PATCH 10/33] Registration is extended from Auth.php Merge methods and properties between Registration.php and Login.php --- 1-minimal/classes/Registration.php | 175 ++++++++++++----------------- 1 file changed, 72 insertions(+), 103 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index b354cfa32..b79ced4c6 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -3,122 +3,91 @@ /** * class Registration * handles the user registration -* +* * @author Panique * @version 1.0 */ -class Registration +class Registration extends Auth { - private $conn; // database connection - private $is_registration_ok = false; - private $errors = array(); // collection of error messages + private $is_registration_ok = false; - const DATA_MISSING = 1; - const DATA_INVALID = 2; - const DATA_MISMATCH = 3; - const REGISTRATION_FAILED = 1; - const USER_EXISTS = 1; - - public function __construct() - { - $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - if ($this->conn->connect_errno || ! $this->conn->set_charset(DB_CHARSET)) { - die("Sorry, no database connection."); - } + public function __construct() + { + parent::__construct(); + $this->is_registration_ok = $this->registerNewUser(); + } - $this->is_registration_ok = $this->registerNewUser(); - } + public function isRegistrationSuccessful() + { + return $this->is_registration_ok; + } - public function getErrors($name = null) - { - if (is_null($name)) { - return $this->errors; - } - if (isset($this->errors[$name])) { - return $this->errors[$name]; - } - return null; - } + /** + * registerNewUser + * + * handles the entire registration process. checks all error possibilities, and creates a new user in the database if + * everything is fine + */ + private function registerNewUser() + { + $this->errors = array(); + if (filter_has_var(INPUT_POST, 'register')) { + return false; + } - public function isRegistrationSuccessful() - { - return $this->is_registration_ok; - } + //1 - Form filtering + $arguments = array( + 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), + 'user_email' => FILTER_VALIDATE_EMAIL, + 'user_password_new' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + 'user_password_repeat' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + ); + $params = filter_input_array(INPUT_POST, $arguments); + if (! $params) { + $this->errors['submission'] = self::DATA_MISSING; + return false; + } - /** - * registerNewUser - * - * handles the entire registration process. checks all error possibilities, and creates a new user in the database if - * everything is fine - */ - private function registerNewUser() - { - $this->errors = array(); - if (filter_has_var(INPUT_POST, 'register')) { - return false; - } + foreach (array_keys($arguments) as $keys) { + $value = $params[$keys]; + if (is_null($value)) { + $this->errors[$keys] = self::DATA_MISSING; + } elseif (! $value) { + $this->errors[$keys] = self::DATA_INVALID; + } + } + if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { + $this->errors['user_password'] = self::DATA_MISMATCH; + } + if (count($this->errors)) { + return false; + } - //1 - Form filtering - $arguments = array( - 'user_name' => array( - 'filter' => FILTER_VALIDATE_REGEXP, - 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i') - ), - 'user_email' => FILTER_VALIDATE_EMAIL, - 'user_password_new' => array( - 'filter' => FILTER_VALIDATE_REGEXP, - 'options' => array('regexp' => '/^.{6,}$/') - ), - 'user_password_repeat' => array( - 'filter' => FILTER_VALIDATE_REGEXP, - 'options' => array('regexp' => '/^.{6,}$/') - ), - ); - $params = filter_input_array(INPUT_POST, $arguments); - if (! $params) { - $this->errors['submission'] = self::DATA_MISSING; - return false; - } + //2 - data prepared and sanitized for db inclusion + $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); + unset($params['user_password_new'], $params['user_password_repeat']); + $params = array_map(array($this->conn, 'real_escape_string'), $params); - foreach (array_keys($arguments) as $keys) { - if (is_null($params[$keys])) { - $this->errors[$keys] = self::DATA_MISSING; - } elseif (! $params[$keys]) { - $this->errors[$keys] = self::DATA_INVALID; - } - } - if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { - $this->errors['user_password'] = self::DATA_MISMATCH; - } - if (count($this->errors)) { - return false; - } + //3 - check if user already in the table + $res = $this->conn->query( + "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" + ); - //2 - data prepared and sanitized for db inclusion - $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); - unset($params['user_password_new'], $params['user_password_repeat']); - $params = array_map(array($this->conn, 'real_escape_string'), $params); + if ($res->num_rows > 0) { + $this->errors['uniqueness'] = self::USER_EXISTS + return false; + } - //3 - check if user already in the table - $res = $this->conn->query( - "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" - ); + //4 - write new users data into database + $res = $this->conn->query( + "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" + ); - if ($res->num_rows > 0) { - $this->errors['uniqueness'] = self::USER_EXISTS; - return false; - } + if (! $res) { + $this->errors['registration'] = self::REGISTRATION_FAILED; + return false; + } - //4 - write new users data into database - $res = $this->conn->query( - "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" - ); - - if (! $res) { - $this->errors['registration'] = self::REGISTRATION_FAILED; - return false; - } - - return true; - } + return true; + } } From 9216378885847ece7f23e3e96925edf8de7639dd Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 08:37:44 +0200 Subject: [PATCH 11/33] Login/php extends Auth.php Login is rewrite to extends Auth --- 1-minimal/classes/Login.php | 287 ++++++++++++++++++------------------ 1 file changed, 140 insertions(+), 147 deletions(-) diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index 6231c77aa..cc76a274e 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -1,150 +1,143 @@ - * @version 1.2 - */ -class Login { - - private $db_connection = null; // database connection - - private $user_name = ""; // user's name - private $user_email = ""; // user's email - private $user_password_hash = ""; // user's hashed and salted password - private $user_is_logged_in = false; // status of login - - public $errors = array(); // collection of error messages - public $messages = array(); // collection of success / neutral messages - - - /** - * the function "__construct()" automatically starts whenever an object of this class is created, - * you know, when you do "$login = new Login();" - */ - public function __construct() { - - // create/read session - session_start(); - - // check the possible login actions: - // 1. logout (happen when user clicks logout button) - // 2. login via session data (happens each time user opens a page on your php project AFTER he has sucessfully logged in via the login form) - // 3. login via post data, which means simply logging in via the login form. after the user has submit his login/password successfully, his - // logged-in-status is written into his session data on the server. this is the typical behaviour of common login scripts. - - // if user tried to log out - if (isset($_GET["logout"])) { - - $this->doLogout(); - - } - // if user has an active session on the server - elseif (!empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1)) { - - $this->loginWithSessionData(); - - // if user just submitted a login form - } elseif (isset($_POST["login"])) { - - $this->loginWithPostData(); - - } - } - - - private function loginWithSessionData() { - - // set logged in status to true, because we just checked for this: - // !empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1) - // when we called this method (in the constructor) - $this->user_is_logged_in = true; - - } - - - private function loginWithPostData() { - - // if POST data (from login form) contains non-empty user_name and non-empty user_password - if (!empty($_POST['user_name']) && !empty($_POST['user_password'])) { - - // create a database connection, using the constants from config/db.php (which we loaded in index.php) - $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - - // if no connection errors (= working database connection) - if (!$this->db_connection->connect_errno) { - - // escape the POST stuff - $this->user_name = $this->db_connection->real_escape_string($_POST['user_name']); - // database query, getting all the info of the selected user - $checklogin = $this->db_connection->query("SELECT user_name, user_email, user_password_hash FROM users WHERE user_name = '".$this->user_name."';"); - - // if this user exists - if ($checklogin->num_rows == 1) { - - // get result row (as an object) - $result_row = $checklogin->fetch_object(); - - // using PHP 5.5's password_verify() function to check if the provided passwords fits to the hash of that user's password - if (password_verify($_POST['user_password'], $result_row->user_password_hash)) { - - // write user data into PHP SESSION [a file on your server] - $_SESSION['user_name'] = $result_row->user_name; - $_SESSION['user_email'] = $result_row->user_email; - $_SESSION['user_logged_in'] = 1; - - // set the login status to true - $this->user_is_logged_in = true; - - } else { - - $this->errors[] = "Wrong password. Try again."; - - } - - } else { - - $this->errors[] = "This user does not exist."; - } - - } else { - - $this->errors[] = "Database connection problem."; - } - - } elseif (empty($_POST['user_name'])) { - - $this->errors[] = "Username field was empty."; - - } elseif (empty($_POST['user_password'])) { - - $this->errors[] = "Password field was empty."; - } - - } - - /** - * perform the logout - */ - public function doLogout() { - - $_SESSION = array(); - session_destroy(); - $this->user_is_logged_in = false; - $this->messages[] = "You have been logged out."; - - } - - /** - * simply return the current state of the user's login - * @return boolean user's login status - */ - public function isUserLoggedIn() { - - return $this->user_is_logged_in; - - } - -} \ No newline at end of file +* class Login +* handles the user login/logout/session +* +* @author Panique +* @version 1.2 +*/ +class Login extends Auth +{ + private $is_logged_in = false; // status of login + private $is_logged_out = false; + + /** + * the function "__construct()" automatically starts whenever an object of this class is created, + * you know, when you do "$login = new Login();" + */ + public function __construct() { + + parent::__construct(); + + // create/read session + if (empty(session_id())) { + session_start(); + } + + $this->is_logged_out = false; + $this->is_logged_in = false; + if (isset($_GET["logout"])) { + $this->is_logged_out = $this->doLogout(); + if ($this->is_logged_out) { + $this->is_logged_in = false; + } + return; + } + + // if user has an active session on the server + if (isset($_SESSION['user_name'], $_SESSION['user_logged_in']) && 1 == $_SESSION['user_logged_in']) { + $this->is_logged_in = $this->loginWithSessionData(); + return; + + } + + // if user just submitted a login form + if (isset($_POST["login"])) { + $this->is_logged_in = $this->loginWithPostData(); + } + } + + private function loginWithSessionData() + { + // set logged in status to true, because we just checked for this: + // !empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1) + // when we called this method (in the constructor) + $login = filter_var($_SESSION['user_name'], FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[a-z0-9]{2,64}$/i'))); + if (! $login) { + $this->errors['session'] = self::DATA_INVALID; + return false; + } + + //2 - DB Connection + $res = $this->conn->query( + "SELECT * FROM users WHERE user_name = '".$this->conn->real_escape_string($login)."'" + ); + if ($res->num_rows != 1) { + $this->errors['user'] = self::USER_UNKNOWN; + return false; + } + + $user = $res->fetch_assoc(); + foreach ($user as $key => $value) { + $_SESSION[$key] = $value; + } + $_SESSION['user_logged_in'] = 1; + return true; + } + + private function loginWithPostData() + { + if (! filter_has_var(INPUT_POST, 'user_name') || ! filter_has_var(INPUT_POST, 'user_password') ) { + $this->errors['submission'] = self::DATA_MISSING; + return false; + } + + $params = filter_input_array( + INPUT_POST, + array( + 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), + 'user_password' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + ) + ) + + if (! isset($params['user_name'], $params['user_password'])) { + $this->errors['validation'] = self::DATA_INVALID; + return false; + } + + $params['user_name'] = $this->conn->real_escape_string($params['user_name']); + $res = $this->conn->query("SELECT * FROM users WHERE user_name = '{$params['user_name']}'"); + if ($res->num_rows != 1) { + $this->errors['user'] = self::USER_UNKNOWN; + return false; + } + + $user = $res->fetch_assoc(); + if (! password_verify($param['user_password'], $user['user_password_hash'])) { + $this->errors['password'] = self::DATA_INVALID; + return false; + } + + foreach ($user as $key => $value) { + $_SESSION[$key] = $value; + } + $_SESSION['user_logged_in'] = 1; + return true; + } + + /** + * perform the logout + */ + public function doLogout() + { + $_SESSION = array(); + session_destroy(); + return true; + } + + /** + * simply return the current state of the user's login + * @return boolean user's login status + */ + public function isUserLoggedIn() + { + return $this->is_logged_in; + } + + public function isUserLogOut() + { + return $this->is_logged_out; + } + +} From 2f6b2f33731f14fd62a439ebd19358d3d8fcbdf0 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 08:39:03 +0200 Subject: [PATCH 12/33] Create Auth.php Base Class to be extended by Login and Registration --- 1-minimal/classes/Auth.php | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 1-minimal/classes/Auth.php diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php new file mode 100644 index 000000000..228afdc86 --- /dev/null +++ b/1-minimal/classes/Auth.php @@ -0,0 +1,41 @@ + +* @version 1.0 +*/ +class Auth +{ + private $conn; // database connection + private $errors = array(); // collection of error messages + + const DATA_MISSING = 1; + const DATA_INVALID = 2; + const DATA_MISMATCH = 3; + const REGISTRATION_FAILED = 1; + const USER_EXISTS = 1; + const USER_UNKNOWN = 2; + + public function __construct() + { + $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); + if ($this->conn->connect_errno || ! $this->conn->set_charset(DB_CHARSET)) { + die("Sorry, no database connection."); + } + } + + public function getErrors($name = null) + { + if (is_null($name)) { + return $this->errors; + } + if (isset($this->errors[$name])) { + return $this->errors[$name]; + } + return null; + } + +} From 04b8800337384123455bd1b6956a46428aaf4915 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 08:46:02 +0200 Subject: [PATCH 13/33] Added function to validate submitted data --- 1-minimal/classes/Auth.php | 62 +++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php index 228afdc86..f0b7415cc 100644 --- a/1-minimal/classes/Auth.php +++ b/1-minimal/classes/Auth.php @@ -11,6 +11,10 @@ class Auth { private $conn; // database connection private $errors = array(); // collection of error messages + private $regexp = array( + 'user_name' => '^[a-zA-Z0-9]{2,64}$', + 'user_password' => '^.{6,}$' + ); const DATA_MISSING = 1; const DATA_INVALID = 2; @@ -18,7 +22,7 @@ class Auth const REGISTRATION_FAILED = 1; const USER_EXISTS = 1; const USER_UNKNOWN = 2; - + public function __construct() { $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); @@ -38,4 +42,60 @@ public function getErrors($name = null) return null; } + protected function isValidEmail($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var($str, FILTER_VALIDATE_EMAIL); + if (! $str || 64 > strlen($str)) { + return false; + } + + return $str; + } + + protected function isValidPassword($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var( + $str, + FILTER_VALIDATE_REGEXP, + array( + 'options' => array( + 'regexp' => '/'.$this->regexp['user_password'].'/' + ) + ) + ); + if (! $str) { + return false; + } + + return $str; + } + + protected function isValidUserName($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var( + $str, + FILTER_VALIDATE_REGEXP, + array( + 'options' => array( + 'regexp' => '/'.$this->regexp['user_name'].'/' + ) + ) + ); + if (! $str) { + return false; + } + + return $str; + + } + } From 4009d4e29450692d928b5b24af4dfb5c999841a7 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 08:56:05 +0200 Subject: [PATCH 14/33] Added PHPDocs comments --- 1-minimal/classes/Registration.php | 39 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index b79ced4c6..f5285fa0d 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -11,12 +11,21 @@ class Registration extends Auth { private $is_registration_ok = false; + /** + * The constructor execute the registration on set the registration status + * + */ public function __construct() { parent::__construct(); $this->is_registration_ok = $this->registerNewUser(); } + /** + * return the registration status + * + * @return boolean + */ public function isRegistrationSuccessful() { return $this->is_registration_ok; @@ -25,29 +34,33 @@ public function isRegistrationSuccessful() /** * registerNewUser * - * handles the entire registration process. checks all error possibilities, and creates a new user in the database if + * handles the entire registration process. + * checks all error possibilities, + * and creates a new user in the database if * everything is fine + * + * @return boolean + * */ private function registerNewUser() { + //1 - reset the errors property $this->errors = array(); if (filter_has_var(INPUT_POST, 'register')) { return false; } - //1 - Form filtering + //2 - Input Filtering and Validation $arguments = array( - 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), - 'user_email' => FILTER_VALIDATE_EMAIL, - 'user_password_new' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), - 'user_password_repeat' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidUserName')), + 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidEmail')), + 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidPassword')), + 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidPassword')), ); $params = filter_input_array(INPUT_POST, $arguments); if (! $params) { - $this->errors['submission'] = self::DATA_MISSING; - return false; + $params = array_fill_keys(array_keys($arguments), null); } - foreach (array_keys($arguments) as $keys) { $value = $params[$keys]; if (is_null($value)) { @@ -63,18 +76,18 @@ private function registerNewUser() return false; } - //2 - data prepared and sanitized for db inclusion + //3 - data prepared and sanitized for db inclusion $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); unset($params['user_password_new'], $params['user_password_repeat']); $params = array_map(array($this->conn, 'real_escape_string'), $params); - //3 - check if user already in the table + //4 - check if user already in the table $res = $this->conn->query( "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" ); if ($res->num_rows > 0) { - $this->errors['uniqueness'] = self::USER_EXISTS + $this->errors['user_name'] = self::USER_EXISTS; return false; } @@ -84,7 +97,7 @@ private function registerNewUser() ); if (! $res) { - $this->errors['registration'] = self::REGISTRATION_FAILED; + $this->errors['user_name'] = self::REGISTRATION_FAILED; return false; } From 7189e458865f1f72b95681e32693e24dd58b400a Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 09:41:57 +0200 Subject: [PATCH 15/33] Adding check to see if the session is not corrupted --- 1-minimal/classes/Login.php | 292 +++++++++++++++++++++--------------- 1 file changed, 170 insertions(+), 122 deletions(-) diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index cc76a274e..7ee9e4714 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -9,135 +9,183 @@ */ class Login extends Auth { - private $is_logged_in = false; // status of login - private $is_logged_out = false; - - /** - * the function "__construct()" automatically starts whenever an object of this class is created, - * you know, when you do "$login = new Login();" + /** + * the User status + * @var boolean + */ + private $is_logged_in = false; // status of login + + /** + * The constructor handles login/logout action */ - public function __construct() { - - parent::__construct(); - - // create/read session - if (empty(session_id())) { - session_start(); - } - - $this->is_logged_out = false; - $this->is_logged_in = false; - if (isset($_GET["logout"])) { - $this->is_logged_out = $this->doLogout(); - if ($this->is_logged_out) { - $this->is_logged_in = false; - } - return; - } - - // if user has an active session on the server - if (isset($_SESSION['user_name'], $_SESSION['user_logged_in']) && 1 == $_SESSION['user_logged_in']) { - $this->is_logged_in = $this->loginWithSessionData(); - return; - - } - - // if user just submitted a login form - if (isset($_POST["login"])) { - $this->is_logged_in = $this->loginWithPostData(); - } - } - - private function loginWithSessionData() - { - // set logged in status to true, because we just checked for this: - // !empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1) - // when we called this method (in the constructor) - $login = filter_var($_SESSION['user_name'], FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[a-z0-9]{2,64}$/i'))); - if (! $login) { - $this->errors['session'] = self::DATA_INVALID; + public function __construct() + { + parent::__construct(); + // create/read session + if (empty(session_id())) { + session_start(); + } + + $this->is_logged_in = false; + if (isset($_SESSION['session_token'])) { + $this->is_logged_in = $this->loginWithSessionData(); + } elseif (filter_has_var(INPUT_POST, 'login')) { + $this->is_logged_in = $this->loginWithPostData(); + } + + if (! $this->is_logged_in || filter_has_var(INPUT_GET, 'logout')) { + $this->doLogout(); + } + } + + /** + * perform the logout + */ + public function doLogout() + { + $_SESSION = array(); + session_destroy(); + } + + /** + * simply return the current state of the user's login + * @return boolean user's login status + */ + public function isUserLoggedIn() + { + return $this->is_logged_in; + } + + /** + * Connect a user depending on his session data + */ + public function loginWithSessionData() + { + if (! $this->isValidateToken($_SESSION['user_token'])) { + $this->errors['user_token'] = self::DATA_INVALID; return false; - } - - //2 - DB Connection - $res = $this->conn->query( - "SELECT * FROM users WHERE user_name = '".$this->conn->real_escape_string($login)."'" - ); - if ($res->num_rows != 1) { - $this->errors['user'] = self::USER_UNKNOWN; - return false; - } - - $user = $res->fetch_assoc(); - foreach ($user as $key => $value) { - $_SESSION[$key] = $value; - } - $_SESSION['user_logged_in'] = 1; - return true; - } - - private function loginWithPostData() - { - if (! filter_has_var(INPUT_POST, 'user_name') || ! filter_has_var(INPUT_POST, 'user_password') ) { - $this->errors['submission'] = self::DATA_MISSING; + } + + list($login, ) = explode('|', $_SESSION['user_token'); + $login = filter_var($_SESSION['user_name'], FILTER_CALLBACK, array($this, 'isValidUserName')); + if (! $login) { + $this->errors['user_name'] = self::DATA_INVALID; return false; - } - - $params = filter_input_array( - INPUT_POST, - array( - 'user_name' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^[a-z0-9]{2,64}$/i')), - 'user_password' => array('filter' => FILTER_VALIDATE_REGEXP, 'options' => array('regexp' => '/^.{6,}$/')), - ) - ) - - if (! isset($params['user_name'], $params['user_password'])) { - $this->errors['validation'] = self::DATA_INVALID; + } + + $user = $this->getUserByName($login); + if (! $user) { + $this->errors['user_name'] = self::USER_UNKNOWN; + return false; + } + + foreach ($user as $key => $value) { + $_SESSION[$key] = $value; + } + $_SESSION['user_token'] = $this->generateToken($user['user_name']); + return true; + } + + /** + * Connect a user depending on his submitted post data + * + * @return boolean + */ + public function loginWithPostData() + { + $this->errors = array(); + $params = filter_input_array( + INPUT_POST, + array( + 'user_name' => array( + 'filter' => FILTER_CALLBACK, + 'options' => array($this, 'isValidUserName') + ), + 'user_password' => array( + 'filter' => FILTER_CALLBACK, + 'options' => array($this, 'isValidPassword') + ), + ) + ); + + if (! $params) { + $params = array_fill_keys(array('user_name', 'user_password', null); + } + + foreach (array('user_name', 'user_password') as $key) { + if (! is_null($params[$key])) { + $this->errors[$key] = self::DATA_MISSING; + } else if (! $params[$key]) { + $this->errors[$key] = self::DATA_INVALID; + } + } + + if (count($this->errors)) { return false; - } + } - $params['user_name'] = $this->conn->real_escape_string($params['user_name']); - $res = $this->conn->query("SELECT * FROM users WHERE user_name = '{$params['user_name']}'"); - if ($res->num_rows != 1) { - $this->errors['user'] = self::USER_UNKNOWN; - return false; - } + $user = $this->getUserByName($params['user_name']); + if (! $user) { + $this->errors['user'] = self::USER_UNKNOWN; + return false; + } - $user = $res->fetch_assoc(); - if (! password_verify($param['user_password'], $user['user_password_hash'])) { + if (! password_verify($param['user_password'], $user['user_password_hash'])) { $this->errors['password'] = self::DATA_INVALID; return false; - } - - foreach ($user as $key => $value) { - $_SESSION[$key] = $value; - } - $_SESSION['user_logged_in'] = 1; - return true; - } - - /** - * perform the logout - */ - public function doLogout() - { - $_SESSION = array(); - session_destroy(); - return true; - } - - /** - * simply return the current state of the user's login - * @return boolean user's login status - */ - public function isUserLoggedIn() - { - return $this->is_logged_in; - } - - public function isUserLogOut() - { - return $this->is_logged_out; - } + } + + foreach ($user as $key => $value) { + $_SESSION[$key] = $value; + } + $_SESSION['user_token'] = $this->generateToken($user['user_name']); + return true; + } + + /** + * return the user data + * @param str $login the user name + * @return array the user info + */ + private function getUserByName($login) + { + $login = $this->conn->real_escape_string($login); + $res = $this->conn->query("SELECT * FROM users WHERE user_name = '$login'"); + if ($res->num_rows != 1) { + return array(); + } + return $res->fetch_assoc(); + } + + /** + * generate a unique token + * @param string $login a string to generate the token with + * @return string the generated token + */ + private function generateToken($login) + { + $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; + $timestamp = time(); + $secret = sha1($login.'|'.self::SECRET_KEY.'|'.$userAgent.'|'.$timestamp); + return $login.'|'.$timestamp.'|'.$secret; + } + + /** + * validate a token + * @param string $str the token to be validated + * @return boolean + */ + private function isValidateToken($str) + { + list($login, $timestamp, $secret) = explode('|', $str); + $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; + if ( + sha1($login.'|'.self::SECRET_KEY.'|'.$userAgent.'|'.$timestamp) != $secret || + strtotime('NOW - 30 MINUTES') > $timestamp + ) { + return false; + } + return true; + } } From ba8166f25def819bea095911b0b19455a57b1410 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 09:50:38 +0200 Subject: [PATCH 16/33] Added Methods and PHPDocs comments --- 1-minimal/classes/Auth.php | 67 ++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php index f0b7415cc..5a4e9c98d 100644 --- a/1-minimal/classes/Auth.php +++ b/1-minimal/classes/Auth.php @@ -11,7 +11,7 @@ class Auth { private $conn; // database connection private $errors = array(); // collection of error messages - private $regexp = array( + public static final $regexp = array( 'user_name' => '^[a-zA-Z0-9]{2,64}$', 'user_password' => '^.{6,}$' ); @@ -23,6 +23,9 @@ class Auth const USER_EXISTS = 1; const USER_UNKNOWN = 2; + /** + * The Constructor initialize the db connection + */ public function __construct() { $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); @@ -31,6 +34,27 @@ public function __construct() } } + /** + * Return the errors + * @param string $name an specified regular expression + * @return mixed + */ + public function getRegexp($name = null) + { + if (is_null($name)) { + return self::$regexp; + } + if (isset(self::$regexp[$name])) { + return self::$regexp[$name]; + } + return null; + } + + /** + * Return the errors + * @param string $name an specified error + * @return mixed + */ public function getErrors($name = null) { if (is_null($name)) { @@ -42,7 +66,12 @@ public function getErrors($name = null) return null; } - protected function isValidEmail($str = null) + /** + * check to see if the email is valid + * @param string $str the email to test + * @return mixed return the status to work with filter_* function + */ + public static function isValidEmail($str = null) { if (is_null($str)) { return null; @@ -55,7 +84,12 @@ protected function isValidEmail($str = null) return $str; } - protected function isValidPassword($str = null) + /** + * check to see if the password is valid + * @param string $str the password to test + * @return mixed the status to work with filter_* function + */ + public static function isValidPassword($str = null) { if (is_null($str)) { return null; @@ -65,7 +99,7 @@ protected function isValidPassword($str = null) FILTER_VALIDATE_REGEXP, array( 'options' => array( - 'regexp' => '/'.$this->regexp['user_password'].'/' + 'regexp' => '/'.self::regexp['user_password'].'/' ) ) ); @@ -76,7 +110,12 @@ protected function isValidPassword($str = null) return $str; } - protected function isValidUserName($str = null) + /** + * check to see if the username is valid + * @param string $str the username to test + * @return mixed the status to work with filter_* function + */ + public static function isValidUserName($str = null) { if (is_null($str)) { return null; @@ -86,7 +125,7 @@ protected function isValidUserName($str = null) FILTER_VALIDATE_REGEXP, array( 'options' => array( - 'regexp' => '/'.$this->regexp['user_name'].'/' + 'regexp' => '/'.self::regexp['user_name'].'/' ) ) ); @@ -95,7 +134,21 @@ protected function isValidUserName($str = null) } return $str; - } + /** + * return the user data + * @param str $login the user name + * + * @return array the user info + */ + private function getUserByName($login) + { + $login = $this->conn->real_escape_string($login); + $res = $this->conn->query("SELECT * FROM users WHERE user_name = '$login'"); + if ($res->num_rows != 1) { + return array(); + } + return $res->fetch_assoc(); + } } From fe524eb29ea254acd000c06a75787fe48a9c1c76 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 09:53:12 +0200 Subject: [PATCH 17/33] Update Login.php --- 1-minimal/classes/Login.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index 7ee9e4714..88d9409bc 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -67,7 +67,7 @@ public function loginWithSessionData() } list($login, ) = explode('|', $_SESSION['user_token'); - $login = filter_var($_SESSION['user_name'], FILTER_CALLBACK, array($this, 'isValidUserName')); + $login = filter_var($_SESSION['user_name'], FILTER_CALLBACK, array('options' => 'Auth::isValidUserName')); if (! $login) { $this->errors['user_name'] = self::DATA_INVALID; return false; @@ -99,11 +99,11 @@ public function loginWithPostData() array( 'user_name' => array( 'filter' => FILTER_CALLBACK, - 'options' => array($this, 'isValidUserName') + 'options' => array('Auth::isValidUserName') ), 'user_password' => array( 'filter' => FILTER_CALLBACK, - 'options' => array($this, 'isValidPassword') + 'options' => array('Auth::isValidPassword') ), ) ); From 35c41dbb1bc11b6d5b1727b2a791adccd458ad06 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 09:56:14 +0200 Subject: [PATCH 18/33] Update Registration.php --- 1-minimal/classes/Registration.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index f5285fa0d..b5126320a 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -9,6 +9,10 @@ */ class Registration extends Auth { + /** + * Registration Status + * + */ private $is_registration_ok = false; /** @@ -52,10 +56,10 @@ private function registerNewUser() //2 - Input Filtering and Validation $arguments = array( - 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidUserName')), - 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidEmail')), - 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidPassword')), - 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array($this, 'isValidPassword')), + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), + 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidEmail')), + 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), + 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), ); $params = filter_input_array(INPUT_POST, $arguments); if (! $params) { @@ -91,7 +95,7 @@ private function registerNewUser() return false; } - //4 - write new users data into database + //5 - write new user data into database $res = $this->conn->query( "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" ); From 6fa71f85c76d79af6c5eb4cd853b4b13b1243741 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 09:58:14 +0200 Subject: [PATCH 19/33] Update Registration.php --- 1-minimal/classes/Registration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index b5126320a..a640b0038 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -74,7 +74,7 @@ private function registerNewUser() } } if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { - $this->errors['user_password'] = self::DATA_MISMATCH; + $this->errors['user_password_repeat'] = self::DATA_MISMATCH; } if (count($this->errors)) { return false; From cbff6b80717fe128c2ebb010baa32397500380af Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:18:22 +0200 Subject: [PATCH 20/33] Update Auth.php --- 1-minimal/classes/Auth.php | 96 +++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php index 5a4e9c98d..dd02690d3 100644 --- a/1-minimal/classes/Auth.php +++ b/1-minimal/classes/Auth.php @@ -9,19 +9,42 @@ */ class Auth { - private $conn; // database connection - private $errors = array(); // collection of error messages + /** + * Database connection + * @var MySQLi + */ + private $conn; + + /** + * Collection of error messages + * @var array + */ + private $errors = array(); + + /** + * Collection of regular expressions to validate user data + * @var array + */ public static final $regexp = array( 'user_name' => '^[a-zA-Z0-9]{2,64}$', 'user_password' => '^.{6,}$' ); - const DATA_MISSING = 1; - const DATA_INVALID = 2; - const DATA_MISMATCH = 3; - const REGISTRATION_FAILED = 1; - const USER_EXISTS = 1; - const USER_UNKNOWN = 2; + /******************************************************** + * Possible Error using Constants to enable localization + ********************************************************/ + const DATA_MISSING = 1; //data is missing + const DATA_INVALID = 2; //data is invalid + const DATA_MISMATCH = 3; //string mismatch between 2 string + const REGISTRATION_FAILED = 1; //registration failed (db error) + const USER_EXISTS = 1; //user submitted already exists in database + const USER_UNKNOWN = 2; //user unknown (user name OR password Error) + + /** + * Used to generated a unique token for each user + * @var string + */ + private $secretKey = 'This is my hidden secret key'; //you should change this phrase /** * The Constructor initialize the db connection @@ -35,7 +58,7 @@ public function __construct() } /** - * Return the errors + * Return the regular expressions (can be use to match PHP and HTML5 regular expression) * @param string $name an specified regular expression * @return mixed */ @@ -99,7 +122,7 @@ public static function isValidPassword($str = null) FILTER_VALIDATE_REGEXP, array( 'options' => array( - 'regexp' => '/'.self::regexp['user_password'].'/' + 'regexp' => '/'.self::$regexp['user_password'].'/' ) ) ); @@ -125,7 +148,7 @@ public static function isValidUserName($str = null) FILTER_VALIDATE_REGEXP, array( 'options' => array( - 'regexp' => '/'.self::regexp['user_name'].'/' + 'regexp' => '/'.self::$regexp['user_name'].'/' ) ) ); @@ -151,4 +174,55 @@ private function getUserByName($login) } return $res->fetch_assoc(); } + + /** + * is a user already with the given login OR email exists in the database + * @param str $login the user name + * @param str $email the user email + * + * @return boolean + */ + private function isUserExists($login, $email) + { + $login = $this->conn->real_escape_string($login); + $email = $this->conn->real_escape_string($email); + $res = $this->conn->query( + "SELECT COUNT(user_id) AS nb FROM users WHERE user_name = '$login' OR user_email = '$email'" + ); + $nb = $res->fetch_assoc(); + return (bool) $nb['nb']; + } + + /** + * generate a unique token + * @param string $login a string to generate the token with + * @return string the generated token + */ + private function generateToken($login) + { + $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; + $timestamp = time(); + $secret = sha1($login.'|'.$this->secretKey.'|'.$userAgent.'|'.$timestamp); + return $login.'|'.$timestamp.'|'.$secret; + } + + /** + * validate a token against itself and against time + * which makes session timeout possible + * @param string $str the token to be validated + * @return boolean + */ + private function isValidateToken($str) + { + list($login, $timestamp, $secret) = explode('|', $str); + $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; + if ( + sha1($login.'|'.$this->secretKey.'|'.$userAgent.'|'.$timestamp) != $secret || + strtotime('NOW - 30 MINUTES') > $timestamp + ) { + return false; + } + return true; + } + } From f3c8693c66df361dd72cb2949089a7466609f42e Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:21:23 +0200 Subject: [PATCH 21/33] Update Registration.php --- 1-minimal/classes/Registration.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index a640b0038..5a0aa648a 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -73,29 +73,23 @@ private function registerNewUser() $this->errors[$keys] = self::DATA_INVALID; } } + if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { $this->errors['user_password_repeat'] = self::DATA_MISMATCH; } + + if ($this->isUserExists($params['user_name'], $params['user_email'])) { + $this->errors['user_name'] = self::USER_EXISTS; + } + if (count($this->errors)) { return false; } - //3 - data prepared and sanitized for db inclusion + //3 - write new user data into database $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); unset($params['user_password_new'], $params['user_password_repeat']); $params = array_map(array($this->conn, 'real_escape_string'), $params); - - //4 - check if user already in the table - $res = $this->conn->query( - "SELECT * FROM users WHERE user_name = '{$params['user_name']}' OR user_email = '{$params['user_email']}'" - ); - - if ($res->num_rows > 0) { - $this->errors['user_name'] = self::USER_EXISTS; - return false; - } - - //5 - write new user data into database $res = $this->conn->query( "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" ); From 54abd4e5d3ac9dc2bf3141a0de99c6f430ab0002 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:22:23 +0200 Subject: [PATCH 22/33] Update Registration.php --- 1-minimal/classes/Registration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 5a0aa648a..130b5932c 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -74,11 +74,11 @@ private function registerNewUser() } } - if (empty($this->errors) && ($params['user_password_new'] != $params['user_password_repeat'])) { + if (! $this->errors && ($params['user_password_new'] != $params['user_password_repeat'])) { $this->errors['user_password_repeat'] = self::DATA_MISMATCH; } - if ($this->isUserExists($params['user_name'], $params['user_email'])) { + if (! $this->errors && $this->isUserExists($params['user_name'], $params['user_email'])) { $this->errors['user_name'] = self::USER_EXISTS; } From 4d67fc1ebf5e500f759877c9fd41eb697f0124c6 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:24:14 +0200 Subject: [PATCH 23/33] Change method visibility --- 1-minimal/classes/Login.php | 53 +++---------------------------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index 88d9409bc..ab10fcb10 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -51,7 +51,7 @@ public function doLogout() * simply return the current state of the user's login * @return boolean user's login status */ - public function isUserLoggedIn() + public function isUserLoggedIn() { return $this->is_logged_in; } @@ -59,7 +59,7 @@ public function isUserLoggedIn() /** * Connect a user depending on his session data */ - public function loginWithSessionData() + private function loginWithSessionData() { if (! $this->isValidateToken($_SESSION['user_token'])) { $this->errors['user_token'] = self::DATA_INVALID; @@ -91,7 +91,7 @@ public function loginWithSessionData() * * @return boolean */ - public function loginWithPostData() + private function loginWithPostData() { $this->errors = array(); $params = filter_input_array( @@ -141,51 +141,4 @@ public function loginWithPostData() $_SESSION['user_token'] = $this->generateToken($user['user_name']); return true; } - - /** - * return the user data - * @param str $login the user name - * @return array the user info - */ - private function getUserByName($login) - { - $login = $this->conn->real_escape_string($login); - $res = $this->conn->query("SELECT * FROM users WHERE user_name = '$login'"); - if ($res->num_rows != 1) { - return array(); - } - return $res->fetch_assoc(); - } - - /** - * generate a unique token - * @param string $login a string to generate the token with - * @return string the generated token - */ - private function generateToken($login) - { - $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; - $timestamp = time(); - $secret = sha1($login.'|'.self::SECRET_KEY.'|'.$userAgent.'|'.$timestamp); - return $login.'|'.$timestamp.'|'.$secret; - } - - /** - * validate a token - * @param string $str the token to be validated - * @return boolean - */ - private function isValidateToken($str) - { - list($login, $timestamp, $secret) = explode('|', $str); - $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; - if ( - sha1($login.'|'.self::SECRET_KEY.'|'.$userAgent.'|'.$timestamp) != $secret || - strtotime('NOW - 30 MINUTES') > $timestamp - ) { - return false; - } - return true; - } - } From 1903f8e1e297abb02d100b302453e3840e6a7e5a Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:26:04 +0200 Subject: [PATCH 24/33] Update Login.php --- 1-minimal/classes/Login.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index ab10fcb10..d869c0aea 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -97,14 +97,8 @@ private function loginWithPostData() $params = filter_input_array( INPUT_POST, array( - 'user_name' => array( - 'filter' => FILTER_CALLBACK, - 'options' => array('Auth::isValidUserName') - ), - 'user_password' => array( - 'filter' => FILTER_CALLBACK, - 'options' => array('Auth::isValidPassword') - ), + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), + 'user_password' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), ) ); From 51c8c7bf26fb87c47ec0da58177a1d6ad3c64a64 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:38:38 +0200 Subject: [PATCH 25/33] Update register.php using Auth::$regexp to normalize pattern info --- 1-minimal/views/register.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/1-minimal/views/register.php b/1-minimal/views/register.php index f02a6be81..bdf610a46 100644 --- a/1-minimal/views/register.php +++ b/1-minimal/views/register.php @@ -24,17 +24,17 @@ - + - + - + @@ -42,4 +42,4 @@ Back to Login Page - \ No newline at end of file + From 1400bf1e40143bb35808313f800e3b10475d2c74 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:39:41 +0200 Subject: [PATCH 26/33] Update not_logged_in.php --- 1-minimal/views/not_logged_in.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/1-minimal/views/not_logged_in.php b/1-minimal/views/not_logged_in.php index 29397f4a5..1484e3350 100644 --- a/1-minimal/views/not_logged_in.php +++ b/1-minimal/views/not_logged_in.php @@ -23,12 +23,12 @@
- + - - + +
Register new account - \ No newline at end of file + From 25dca9cb026aa9dd588c66fc8c100dd31d5f75e2 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:41:04 +0200 Subject: [PATCH 27/33] Update not_logged_in.php --- 1-minimal/views/not_logged_in.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/1-minimal/views/not_logged_in.php b/1-minimal/views/not_logged_in.php index 1484e3350..aae6a9d66 100644 --- a/1-minimal/views/not_logged_in.php +++ b/1-minimal/views/not_logged_in.php @@ -3,21 +3,15 @@ errors) { - foreach ($login->errors as $error) { - echo $error; +$errors = $login->getErrors(); +if (count($errors)) { + foreach ($errors as $key => $value) { + echo $key .':' . $error; } } - -// show positive messages -if ($login->messages) { - foreach ($login->messages as $message) { - echo $message; - } -} - +*/ ?> From 34aa25bd3a5dd181f6d654bc2b312e0c79c556c6 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:42:26 +0200 Subject: [PATCH 28/33] Update register.php --- 1-minimal/views/register.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/1-minimal/views/register.php b/1-minimal/views/register.php index bdf610a46..a71ba8402 100644 --- a/1-minimal/views/register.php +++ b/1-minimal/views/register.php @@ -2,21 +2,15 @@ errors) { - foreach ($registration->errors as $error) { - echo $error; +$errors = $registration->getErrors(); +if (count($errors)) { + foreach ($errors as $key => $value) { + echo $key . ' : '. $value; } } - -// show positive messages -if ($registration->messages) { - foreach ($registration->messages as $message) { - echo $message; - } -} - +*/ ?> @@ -35,7 +29,7 @@ - + From c5332c480a640353f56accaec232f5533726a8ae Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:46:00 +0200 Subject: [PATCH 29/33] Update index.php --- 1-minimal/index.php | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/1-minimal/index.php b/1-minimal/index.php index 4c062fb13..eb15961ce 100644 --- a/1-minimal/index.php +++ b/1-minimal/index.php @@ -23,26 +23,27 @@ // if you are using PHP 5.3 or PHP 5.4 you have to include the password_api_compatibility_library.php // (this library adds the PHP 5.5 password hashing functions to older versions of PHP) -require_once("libraries/password_compatibility_library.php"); +require "libraries/password_compatibility_library.php"; // include the configs / constants for the database connection -require_once("config/db.php"); +require "config/db.php"; + +// load the Auth class +require "classes/Auth.php"; // load the login class -require_once("classes/Login.php"); +require "classes/Login.php"; + +// by default the user is not logged in. you can do whatever you want here. +// for demonstration purposes, we simply show the "you are not logged in" view. +$view = "not_logged_in"; // create a login object. when this object is created, it will do all login/logout stuff automatically // so this single line handles the entire login process. in consequence, you can simply ... $login = new Login(); - -// ... ask if we are logged in here: -if ($login->isUserLoggedIn() == true) { +if ($login->isUserLoggedIn()) { // the user is logged in. you can do whatever you want here. // for demonstration purposes, we simply show the "you are logged in" view. - include("views/logged_in.php"); - -} else { - // the user is not logged in. you can do whatever you want here. - // for demonstration purposes, we simply show the "you are not logged in" view. - include("views/not_logged_in.php"); -} \ No newline at end of file + $view = "logged_in"; +} +include 'views/'.$view.'.php'; From b858f08f8f0e27fd07100a60241d00c9ab484ce6 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Mon, 1 Jul 2013 10:47:19 +0200 Subject: [PATCH 30/33] Update register.php --- 1-minimal/register.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/1-minimal/register.php b/1-minimal/register.php index 77025b9c5..2dc1ac105 100644 --- a/1-minimal/register.php +++ b/1-minimal/register.php @@ -23,17 +23,20 @@ // if you are using PHP 5.3 or PHP 5.4 you have to include the password_api_compatibility_library.php // (this library adds the PHP 5.5 password hashing functions to older versions of PHP) -require_once("libraries/password_compatibility_library.php"); +require "libraries/password_compatibility_library.php"; // include the configs / constants for the database connection -require_once("config/db.php"); +require "config/db.php"; + +// load the Auth class +require "classes/Auth.php"; // load the registration class -require_once("classes/Registration.php"); +require "classes/Registration.php"; // create the registration object. when this object is created, it will do all registration stuff automaticly // so this single line handles the entire registration process. $registration = new Registration(); // showing the register view (with the registration form, and messages/errors) -include("views/register.php"); +include "views/register.php"; From 0d8d0b80219ce87eca0542659b17e2262b13506e Mon Sep 17 00:00:00 2001 From: Ignace Butera Date: Mon, 1 Jul 2013 11:16:17 +0200 Subject: [PATCH 31/33] Bug and indentation fixes --- 1-minimal/classes/Auth.php | 247 ++++++++++++++--------------- 1-minimal/classes/Login.php | 53 ++++--- 1-minimal/classes/Registration.php | 145 ++++++++--------- 1-minimal/config/db.php | 12 +- 1-minimal/index.php | 10 +- 1-minimal/register.php | 2 +- 6 files changed, 226 insertions(+), 243 deletions(-) diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php index dd02690d3..cc231e5bd 100644 --- a/1-minimal/classes/Auth.php +++ b/1-minimal/classes/Auth.php @@ -9,160 +9,152 @@ */ class Auth { - /** - * Database connection - * @var MySQLi - */ - private $conn; - - /** + /** + * Database connection + * @var MySQLi + */ + private $conn; + + /** * Collection of error messages * @var array */ - private $errors = array(); - - /** + private $errors = array(); + + /** * Collection of regular expressions to validate user data * @var array */ - public static final $regexp = array( - 'user_name' => '^[a-zA-Z0-9]{2,64}$', - 'user_password' => '^.{6,}$' - ); + public static $regexp = array( + 'user_name' => '^[a-zA-Z0-9]{2,64}$', + 'user_password' => '^.{6,}$' + ); - /******************************************************** - * Possible Error using Constants to enable localization + /******************************************************** + * Possible Error using Constants to enable localization ********************************************************/ - const DATA_MISSING = 1; //data is missing - const DATA_INVALID = 2; //data is invalid - const DATA_MISMATCH = 3; //string mismatch between 2 string - const REGISTRATION_FAILED = 1; //registration failed (db error) - const USER_EXISTS = 1; //user submitted already exists in database - const USER_UNKNOWN = 2; //user unknown (user name OR password Error) - - /** + const DATA_MISSING = 1; //data is missing + const DATA_INVALID = 2; //data is invalid + const DATA_MISMATCH = 3; //string mismatch between 2 string + const REGISTRATION_FAILED = 1; //registration failed (db error) + const USER_EXISTS = 1; //user submitted already exists in database + const USER_UNKNOWN = 2; //user unknown (user name OR password Error) + + /** * Used to generated a unique token for each user * @var string */ - private $secretKey = 'This is my hidden secret key'; //you should change this phrase - - /** + private $secretKey = 'This is my hidden secret key'; //you should change this phrase + + /** * The Constructor initialize the db connection */ - public function __construct() - { - $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); - if ($this->conn->connect_errno || ! $this->conn->set_charset(DB_CHARSET)) { - die("Sorry, no database connection."); - } - } - - /** + public function __construct() + { + $this->conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); + if ($this->conn->connect_errno || ! $this->conn->set_charset(DB_CHARSET)) { + die("Sorry, no database connection."); + } + } + + /** * Return the regular expressions (can be use to match PHP and HTML5 regular expression) * @param string $name an specified regular expression * @return mixed */ - public function getRegexp($name = null) - { - if (is_null($name)) { - return self::$regexp; - } - if (isset(self::$regexp[$name])) { - return self::$regexp[$name]; - } - return null; - } - - /** + public function getRegexp($name = null) + { + if (is_null($name)) { + return self::$regexp; + } + if (isset(self::$regexp[$name])) { + return self::$regexp[$name]; + } + return null; + } + + /** * Return the errors * @param string $name an specified error * @return mixed */ - public function getErrors($name = null) - { - if (is_null($name)) { - return $this->errors; - } - if (isset($this->errors[$name])) { - return $this->errors[$name]; - } - return null; - } - - /** + public function getErrors($name = null) + { + if (is_null($name)) { + return $this->errors; + } + if (isset($this->errors[$name])) { + return $this->errors[$name]; + } + return null; + } + + /** * check to see if the email is valid * @param string $str the email to test - * @return mixed return the status to work with filter_* function + * @return mixed return the status to work with filter_* function */ - public static function isValidEmail($str = null) - { - if (is_null($str)) { - return null; - } - $str = filter_var($str, FILTER_VALIDATE_EMAIL); - if (! $str || 64 > strlen($str)) { - return false; - } - - return $str; - } - - /** + public static function isValidEmail($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var($str, FILTER_VALIDATE_EMAIL); + if (! $str || 64 > strlen($str)) { + return false; + } + + return $str; + } + + /** * check to see if the password is valid * @param string $str the password to test - * @return mixed the status to work with filter_* function + * @return mixed the status to work with filter_* function */ - public static function isValidPassword($str = null) - { - if (is_null($str)) { - return null; - } - $str = filter_var( - $str, - FILTER_VALIDATE_REGEXP, - array( - 'options' => array( - 'regexp' => '/'.self::$regexp['user_password'].'/' - ) - ) - ); - if (! $str) { - return false; - } - - return $str; - } - - /** + public static function isValidPassword($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var( + $str, + FILTER_VALIDATE_REGEXP, + array('options' => array('regexp' => '/'.self::$regexp['user_password'].'/')) + ); + if (! $str) { + return false; + } + + return $str; + } + + /** * check to see if the username is valid * @param string $str the username to test - * @return mixed the status to work with filter_* function + * @return mixed the status to work with filter_* function */ - public static function isValidUserName($str = null) - { - if (is_null($str)) { - return null; - } - $str = filter_var( - $str, - FILTER_VALIDATE_REGEXP, - array( - 'options' => array( - 'regexp' => '/'.self::$regexp['user_name'].'/' - ) - ) - ); - if (! $str) { - return false; - } - - return $str; - } + public static function isValidUserName($str = null) + { + if (is_null($str)) { + return null; + } + $str = filter_var( + $str, + FILTER_VALIDATE_REGEXP, + array('options' => array('regexp' => '/'.self::$regexp['user_name'].'/')) + ); + if (! $str) { + return false; + } + + return $str; + } /** * return the user data * @param str $login the user name - * + * * @return array the user info */ private function getUserByName($login) @@ -174,12 +166,12 @@ private function getUserByName($login) } return $res->fetch_assoc(); } - + /** * is a user already with the given login OR email exists in the database * @param str $login the user name * @param str $email the user email - * + * * @return boolean */ private function isUserExists($login, $email) @@ -189,12 +181,12 @@ private function isUserExists($login, $email) $res = $this->conn->query( "SELECT COUNT(user_id) AS nb FROM users WHERE user_name = '$login' OR user_email = '$email'" ); - $nb = $res->fetch_assoc(); - return (bool) $nb['nb']; + $count = $res->fetch_assoc(); + return (bool) $count['nb']; } - + /** - * generate a unique token + * generate a unique token * @param string $login a string to generate the token with * @return string the generated token */ @@ -207,7 +199,7 @@ private function generateToken($login) } /** - * validate a token against itself and against time + * validate a token against itself and against time * which makes session timeout possible * @param string $str the token to be validated * @return boolean @@ -224,5 +216,4 @@ private function isValidateToken($str) } return true; } - } diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index d869c0aea..4433b2186 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -17,14 +17,16 @@ class Login extends Auth /** * The constructor handles login/logout action - */ - public function __construct() + */ + public function __construct() { parent::__construct(); + // create/read session - if (empty(session_id())) { + $sessionId = session_id(); + if (empty($sessionId)) { session_start(); - } + } $this->is_logged_in = false; if (isset($_SESSION['session_token'])) { @@ -49,25 +51,29 @@ public function doLogout() /** * simply return the current state of the user's login + * * @return boolean user's login status */ - public function isUserLoggedIn() + public function isUserLoggedIn() { return $this->is_logged_in; } /** * Connect a user depending on his session data - */ + */ private function loginWithSessionData() { + $this->errors = array(); + //1 - Input Filtering and Validation if (! $this->isValidateToken($_SESSION['user_token'])) { $this->errors['user_token'] = self::DATA_INVALID; return false; } - list($login, ) = explode('|', $_SESSION['user_token'); - $login = filter_var($_SESSION['user_name'], FILTER_CALLBACK, array('options' => 'Auth::isValidUserName')); + //2 - User Authentification + $auth = explode('|', $_SESSION['user_token']); + $login = filter_var($auth[0], FILTER_CALLBACK, array('options' => 'Auth::isValidUserName')); if (! $login) { $this->errors['user_name'] = self::DATA_INVALID; return false; @@ -76,9 +82,10 @@ private function loginWithSessionData() $user = $this->getUserByName($login); if (! $user) { $this->errors['user_name'] = self::USER_UNKNOWN; - return false; + return false; } + //3 - Session Update foreach ($user as $key => $value) { $_SESSION[$key] = $value; } @@ -93,42 +100,36 @@ private function loginWithSessionData() */ private function loginWithPostData() { + $this->errors = array(); - $params = filter_input_array( - INPUT_POST, - array( - 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), - 'user_password' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), - ) + //1 - Input Filtering and Validation + $arguments = array( + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), + 'user_password' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), ); - - if (! $params) { - $params = array_fill_keys(array('user_name', 'user_password', null); - } - - foreach (array('user_name', 'user_password') as $key) { + $params = filter_input_array(INPUT_POST, $arguments); + foreach (array_keys($arguments) as $key) { if (! is_null($params[$key])) { $this->errors[$key] = self::DATA_MISSING; } else if (! $params[$key]) { $this->errors[$key] = self::DATA_INVALID; } } - if (count($this->errors)) { return false; } - + //2 - User Authentification $user = $this->getUserByName($params['user_name']); if (! $user) { $this->errors['user'] = self::USER_UNKNOWN; - return false; + return false; } - if (! password_verify($param['user_password'], $user['user_password_hash'])) { + if (! password_verify($params['user_password'], $user['user_password_hash'])) { $this->errors['password'] = self::DATA_INVALID; return false; } - + //3 - Session Update foreach ($user as $key => $value) { $_SESSION[$key] = $value; } diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index 130b5932c..b1af51fe3 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -9,96 +9,87 @@ */ class Registration extends Auth { - /** + /** * Registration Status - * + * @var boolean */ - private $is_registration_ok = false; + private $is_registration_ok = false; - /** + /** * The constructor execute the registration on set the registration status - * */ - public function __construct() - { - parent::__construct(); - $this->is_registration_ok = $this->registerNewUser(); - } + public function __construct() + { + parent::__construct(); + if (filter_has_var(INPUT_POST, 'register')) { + $this->is_registration_ok = $this->registerNewUser(); + } + } - /** + /** * return the registration status * * @return boolean */ - public function isRegistrationSuccessful() - { - return $this->is_registration_ok; - } + public function isRegistrationSuccessful() + { + return $this->is_registration_ok; + } + + /** + * registerNewUser + * + * handles the entire registration process. + * checks all error possibilities, + * and creates a new user in the database if + * everything is fine + * + * @return boolean + * + */ + private function registerNewUser() + { + //1 - Input Filtering and Validation + $arguments = array( + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), + 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidEmail')), + 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), + 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), + ); + $params = filter_input_array(INPUT_POST, $arguments); + foreach (array_keys($arguments) as $keys) { + if (is_null($params[$keys])) { + $this->errors[$keys] = self::DATA_MISSING; + } elseif (! $params[$keys]) { + $this->errors[$keys] = self::DATA_INVALID; + } + } + + if (! $this->errors && ($params['user_password_new'] != $params['user_password_repeat'])) { + $this->errors['user_password_repeat'] = self::DATA_MISMATCH; + } - /** - * registerNewUser - * - * handles the entire registration process. - * checks all error possibilities, - * and creates a new user in the database if - * everything is fine - * - * @return boolean - * - */ - private function registerNewUser() - { - //1 - reset the errors property - $this->errors = array(); - if (filter_has_var(INPUT_POST, 'register')) { - return false; - } + if (! $this->errors && $this->isUserExists($params['user_name'], $params['user_email'])) { + $this->errors['user_name'] = self::USER_EXISTS; + } - //2 - Input Filtering and Validation - $arguments = array( - 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), - 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidEmail')), - 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), - 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), - ); - $params = filter_input_array(INPUT_POST, $arguments); - if (! $params) { - $params = array_fill_keys(array_keys($arguments), null); - } - foreach (array_keys($arguments) as $keys) { - $value = $params[$keys]; - if (is_null($value)) { - $this->errors[$keys] = self::DATA_MISSING; - } elseif (! $value) { - $this->errors[$keys] = self::DATA_INVALID; - } - } - - if (! $this->errors && ($params['user_password_new'] != $params['user_password_repeat'])) { - $this->errors['user_password_repeat'] = self::DATA_MISMATCH; - } - - if (! $this->errors && $this->isUserExists($params['user_name'], $params['user_email'])) { - $this->errors['user_name'] = self::USER_EXISTS; - } - - if (count($this->errors)) { - return false; - } + if (count($this->errors)) { + return false; + } - //3 - write new user data into database - $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); - unset($params['user_password_new'], $params['user_password_repeat']); - $params = array_map(array($this->conn, 'real_escape_string'), $params); - $res = $this->conn->query( - "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('."implode("','", $params)".')" - ); + //2 - write new user data into database + $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); + unset($params['user_password_new'], $params['user_password_repeat']); + $params = array_map(array($this->conn, 'real_escape_string'), $params); + $res = $this->conn->query( + "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('".implode("','", $params)."')" + ); - if (! $res) { - $this->errors['user_name'] = self::REGISTRATION_FAILED; - return false; - } + if (! $res) { + $this->errors['user_name'] = self::REGISTRATION_FAILED; + return false; + } - return true; - } + return true; + } } diff --git a/1-minimal/config/db.php b/1-minimal/config/db.php index c735dabc2..b080b9cdc 100644 --- a/1-minimal/config/db.php +++ b/1-minimal/config/db.php @@ -10,17 +10,17 @@ /** database host, usually it's "127.0.0.1" or "localhost", some servers also need port info, like "127.0.0.1:8080" */ -const "DB_HOST" = "127.0.0.1"; +const DB_HOST = "127.0.0.1"; /** name of the database. please note: database and database table are not the same thing! */ -const "DB_NAME" = "login"; +const DB_NAME = "login"; /** user for your database. the user needs to have rights for SELECT, UPDATE, DELETE and INSERT. /** By the way, it's bad style to use "root", but for development it will work */ -const "DB_USER" = "root"; +const DB_USER = "root"; /** The password of the above user */ -const "DB_PASS" = "mysql"; +const DB_PASS = "mysql"; - -const 'DB_CHARSET' = 'utf8'; //connection charset +/** Required to better sanitize your data before DB insertion */ +const DB_CHARSET = 'utf8'; diff --git a/1-minimal/index.php b/1-minimal/index.php index eb15961ce..ac8caa29e 100644 --- a/1-minimal/index.php +++ b/1-minimal/index.php @@ -36,14 +36,14 @@ // by default the user is not logged in. you can do whatever you want here. // for demonstration purposes, we simply show the "you are not logged in" view. -$view = "not_logged_in"; +$view = "views/not_logged_in.php"; // create a login object. when this object is created, it will do all login/logout stuff automatically // so this single line handles the entire login process. in consequence, you can simply ... -$login = new Login(); -if ($login->isUserLoggedIn()) { +$login = new Login; +if ($login->isUserLoggedIn()) { // the user is logged in. you can do whatever you want here. // for demonstration purposes, we simply show the "you are logged in" view. - $view = "logged_in"; + $view = "views/logged_in.php"; } -include 'views/'.$view.'.php'; +include $view; diff --git a/1-minimal/register.php b/1-minimal/register.php index 2dc1ac105..acca86a96 100644 --- a/1-minimal/register.php +++ b/1-minimal/register.php @@ -36,7 +36,7 @@ // create the registration object. when this object is created, it will do all registration stuff automaticly // so this single line handles the entire registration process. -$registration = new Registration(); +$registration = new Registration; // showing the register view (with the registration form, and messages/errors) include "views/register.php"; From 937125abb60ecea67383068d96f95f4adad1c5a2 Mon Sep 17 00:00:00 2001 From: Ignace Butera Date: Tue, 2 Jul 2013 10:10:27 +0200 Subject: [PATCH 32/33] Bug fixes and example rewrite to help understand the new code for 1-minimal --- 1-minimal/_install/users.sql | 5 +- 1-minimal/classes/Auth.php | 53 ++++++++++++----- 1-minimal/classes/Login.php | 61 +++++++++++-------- 1-minimal/classes/Registration.php | 38 +++++++----- 1-minimal/config/db.php | 4 +- 1-minimal/index.php | 1 + 1-minimal/views/not_logged_in.php | 39 +++++++++---- 1-minimal/views/register.php | 94 +++++++++++++++++++++--------- 8 files changed, 196 insertions(+), 99 deletions(-) diff --git a/1-minimal/_install/users.sql b/1-minimal/_install/users.sql index 8e2e03c4f..842979769 100644 --- a/1-minimal/_install/users.sql +++ b/1-minimal/_install/users.sql @@ -32,8 +32,9 @@ CREATE TABLE IF NOT EXISTS `users` ( `user_password_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user''s password in salted and hashed format', `user_email` varchar(64) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user''s email', PRIMARY KEY (`user_id`), - UNIQUE KEY `user_name` (`user_name`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='user data' AUTO_INCREMENT=1 ; + UNIQUE KEY `user_name` (`user_name`), + UNIQUE KEY `user_email` (`user_email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='user data' AUTO_INCREMENT=1; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; diff --git a/1-minimal/classes/Auth.php b/1-minimal/classes/Auth.php index cc231e5bd..97de7a388 100644 --- a/1-minimal/classes/Auth.php +++ b/1-minimal/classes/Auth.php @@ -13,13 +13,13 @@ class Auth * Database connection * @var MySQLi */ - private $conn; + protected $conn; /** * Collection of error messages * @var array */ - private $errors = array(); + protected $errors = array(); /** * Collection of regular expressions to validate user data @@ -30,21 +30,28 @@ class Auth 'user_password' => '^.{6,}$' ); + /** + * action to be taken + * @var string + */ + protected $action; + /******************************************************** * Possible Error using Constants to enable localization ********************************************************/ + const DATA_OK = 128; //data is ok const DATA_MISSING = 1; //data is missing const DATA_INVALID = 2; //data is invalid const DATA_MISMATCH = 3; //string mismatch between 2 string - const REGISTRATION_FAILED = 1; //registration failed (db error) - const USER_EXISTS = 1; //user submitted already exists in database - const USER_UNKNOWN = 2; //user unknown (user name OR password Error) + const REGISTRATION_FAILED = 4; //registration failed (db error) + const USER_EXISTS = 5; //user submitted already exists in database + const USER_UNKNOWN = 6; //user unknown (user name OR password Error) /** * Used to generated a unique token for each user * @var string */ - private $secretKey = 'This is my hidden secret key'; //you should change this phrase + protected $secretKey = 'This is my hidden secret key'; //you should change this phrase /** * The Constructor initialize the db connection @@ -100,7 +107,7 @@ public static function isValidEmail($str = null) return null; } $str = filter_var($str, FILTER_VALIDATE_EMAIL); - if (! $str || 64 > strlen($str)) { + if (! $str || 64 < strlen($str)) { return false; } @@ -157,7 +164,7 @@ public static function isValidUserName($str = null) * * @return array the user info */ - private function getUserByName($login) + protected function getUserByName($login) { $login = $this->conn->real_escape_string($login); $res = $this->conn->query("SELECT * FROM users WHERE user_name = '$login'"); @@ -174,7 +181,7 @@ private function getUserByName($login) * * @return boolean */ - private function isUserExists($login, $email) + protected function isUserExists($login, $email) { $login = $this->conn->real_escape_string($login); $email = $this->conn->real_escape_string($email); @@ -182,7 +189,7 @@ private function isUserExists($login, $email) "SELECT COUNT(user_id) AS nb FROM users WHERE user_name = '$login' OR user_email = '$email'" ); $count = $res->fetch_assoc(); - return (bool) $count['nb']; + return (int) $count['nb']; } /** @@ -190,7 +197,7 @@ private function isUserExists($login, $email) * @param string $login a string to generate the token with * @return string the generated token */ - private function generateToken($login) + protected function generateToken($login) { $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; $timestamp = time(); @@ -204,16 +211,32 @@ private function generateToken($login) * @param string $str the token to be validated * @return boolean */ - private function isValidateToken($str) + protected function isValidToken($str) { - list($login, $timestamp, $secret) = explode('|', $str); + $auth = explode('|', $str); $userAgent = (isset($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; if ( - sha1($login.'|'.$this->secretKey.'|'.$userAgent.'|'.$timestamp) != $secret || - strtotime('NOW - 30 MINUTES') > $timestamp + count($auth) != 3 || + strtotime('NOW - 30 MINUTES') > $auth[1] || + sha1($auth[0].'|'.$this->secretKey.'|'.$userAgent.'|'.$auth[1]) != $auth[2] ) { return false; } return true; } + + /** + * tell if a value is null, false or set + * @param mixed $str the value to valid + * @return int + */ + protected function isDataValid($value = null) + { + if (is_null($value)) { + return self::DATA_MISSING; + } elseif (! $value) { + return self::DATA_INVALID; + } + return self::DATA_OK; + } } diff --git a/1-minimal/classes/Login.php b/1-minimal/classes/Login.php index 4433b2186..4ec539447 100644 --- a/1-minimal/classes/Login.php +++ b/1-minimal/classes/Login.php @@ -28,10 +28,17 @@ public function __construct() session_start(); } - $this->is_logged_in = false; - if (isset($_SESSION['session_token'])) { + //the action to take + $action = filter_input( + INPUT_GET, + 'action', + FILTER_SANITIZE_STRING, + FILTER_REQUIRE_SCALAR|FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH + ); + + if (isset($_SESSION['user_token'])) { $this->is_logged_in = $this->loginWithSessionData(); - } elseif (filter_has_var(INPUT_POST, 'login')) { + } elseif ('login' == $action) { $this->is_logged_in = $this->loginWithPostData(); } @@ -45,6 +52,7 @@ public function __construct() */ public function doLogout() { + $this->is_logged_in = false; $_SESSION = array(); session_destroy(); } @@ -66,7 +74,7 @@ private function loginWithSessionData() { $this->errors = array(); //1 - Input Filtering and Validation - if (! $this->isValidateToken($_SESSION['user_token'])) { + if (! $this->isValidToken($_SESSION['user_token'])) { $this->errors['user_token'] = self::DATA_INVALID; return false; } @@ -77,19 +85,13 @@ private function loginWithSessionData() if (! $login) { $this->errors['user_name'] = self::DATA_INVALID; return false; - } - - $user = $this->getUserByName($login); - if (! $user) { + } elseif (! ($user = $this->getUserByName($login))) { $this->errors['user_name'] = self::USER_UNKNOWN; return false; } //3 - Session Update - foreach ($user as $key => $value) { - $_SESSION[$key] = $value; - } - $_SESSION['user_token'] = $this->generateToken($user['user_name']); + $this->loadSession($user); return true; } @@ -102,38 +104,47 @@ private function loginWithPostData() { $this->errors = array(); + //1 - Input Filtering and Validation $arguments = array( - 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), - 'user_password' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidUserName'), + 'user_password' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidPassword'), ); $params = filter_input_array(INPUT_POST, $arguments); - foreach (array_keys($arguments) as $key) { - if (! is_null($params[$key])) { - $this->errors[$key] = self::DATA_MISSING; - } else if (! $params[$key]) { - $this->errors[$key] = self::DATA_INVALID; + $this->errors = array_map(array($this, 'isDataValid'), $params); + foreach ($this->errors as $keys => $value) { + if ($value == self::DATA_OK) { + unset($this->errors[$keys]); } } if (count($this->errors)) { return false; } + //2 - User Authentification $user = $this->getUserByName($params['user_name']); if (! $user) { - $this->errors['user'] = self::USER_UNKNOWN; + $this->errors['user_name'] = self::USER_UNKNOWN; return false; - } - - if (! password_verify($params['user_password'], $user['user_password_hash'])) { - $this->errors['password'] = self::DATA_INVALID; + } elseif (! password_verify($params['user_password'], $user['user_password_hash'])) { + $this->errors['user_password'] = self::DATA_INVALID; return false; } + //3 - Session Update + $this->loadSession($user); + return true; + } + + /** + * load User Data into the session + * @return void + */ + private function loadSession(array $user) + { foreach ($user as $key => $value) { $_SESSION[$key] = $value; } $_SESSION['user_token'] = $this->generateToken($user['user_name']); - return true; } } diff --git a/1-minimal/classes/Registration.php b/1-minimal/classes/Registration.php index b1af51fe3..e9f068fe0 100644 --- a/1-minimal/classes/Registration.php +++ b/1-minimal/classes/Registration.php @@ -21,7 +21,15 @@ class Registration extends Auth public function __construct() { parent::__construct(); - if (filter_has_var(INPUT_POST, 'register')) { + + $action = filter_input( + INPUT_GET, + 'action', + FILTER_SANITIZE_STRING, + FILTER_REQUIRE_SCALAR|FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH + ); + + if ('register' == $action) { $this->is_registration_ok = $this->registerNewUser(); } } @@ -51,25 +59,28 @@ private function registerNewUser() { //1 - Input Filtering and Validation $arguments = array( - 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidUserName')), - 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidEmail')), - 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), - 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => array('Auth::isValidPassword')), + 'user_name' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidUserName'), + 'user_email' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidEmail'), + 'user_password_new' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidPassword'), + 'user_password_repeat' => array('filter' => FILTER_CALLBACK, 'options' => 'Auth::isValidPassword'), ); $params = filter_input_array(INPUT_POST, $arguments); - foreach (array_keys($arguments) as $keys) { - if (is_null($params[$keys])) { - $this->errors[$keys] = self::DATA_MISSING; - } elseif (! $params[$keys]) { - $this->errors[$keys] = self::DATA_INVALID; + $this->errors = array_map(array($this, 'isDataValid'), $params); + foreach ($this->errors as $key => $value) { + if ($value == self::DATA_OK) { + unset($this->errors[$key]); } } - if (! $this->errors && ($params['user_password_new'] != $params['user_password_repeat'])) { + if (! isset($this->errors['user_password_new'], $this->errors['user_password_repeat']) && + ($params['user_password_new'] != $params['user_password_repeat']) + ) { $this->errors['user_password_repeat'] = self::DATA_MISMATCH; } - if (! $this->errors && $this->isUserExists($params['user_name'], $params['user_email'])) { + if (! isset($this->errors['user_name'], $this->errors['user_email']) && + $this->isUserExists($params['user_name'], $params['user_email']) + ) { $this->errors['user_name'] = self::USER_EXISTS; } @@ -78,13 +89,12 @@ private function registerNewUser() } //2 - write new user data into database - $params['user_password'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); + $params['user_password_hash'] = password_hash($params['user_password_new'], PASSWORD_DEFAULT); unset($params['user_password_new'], $params['user_password_repeat']); $params = array_map(array($this->conn, 'real_escape_string'), $params); $res = $this->conn->query( "INSERT INTO users (".implode(',', array_keys($params)).") VALUES ('".implode("','", $params)."')" ); - if (! $res) { $this->errors['user_name'] = self::REGISTRATION_FAILED; return false; diff --git a/1-minimal/config/db.php b/1-minimal/config/db.php index b080b9cdc..de9532732 100644 --- a/1-minimal/config/db.php +++ b/1-minimal/config/db.php @@ -13,14 +13,14 @@ const DB_HOST = "127.0.0.1"; /** name of the database. please note: database and database table are not the same thing! */ -const DB_NAME = "login"; +const DB_NAME = "test"; /** user for your database. the user needs to have rights for SELECT, UPDATE, DELETE and INSERT. /** By the way, it's bad style to use "root", but for development it will work */ const DB_USER = "root"; /** The password of the above user */ -const DB_PASS = "mysql"; +const DB_PASS = "troldbois"; /** Required to better sanitize your data before DB insertion */ const DB_CHARSET = 'utf8'; diff --git a/1-minimal/index.php b/1-minimal/index.php index ac8caa29e..13d1d4b70 100644 --- a/1-minimal/index.php +++ b/1-minimal/index.php @@ -21,6 +21,7 @@ * @license http://opensource.org/licenses/MIT MIT License */ + // if you are using PHP 5.3 or PHP 5.4 you have to include the password_api_compatibility_library.php // (this library adds the PHP 5.5 password hashing functions to older versions of PHP) require "libraries/password_compatibility_library.php"; diff --git a/1-minimal/views/not_logged_in.php b/1-minimal/views/not_logged_in.php index aae6a9d66..ea89efb90 100644 --- a/1-minimal/views/not_logged_in.php +++ b/1-minimal/views/not_logged_in.php @@ -1,26 +1,41 @@ - + getErrors(); -if (count($errors)) { - foreach ($errors as $key => $value) { - echo $key .':' . $error; - } +$errors = array(); +if (! $login->isUserLoggedIn()) { + // show negative messages + $errors = $login->getErrors(); } -*/ ?> - -
+ +
- + +
+ + + +

You did not submit a login

+ +

The submitted login is invalid!!

+ +

unknown account!

+ + + + +

You did not submit an password

+ +

The submitted password is invalid!!

+ + +
Register new account diff --git a/1-minimal/views/register.php b/1-minimal/views/register.php index a71ba8402..fb99d8855 100644 --- a/1-minimal/views/register.php +++ b/1-minimal/views/register.php @@ -1,39 +1,75 @@ - - -getErrors(); -if (count($errors)) { - foreach ($errors as $key => $value) { - echo $key . ' : '. $value; - } -} -*/ -?> - - -
- +isRegistrationSuccessful()) { + // show negative messages + $errors = $registration->getErrors(); + ?> + + +
- - + + + +

You did not submit a login

+ +

The submitted login is invalid!!

+ +

an account with the same credentails already exists

+ +

An error occurs during your registration please try again later!

+ + +
+ +
- - + + + +

You did not submit an email

+ +

The submitted email is invalid or is longer than 64 characters!!

+ + +
+ +
- - - - - - - + + + +

You did not submit an password

+ +

The submitted password is invalid or is shorter than 6 characters!!

+ + +
+
+ + + + + +

You did not submit an password

+ +

The submitted password is invalid or is shorter than 6 characters!!

+ +

The submitted passwords do not match!!

+ + +
+ + +

You are register, to Log click on the link below.

+ Back to Login Page - From d1edbdea6608d56c9202b5159359dc99c8b13e73 Mon Sep 17 00:00:00 2001 From: nyamsprod Date: Tue, 2 Jul 2013 10:15:48 +0200 Subject: [PATCH 33/33] Update db.php --- 1-minimal/config/db.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-minimal/config/db.php b/1-minimal/config/db.php index de9532732..6ef60c620 100644 --- a/1-minimal/config/db.php +++ b/1-minimal/config/db.php @@ -10,17 +10,17 @@ /** database host, usually it's "127.0.0.1" or "localhost", some servers also need port info, like "127.0.0.1:8080" */ -const DB_HOST = "127.0.0.1"; +const DB_HOST = "localhost"; /** name of the database. please note: database and database table are not the same thing! */ -const DB_NAME = "test"; +const DB_NAME = "dbname"; /** user for your database. the user needs to have rights for SELECT, UPDATE, DELETE and INSERT. /** By the way, it's bad style to use "root", but for development it will work */ const DB_USER = "root"; /** The password of the above user */ -const DB_PASS = "troldbois"; +const DB_PASS = "password"; /** Required to better sanitize your data before DB insertion */ const DB_CHARSET = 'utf8';