username and password passed as integers rather than strings - php

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 :)

Related

How to make a Multi Login User Using PHP?

<?php
ini_set('display_errors', '1');
require_once 'core/init.php';
if(logged_in() === TRUE) {
header('location: dashboard.php');
}
if($_POST) {
$username = $_POST['username'];
$password = $_POST['password'];
if($username == "") {
echo "Username Field is Required <br />";
}
if($password == "") {
echo "Password Field is Required <br />";
}
if($username && $password) {
if(userExists($username) == TRUE) {
$login = login($username, $password);
if($login) {
$userdata = userdata($username);
$_SESSION['id'] = $userdata['id'];
header('location: dashboard.php');
exit();
} else {
echo "Incorrect username/password combination";
}
} else{
echo "Username does not exists";
}
}
} // /if
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles1.css">
<script type="text/javascript" src="jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="scripts.js"></script>
<title>Login</title>
</head>
<body class="container">
<div class = "login-box">
<img src = "image/person1.png" class = "avatar">
<h1 id = "login-header">Login</h1>
<form id=registration_form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST">
<div>
<label for="username">Username</label>
<input type="text" name="username" id="form_username" autocomplete="off" placeholder="Username" />
<span id="username_error"></span>
</div>
<br />
<div>
<label for="password">Password</label>
<input type="password" name="password" id="form_password" autocomplete="off" placeholder="Password" />
<span id="password_error"></span>
</div>
<br />
<div>
<input type="submit" name="btnLogin" value = "Login">
</div>
Not yet a member? Register
</form>
</body>
</html>
Can somebody help me regarding to my PHP. I'm very new in PHP. My website must have a multi-login user. But I try to do it and I failed. I don't received any error. But the problem is when I press the login button nothing happen. If the user_type is equal to admin I want to link it to adminPanel.php and if user_type is equal to user I want to link it to userPanel.php. Can somebody fix my code below. I really appreciate it.
function login($username, $password) {
global $connect;
$userdata = userdata($username);
if($userdata) {
$makePassword = makePassword($password, $userdata['salt']);
$sql = "SELECT * FROM tbl_user WHERE username = '$username' AND password = '$makePassword'";
$query = $connect->query($sql);
if($query->num_rows == 1) {
$logged_in_user = mysqli_fetch_assoc($query);
if ($logged_in_user['user_type'] == 'admin') {
$_SESSION['user'] = $logged_in_user;
header('location: adminPanel.php');
}else{
$_SESSION['user'] = $logged_in_user;
header('location: userPanel.php');
}
}
}
$connect->close();
// close the database connection
}
Forword
I feel generous tonight...
This may not fix your issue. As I said in the comments, there are many things that can be wrong. Without more information on what is happening, how you do things there is no way to tell.
These are things that are important (things to check)
how you submit the post (the form)
fields could be named wrong, form could be setup wrong etc.
the form action could simply be wrong
the form method could simply be wrong
how you handle that submission
variables could be sent to login() incorrectly, login($password,$username) instead of login($username,$password)
vairables could simply be translated wrong, for example you could have $_POST['user'] insead of $_POST['username']
you could be doing validation checks on input, which may or may not remove data, could be wrong.
how you handle starting the session
you can't use session until you start it
what if any output you have when handling the submission
output before header location will prevent the redirect
header location does not exit the current code scope, stuff after it can run so you should call exit after doing a redirect.
how you connect to the DB
you may have DB error
what if any errors you get, what error reporting do you have
you could have errors your not reporting for any of the above, and many things I didn't mention.
You probably shouldn't roll you own login system until you have a better handle on the security implications ( and other things).
Password/Security
The makePassword function is not included (in your code), but in any case you should use the built in (PHP5.4+) password function. It's much more secure and saves a lot of work:
function makePassword($plaintext){
return password_hash($plaintext, PASSWORD_DEFAULT);
}
This will return a 60 char long hash, but it's recommended to use VARCHAR(255).
It will look something like this in the DB:
//$2y = BCRYPT (default), $10 Cost or iterations (default), that's all I can remember.
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
Then for login (MySqli):
//session_start(); //make sure this is called
function login($username, $password, \mysqli $connect) //use type hinting
{
//can fail because of syntax errors, missing privileges
$stmt = $connect->prepare('SELECT * FROM tbl_user WHERE username = ?') OR die($connect->error);
//can fail because of incorrect number of arguments, invalid types
$stmt->bind_param("s", $username) OR die($stmt->error);
//can fail for various reasons
$stmt->execute() OR die($stmt->error);
$result = $stmt->get_result();
if($result->num_rows == 1) {
$user = $result->fetch_assoc($query);
if(password_verify($password, $user['password'])){
$_SESSION['user'] = $user;
header('location: '.$user['user_type'].'Panel.php');
exit;
}else{
//password error
}
}else{
//username error
}
}
Personally I only use PDO these days. It's been several years sense I used MySqli (so forgive me if I got anything wrong here).
For PDO, this is how I connect with it:
$dsn = 'mysql:dbname=database;host=localhost';
$user = 'user';
$pass = 'pass';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
try{
$PDO = new PDO($dsn, $user, $pass, $options);
}catch(PDOException $e){
//only show end user error codes
die("Error[{$e->getCode()}] connection to DB");
}
The options turn on, Exception error reporting and set the default fetch mode to fetch associative array. With those settings the same thing as above can be done like this:
//session_start(); //make sure this is called
function login($username, $password, \PDO $Pdo) //use type hinting
{
try{
$stmt = $Pdo->prepare('SELECT * FROM tbl_user WHERE username = :username');
$stmt->execute([':username' => $username]);
if($stmt->rowCount()){
$user = $stmt->fetch();
if(password_verify($password, $user['password'])){
$_SESSION['user'] = $user;
header('location: '.$user['user_type'].'Panel.php');
exit;
}else{
//password error, return an error, or throw an exception etc.
}
}else{
//username error
}
}catch(PDOException $e){
//only show end user error codes
die("Database Error[{$e->getCode()}]");
}
}
If you notice it takes around 5 calls to MySqi, and PDO takes only 3 calls. Besides that MySqi is dealing with 3 objects (mysqli, mysqli_stmt, mysqli_result), PDO deals with only 2 (PDO, PDOStatment). Error reporting is also much cleaner.
A few other notes.
use password_hash($plaintext, algo) to create hashes
use password_verify($plaintext, $hash) to check passwords (note plaintext)
use prepared statements
Do not lookup by password, it's not a secure way of verifing 2 hashes are the same (casing, encoding etc...)
use session_start() before using $_SESSION
Do not output anything (not even a single space) before using header
call exit; after using header as it doesn't exit the script it's called in, so it can run code beneath it and produce unexpected results
avoid using global it can be hard to debug your code, instead use dependency injection (pass in the DB connection)
use DRY principals (Dont Repeat Yourself)
And there is probably a bunch of stuff I am forgetting.
UPDATE
Based on the code you added, the part that handles the form submission can be done like this:
<?php
error_reporting(E_ALL); //unclear
ini_set('display_errors', '1');
require_once 'core/init.php';
if(true === logged_in()) { //put constant values on the left
header('location: dashboard.php');
}
if('POST' == $_SERVER['REQUEST_METHOD']){ //put constant values on the left
//ternary condition (shorthand if then)
$username = empty($_POST['username']) ? false : $_POST['username'];
$password = empty($_POST['password']) ? false : $_POST['password'];
//PHP7+ null coalescing can be used instead of above
//$username = $_POST['username'] ?? false;
if(!$username) {
echo "Username Field is Required <br />";
}
if(!$password) {
echo "Password Field is Required <br />";
}
if($username && $password) {
login($username, $password);
//don't forget the connection, if you use the functions without
//it as a global, (which I refuse to use). I once spent a week
//tracking down changes to a global variable in some code I was fixing, never again.
// global $connect;
// login($username, $password, $connect);
}
}
You don't need to do redirects after calling login it's already doing them. You don't need to check if the user exists because you are already checking when fetching there saved password. If you need to know that information there you can either throw exceptions (to much to cover) or you can have the login function return them. In the case that the login is successfule the code will exit before the errors can return.
Summery
My best guess, barring any errors (and assuming the session is started) is that this is happening
form submission, to self
call to login()
everything works, call to header('location: adminPanel.php'); (with no exit)
code returns to the form page (because no exit)
call to header('location: dashboard.php'); And exit();
But that is just a guess, because when yo say "when I press the login button nothing happen" that can mean many things.
One of these days I will put a tutorial for something like this on my website, but it will be more comprehensive.
Anyway, hope it helps you.

