Creating an Admin product system in PHP - Authentication error - php

I'm creating an e-commerce website. I am working on an admin page that lets the "store manager" log in to do things like add or remove products. In my database, I created a table called admin, with these fields:
id
password
time_last_logged_in
I inserted a row for my store manager, I can see the username and password so I know the person exists in the database, but when I try to log in it echoes out the error below.
admin_login.php
<?php
session_start();
if (isset($_SESSION["manager"])) {
header("location: index.php");
exit();
}
?>
<?php
if (isset($_POST["username"]) && isset($_POST["password"])) {
$manager = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["username"]); // filter everything but numbers and letters
$password = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["password"]); // filter everything but numbers and letters
// Connect to the MySQL database
include "../scripts/connect_to_mysql.php";
$sql = mysql_query("SELECT id FROM admin WHERE username='$manager' AND password='$password' LIMIT 1"); // query the person
// ------- MAKE SURE PERSON EXISTS IN DATABASE ---------
$existCount = mysql_num_rows($sql); // count the row nums
if ($existCount == 1) { // evaluate the count
while($row = mysql_fetch_array($sql)){
$id = $row["id"];
}
$_SESSION["id"] = $id;
$_SESSION["manager"] = $manager;
$_SESSION["password"] = $password;
header("location: index.php");
exit();
} else {
**echo 'That information is incorrect, try again Click Here';**
exit();
}
}
?>
I use a connect_test.php script to verify that it's connecting to the database and that there's no problem connecting.
index.php
<?php
session_start();
if (!isset($_SESSION["manager"])) {
header("location: admin_login.php");
exit();
}
// Be sure to check that this manager SESSION value is in fact in the database
$managerID = preg_replace('#[^0-9]#i', '', $_SESSION["id"]); // filter everything but numbers and letters
$manager = preg_replace('#[^A-Za-z0-9]#i', '', $_SESSION["manager"]); // filter everything but numbers and letters
$password = preg_replace('#[^A-Za-z0-9]#i', '', $_SESSION["password"]); // filter everything but numbers and letters
// Run mySQL query to be sure that this person is an admin and that their password session var equals the database information
// Connect to the MySQL database
include "../scripts/connect_to_mysql.php";
$sql = mysql_query("SELECT * FROM admin WHERE id='$managerID' AND username='$manager' AND password='$password' LIMIT 1"); // query the person
// ------- MAKE SURE PERSON EXISTS IN DATABASE ---------
$existCount = mysql_num_rows($sql); // count the row nums
if ($existCount == 0) { // evaluate the count
echo "Your login session data is not on record in the database.";
exit();
}
?>
Why might my code return That information is incorrect, try again Click Here'; instead of a successful validation?

