recently revealed a problem in my login handler. The thing is, that even though the entered password is correct and matches the one in the database, script still sends me to the mistake page.
session_start();
include ("db.php");
if (isset($_POST['login'])) {
$login = $_POST['login'];
$login = stripslashes($login);
$login = htmlspecialchars($login);
$login = trim($login);
if ($login == '') {
unset($login);
}
}
if (isset($_POST['password'])) {
$password=$_POST['password'];
$password = stripslashes($password);
$password = htmlspecialchars($password);
$password = trim($password);
$password = hash("md5",$password);
if ($password =='') {
unset($password);
}
}
if (empty($login) or empty($password))
{
exit (header('location:index.php'));
}
$result = mysql_query("SELECT * FROM users_data WHERE login='$login'");
$row = mysql_fetch_array($result);
if (empty($row['password']))
{
exit (header('location:mistake.php'));
}
else {
if ($row['password']==$password) {
$_SESSION['login']=$row['login'];
$_SESSION['users_id']=$row['users_id'];
header('location:first.php');
}
else {
header('location:mistake.php');
}
}
The HTML form:
<form action="login.php" method="post" class="login">
<label><span>Login:</span>
<input name="login" type="text" size="20" maxlength="100">
</label>
<label><span>Password:</span>
<input name="password" type="password" size="20" maxlength="100">
</label>
<p>
<input type="submit" name="submit" class ="submit" value="Login">
</p>
UPD: Thank you for your answers, finally I've got where the problem was - I just specified not enough length of password values in the database.
First of all why would you store the password in the database without hashing them(e.g. md5).
If you would do that, then there would be no need to process the password and you could just compare the stored md5(password) with the md5 hash of the password posted by the user.
Also w.r.t it is most likely that you are being redirected to the mistake.php page instead of the success.php page because of the encoding.
It would help if you provide us with the password you are using to test the code (assuming you are testing it. ;) ).
Cheers!
EDIT: Please look at better encryption techniques, as suggested by #jayblancard in the comments below.
try to use isset() instead of empty
if (isset($row['password']))
I will just advice you to try to debug your code, mistake DOT php is called in multiple places so use a die("die message") to see which one is being fired.
Since you don't have tests to your code debug output of valid and invalid input and check output.
Once you are satisfied with the inputs and outputs, check if conditions if they are behaving as expected like previously using die condition maybe.
NB: your code is messy look at this to lean basics
Also look at OO programming
Related
my website is http://setch.me
I have a page that I use to add new entries to the artists table, how do I set a simple username/password to this page with normal php(no framework)?
I've looked it up and I found similar questions but none of them is using php only
It's simply you just need to create a form
<form action="" method="post">
<input type="text" name="user"/>
<input type="password" name="pass"/>
</form>
And submit data and compare it with your private username and password
example
<?php
if(isset($_POST["submit"])) {
// Here you put you own login data you can use mysql to get it
$username = "admin";
$password = "admin";
$username_post = htmlspecialchars($_POST["user"]);
$password_post = htmlspecialchars($_POST["pass"]);
if(($username_post == $username) && ($password_post == $password)) {
session_start();
$_SESSION["admin"] = $username;
}
}
?>
and put this code in page that you want to add new entries
<?php
session_start();
if(empty($_SESSION["admin"])) {die();}
?>
Php-login comes with three versions. The first one (One-file version) maybe is what you are looking for.
I'm trying to use the following form to log in, but it always jump to invalid username. Am I missing anything in here?
Database Connection:
$link = mysqli_connect("localhost","X","X","X");
if($link == false) {
die("Error" .mysqli_connect_error());
}
Login Script:
<?php
if (!isset($_POST['submit'])) {
?>
<!-- The HTML login form -->
<form action="<?=$_SERVER['PHP_SELF']?>" method="post">
Username: <input type="text" name="username" /><br />
Password: <input type="password" name="password" /><br />
<input type="submit" name="submit" value="Login" />
</form>
<?php
} else {
// Include database credentials
include('../db_connect.php');
$mysqli = new mysqli($link);
// check connection
if ($mysqli->connect_errno) {
echo "<p>MySQL error no {$mysqli->connect_errno} : {$mysqli->connect_error}</p>";
exit();
}
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * from admin WHERE admin_email LIKE '{$username}' AND admin_password LIKE '{$password}' LIMIT 1";
$result = $mysqli->query($sql);
if (!$result->num_rows == 1) {
echo "<p>Invalid username/password combination</p>";
} else {
echo "<p>Logged in successfully</p>";
// do stuffs
}
}
?>
I'm not 100% sure, but I think getting rid of the {} around the $username and $password should fix the issue, and yea, using LIKE for login is bad. I could then type %abijeet% in my username and %p% in the password field and get logged in as long as there is someone called abijeet in the system and has a password with the letter p in it.
Using PDO
Also, filtering the input from the $_POST is a good idea. In general, I'd ask you to drop using mysqli and look into PDO - http://php.net/manual/en/book.pdo.php
Using PDO properly with parameters will secure you against SQL Injection attacks.
Hashing the password
Don't store the password in plain test, hash it before saving. Check here - http://php.net/manual/en/function.password-hash.php
UPDATE -
OK, so as pointed out the {} are ok. Another thing that looks suspicious to me is the condition checking.
I would change it to this -
// Check the condition checking below!
if ($result->num_rows !== 1) {
echo "<p>Invalid username/password combination</p>";
} else {
echo "<p>Logged in successfully</p>";
// do stuffs
}
It could be an operator precedence issue and is anyways more confusing.
I have completed a login form and it works 100% on my WAMP server. However when I run it on a live server everything works 100%, apart from when I log in it does not redirect my page to the page it should (just displays a blank HTML page). It is however logged in, because if I enter the url of the page it should go, it displays like it should. The path to the file is correct. I hope my problem is clear. Here is the code for my login form:
<?php
include_once "includes/scripts.php";
session_start();
include_once ("includes/connect.php");
if(isset($_SESSION['logged_in'])) {
header('location: admin_cms.php');
exit();
} else {
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = md5($_POST['password']);
if(empty($username) or empty($password)) {
$error = '<p>NOTE: Fields are blank</p>';
} else {
$query = $pdo->prepare("SELECT * FROM users WHERE user_name = ? AND user_password =?");
$query->bindValue(1, $username);
$query->bindValue(2, $password);
$query->execute();
$num = $query->rowCount();
if($num == 1) {
$_SESSION['logged_in'] = true;
header('location: admin_cms.php');
exit();
} else {
$error = "<p>NOTE: The username or password is incorrect</p>";
}
}
}
?>
<div id="login_container">
<br><img src="images/camelhorst_logo_full.png" style="margin-top:38px;">
<h1>LOGIN<img src="images/three_column_grid_line.png" alt="line"></h1>
<form acton = "admin.php" method="post" autocompleate="off">
<label>Username:</label>
<input type="text" name="username" placeholder="Your Username" required autocomplete="off">
<label>Password:</label>
<input type="password" name="password" placeholder="Your Password" required autocomplete="off">
<input type="submit" value="Login" name="submit_login">
</form>
<?php
if(isset($error)) {
echo $error;
}
?>
<p id="copyright_admin"> © CAMELHORSE CREATIVE STUDIO 2013 </p>
</div><!--login_container-->
<?php
}
?>
</body>
</html>
Firstly, the
session_start()
must be at the very top of the page. There can be nothing, no whitespace before it.
Secondly,
if (empty($username) or empty($password)){
needs to be replaced with this
if (empty($username) || empty($password)){
Try that and see if it works
Also, this is a bit off topic and I'm sure that it's not what's causing your problem, but md5() is very outdated. Try using
sha1();
for encryption instead. sha1() is also a bit old, but it's better than md5().
This too, is kind of off topic. But, it seems notable. You have
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = md5($_POST['password']);
if(empty($username) or empty($password)){
$error = '<p>NOTE: Fields are blank</p>';
}
By default, md5 returns a 32 character hex number even if the value of what's being encrypted is empty. So, the condition
empty($password)
is kind of redundant. What's better to have is this:
if(isset($_POST['username'], $_POST['password'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$pass_enc = md5($_POST['password']);
if(empty($username) || empty($password)){
$error = '<p>NOTE: Fields are blank</p>';
}
change redirection to this.
echo "<script>window.location='admin_cms.php'<script>";
Most times, when your header() redirection fails, it is because there has been previous output (even a whitespace matters here), so you may need to be sure there has been no previous output on the file or any included files.
<?php include_once "includes/scripts.php"; ?>
include_once ("includes/connect.php");
NB: Any space outside the <?php ?> tags is considered output.
E.g.
<?php ...some php code... '
//space below causes output to be written to html
?>
<?php
...more php code here...
?>
Iqbal Malik is right. you should use
echo "window.location='admin_cms.php'";
for the redirection however if you want to keep the header() thing you must put
ob_start()
on top of the page, right under
session_start()
it will work like a charm.
edit:
About the md5 / sha1 thing, Ijust started using:
hash("sha512", md5($password))
for my password encryption.
I'm creating a login script and its failing each time even when I input the correct credentials. I firstly thought this was to do with the crypt function which has been explained in depth and have done further research upon to find a good method.
Anyway I have remove the crypt function in both the login and register to test the login script. Upon removing this I still got an error which stated Invalid username or password.
I wanted to see what was actually been passed in my POST variables, so I echoed these variables as they are defined e.g.
$username = isset($_POST['username']);
echo $username;
outputs: 1
however
echo $_POST['username'];
outputs admin (which is the username I have been using)
If I remove the isset from this POST variable then I am returned with the true value but this still fails my login script.
I don't understand whats going wrong as I've used this same statement in a different function to test it and it works, instead of using POST variables I am already setting the username and password and then wrapping in a foreach statement and this works.
It must be something to do with my POST variables and the way I am handling it but I don't have the experience/knowledge to solve the problem. I can't understand why my POST data is returned as a integer but then even when I remove the isset tag my statement is still false?
Any input and help is greatly welcomed and appreciated.
Below is my code, if there's anything else required please ask:
index.php
<form id="loginForm" method="POST" action="classes/class.Login.php">
<input type="text" id="username" name="username" placeholder="Username"/>
<input type="password" id="password" name="password" placeholder="Password" class="showpassword"/>
<input type="submit" name="submit" value="Log in"/>
classes/class.Login.php
public function loginuser() {
$username = isset($_POST['username']);
$password = isset($_POST['password']);
//$salt = "boo";
//$pw = crypt($password, $salt);
$stmt = $this->pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password LIMIT 1");
$stmt->bindValue(":username", $_POST['username'], PDO::PARAM_STR);
$stmt->bindValue(":password", $_POST['password'], PDO::PARAM_STR);
if ($stmt->fetch(PDO::FETCH_ASSOC))
{
$_SESSION['authorized'] = true;
$_SESSION['username'] = $username;
header('Location: testloginrequired.php');
} else {
echo "Invaild username or password. Try again";
}
}// end loginuser
Change:
$username = isset($_POST['username']);
to :
$username = ($_POST['username']);
isset function returns a boolean value (true,false) , so your $username would be boolean (true or 1) not a string!
$username = isset($_POST['username']);
Is just checking if the variable is set. Get rid of the isset and change it simply to
$username = $_POST['username'];
If that doesn't work, then do this
$username = settype($username, "string");
Use construction:
if (isset($_POST['username'])) $username = $_POST['username'];
If you will remove "isset" check, you will get warning, if key 'username' will not exists in POST.
Improvement of your code:
$username = (isset($_POST['username'])) ? $_POST['username'] : '';
This is ternary operator and it's suitable in your case. If key 'username' exists in POST, then $username will equals $_POST['username'], otherwise $username will empty. Enjoy :)
Building a simple login page. If the user types in a password and password confirmation that don't match, I want to reset the registration form and print an message. Currently, the message does not print, but carries on through the script. This is what I've tried, by way of setting a SESSION variable when the error occurs, and showing this variable upon reload:
registration.php:
<?php
session_start();
if (isset($_SESSION['errmsg'])) {
print($_SESSION['errmsg']);
unset($_SESSION['errmsg']);
}
?>
<form name="register" action="register.php" method="post">
<label>Username</label><input type="text" name="username" maxlength="20" />
<label>Password</label><input type="password" name="pass" />
<label>Password Again</label><input type="password" name="pass_confirm" />
<input type="submit" value="Register" />
</form>
register.php:
<?php
function create_salt() {
$string = md5(uniqid(rand(), true));
return substr($string, 0, 3);
}
session_start();
$username = $_POST['username'];
$pass = $_POST['pass'];
$pass_confirm = $_POST['pass_confirm'];
if ($pass != $pass_confirm) {
$_SESSION['errmsg'] = "Passwords do not match.";
header('Location: registration.php');
}
if (strlen($username) > 20) {
header('Location: registration.php');
}
$hash = hash('sha256', $pass);
$salt = create_salt();
$hash = hash('sha256', $salt . $hash);
$conn = mysql_connect('localhost', 'test4', 'test4');
mysql_select_db('test4', $conn);
$username = mysql_real_escape_string($username);
$query = "INSERT INTO users (username, password, salt) VALUES ('$username', '$hash', '$salt');";
mysql_query($query);
mysql_close();
header('Location: index.php');
?>
The important part is the line if ($pass != $pass_confirm) { .... Currently if the passwords do not match this condition is met, but it will carry on through the script rather than reloading via header(Location: registration.php). I am aware that header() cannot be invoked after data has been sent, which is probably causing the problem.
If so, is there a better way to do this in PHP or should I be looking at alternatives?
A die(); or exit; solves the problem.
header('Location: registration.php');
die();
If you need to output some data and then possibly choose to redirect, you can use output buffering. This causes the output you've generated to be placed in a buffer instead of being sent to the user. If you need to redirect, it works because there's no data sent yet. If you don't redirect, you make use of what's in the buffer and output once the script is done.
See this PHP Manual page to lean much more about PHP output buffering:
http://www.php.net/manual/en/intro.outcontrol.php
Also, note that you're calling header() twice if you have the error - the second header call with the 'location' type will overwrite the first and send you to index.php.
Please see #talereader's answer above - the key is to determine that you're in the error state and call the header (which you do) and then terminate the script immediately.
Why not do all your checking and set a flag if something fails. i.e $failed = true; then before you do any actual processing do if (!$failed) { //process }.