PHP/MySQL Login Page Not Redirecting

I'm trying to create a login page that queries the database to check if the username and password are valid and allowing access to the following pages using sessions. Currently, I'm just using XAMPP to test the login. This is the following code I have in a PHP page.
<?php
include("config.php");
session_start();
// Check for POST method
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = stripslashes($_POST['username']);
$username = mysqli_real_escape_string($con, $username);
$password = stripslashes($_POST['password']);
$password = mysqli_real_escape_string($con, $password);
//Search database for username and password
$stmt = $con->prepare("SELECT * FROM users
WHERE username = ? LIMIT 1"); // Prepared statement
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_object();
if(password_verify($_POST['password'], $user->password)) {
echo("working");
$_SESSION['loggedin'] = true;
$_SESSION['user'] = $user->username;
header("Location: index.php");
} else {
echo("no user");
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Login</title>
</head>
<body>
<form id="loginForm" method="post" action="">
<input type="text" name="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<input type="submit" name="submit" value="Login">
</form>
</body>
</html>
I added an echo statement just to see if it would output "no user" for both user/passwords sets in the database and not in it. They both display "no user" so I don't think I'm searching the database correctly. I'm sort of new to PHP and I used this code.
UPDATE
Thanks to comments, fixed passwords so that they were hashed.
When it still was not working:
Set password datatype in database to VARCHAR(60), recommended VARCHAR(255)
I realized it was because I had password datatype set to VARCHAR(40). Since I was using bycrypt to hash, it is a 60 character string. I set my password to the recommended VARCHAR(255) in case I decided to use PASSWORD_DEFAULT in the future. I failed to realize this is all mentioned in password_hash() documentation when initially creating the database and fields.
Added session_start() to all pages referencing $_SESSION[]
Echoed var_dump() to display the result of password_verify() that returned true when I entered the correct information, however, the page stil kept redirecting me to login. In the PHP I was redirecting to I had this section of code:
<?php
if($_SESSION['loggedin'] == false) {
header("Location: login.php");
} else {
}
?>
I forgot to put session_start(); in the PHP page so it kept redirecting me to the login.

PHP redirect works in Chrome but not other browsers

SO I am trying to learn myself MVC via the help of a book. Im still at a very basic level so please keep that in mind should you be kind enough to answer.
This is part of my application layout:
Now I have a simple login form
<form method="post" action="index.php">
<input type="text" name="action" value="login" style="display: none">
<label for="email">Email</label>
<input type="email" required="required" name="email" id="email" placeholder="Enter Your Email" />
<br />
<label for="password">Password</label>
<input type="password" required="required" name="password" id="password" placeholder="Enter Your Password" />
<button type="submit" name="submit">Login</button>
</form>
Note the first field name="action" value="login" since the redirect is dependent on that specific field.
MODEL
users_db.php
function login($email, $pword)
{
$sql = "SELECT * FROM users WHERE email = :email AND pword = :pword ";
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':email', $email);
$stmnt->bindValue(':pword', $pword);
$stmnt->execute();
if ($stmnt->rowCount() > 0) {
return $stmnt->fetchAll();
} else {
return null;
}
}
Directory - users
index.php servers as controller. The following is a partial extract of the "controller" and is where the problem occurs.
require_once('../config/db.php');
require_once('../model/users_db.php');
if(isset($_POST['action'])) {
$action = $_POST['action'];
if ($action == 'login') {
$email = htmlspecialchars($_POST['email']);
$pword = htmlspecialchars($_POST['password']);
$users = login($email, $pword);
if (is_array($users)) {
foreach ($users as $user) {
session_start();
$_SESSION['firstname'] = $user['firstname'];
$_SESSION['lastname'] = $user['lastname'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['userType'] = $user['userType'];
$_SESSION['userID'] = $user['userID'];
header('Location:welcome.php');
die();
}
APP FLOW / STEPS
User enters email and password in the form.
Form info gets passed to index.php the "controller" which includes email, pword. and hidden input field value
Inside the index.php file the controller checks whether the hidden input field action value is set to login which it is.
If login is set it calls the login function from the users_db model, which queries db and returns all user info .
Assuming correct email & pword is enterd, index.php redirects user to a welcome page and exit()
The following works perfectly in Chrome but all other browsers redirects to a 404 error index.php not found. This is rather strange for me, would greatly appreciate it if anyone can provide some input as to why the above error occurs?
Try this
error_reporting(E_ALL | E_WARNING | E_NOTICE);
ini_set('display_errors', TRUE);
flush();
header("Location: http://www.website.com/");
echo '<script>window.location.replace("http://www.example.com")</script>';
die('should have redirected by now');
PHP redirects use header codes to tell the browser to redirect. But if your PHP code echo (even a warning) before that header location, some browsers won't redirect.
In the above code it flushes everything and send the header location. It also tell browser to redirect using javascript, so it will work even the php header redirect didn't work.
Hope it helps
There are more than one problems with that code, other than the redirection.
The reason why the header function doesn't work is because the header needs to have an absolute URL, like http://www.example.com/replace.php, besides that, there needs to be a space between the Location: header name and the value, like:
header('Location: http://www.example.com/replace.php').
Note that in order to set a response header using the header function, no previous headers should've been sent, if you have anything as small as a space that is returned before you call the header function, it won't work.
Now, let's talk about the rest of the problems that this code has:
1 - The session_start() function needs to be called at the top of your page, way before you start working with the $_SESSION superglobal.
2 - You're calling die() in a foreach loop, meaning your code will iterate through the array only a single time and then the code will halt. Move the die() call outside of the loop.
3 - Validate the input using the filter_val function (http://php.net/manual/ro/function.filter-input.php) ~ I'm talking mostly about the email, but I think you can apply it to other inputs as well.
4 - Don't store the password in plain text format, use the password hashing API that PHP offers (https://www.sitepoint.com/hashing-passwords-php-5-5-password-hashing-api/)
Possibly another solution:
users_db.php
function login($email, $pword)
{
$sql = "SELECT * FROM users WHERE email = :email AND pword = :pword LIMIT 1";
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':email', $email);
$stmnt->bindValue(':pword', $pword);
$stmnt->execute();
if ($stmnt->rowCount() > 0) {
return $stmnt->fetchAll();
} else {
return null;
}
}
index.php
require_once('../config/db.php');
require_once('../model/users_db.php');
if(isset($_POST['action'])) {
$action = $_POST['action'];
if ($action == 'login') {
$email = htmlspecialchars($_POST['email']);
$pword = htmlspecialchars($_POST['password']);
$user = login($email, $pword);
if ($user != null) {
session_start();
$_SESSION['firstname'] = $user['firstname'];
$_SESSION['lastname'] = $user['lastname'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['userType'] = $user['userType'];
$_SESSION['userID'] = $user['userID'];
header('Location: welcome.php');
echo '<script>window.location.replace("http://www.example.com")</script>';
die();
}
}
}
At the end die() function in foreach --> remove it and then try.
Please check if your php code did not have error, and
look for white space after :
ex: header('Location: welcome.php');

How do I check the password?

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

Login page, not working

I am still learning php and i stuck on an error that i can not find.
So i have a simple form with an email and password. I am hashing the password with a random salt key and sha512 and the hased password is behind the variable "p".
Here is the html code:
<form action="includes/process_login.php" method="post" name="login_form">
<input placeholder="Email address" type="text" name="email" id="email">
<input placeholder="Password" type="password" name="password" id="password">
<button class="button" onclick="formhash(this.form, this.form.password);">Login</button>
</form>
Okay and here is the js file with the function:
function formhash(form, password) {
// Create a new element input, this will be our hashed password field.
var p = document.createElement("input");
// Add the new element to our form.
form.appendChild(p);
p.name = "p";
p.type = "hidden";
p.value = hex_sha512(password.value);
// Make sure the plaintext password doesn't get sent.
password.value = "";
// Finally submit the form.
form.submit();
}
I have the query here:
function login($email, $password, $mysqli) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, password, salt
FROM users
WHERE email = ?
LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $db_password, $salt);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
And the process_login.php file:
if (isset($_POST['email'], $_POST['p'])) {
$email = $_POST['email'];
$password = $_POST['p']; // The hashed password.
if (login($email, $password, $mysqli) == false) {
// Login success
header('Location: ../desk.php');
} else {
// Login failed
header('Location: ../index.php?error=1');
}
} else {
// The correct POST variables were not sent to this page.
echo 'Invalid Request';
}
And i think that the error is somewhere in the process_login.php file but i cant find it. Everything seems fine to me, but when i try to login with some existing credentials i see: "Invalid Request" which means that the variables were not send and it is a mistery for me why...
You are severely misusing the hash function. When your function sends a hash of the password, this hash effectively becomes a password. That is your essentially achieving nothing by hashing the password before transmition.
If you want a secure login form you should have communications to your site encrypted with TLS (HTTPS).
An alternative is Secure remote password but this is surely too complex to implement.
I recommend not to hash your password with javascript since javascript is executing on client side. So users can manipulate the input!
I recommend to hash the password with php (server side). Maybe with md5 or something else.
Remove the onClick event in the form:
<form action="includes/process_login.php" method="post" name="login_form">
<input placeholder="Email address" type="text" name="email" id="email">
<input placeholder="Password" type="password" name="password" id="password">
<button class="button" type="submit">Login</button>
</form>
After that you can simply delete the javascript function formhash.
Then you have to change the PHP-Script:
process_login.php
if (isset($_POST['email'], $_POST['password'])) {
$email = $_POST['email'];
$password = hash('sha512', $_POST['password']); // The hashed password (sha512)
if (login($email, $password, $mysqli) == false) {
// Login success
header('Location: ../desk.php');
} else {
// Login failed
header('Location: ../index.php?error=1');
}
} else {
// The correct POST variables were not sent to this page.
echo 'Invalid Request';
}

Categories