The Problem(s?)
The way I see it, there are several problems with your code. I'll try to address each one and tell you how to solve each issue.
Issue #1: You are using REGEX To strip your code.
There are much better alternatives, the best of which is prepared statements which you should obviously use. Sadly, mysql_* functions don't support it. Which get's me to the next issue:
Issue #2: You are using mysql_* functions.
You shouldn't be using functions like mysql_query() and mysql_num_rows(), instead, consider moving to a better and more secure alternative, such as MySQLi (Good) or PDO (Awesome).
Issue #2.5: You are not using prepared statements.
A Prepared statement is automatically escaped and any malicious code or characters is render useless, same goes for SQL injections. You should use a better database handler that supports it (See Issue #2).
Issue #3: You are testing specifically.
You seem to test only if the row count is equal to exactly one. But what if there are (by accident) 2? Instead of testing what should be, test for what should not be:
if ($existCount != 0) { ...
Issue #4: You are not selecting the correct fields.
You only select the id field in your query, where instead you should be selecting all of the relevant fields (like username and password), in order to receive information.
Issue #5: You are not using secure storing.
If someone were to steal your database, they would have easy access to all your passwords. Consider using an encrypting method like sha1().
Issue #6: You are not testing for errors.
Errors can and will occur, you should test for them, with mysql_query() you should probably do something like
mysql_query("SELECT....") or die(mysql_error());
In PDO that would be something like
if (!$stmt->execute()) { throw new Exception("Execution failed.` . var_export($stmt->errorInfo(), true)); }
Try to correct those, and tell us if your problem persists.
Good luck :)

Try doing:
$sql = mysql_query("SELECT ... LIMIT 1") or die(mysql_error());
Your code assumes the query succeeds, which is very bad form. Always check for error conditions. You may have failed to connect to the database. perhaps your DB is malformed and you've got 2 or more records with the same username/password combo, etc...

I'm new to PHP myself, but I noticed that your select statement in the first code sample above selects only the id. That might be the problem. You should change it to select * and see if that makes any difference.
Good luck

Related

Adding a 'check username' to registration form PHP

Please could someone give me some much needed direction...
I have a registration form, however I need to add a condition that if the username is already in the table, then a message will appear. I have a had a few goes except it just keeps adding to the SQL table.
Any help would be much appreciated. Here is my current code:
Thanks in advance!
<?php
session_start();session_destroy();
session_start();
$regname = $_GET['regname'];
$passord = $_GET['password'];
if($_GET["regname"] && $_GET["regemail"] && $_GET["regpass1"] && $_GET["regpass2"] )
{
if($_GET["regpass1"]==$_GET["regpass2"])
{
$host="localhost";
$username="xxx";
$password="xxx";
$conn= mysql_connect($host,$username,$password)or die(mysql_error());
mysql_select_db("xxx",$conn);
$sql="insert into users (name,email,password) values('$_GET[regname]','$_GET[regemail]','$_GET[regpass1]')";
$result=mysql_query($sql,$conn) or die(mysql_error());
print "<h1>you have registered sucessfully</h1>";
print "<a href='login_index.php'>go to login page</a>";
}
else print "passwords don't match";
}
else print"invaild input data";
?>
User kingkero offered a good approach. You could modify your table so that the username field is UNIQUE and therefore the table cannot contain rows with duplicate usernames.
However, if you cannot modify the table or for other reasons want to choose a different approach, you can first try to run a select on the table, check the results and act accordingly:
$result=mysql_query('SELECT name FROM users WHERE name="'.$_GET['regname'].'"');
$row = mysql_fetch_row($result);
You can then check $row if it contains the username:
if($row['name']==$_GET['regname'])
If this statement returns true, then you can show the user a message and tell him to pick a different username.
Please note
Using variables that come directly from the client (or browser) such as what might be stored in $_GET['regname'] and using them to build your SQL statement is considered unsafe (see the Wikipedia article on SQL-Injections).
You can use
$regname=mysql_escape_string($_GET['regname'])
to make sure that its safe.
Firstly, there is some chaos on the second line:
session_start();session_destroy();
session_start();
Why you doing it? Just one session_start(); needed.
Then you can find users by simple SQL query:
$sql="SELECT * FROM users WHERE name = '$regname'";
$result=mysql_query($sql) or die(mysql_error());
if (mysql_num_rows($result) > 0) {
//...echo your message here
}
When you got it, I suggest you to rewrite your code with use of PDO and param data binding, in order to prevent SQL injections and using of obsolete functions.

Check values on mysql table and select ones that are set to "1"

I looked all over. I cannot figure this out.
<?php
session_start();
if (!empty($_POST[username]))
{
require_once("connect.php");
// Check if he has the right info.
$query = mysql_query("SELECT * FROM members
WHERE username = '$_POST[username]'
AND password = '$_POST[password]'")
or die ("Error - Couldn't login user.");
$row = mysql_fetch_array($query)
or die ("Error - Couldn't login user.");
if (!empty($row[username])) // he got it.
{
$_SESSION[username] = $row[username];
echo "Welcome $_POST[username]! You've been successfully logged in.";
exit();
}
else // bad info.
{
echo "Error - Couldn't login user.<br /><br />
Please try again.";
exit();
}
if($isadmin["admin"]==1)
{
echo $admin;
}
else
{
}
}
$admin = <<<XYZ
<div id="admintab">
Admin ยป
<div id="admin">
ADMIN PANEL
<div id="exitadmin">
</div>
<div id="artistline" />
</div>
</div>
XYZ;
?>
I do know that the $admin value is working. I have tested it. Basically, I have a register system. By default, it sets your admin value to '0'. But let's say i want to add an admin. I change the '0' to a '1' via mysql. I want to know how to make php find users with their admin value set to '1' that are in the database (row name: admin), and display the admin panel to them only.
Why have you used
if($isadmin["admin"]==1)
as you have
$row = mysql_fetch_array($query)
so convert
if($isadmin["admin"]==1)
to
if($row["admin"]==1)
you should check the value before insert and select the data and also use
mysql_real_escape_string($_POST['username'])
so that sql injection not apply
You need to change if($isadmin["admin"]==1) to if($row['admin'] == 1) -- you can leave out the == 1 part if 1 & 0 are the only answers as 1 will always be true and 0 will be false.
Obligitarily, I need to mention that storing passwords in your database in plain text is a bad idea, you should be at the very least hashing them before you store them. Something like $password = hash('sha256', $salt.$_POST['password']) at the registration and login stages.
I should also point out that you shouldn't feed naked values into your database with a query, you don't need to worry about password if you're hashing it, but you do if you're not and you need to do username anyway otherwise anyone can run SQL queries in your database:
$username = mysql_real_escape_string($_POST['username'])
Firstly, I am obligated to point out that not filtering $_POST (and $_GET and $_COOKIE and so on) is very dangerous, because of SQL injection. Secondly, the variable $isadmin doesn't magically exist until you've defined it.
I would suggest designing a more capable user group system, but just to answer the question, the variable you want to check is $row["is_admin"], given that is_admin is a valid column in the table. Also, you don't need to do if ($row["is_admin"] == 1) - 1 evaluates to TRUE in PHP.

One login script, two tables

I have a website for my school I am designing.
I am struggling how to work this for my script, but there are two sections to the website. If a teacher logs in, from the table lesson_teachers, it should redirect them to lesson.php. If a student logs in, from the table users, it redirects them to home.php.
I think the select query for the teachers table may be something like this:
SELECT id FROM lesson_teachers WHERE username='$user_login' AND password='$md5password_login' LIMIT 1
I am trying to fit that select statement into my login script below, so that people with usernames and passwords in both tables can log into one script.
if (isset($_POST["user_login"]) && isset($_POST["password_login"])) {
$user_login = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["user_login"]); // filter everything but numbers and letters
$password_login = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["password_login"]); // filter everything but numbers and letters
$md5password_login = md5($password_login);
$sql = mysql_query("SELECT id FROM users WHERE username='$user_login' AND password='$md5password_login' LIMIT 1"); // query the person
//Check for their existance
$userCount = mysql_num_rows($sql); //Count the number of rows returned
if ($userCount == 1) {
while($row = mysql_fetch_array($sql)){
$id = $row["id"];
}
$_SESSION["id"] = $id;
$_SESSION["user_login"] = $user_login;
$_SESSION["password_login"] = $password_login;
exit("<meta http-equiv=\"refresh\" content=\"0\">");
} else {
echo 'That information is incorrect, try again';
exit();
}
}
Your user table should either have a roles relation or at least a tinyint 1 field (0 for student, 1 for teacher) in your user table so you don't have to use 2 tables to achieve this.
Pretending I agreed with the query, this is what it might look like:
SELECT id, level FROM users WHERE username='$user_login' AND password='$md5password_login' LIMIT 1
where level is 0 for student, 1 for teacher. Any data relevant to either student or teacher on its own could be stored in a relation table.
Then you could say:
if($row['level'] == 1)
{
header('Location: /teacher-url');
exit;
}
else
{
header('Location: /student-url');
exit;
}
Now for the extra nuggets:
Please don't use this method for comparing passwords. You could basically login as another user accidentally or by happenstance if you were trying to hack since it strips characters. So "pa_s$sw==0ord" turns into "password"
Just run a sha1 (or better) encryption comparison on the posted input versus the stored sha1 encrypted password in the DB. That's the best real comparison to user passwords vs input.
And storing a password in $_SESSION just plain makes no sense. Why would you ever use it like this? Perhaps if you tell we can point you in a better direction.
And as Elias said, use PDO or mysqli. They will sanitize correctly amid the many many other reasons to use them over mysql_ functions.
I should add that we are all aware of how to actually answer your question. We know you want to know HOW to do it with what you've got. But we refuse. Because this habit should be cleaned before it becomes a nightmare. Not trying to be deliberately rude or anything, but a well planned database structure and use of PDO or mysqli will save you tons of time in both database and code. Look into relation tables, the concept of "roles" and sanitizing user input. From that you can construct the user system in a way that makes sense.
Firstly, you will only find 1 match per user/password pair,
so instead of
while($row = mysql_fetch_array($sql)){
$id = $row["id"];
}
you can simply do
$row = mysql_fetch_array($sql);
$id = $row["id"];
As for the teach/student redirect, you will need a hidden variable in the login from to identity type= teacher or student
then based on this variable, you can do
if ($type=='student')
header('location:home.php');
if ($type=='teacher')
header('location:lession.php');
after setting your session variables.

SQL query error?

I'm getting this error and I don't quite understand why. I've been going over this for hours now, tried looking into it via research, no luck.
In my PHP login system, I check if the row is selected:
//Start session
session_start();
//Include database connection details
require_once('config.php');
//Array to store validation errors
$errmsg_arr = array();
//Validation error flag
$errflag = false;
//Connect to mysql server
$link = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
if(!$link) {
die('Failed to connect to server: ' . mysql_error());
}
//Select database
$db = mysql_select_db(DB_DATABASE);
if(!$db) {
die("Unable to select database");
}
//Prevent SQL injection.
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
//Sanitize the POST values
$login = clean($_POST['login']);
$password = clean($_POST['password']);
//Input Validations
if($login == '') {
$errmsg_arr[] = 'Login ID missing';
$errflag = true;
}
if($password == '') {
$errmsg_arr[] = 'Password missing';
$errflag = true;
}
//If there are input validations, redirect back to the login form
if($errflag) {
$_SESSION['ERRMSG_ARR'] = $errmsg_arr;
session_write_close();
echo "input validation";
exit();
}
//Create query
$qry="SELECT * FROM details WHERE USERNAME='$login' AND PASSWORD='".md5($_POST['password'])."'";
$result=mysql_query($qry);
//Check whether the query was successful or not
if($result) {
if(mysql_num_rows($result) == 1) {
//Login Successful
session_regenerate_id();
$member = mysql_fetch_assoc($result);
$_SESSION['MEMBER_ID'] = $member['USERNAME'];
session_write_close();
header("location: client-index.php");
exit();
}else {
//Login failed
echo "login failed?";
exit();
}
}else {
die("Query failed");
}
?>
It echos "failed", for whatever reason.
If you told us what the error is, it might help us answer your question better.
But at any rate, this is emphatically the WRONG way to go about this. There are many serious problems with this system.
First of all, you're not sanitizing your inputs. Since you're mixing your data and commands together, all a user would have to do is enter a username of "x' or 1 = 1' --" to get into the system. Here's why: the only command the SQL server would get is "SELECT * FROM details WHERE USERNAME = 'x' or 1 = 1". In other words, if the username is x or 1 = 1 (which it is), then the SQL server would respond with a positive result. (The two dashes at the end of the "username" denote a comment in SQL, so everything after that in the query would be ignored).
A truly malicious attacker could even wreak havoc on your system by entering a username "x'--; DROP TABLES;', and your entire database would be gone. (See this comic for where I got this.)
In fact, you shouldn't even really be using mysql_query at all. According to the PHP documentation:
Use of this extension is discouraged. Instead, the MySQLi or PDO_MySQL extension should be used.
I would do a bit more reading on the subject if I were you. Even if this is just for practice, it's still best to get things right the first time. Look into PDO: it's not too hard to learn, yet quite useful. Its main advantage is that it does not mix data and commands, so you won't have the same problem of unsanitized inputs messing up your database.
Also, while it's good to see that you're hashing your passwords--and you'd be amazed at how many companies that should know better do not--MD5 is no longer considered cryptographically secure. It's relatively easy to get what's called a "hash collision," where two different plaintexts produce the same hash. Now, SHA-256 should be the minimum you use.
Also, on the subject of hashing, you should be adding something called salt. A salt is some kind of random text that you add to your plaintext in order to further obfuscate it. The reason for this is that there are what's called rainbow tables out there. A rainbow table is a list of pre-calculated hashes of all common passwords. If someone were to get a hold of your database, they could then compare all the passwords to rainbow tables to find their plaintexts.
Finally, in order to slow down brute force attacks--where an attacker tries all alphanumeric combinations until they get the password--you should also be using a loop where the hash algorithm gets re-calculated x number of times, usually between 1000 and 10000 times. PHP's crypt does this very nicely.
And BTW: don't feel bad. I've done all these things before, too. That's why I know that you shouldn't do them. Don't worry--you'll get there soon enough. Keep at it!
I am new to site so can not add comments maybe this wont help much but ill give it a go anyway
in your sql query it looks like you passing variable $login as text not variable value
$qry="SELECT * FROM details WHERE USERNAME='$login' AND PASSWORD='".md5($_POST['password'])."'";
and it should be
$qry="SELECT * FROM details WHERE USERNAME=".$login." AND PASSWORD='".md5($_POST['password'])."'";
is it a query failed or login failed?
anyway if query failed :
try to change your query in to this :
surrounds your fields with backtick (not single quote)
$qry="SELECT * FROM details WHERE `USERNAME`='$login' AND `PASSWORD`='".md5($_POST['password'])."'";
if login failed :
if(mysql_num_rows($result) == 1) {
//Login successful
}else {
//Login failed
}
are you sure that the query will only have 1 result? because with this condition, if results is greater than 1 it will also failed to login.

how to get the session id

please help i have the following php code for my login session but i am trying to get the $_session['user_id'] instead of the $_session['email']. i tried print_f function to see what i can use but user_id array says 0 which cannot be right unless i read it wrong.
session_start();
$email = strip_tags($_POST['login']);
$pass = strip_tags($_POST['password']);
if ($email&&$password) {
$connect = mysql_connect("xammp","root"," ") or die (" ");
mysql_select_db("dbrun") or die ("db not found");
$query = mysql_query("SELECT email,pass FROM members WHERE login='$email'");
$numrows = mysql_num_rows($query);
if ($numrows!=0) {
// login code password check
while ($row = mysql_fetch_assoc($query)) {
$dbemail = $row['login'];
$dbpass = $row['password'];
}
// check to see if they match!
if ($login==$dbemail&&$password==$dbpass) {
echo "welcome <a href='member.php'>click to enter</a>";
$_SESSION['login']=$email;
} else {
echo (login_fail.php);
}
} else {
die ("user don't exist!");
}
//use if needed ==> echo $numrows;
} else {
die ("Please enter a valid login");
}
i am trying to get the $_session['user_id'] instead how can get this to use instead of $_session['email']. tried using $_session['user_id'] but instead i got undefined error msg.
Well, you don't define $_session['user_id'] anywhere in this script, so it's no surprise that it's not defined. You have to assign it a value before you can refer to it.
Also, note that there all kinds of security problems with this code.
You're running your MySQL connection as the root user. This is NOT a good idea.
You're trusting user input, which opens your script up to a SQL injection attack. Stripping HTML tags from the user input does not make it safe. Suppose that I came to your site, and filled in the "email" field with this:
bob#example.com'; GRANT ALL PRIVILEGES ON *.* TO 'evil_bob' IDENTIFIED BY '0wned_joo';
As currently written, your script would happily run its query as normal, and also create an account called "evil_bob" with full privileges to all the information in all of the databases on your server.
To avoid this, NEVER assume that user input is safe. Validate it. And to be extra sure, don't stick variables straight into SQL you've written. Use bound parameters instead. There are a few cases where it's hard to avoid -- for example, if you need to specify the name of a column rather than a piece of data, a bound parameter will not help and you'll have to do it some other way. However, for any piece of data you're using as part of a query, bind it.

Categories