Finally I have got this function to work. It does its job but it looks real messy, just wanna hear your thoughts and maybe theirs something I could improve?
Thanks alot!
Login
$result = mysql_query("SELECT * FROM users WHERE username = '".mysql_real_escape_string($_POST['username'])."' AND password = '".md5($_POST['password'])."'");
$row = mysql_fetch_object($result);
if (mysql_num_rows($result) == 0) {
exit('Bad Login');
}
$_SESSION['id'] = mysql_result($result, 0, 'id');
# The user wants to be remembered
if (isset($_POST['remember'])) {
$key = md5(uniqid());
setcookie('remember', $key, time()+900000); /* expire in 10 days */
mysql_query("UPDATE users SET sessionkey = '$key' WHERE id = ".mysql_result($result, 0, 'id'));
}
And on each page I check:
if (isset($_SESSION['id'])) {
header("Location: welcome.php");
}
elseif (isset($_COOKIE['remember'])) {
$rs = mysql_query("SELECT * FROM users WHERE sessionkey = '$_COOKIE[remember]'");
if (mysql_num_rows($rs) == 1) {
$_SESSION['id'] = 1;
header("Location: welcome.php");
}
}
Put the code that checks if the number of rows is zero before the mysql_fetch_object($result) statement. That way, you don't waste that extra CPU cycle if the user doesn't exist.
Change this (in both places):
mysql_result($result, 0, 'id');
to
$row->id;
Also, if your id column isn't sanitary (i.e.: the user has entered some data for it at some point), you're going to want to escape it in your UPDATE query.
Just a matter of preference on this one, but when I check URL parameters existance, I like to use !empty() instead of isset. The reason is that if the parameter is set but empty, it will still return false:
!empty($_POST['remember'])
Also on that note, be sure to sanitize $_COOKIE['remember']. Cookie values can be changed by the user.
mysql_query("SELECT * FROM users WHERE sessionkey = '" . mysql_real_escape_string($_COOKIE[remember]) . "'");
Lastly, it might be a good idea not to select * in your query, as this can bump you up against a performance wall later on in your app. Consider just selecting, say, the ID of the user:
mysql_query("SELECT id FROM users ...
Everything else looks pretty good!
I'm no PHP expert, but there's probably an off-the-shelf solution for session management - I would suggest using it over rolling your own.
Related
so i'm having trouble and i really have no idea why i'm having this issue because all looks well. But basically i'm trying create multiple user levels for a web page i'm making. For some reason only the regular user role is working at the moment. Basically I want admins to be led to a different user interface. If anyone knows any good content on how to make certain pages only available when a session is started that would be very helpful because that would be my next step after I solve this, also how to create a difference in regular user sessions and admin sessions if that makes sence... But back to my real problem, please tell me why admins arent being led to my admin.php page.. I'm posting the code below.
<?php
session_start();
include 'db.php';
mysqli_select_db($conn, 'users');
$user = $_POST ['user'];
$pass = $_POST ['pass'];
$reg = '0';
$admin = '1';
$hashedpassword = password_hash ($pass, PASSWORD_DEFAULT);
//this query is for admin users **dont forget to change active to 1 within
db
$qa = "select * from users where username ='$user' and active = '0' and admin = '$admin'";
//this query is for regular users
$q = "select * from users where username ='$user' and active = '0' and admin
= '$reg'";
//these will run the querys above (a = admin)
$resulta = mysqli_query($conn, $qa);
$result = mysqli_query($conn, $q);
//will count rows and verify admin users
$numa = mysqli_num_rows($resulta);
$rowa = mysqli_fetch_array($resulta, MYSQLI_ASSOC);
//will count rows and verify regular users
$num = mysqli_num_rows($result);
$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
if(password_verify($pass,$row['password']))
{
if ($num == 1) {
$_SESSION['username'] = $user;
header('location:index.php');
}
else if (password_verify($pass,$rowa['password']))
{
if ($numa == 1) {
$_SESSION['username'] = $user;
header('location:admin.php');
}
}
}
echo mysqli_error($conn);
?>
your code seems a little confusing to me, so I've sampled it down, instead of running two different queries, why not just one.
Look at this code below, this will help you transfer to admin page when admin logs in, and redirects you to regular page in case of all others.
All I am doing is checking the row value, instead of checking the count again.
<?php
session_start();
include 'db.php';
mysqli_select_db($conn, 'users');
$user=mysqli_real_escape_string($conn,$_POST['username']);
$pass=mysqli_real_escape_string($conn,$_POST['password']);
$hashedpassword = password_hash ($pass, PASSWORD_DEFAULT);
$sql="select * from users where username ='$user' and active = '0'";
$result=mysqli_query($conn,$sql);
$row=mysqli_fetch_array($result, MYSQLI_ASSOC);
if(password_verify($mypassword, $row["pass"])) {
$_SESSION['username']=$user;
if($row["admin"] == "1")
header("location: admin.php");
else if($row["admin"]=="0")
header("location: index.php");
}
else
echo mysqli_error($conn);
?>
Hey guys ive put together a basic user log in for a secure admin area and it seems to work great, if you enter a correct user/pass you get access, if you enter the wrong user pass, you get no access. However if you enter nothing in both fields you get access.
This is how it works.
Creating a user, a basic form POSTS to this php file.
<?php
$con = mysqli_connect(credentials are all good) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$some_str = md5(uniqid(mt_rand(), true));
$base_64str = base64_encode($some_str);
$modified_base64 = str_replace('+', '.', $base_64str);
$gensalt = substr($modified_base64, 0, 22);
$format_str = "$2y$10$"; // 2y for Blowfish and 10 times.
$salt = $format_str . $gensalt . "$";
$hashed_pass = crypt($escapedPass, $salt);
$query = "INSERT INTO `userpass` (`username`, `password`, `salt`) VALUES ('$escapedUser', '$hashed_pass', '$salt'); ";
if(isset($escapedUser) && isset($hashed_pass))
{
mysqli_query($con, $query);
header("Location: ausers.php");
exit();
}
Echo "Something went wrong!";
?>
The database appears to be storing these fine
We then log in with this code
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$saltQuery = "select salt from userpass where username = '$escapedUser';";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
if(isset($escapedUser) && isset($hashed_pass))
{
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
}
header("Location: alogin.htm");
exit();
}
Echo "Something went wrong!";
?>
So as i said, this seems to work fine for when any user pass combination is given whether access granted or denied however using no user and pass and pressing log in allows entry. Any ideas? THeres no blank rows in the database table.
Side question, is this salt/hash method correct, its my first attempt.
For your login code, your condition relies on an isset() test. You perform this test on $escapedUser and $hashed_pass. Both of these variables were actually assigned values earlier in the code! Once you assign a value to the variable, it will pass the isset() test, even if the value is an empty string. You might want to use an empty() check, perhaps on the original $_POST variables.
Moving on to the inner condition, which tests if the mysql query returns exactly 1 row of results. If there were truly no rows with empty values, then this condition would never pass because the query would return 0 rows. But it is passing. Two things to consider:
Notice that your registering code uses the same isset() test. Therefore it is very possible that someone used your registration form, submitted empty fields, and successfully registered a row with empty user and password fields. Have you explicitly queried your database for empty fields and actually come up with 0 results?
Your query uses SELECT *. Perhaps this is causing the query to return some sort of aggregate value (like a COUNT() or something that always has a result no matter what). Perhaps try explicitly defining the columns to return?
I cannot comment on your salt/hash method as I have no experience in that part. Hope you find this helpful!
In my opinion you need more than one level of checks in any form, whether it be registration, comments, login, etc. The way I prefer to go about it is a tiered approach. It may work better for you, but it's just an example.
By doing it this way, you ensure that your input will never be empty. Another issue I see with your login script is that you never compare the input with the database so how can you know if they entered the correct information? The only thing allowing them to login is that the query returned a record. This is also why they can login with a blank form.
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
/* Ensures that form was submitted before any processing is done */
if (isset($_POST)) {
$User = $_POST['user']);
$Pass = $_POST['pass']);
if (!empty($User)) {
if (!empty($Pass)) {
$escapedUser = mysqli_real_escape_string($con, $User);
$escapedPass = mysqli_real_escape_string($con, $Pass);
/* you need to verify the password here, before adding the salt */
$saltQuery = "select salt from userpass where username = '$escapedUser'";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
/* you need to verify the username somewhere here */
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
} else {
header("Location: alogin.htm");
exit();
}
} else {
echo "Please enter a password.";
}
} else {
echo "Please enter a username.";
}
} else {
echo "You have not entered any information.";
}
?>
I'm probably not using the best method to create a user system, but it doesn't need to be fancy. I also know that I'm not the most organized
The logins and everything are alright, but I'm having a problem updating the credentials.
For example, I'm allowing users to change their username. I have the "Change Username" (Not that name) form to submit to update-username.php.
I already have mysql_real_escape_string, in the function "cleanString" in another page. My textarea submitting already has the old text in it, so you can change and view it before hand.
$user_id = "";
if(isset($_POST['id']))
{
$user_id = $_POST['id'];
}
$query = "SELECT username,email,display_name,access,password FROM users WHERE user_id='$user_id'";
$results = mysql_query($query);
if(!$results) { //Check to see if query failed
die(mysql_error());
}
$resultsfetch=mysql_fetch_array($results);
$username = $resultsfetch['username'];
$usernamenew = $_POST['usernameinput'];
if(isset($_POST['usernameinput'])) {
$usernamenew = cleanString($_POST['usernameinput']);
}
if($usernamenew !=$username){
$submit = "UPDATE users SET username = '$usernamenew' WHERE user_id = '$user_id'";
mysql_query($submit);
if(!$submit) { //Check to see if query failed
die(mysql_error());
}
}
It's probably something stupid or simple that I missed, or something really huge. Mainly because I am absent minded.
$submit = sprintf("UPDATE users SET username = '%s' WHERE user_id = %d",mysql_real_escape_string($usernamenew),mysql_real_escape_string($user_id));
If the page is loaded, $user_id will be NULL so noting will be updated! Make sure that this page loads, by sending $_POST['id'] . if these things are correct, check this.
"Did the database user have any permission to update the table? "
I have re-arranged your code. added comments where i changed. Try this
if (isset($_POST['id'], $_POST['usernameinput'])) { // Check if both POST id and usernameinput is available
$user_id = (int)$_POST['id']; //assuming this is an integer
$query = "SELECT username,email,display_name,access,password FROM users WHERE user_id='$user_id'";
$results = mysql_query($query);
if (!$results) {//Check to see if query failed
die(mysql_error());
}
if (mysql_num_rows($result) > 0) { //verify if there is really a user with such id
$resultsfetch = mysql_fetch_array($results);
$username = $resultsfetch['username'];
$usernamenew = cleanString($_POST['usernameinput']);
if ($usernamenew != $username) {
$submit = "UPDATE users SET username = '$usernamenew' WHERE user_id = '$user_id'";
if (!mysql_query($submit)) {//Check to see if query failed
die(mysql_error());
}
}
}else{
die("no such user with userid=$user_id");
}
}
Warning: mysql_ function is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQL extension should be used.
So, I guess I figured it out. It's an issue with my code carrying over to the next page.
The code I had been shown only broke the page, whether it be missing an integer, or something else. I'm not 100% sure.
Thanks for all the help guys, but now I know the issue.
EDIT:
I had forgotten to echo the $user_id in my hidden field.
First of all, I am testing on localhost. I have this index.php file which contains the following "remember me" checkbox:
<input type="checkbox" id="login_remember" name="login_remember">
The login form posts to loginvalidate.php, which includes the following php script. I have included a lot of comments to ease the process of reading my code. Note that I'm pretty sure that everything below works fine.
if (isset($_POST['login_submit'])) { //SETS VARIABLES FROM FORM
$email = $_POST[trim('login_email')];
$password = $_POST['login_password'];
$remember = isset($_POST['login_remember']) ? '1' : '0';
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
$query = "SELECT password FROM registeredusers WHERE email = '$email'";
$result = mysqli_query($db_handle, $query) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result);
$numrows = mysqli_num_rows($result);
if ($numrows!=0) //IF EMAIL IS REGISTERED
{
if ($row['password'] == $password) { //IF PASSWORD IN DATABASE == PASSWORD INPUT FROM FORM
if ($remember == '1'){ //IF USER WANTS TO BE REMEMBERED
$randomNumber = rand(99,999999); //RANDOM NUMBER TO SERVE AS A KEY
$token = dechex(($randomNumber*$randomNumber)); //CONVERT NUMBER TO HEXADECIMAL FORM
$key = sha1($token . $randomNumber);
$timeNow = time()*60*60*24*365*30; //STOCKS 30 YEARS IN THE VAR
$sql_database = "registeredusers";
$sql_table = "rememberme";
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
$query_remember = "SELECT email FROM rememberme WHERE email = '$email'"; //IS THE USER IN TABLE ALREADY
$result = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
if (mysqli_num_rows($result) > 0) { //IF USER IS ALREADY IN THE REMEMBERME TABLE
$query_update = "UPDATE rememberme SET
email = '$email'
user_token = '$token'
token_salt = '$randomNumber'
time = '$timeNow'";
}
else { //OTHERWISE, INSERT USER IN REMEMBERME TABLE
$query_insert = "INSERT INTO rememberme
VALUES( '$email', '$token', '$randomNumber', '$timeNow' )";
}
setcookie("rememberme", $email . "," . $key, $timenow);
}
header('Location: homepage.php'); //REDIRECTS: SUCCESSFUL LOGIN
exit();
}
Then, when I close the internet browser and come back to index.php, I want the cookie to automatically connect the user. This is in my index.php:
include 'db_connect.php';
$sql_database = "registeredusers";
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
session_start();
if (isset($_COOKIE['rememberme'])) {
$rememberme = explode(",", $_COOKIE["rememberme"]);
$cookie_email = $rememberme[0];
$cookie_key = $rememberme[1];
$query_remember = "SELECT * FROM rememberme WHERE email = '$cookie_email'"; //IS THE USER IN TABLE ALREADY
$result_remember = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result_remember);
$token = $row['user_token'];
$randomNumber = $row['token_salt'];
$key = sha1($token . $randomNumber); //ENCRYPT TOKEN USING SHA1 AND THE RANDOMNUMBER AS SALT
if ($key == $cookie_key){
echo "lol";
}
}
The problem is, it never echoes "lol". Also, does anyone have any insight on how I could connect the users? AKA, what should go inside these lines:
if ($key == $cookie_key){
echo "lol";
}
Thank you! I'm still new to PHP and SQL so please bear with me if I have made some beginner errors.
EDIT!: After looking again and again at my code, I think that my error might lie in these lines. I'm not sure about the syntax, and the method I am using to store values into $token and $randomNumber:
$query_remember = "SELECT * FROM rememberme WHERE email = '$cookie_email'"; //IS THE USER IN TABLE ALREADY
$result_remember = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result_remember);
$token = $row['user_token'];
$randomNumber = $row['token_salt'];
A login script in PHP can be implemented using sessions.
Using Sessions
Making it simple, sessions are unique and lives as long as the page is open (or until it timeouts). If your browser is closed, the same happens to the session.
How to use it?
They are pretty simple to implement. First, make sure you start sessions at the beginning of each page:
<?php session_start(); ?>
Note: It's important that this call comes before of any page output, or it will result in an "headers already sent" error.
Alright, now your session is up and running. What to do next? It's quite simple: user sends it's login/password through login form, and you validate it. If the login is valid, store it to the session:
if($validLoginCredentials){
$_SESSION['user_id'] = $id;
$_SESSION['user_login'] = $login;
$_SESSION['user_name'] = $name;
}
or as an array (which I prefer):
if($validLoginCredentials){
$_SESSION['user'] = array(
'name' => $name,
'login' => 'login',
'whichever_more' => $informationYouNeedToStore
);
}
Ok, now your user is logged in. So how can you know/check that? Just check if the session of an user exists.
if(isset($_SESSION['user_id'])){ // OR isset($_SESSION['user']), if array
// Logged In
}else{
// Not logged in :(
}
Of course you could go further, and besides of checking if the session exists, search for the session-stored user ID in the database to validate the user. It all depends on the how much security you need.
In the simplest application, there will never exist a $_SESSION['user'] unless you set it manually in the login action. So, simply checking for it's existence tells you whether the user is logged in or not.
Loggin out: just destroy it. You could use
session_destroy();
But keep in mind that this will destroy all sessions you have set up for that user. If you also used $_SESSION['foo'] and $_SESSION['bar'], those will be gone as well. In this case, just unset the specific session:
unset($_SESSION['user']);
And done! User is not logged in anymore! :)
Well, that's it. To remind you again, these are very simple login methods examples. You'll need to study a bit more and improve your code with some more layers of security checks depending on the security requirements of your application.
reason behind your code is not working is
setcookie("rememberme", $email . "," . $key, $timenow); // this is getting expire exactly at same time when it is set
replace it with
setcookie("rememberme", $email . "," . $key, time() * 3600);//expire after 1hour
time()*60*60*24*365*30
this time is greater than 9999 year also you didn't need to set this horror cookie time.
that cookie time you were set is greater than 9999 years and php not allow for this configure.
in my opinion the best solution is setup new expire cookie time lower than 9999 :))
I created this account registration activation script of my own, I have checked it over again and again to find errors, I don't see a particular error...
The domain would be like this:
http://domain.com/include/register.php?key=true&p=AfRWDCOWF0BO6KSb6UmNMf7d333gaBOB
Which comes from an email, when a user clicks it, they get redirected to this script:
if($_GET['key'] == true)
{
$key = $_GET['p'];
$sql = "SELECT * FROM users
WHERE user_key = '" . $key . "'";
$result = mysql_query($sql) or die(mysql_error());
if(mysql_affected_rows($result) > 0)
{
$sql = "UPDATE users
SET user_key = '', user_active = '1'
WHERE user_key = '" . $key . "'";
$result = mysql_query(sql) or die(mysql_error());
if($result)
{
$_SESSION['PROCESS'] = $lang['Account_activated'];
header("Location: ../index.php");
}
else
{
$_SESSION['ERROR'] = $lang['Key_error'];
header("Location: ../index.php");
}
}
else
{
$_SESSION['ERROR'] = $lang['Invalid_key'];
header("Location: ../index.php");
}
}
It doesn't even work at all, I looked in the database with the user with that key, it matches but it keeps coming up as an error which is extremely annoying me. The database is right, the table and column is right, nothing wrong with the database, it's the script that isn't working.
Help me out, guys.
Thanks :)
Change $_GET['key'] == true to $_GET['key'] == "true"
You do before this if, a successful mysql_connect(...) or mysql_pconnect(...) ?
Change mysql_affected_rows($result); to mysql_num_rows($result);. Affected you can use for DELETE or UPDATE SQL statements.
Before you second if was opened, add before you second mysql_result(...), mysql_free_result($result); to free memory allocated to previous result.
if($result) change to if(mysql_affected_rows($result));. You can do that here.
After the header(...); function call's add a return 0; or exit(0); depends on your complete code logic.
You are using $key variable in SQL statements, to get your code more secure on SQL Injection attacks get change $key = $_GET['p']; to $key = mysql_real_escape_string($_GET['p']);
I think your location in header() functions fails. In header() url address should be full like: http://www.example.com/somewhere/index.php
And check your $_GET['p'] variable exists!! If this not exist and if $_GET['key'] exists, you find all activated users. Then i think the setting user_key to '' is nessesary if you have user_activated marker.
you shouldnt be using:
if(mysql_affected_rows($result) > 0)
You should be using mysql_num_rows()
Your problem is:
$result = mysql_query($sql) or die(mysql_error());
"or" makes your statement boolean so $result gets a True instead of value returned by mysql_query()
echo 'Hello' or die('bye'); // outputs nothing, because result is True not 'Hello'
3 or die() == True; // true
3 or die() != 3; // true
OR is the same as || and it is operator of logical statement.
This will work:
$result = mysql_query($sql);
if(!$result) die(mysql_error());
The same mistake was made a few hours ago: link
Cases where OR can be used:
defined('FOO') or
define('FOO', 'BAR');
mysql_connect(...) or die(...);
mysql_select_db( .... ) or die(...);
mysql_query('UPDATE ...') or die(...);
if(FOO or BAR) { ... }