Revision: 26385
Updated Code
at November 27, 2011 08:45 by ptejada
Updated Code
<?php // For Support visit http://crusthq.com/projects/uFlex/ // --------------------------------------------------------------------------- // uFlex - An all in one authentication system PHP class // Copyright (C) 2011 Pablo Tejada // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.html. // --------------------------------------------------------------------------- /*Thought the Class Official name is userFlex the object is simply named uFlex*/ class uFlex { //Constants const debug = true; //Logs extra bits of errors for developers const version = 0.75; const salt = "sd5a4"; //IMPORTANT: Please change this value as it will make this copy unique and secured //End of constants\\\\ var $id; //Signed user ID var $sid; //Current User Session ID var $username; //Signed username var $pass; //Holds the user password hash var $signed; //Boolean, true = user is signed-in var $data; //Holds entire user database row var $console; //Cotainer for errors and reports var $log; //Used for traking errors and reports var $confirm; //Holds the hash for any type of comfirmation var $tmp_data; //Holds the temporary user information during registration var $opt = array( //Array of Internal options "table_name" => "users", "cookie_time" => "+30 days", "cookie_name" => "auto", "cookie_path" => "/", "cookie_host" => false, "user_session" => "userData", "default_user" => array( "username" => "Guest", "user_id" => 0, "password" => 0, "signed" => false ) ); var $validations = array( //Array for default field validations "username" => array( "limit" => "3-15", "regEx" => '/^([a-zA-Z0-9_])+$/' ), "password" => array( "limit" => "3-15", "regEx" => false ), "email" => array( "limit" => "4-35", "regEx" => '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/' ) ); var $encoder = array( "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z", 0,2,3,4,5,6,7,8,9 ); //Array of errors var $errorList = array( //Database Error while caling register functions 1 => "New User Registration Failed", //Database Error while calling update functions 2 => "The Changes Could not be made", //Database Error while calling activate function 3 => "Account could not be activated", //When calling pass_reset and the given email doesn't exist in database 4 => "We don't have an account with this email", //When calling new_pass, the confirmation hash did not match the one in database 5 => "Password could not be changed. The request can't be validated", 6 => "Logging with cookies failed", 7 => "No Username or Password provided", 8 => "Your Account has not been Activated. Check your Email for instructions", 9 => "Your account has been deactivated. Please contact Administrator", 10 => "Wrong Username or Password", //When calling check_hash with invalid hash 11 => "Confirmation hash is invalid", //Calling check_hash hash failed database match test 12 => "Your identification could not be confirmed", //When saving hash to database fails 13 => "Failed to save confirmation request", 14 => "You need to reset your password to login" ); /** EDITS BELOW THIS LINE WILL NOT BE KEPT WHEN UPDATING CLASS USING THE UPDATER SCRIPT **/ /** * Public function to initiate a login request at any time * * @access public * @param string $user username or email * @param string $pass password * @param bool|int $auto boolean to remember or not the user */ function login($user=false,$pass=false,$auto=false){ //reconstruct object self::__construct($user,$pass,$auto); } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Register A New User -Takes two parameters, the first being required @info = array object (takes an associatve array, the index being the fieldname(column in database) and the value its content(value) +optional second parameter @activation = boolean(true/false) default = false Returns activation hash if second parameter @activation is true Returns true if second parameter @activation is false Returns false on Error */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function register($info,$activation = false){ $this->logger("registration"); //Index for Errors and Reports //Saves Registration Data in Class $this->tmp_data = $info; //Validate All Fields if(!$this->validateAll()) return false; //There are validations error //Built in actions for special fields //Hash Password if(isset($info['password'])){ $this->hash_pass($info['password']); $info['password'] = $this->pass; } //Check for Email in database if(isset($info['email'])) if($this->check_field('email',$info['email'],"This Email is Already in Use")) return false; //Check for username in database if(isset($info['username'])) if($this->check_field('username',$info['username'], "This Username is not available")) return false; //Check for errors if($this->has_error()) return false; //Set Registration Date $info['reg_date'] = time(); //User Activation if(!$activation){ //Activates user upon registration $info['activated'] = 1; } //Prepare Info for SQL Insertion foreach($info as $index => $val){ if(!preg_match("/2$/",$index)){ //Skips double fields $into[] = $index; $values[] = "'".mysql_real_escape_string($val)."'"; } } $into = implode(", ",$into); $values = implode(",",$values); //Prepare New User Query $sql = "INSERT INTO {$this->opt['table_name']} ($into) VALUES($values)"; //exit($sql); //Enter New user to Database if($this->check_sql($sql)){ $this->report("New User \"{$info['username']}\" has been registered"); $this->id = mysql_insert_id(); if($activation){ //Insert Validation Hash $this->make_hash($this->id); $this->save_hash(); return $this->confirm; } return true; }else{ $this->error(1); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Similar to the register method function in structure This Method validates and updates any field in the database -Takes one parameter @info = array object (takes an associatve array, the index being the fieldname(column in database) and the value its content(value) On Success returns true On Failure return false */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function update($info){ $this->logger("update"); //Index for Errors and Reports //Saves Updates Data in Class $this->tmp_data = $info; //Validate All Fields if(!$this->validateAll()) return false; //There are validations error //Built in actions for special fields //Hash Password if(isset($info['password'])){ $this->hash_pass($info['password']); $info['password'] = $this->pass; } //Check for Email in database if(isset($info['email'])) if($this->check_field('email',$info['email'],"This Email is Already in Use")) return false; //Check for errors if($this->has_error()) return false; //Prepare Info for SQL Insertion foreach($info as $index => $val){ if(!preg_match("/2$/",$index)){ //Skips double fields $value = "'".mysql_real_escape_string($val)."'"; $set[] = "{$index}={$value}"; } } $set = implode(", ",$set); //Prepare User Update Query $sql = "UPDATE {$this->opt['table_name']} SET $set WHERE user_id='{$this->id}'"; //exit($sql); //Check for Changes if($this->check_sql($sql)){ $this->report("Information Updated"); $_SESSION['uFlex']['update'] = true; return true; }else{ $this->error(2); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Adds validation to queue for either the Registration or Update Method Single Entry: Requires the first two parameters @name = string (name of the field to be validated) @limit = string (range in the format of "5-10") *to make a field optional start with 0 (Ex. "0-10") Optional third paramenter @regEx = string (Regular Expresion to test the field) _____________________________________________________________________________________________________ Multiple Entry: Takes only the first argument @name = Array Object (takes an object in the following format: array( "username" => array( "limit" => "3-15", "regEx" => "/^([a-zA-Z0-9_])+$/" ), "password" => array( "limit" => "3-15", "regEx" => false ) ); */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function addValidation($name,$limit = "0-1",$regEx = false){ $this->logger("registration"); if(is_array($name)){ if(!is_array($this->validations)) $this->validations = array(); //If is not an array yet, make it one $new = array_merge($this->validations,$name); $this->validations = $new; $this->report("New Validation Object added"); }else{ $this->validations[$name]['limit'] = $limit; $this->validations[$name]['regEx'] = $regEx; $this->report("The $name field has been added for validation"); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Activates Account with hash Takes Only and Only the URL parameter of the confirmation page @hash = string Returns true on account activation and false on failure */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function activate($hash){ $this->logger("activation"); if(!$this->check_hash($hash)) return false; $sql = "UPDATE {$this->opt['table_name']} SET activated=1, confirmation='' WHERE confirmation='{$hash}' AND user_id='{$this->id}'"; if($this->check_sql($sql)){ $this->report("Account has been Activated"); return true; }else{ $this->error(3); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Method to reset password, Returns confirmation code to reset password -Takes one parameter and is required @email = string(user email to reset password) On Success it returns an array(email,username,user_id,hash) which could then be use to construct the confirmation URL and Email On Failure it returns false */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function pass_reset($email){ $this->logger("pass_reset"); $sql = "SELECT * FROM {$this->opt['table_name']} WHERE email='{$email}'"; $user = $this->getRow($sql); if($user){ if(!$user['activated'] and !$user['confirmation']){ //The Account has been manually disabled and can't reset password $this->error(9); return false; } $this->make_hash($user['user_id']); $this->id = $user['user_id']; $this->save_hash(); $data = array( "email" => $email, "username" => $user['username'], "user_id" => $user['user_id'], "hash" => $this->confirm ); return $data; }else{ $this->error(4); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Changes a Password with a Confirmation hash from the pass_reset method *this is for users that forget their passwords to change the signed user password use ->update() -Takes two parameters @hash = string (pass_reset method hash) @new = array (an array with indexes 'password' and 'password2') Example: array( [password] => pass123 [password2] => pass123 ) *use ->addValidation('password', ...) to validate password Returns true on a successful password change Returns false on error */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function new_pass($hash,$newPass){ $this->logger("new_pass"); if(!$this->check_hash($hash)) return false; $this->tmp_data = $newPass; if(!$this->validateAll()) return false; //There are validations error $pass = $this->hash_pass($newPass['password']); $sql = "UPDATE {$this->opt['table_name']} SET password='{$pass}', confirmation='', activated=1 WHERE confirmation='{$hash}' AND user_id='{$this->id}'"; if($this->check_sql($sql)){ $this->report("Password has been changed"); return true; }else{ //Error $this->error(5); return false; } } /*////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*\ ////////Private and Secondary Methods below this line\\\\\\\\\\\\\ \*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////////////////*/ /*Object Constructor*/ function __construct($user = false,$pass = false,$auto = false){ $this->logger("login"); //Index for Reports and Errors; if(!isset($_SESSION) and !headers_sent()){ session_start(); $this->report("Session is been started..."); }elseif(isset($_SESSION)){ $this->report("Session has already been started"); }else{ $this->error("Session could not be started"); return; //Finish Execution } $this->sid = session_id(); $result = $this->loginUser($user,$pass,$auto); if($result == false){ $this->session($this->opt['default_user']); $this->update_from_session(); $this->report("User is " + $this->username); }else{ if(!$auto and isset($_SESSION['uFlex']['remember'])){ unset($_SESSION['uFlex']['remember']); $this->setCookie(); } } return true; } /** * Private Login proccesor function * */ private function loginUser($user = false,$pass = false,$auto = false){ //Session Login if($this->session("signed")){ $this->report("User Is signed in from session"); $this->update_from_session(); if(isset($_SESSION['uFlex']['update'])){ $this->report("Updating Session from database"); //Get User From database because its info has change during current session $update = $this->getRow("SELECT * FROM {$this->opt['table_name']} WHERE user_id='{$this->id}'"); $this->update_session($update); $this->log_login(); //Update last_login } return true; } //Cookies Login if(isset($_COOKIE[$this->opt['cookie_name']]) and !$user and !$pass){ $c = $_COOKIE[$this->opt['cookie_name']]; $this->report("Attemping Login with cookies"); if($this->check_hash($c,true)){ $auto = true; $cond = "username='{$this->username}'"; }else{ $this->error(6); $this->logout(); return false; } }else{ //Credentials Login if($user && $pass){ if(preg_match($this->validations['email']['regEx'],$user)){ //Login using email $cond = "email='{$user}'"; }else{ //Login using username $cond = "username='{$user}'"; } $this->hash_pass($pass); $this->report("Credentials received"); }else{ $this->error(7); return false; } } $this->report("Querying Database to authenticate user"); //Query Database and check login $sql = "SELECT * FROM {$this->opt['table_name']} WHERE {$cond} AND password='{$this->pass}'"; $userFile = $this->getRow($sql); if($userFile){ //If Account is not Activated if($userFile['activated'] == 0){ if($userFile['last_login'] == 0){ //Account has not been activated $this->error(8); }else if(!$userFile['confirmation']){ //Account has been deactivated $this->error(9); }else{ //Account deativated due to a password reset or reactivation request $this->error(14); } return false; } //Account is Activated and user is logged in $this->update_session($userFile); //If auto Remember User if($auto){ $this->setCookie(); } $this->log_login(); //Update last_login //Done $this->report("User Logged in Successfully"); return true; }else{ if(isset($_COOKIE[$this->opt['cookie_name']])){ $this->logout(); } $this->error(10); return false; } } function logout(){ $this->logger("login"); $deleted = setcookie($this->opt['cookie_name'],"",time() - 3600,"/"); //Deletes the Auto Coookie $this->signed = 0; //Import default user object $this->data = $_SESSION[$this->opt['user_session']] = $this->opt['default_user']; if(!$deleted){ $this->report("The Autologin cookie could not be deleted"); } $this->report("User Logged out"); } private function log_login(){ //Update last_login $time = time(); $sql = "UPDATE {$this->opt['table_name']} SET last_login='{$time}' WHERE user_id='{$this->id}'"; if($this->check_sql($sql)) $this->report("Last Login updated"); } function setCookie(){ if($this->pass and $this->id){ $code = $this->make_hash($this->id,$this->pass); if(!headers_sent()){ //echo "PHP"; setcookie($this->opt['cookie_name'],$code,strtotime($this->opt['cookie_time']), $this->opt['cookie_path'],$this->opt['cookie_host']); }else{ //Headers have been sent use JavaScript to set cookie $time = intval($this->opt['cookie_time']); echo "<script>"; echo ' function setCookie(c_name,value,expiredays){ var exdate=new Date(); exdate.setDate(exdate.getDate()+expiredays); document.cookie=c_name+ "=" +escape(value)+((expiredays==null) ? "" : "; expires="+exdate.toUTCString()); path=escape("'. $this->opt["cookie_path"].'"); } '; echo "setCookie('{$this->opt['cookie_name']}','{$code}',{$time})"; echo "</script>"; } $this->report("Cookies have been updated for auto login"); }else{ $this->error("Info required to set the cookie {$this->opt['cookie_name']} is not available"); } } private function session($index=false, $val=false){ if(is_string($index) and !$val){ return @$_SESSION[$this->opt['user_session']][$index]; } if(is_string($index) and $val){ $_SESSION[$this->opt['user_session']][$index] = $val; return; } if(is_array($index) and !$val){ $_SESSION[$this->opt['user_session']] = $index; return; } //return full session user data return $_SESSION[$this->opt['user_session']]; } private function update_session($d){ unset($_SESSION['uFlex']['update']); $this->session($d); $this->session("signed",1); $this->report("Session updated"); $this->update_from_session(); } private function update_from_session(){ $d = $this->session(); $this->id = $d['user_id']; $this->data = $d; $this->username = $d['username']; $this->pass = $d['password']; $this->signed = $d['signed']; $this->report("Session has been imported to the object"); } function hash_pass($pass){ $salt = uFlex::salt; $this->pass = md5($salt.$pass.$salt); return $this->pass; } function logger($log){ $this->log = $log; unset($this->console['errors'][$log]); unset($this->console['form'][$log]); $this->report(">>Startting new $log request"); } function report($str = false){ $index = $this->log; if($str){ $str = ucfirst($str); $this->console['reports'][$index][] = $str; //Strore Report }else{ if($index){ return $this->console['reports'][$index]; //Return the $index Reports Array }else{ return $this->console['reports']; //Return the Full Reports Array } } } function error($str = false){ $index = $this->log; if($str){ $err = is_int($str) ? $this->errorList[$str] : $str; $this->console['errors'][$index][] = $err; //Store Error if(is_int($str)){ $this->report("Error[{$str}]: {$err}"); //Report The error }else{ $this->report("Error: {$str}"); //Report The error } }else{ if($index){ if(!isset($this->console['errors'][$index])) return false; return $this->console['errors'][$index]; //Return the $index Errors Array }else{ return $this->console['errors']; //Return the Full Error Array } } } //Adds fields with errors to the console function form_error($field = false,$error = false){ $index = $this->log; if($field){ if($error){ $this->console['form'][$index][$field] = $error; $this->error($error); }else{ $this->console['form'][$index][] = $field; } }else{ if($index){ if(!isset($this->console['form'][$index])) return false; return $this->console['form'][$index]; //Return the $index Errors Array }else{ return $this->console['form']; //Return the Full form Array } } } //Check for errors in the console function has_error($index = false){ //Check for errors $index = $index?$index:$this->log; $count = @count($this->console['errors'][$index]); if($count){ $this->report("$count Error(s) Found!"); return true; }else{ $this->report("No Error Found!"); return false; } } //Generates a unique comfirm hash function make_hash($uid,$hash = false){ $e_uid = $this->encode($uid); $e_uid_length = strlen($e_uid); $e_uid_length = str_pad($e_uid_length,2,0,STR_PAD_LEFT); $e_uid_pos = rand(10,32 - $e_uid_length - 1); if(!$hash){ $hash = md5(uniqid(rand(),true)); } //$code = substr($code, 0, $length); $code = $e_uid_pos.$e_uid_length; $code .= substr($hash,0,$e_uid_pos - strlen($code)); $code .= $e_uid; $code .= substr($hash,strlen($code)); $this->confirm = $code; return $code; } //Validates a confirmation hash function check_hash($hash,$bypass = false){ if(strlen($hash) != 32 || !preg_match("/^[0-9]{4}/",$hash)){ $this->error(11); return; } $e_uid_pos = substr($hash,0,2); $e_uid_length = substr($hash,2,2); $e_uid = substr($hash,$e_uid_pos,$e_uid_length); $uid = $this->decode($e_uid); $sql = "SELECT * FROM {$this->opt['table_name']} WHERE user_id={$uid} AND confirmation='{$hash}'"; //Bypass hash confirmation and get the user by partially matching its password if($bypass){ preg_match("/^([0-9]{4})(.{2,".($e_uid_pos - 4)."})(".$e_uid.")/",$hash,$exerpt); $pass = $exerpt[2]; $sql = "SELECT * FROM {$this->opt['table_name']} WHERE user_id={$uid} AND password LIKE '{$pass}%'"; } $result = $this->getRow($sql); if(!$result){ $this->report("The user ID and the confirmation hash did not match"); $this->error(12); return false; } if($this->signed and $this->id == $result['user_id']){ $this->logout(); } //Hash is valid import user's info to object $this->data = $result; $this->id = $result['user_id']; $this->username = $result['username']; $this->pass = $result['password']; $this->report("Hash successfully validated"); return true; } //Saves the confirmation hash in the database function save_hash(){ if($this->confirm and $this->id){ $sql = "UPDATE {$this->opt['table_name']} SET confirmation='{$this->confirm}', activated=0 WHERE user_id='{$this->id}'"; if(!$this->check_sql($sql)){ $this->error(13); return false; }else{ $this->report("Confirmation hash has been saved"); } }else{ $this->report("Can't save Confirmation hash"); return false; } return true; } //Test field in database for a value function check_field($field,$val,$err = false){ $query = mysql_query("SELECT {$field} FROM {$this->opt['table_name']} WHERE {$field}='{$val}' "); if(mysql_num_rows($query) >= 1){ if($err){ $this->form_error($field,$err); }else{ $this->form_error($field,"The $field $val exists in database"); } $this->report("There was a match for $field = $val"); return true; }else{ $this->report("No Match for $field = $val"); return false; } } //Executes SQL query and checks for success function check_sql($sql,$debug = false){ $this->report("SQL: {$sql}"); //Log the SQL Query if(!mysql_query($sql)){ if(self::debug){ $this->error(mysql_error()); } return false; }else{ $rows = mysql_affected_rows(); if($rows > 0){ //Good, Rows where affected $this->report("$rows row(s) where Affected"); return true; }else{ //Bad, No Rows where Affected $this->report("No rows were Affected"); return false; } } } //Executes SQL query and returns an associate array of results function getRow($sql){ $this->report("SQL: {$sql}"); //Log the SQL Query first $query = mysql_query($sql); if(mysql_error() and self::debug){ $this->error(mysql_error()); } if(@mysql_num_rows($query)){ while($row = mysql_fetch_array($query,MYSQL_ASSOC)){ $rows[] = $row; } }else{ $this->report("Query returned empty"); return false; } return $rows[0]; } //Validates All fields in ->tmp_data array private function validateAll(){ $info = $this->tmp_data; foreach($info as $field => $val){ //Match double fields if(isset($info[$field.(2)])){ if($val != $info[$field.(2)]){ $this->form_error($field, ucfirst($field) . "s did not match"); //return false; }else{ $this->report(ucfirst($field) . "s matched"); } } $this->tmp_data[$field] = trim($val); //Trim white spaces at end and start //Validate field if(!isset($this->validations[$field])) continue; $opt = $this->validations[$field]; $this->validate($field,$opt['limit'],$opt['regEx']); } return $this->has_error() ? false : true; } //Validates field($name) in tmp_data private function validate($name,$limit,$regEx = false){ $Name = ucfirst($name); $str = $this->tmp_data[$name]; $l = explode("-",$limit); $min = intval($l[0]); $max = intval($l[1]); if(!$max and !$min){ $this->error("Invalid second paramater for the $name validation"); return false; } if(!$str){ if(!isset($this->tmp_data[$name])){ $this->report("missing index $name from the POST array"); } if(strlen($str) == $min){ $this->report("$Name is blank and optional - skipped"); return true; } $this->form_error($name,"$Name is required."); return false; } if(strlen($str) > $max){ $this->form_error($name,"The $Name is larger than $max characters."); return false; } if(strlen($str) < $min){ $this->form_error($name,"The $Name is too short. it should at least be $min characters long"); return false; } if($regEx){ preg_match_all($regEx,$str,$match); if(count($match[0]) != 1){ $this->form_error($name,"The $Name \"{$str}\" is not valid"); return false; } } $this->report("The $name is Valid"); return true; } //Encoder function encode($d){ $k=$this->encoder;preg_match_all("/[1-9][0-9]|[0-9]/",$d,$a);$n="";$o=count($k);foreach($a[0]as$i){if($i<$o){ $n.=$k[$i];}else{$n.="1".$k[$i-$o];}} return $n; } //Decoder function decode($d){ $k=$this->encoder;preg_match_all("/[1][a-zA-Z]|[2-9]|[a-zA-Z]|[0]/",$d,$a);$n="";$o=count($k);foreach($a[0]as$i){ $f=preg_match("/1([a-zA-Z])/",$i,$v);if($f==true){ $i=$o+array_search($v[1],$k);}else{$i=array_search($i,$k);}$n.=$i;} return $n; } } ?>
Revision: 26384
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at April 26, 2010 16:45 by ptejada
Initial Code
<?php // --------------------------------------------------------------------------- // uFlex - An all in one authentication system PHP class // Copyright (C) 2010 Pablo Tejada // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.html. // --------------------------------------------------------------------------- // V 0.10 - Last modified 4/26/2010 // +Registration Method // -Custome and Built-in fields validation // -Extendable: add as many fields and validation as required // -Built-in Redundancy check for email and username // -Built-in account activation by email // +Update Method to update anyfield on database // -Built-in Redundancy check for email // -Custome and Built-in fields validation // +Automatic user session handler // -Remember user with cookies // -Handles sessions on new object // +Class wide console // -track and log Errors // -Report every steps for each method // -log validations, connection, SQL queries etc... // --------------------------------------------------------------------------- /*Thought the Class Official name is userFlex the object is simply named uFlex*/ class uFlex{ var $salt = "sd5a4"; //IMPORTANT: Please change this value as it will make this copy unique and secured var $id; var $username; var $pass; var $signed; var $data; var $console; var $log; var $confirm; var $tmp_data; var $validations; /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Register A New User -Takes two parameter the firs been required @info = array object (takes an associatve array, the index being the fieldname(column in database) and the value its content(value) +optional second parameter @activation = boolean(true/false) default = false Returns activation hash if second parameter @activation is true Returns true if second parameter @activation is false Returns false on Error */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function register($info,$activation=false){ $this->log = "registration"; //Index for Errors and Reports //Saves Registration Data in Class $this->tmp_data = $info; //Validate Fields Submited Fields $validation = array( "username" => array( "limit" => "3-15", "regEx" => "/^([a-zA-Z0-9_])+$/" ), "password" => array( "limit" => "3-15", "regEx" => false ), "email" => array( "limit" => "4-45", "regEx" => "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/", "optional" => true ) ); //Add Built in Validation to the Array $this->addValidation($validation); //Validate All Fields in the validations array foreach($this->validations as $field=>$opt){ $this->validate($field,$opt['limit'],$opt['regEx']); } //Check for errors if($this->has_error()) return false; //Built in actions for special fields //Hash Password if(isset($info['password'])){ $this->hash_pass($info['password']); $info['password'] = $this->pass; } //Check for Email in database if(isset($info['email'])){ if($this->check_field('email',$info['email'],"This Email is Already in Use")){ $this->form_error('email'); } } //Check for username in database if(isset($info['username'])){ if($this->check_field('username',$info['username'],"This Username is not available")){ $this->form_error('username'); } } //Check for errors if($this->has_error()) return false; //Updates $Info, add defaults, and clean left overs $info['password'] = $this->pass; $info['confirmation'] = $this->confirm; $info['reg_date'] = time(); //Generates the Confirmation Code $this->uConfirm(); //Activates user upon registration if there is not an activation method if(!$activation){ $info['activated'] = 1; } //Prepare Info for SQL Insertion foreach($info as $index => $val){ if(!preg_match("/2$/",$index)){ //Skips double fields $into[] = $index; $values[] = "'" . mysql_real_escape_string($val) . "'"; } } $into = implode(", ",$into); $values = implode(",",$values); //Prepare New User Query $sql = "INSERT INTO users ($into) VALUES($values)"; //exit($sql); //Enter New user to Database if($this->check_sql($sql,true) ){ $this->report("New User \"{$info['username']}\" has been registered"); if($activation) return "{$this->confirm}:{$this->tmp_data['username']}"; return true; }else{ $this->error("New User Registration Failed"); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Similar to the register method function in structure This Method validates and updates any field in the database -Takes one parameter @info = array object (takes an associatve array, the index being the fieldname(column in database) and the value its content(value) On Success returns true On Failure return false */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function update($info){ $this->log = "update"; //Index for Errors and Reports //Saves Updates Data in Class $this->tmp_data = $info; //Check if there have being Changes foreach($info as $index=>$val){ if($this->data[$index] == $val){ $this->error("{$index} is the same. no changes were made"); return false; }elseif(isset($info[$index.(2)])){ //Check for equal fields if($info[$index] != $info[$index.(2)]){ $this->error("{$index}s did not match"); return false; }else{ $this->report("{$index}s match"); } } } //Defaults or Built in Validations $validation = array( "username" => array( "limit" => "3-15", "regEx" => "/^([a-zA-Z0-9_])+$/" ), "password" => array( "limit" => "3-15", "regEx" => false ), "email" => array( "limit" => "4-45", "regEx" => "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/", "optional" => true ) ); //Add Built in Validation to the quene $this->addValidation($validation); //Validate All Fields in the info array with the validation array foreach($this->validations as $field=>$opt){ if(isset($info[$field])){ $this->validate($field,$opt['limit'],$opt['regEx']); } } //Check for errors if($this->has_error()) return false; //Built in actions for special fields //Hash Password if(isset($info['password'])){ $this->hash_pass($info['password']); $info['password'] = $this->pass; } //Check for Email in database if(isset($info['email'])){ if($this->check_field('email',$info['email'],"This Email is Already in Use")){ $this->form_error('email'); } } //Check for errors if($this->has_error()) return false; //Prepare Info for SQL Insertion foreach($info as $index => $val){ if(!preg_match("/2$/",$index)){ //Skips double fields $value = "'".mysql_real_escape_string($val)."'"; $set[] = "{$index}={$value}"; } } $set = implode(", ",$set); //Prepare User Update Query $sql = "UPDATE users SET $set WHERE user_id='{$this->id}'"; //exit($sql); //Check for Changes if($this->check_sql_change($sql,true) ){ $this->report("Information Updated"); $_SESSION['updated'] = true; return true; }else{ $this->error("The Changes Could not be made"); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Adds validation to quene list for either the Registration or Update Method Single Entry: Requires the first two parameters @name = string (name of the field to be validated) @limit = string (range in the format of "5-10") *to make a field optional start with 0 (Ex. "0-10") Optional third paramenter @regEx = string (Regular Expresion to test the field) Multiple Entry: Takes only the first argument @name = Array Object (takes an object in the following format: array( "username" => array( "limit" => "3-15", "regEx" => "/^([a-zA-Z0-9_])+$/" ), "password" => array( "limit" => "3-15", "regEx" => false ) ); */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function addValidation($name,$limit=false,$regEx=false){ $this->log = "registration"; if(is_array($name)){ if(!is_array($this->validations)) $this->validations = array(); //If is not an array yet, make it one $new = array_merge($this->validations,$name); $this->validations = $new; $this->report("New Validation Object added"); }else{ $this->validations[$name]['limit'] = $limit; $this->validations[$name]['regEx'] = $regEx; $this->report("The $name field has been added for validation"); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Activates Account with hash Takes Only and Only the URL c parameter of the comfirmation page @hash = string Returns true on account activation and false on failure */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function activate($hash){ $d = explode(":",$hash); $this->confirm = $d[0]; $this->username = $d[1]; $sql = "UPDATE users SET activated=1 WHERE confirmation='{$d[0]}' AND username='{$d[1]}'"; if($this->check_sql_change($sql,true)){ $this->report("Account has been Activated"); return true; }else{ $this->error("Account could not be activated"); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Method to reset password, sents an email with a confirmation code to reset password -Takes one parameter and is required @email = string(user email to reset password) On Success it returns a hash which could then be use to construct the confimration URL On Failure it returns false */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function pass_reset($email){ $this->log = "pass_reset"; $this->uConfirm(); $sql = "SELECT username,user_id FROM users WHERE email='{$email}'"; $this-> $query = mysql_query($sql); if(!$query){ $this->error(mysql_error()); return false; } $row = mysql_fetch_assoc($query); if(count($row) > 1){ //Send Email $code = $this->confirm.":{$row['user_id']}"; return $code; }else{ $this->error("We don't have an account with this email"); return false; } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /* Reset a Password with a Confirmation hash from the pass_reset method -Takes two parameters @hash = string (pass_reset method hash) @new = string (New password) *Make sure to validate and comfirm new password in javascript for now Returns true on a successfull password change Returns false on error */ /////////////////////////////////////////////////////////////////////////////////////////////////////// function new_pass($hash,$new){ $d = explode(":",$hash); $this->confirm = $d[0]; $this->id = $d[1]; $pass = $this->hash_pass($new); $sql = "UPDATE users SET password='{$pass}' WHERE confirmation='{$d[0]}' AND user_id='{$d[1]}'"; if($this->check_sql($sql,true)){ $this->report("Your Password has been Changed"); return true; }else{ $this->error("Password could not be changed"); return false; } } ////////Private and Secondary Methods below this line\\\\\\\\\\\\\ /*Star up function*/ function uFlex($user=false,$pass=false,$auto=false){ $this->log = "login"; //Index for Reports and Errors; session_start(); //$this->username = $user; //$this->pass = $pass; $result = $this->login($user,$pass,$auto); if($result == false){ $this->id = 0; $this->username = "Guess"; $this->pass = ""; $this->signed = false; $_SESSION = array("username" => "Guess", "user_id" => 0, "signed" => false ); $this->report("User is Guess"); }else{ } return true; } private function login($user=false,$pass=false,$auto=false){ $this->log = "login"; //Index for Reports and Errors; //Session Login if(@$_SESSION['signed']){ $this->report("User Is signed in from session"); $this->update_from_session(); if(isset($this->data['updated'])){ //Get User From database because its info has change during current session $update = mysql_fetch_assoc(mysql_query("SELECT * FROM users WHERE user_id='{$this->id}'")); $this->update_session($update); unset($_SESSION['updated']); $this->report("Session Updated From Database"); } return true; } if(isset($_COOKIE['auto'])){ //Cookies Login $c = $_COOKIE['auto']; $c = explode(":",$c); //passHash:id => asd5453asf54a:52 //if($c[1] != 1){ return false; $this->report("No auto Login"); } //No AutoLogin set return false $this->id = $c[1]; $this->pass = $c[0]; $auto = true; $this->report("Attemping Login with cookies"); }else{ //Credetials Login if(!$user == false && !$pass == false){ $this->username = $user; $this->hash_pass($pass); $this->report("Creadentials recieved"); }else{ $this->error("No Username or Password provided"); return false; } } $this->report("I got info Quering Database to autenticate user"); //Query Database and check login $query = mysql_query("SELECT * FROM users WHERE user_id='{$this->id}' OR username='{$this->username}' AND password='{$this->pass}'"); if(mysql_num_rows($query) == 1){ $this->data = mysql_fetch_assoc($query); $d = $this->data; //If Account is not Activated if($d['activated'] != 1){ if($d['last_login'] == 0){ //Account has not been activated $this->error("Your Account has not been Activated. Check your Email for instructions"); }else{ //Account has been deactivated $this->error("Your account has been deactivated. Please contact Administrator"); } return false; } //Account is Activated and user is logged in $this->update_session($d); //If auto Remember User if($auto){ $this->setCookie(); } //Update last_login $time = time(); $sql = "UPDATE users SET last_login='{$time}' WHERE user_id='{$this->id}'"; $this->check_sql($sql,true); //Done $this->report("User Logged in Successfully"); return true; }else{ $this->error("Wrong Username or Password"); return false; } } function logout(){ $this->log = "login"; setcookie("auto", "", time()-3600,"/",".".$_SERVER['HTTP_HOST']); //Deletes the Auto Coookie session_unset(); $this->report("User Logged out"); } private function setCookie(){ $value = $this->pass; $value .= ":"; $value .= $this->id; setcookie("auto",$value,strtotime("+15 days"),"/",".".$_SERVER['HTTP_HOST']); $this->report("Cookies have been updated for auto login"); } function update_session($d){ $_SESSION = $d; $_SESSION['signed'] = true; $this->id = $d['user_id']; $this->username = $d['username']; $this->pass = $d['password']; $this->signed = true; $this->report("session updated"); } function update_from_session(){ $d = $_SESSION; $this->id = $d['user_id']; $this->data = $d; $this->username = $d['username']; $this->pass = $d['password']; $this->signed = true; } function hash_pass($pass){ $salt = $this->salt; $this->pass = md5($salt.$pass.$salt); return $this->pass; } function report($str=false){ $index = $this->log; if($str){ $str = ucfirst($str); $this->console['reports'][$index][] = $str; //Strore Report }else{ if($index){ return $this->console['reports'][$index]; //Return the $index Reports Array }else{ return $this->console['reports']; //Return the Full Reports Array } } } function error($str=false){ $index = $this->log; if($str){ $str = ucfirst($str); //Style String by making first character uppercase $this->console['errors'][$index][] = $str; //Strore Error $this->report("Error: {$str}"); //Report The error }else{ if($index){ return $this->console['errors'][$index]; //Return the $index Errors Array }else{ return $this->console['errors']; //Return the Full Error Array } } } //Adds fields with errors to the console function form_error($field=false){ $index = $this->log; if($field){ $this->console['form'][$index][] = $field; }else{ if($index){ return $this->console['form'][$index]; //Return the $index Errors Array }else{ return $this->console['form']; //Return the Full form Array } } } //Check for errors in the console function has_error(){ //Check for errors if($this->console['errors'][$this->log] != ""){ $count = count($this->console['errors'][$this->log]); $this->report("$count Error(s) Found!"); return true; }else{ $this->report("No Error Found!"); return false; } } //Generates a unique comfirm hash function uConfirm($length = false){ $code = md5(uniqid(rand(), true)); if($length != false){ $this->confirm = substr($code, 0, $length); }else{ $this->confirm = $code; } } //Test field in database for a value function check_field($field, $val, $str=false){ $query = mysql_query("SELECT {$field} FROM users WHERE {$field}='{$val}' "); if(mysql_num_rows($query) >= 1){ if($str){ $this->error($str); }else{ $this->error("There was a match for $field = $val"); } return true; }else{ $this->report("No Match on Field $field=$val"); return false; } } //Executes SQL query and checks for success function check_sql($sql,$debug = false){ $this->report("SQL: {$sql}"); //Log the SQL Query first if (!mysql_query($sql)){ if($debug){ $this->error(mysql_error()); } return false; }else{ return true; } } //Executes SQL query and expects a change in database function check_sql_change($sql,$debug = false){ $this->report("SQL: {$sql}"); //Log the SQL Query if (!mysql_query($sql)){ if($debug){ $this->error(mysql_error()); return false; //die('Error: ' . mysql_error()); }else{ return false; } }else{ $rows = mysql_affected_rows(); if($rows > 0){ //Good, Rows where affected $this->report("$rows row(s) where Affected"); return true; }else{ //Bad, No Rows where Affected $this->report("No row was Affected"); return false; } } } //Validates field($name) in tmp_data private function validate($name,$limit,$regEx=false){ $str = $this->tmp_data[$name]; $l = explode("-",$limit); $min = intval($l[0]); $max = intval($l[1]); if(!$max || !$min){ $this->report("Invalid second paramater for the private validate method on $name"); return false; } if(!$str){ if(!isset($this->tmp_data[$name])){ $this->error("missing index $name from the POST array"); } if(strlen($str) == $min){ $this->report("$name is blank and optional - skipped"); return true; } $this->error("$name is required"); $this->form_error($name); return false; } if(strlen($str) > $max){ $this->error("The $name is larger than $max character/digits"); $this->form_error($name); return false; } if(strlen($str) < $min){ $this->error("The $name is too short. it should at least be $min character/digits long"); $this->form_error($name); return false; } if($regEx){ preg_match_all($regEx,$str,$match); //print_r($match);echo count($match[0])."+"; if(count($match[0]) != 1){ $this->error("The $name \"{$str}\" is not valid"); $this->form_error($name); return false; } } $this->report("The $name is Valid"); return true; } } ?>
Initial URL
http://crusthq.com/projects/uflex/
Initial Description
uFlex or userFlex is an all in one PHP user class that provides developers with a simple yet secured, reliable and flexible framework like structure to authenticate their sites and applications. The purpose of uFlex is to handle the tedious processes involved in authenticating users.
Initial Title
All in one PHP user class - uFlex
Initial Tags
class, user
Initial Language
PHP