Coverting PHP login script to use prepared statements - php

I'm trying to learn to convert a PHP login page to use prepared SQL statements with parameters versus just using standard script to protect from SQL injection. Its for a security class and not a programming class and my PHP is weak and be will evident. I can't figure out why I'm not getting any results from the execution. Its using PDO, and I've switch from bindParam to bindValue as suggested on other topics, but I still get a black page from the login.
My db connection is working, and I think my SQL statement and parameters are correct. I really believe the problem is in retrieving the results. Can anyone help why I can get a row count? I've also tried with $stmt->count_rows
<html>
<body>
<?php
$db_hostname = 'localhost';
$db_username = 'testuser';
$db_password = '1234';
$db_dbname = 'testdb';
$db_tablename = 'users';
$db_conn_str = "mysql:host=" . $db_hostname . ";dbname=" . $db_dbname;
try {
$db = new PDO($db_conn_str, $db_username, $db_password);
$stmt = $db->prepare("Select * from users where login = ? and passwd = ?");
$stmt->bindValue(1, $_POST['username']);
$stmt->bindValue(2, $_POST['password']);
$stmt->execute();
$stmt->store_result();
$result = $stmt->fetchAll();
$num = $result->rowCount();
$stmt->close();
}
catch (PDOException $e) {
echo "Error in PDO: " . $e->getMessage();
}
if ($num == 0) {
echo "login failed! <br />";
} else {
$name = $result->fetchColumn(0);
echo "Welcome, $name!<br />";
}
?>

A few issues.
Syntax error after $db_hostname='localhost'
PDO does not have a store_result() method, that's a mysqli method.
Turn off emulated prepared querys. ATTR_EMULATE_PREPARES
You need to also tell PDO to throw Exceptions else it wont ERRMODE_EXCEPTION
Also $result->fetchColumn(0); will fetch the first column so presuming that id your welcome message would say Welcome, 1.
Just count fetchAll() instead of rowCount().
Don't forget htmlentities() to protect against stored XSS
Below is changed code:
<?php
$db_hostname='localhost';
$db_username='testuser';
$db_password='1234';
$db_dbname='testdb';
$db_tablename='users';
$db_conn_str="mysql:host=" . $db_hostname . ";dbname=" . $db_dbname;
try {
$db = new PDO($db_conn_str, $db_username, $db_password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $db->prepare("SELECT * FROM users WHERE login = ? AND passwd = ?");
$stmt->bindValue(1, $_POST['username']);
$stmt->bindValue(2, $_POST['password']);
$stmt->execute();
$result = $stmt->fetchAll();
if (count($result) == 0) {
echo "login failed! <br />";
} else {
echo "Welcome, ".htmlentities($result[0]['name'])."!<br />";
}
$stmt->close();
} catch (PDOException $e) {
echo "Error in PDO: " . $e->getMessage();
}
?>
You should also look into using password_* based functions instead of storing your passwords as plaintext.
Hope it helps.

Related

PHP bindParam not working - blindValue is not the solution

I can't figure this out. I've googled it and a lot of answers refer to blindValue as the solution but I've also tried that with no luck.
The problem is that the SELECT statement is returning zero records but it should return one record. If I hard code the values into the SQL statement it works but passing them in as parameters isn't. Can some one please help me out with this? Thanks.
<?php
function checklogin($email, $password){
try
{
// Connection
$conn;
include_once('connect.php');
// Build Query
$sql = 'SELECT pkUserID, Email, Password, fkUserGroupID FROM tbluser WHERE Email = :email AND Password = :password';
// $sql = 'SELECT pkUserID, Email, Password, fkUserGroupID FROM tbluser WHERE Email = "a" AND Password = "a"';
// Prepare the SQL statement.
$stmt = $conn->prepare($sql);
// Add the value to the SQL statement
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':password', $password, PDO::PARAM_STR);
// Execute SQL
$stmt->execute();
// Get the data in the result object
$result = $stmt->fetchAll(); // $result is NULL always...
// echo $stmt->rowCount(); // rowCount is always ZERO....
// Check that we have some data
if ($result != null)
{
// Start session
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Search the results
foreach($result as $row){
// Set global environment variables with the key fields required
$_SESSION['UserID'] = $row['pkUserID'];
$_SESSION['Email'] = $row['Email'];
}
echo 'yippee';
// Return empty string
return '';
}
else {
// Failed login
return 'Login unsuccessful!';
}
$conn = null;
}
catch (PDOexception $e)
{
return 'Login failed: ' . $e->getMessage();
}
}
?>
the connect code is;
<?php
$servername = 'localhost';
$username = 'admin';
$password = 'password';
try {
// Change this line to connect to different database
// Also enable the extension in the php.ini for new database engine.
$conn = new PDO('mysql:host=localhost;dbname=database', $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// echo 'Connected successfully';
}
catch(PDOException $e)
{
echo 'Connection failed: ' . $e->getMessage();
}
?>
I'm connecting to mySQL. Thanks for the help,
Jim
It was a simple but stupid error.
I had a variable called $password also in the connect.php file which was overwriting the $password that I was passing to the checklogin.
Jim

How do I make an if statement which checks if a variable is in the mysql database

try {
$conn = new PDO("mysql:host=" . $_GLOBALS['servername'] . ";dbname=". $_GLOBALS['dbname'], $_GLOBALS['username'], $_GLOBALS['password']);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM us WHERE username='$suser' and password='$shashpass'"; // SQL Query
$conn->exec($sql);
Thats some of my code, how do I make it so if suser and shashpass are correct it can
execute some code, else it executes other code
This won't work either
<?php
try
{
$conn = new PDO("mysql:host=" . $_GLOBALS['servername'] . ";dbname=". $_GLOBALS['dbname'], $_GLOBALS['username'], $_GLOBALS['password']);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $con->prepare("SELECT * FROM us WHERE username=:user and password=:password"); $query->bindParam(':user',$suser);
$query->bindParam(':password',$shashpass); $query->execute(); $result = $query->fetch(PDO::FETCH_ASSOC);
if(!empty($result)){ } else { } }
catch(PDOException $e) {
echo $sql . $e->getMessage();
}
You don't pre-hash the password when verifying it. Instead you SELECT the password hash from that user (if it exists) and then use password_verify() to verify that it's correct based on the plain text password sent by the web form.
$stmt = $conn->prepare("SELECT password FROM us WHERE username=?");
$stmt->execute([$suser]);
if ($user = $stmt->fetch(PDO::FETCH_ASSOC)) {
if (password_verify($plain_text_password, $user['password'])) {
// Successful login
}
else {
// Valid user, but invalid password
}
}
else {
// User doesn't exist
}
If you're not using password_hash() and password_verify(), You're Doing It Wrong™.
you are using PDO in wrong way , you need to use prepared statements in PDO to be secure from mysql injections, try to use the code below:
try {
$conn = new PDO("mysql:host=" . $_GLOBALS['servername'] . ";dbname=". $_GLOBALS['dbname'], $_GLOBALS['username'], $_GLOBALS['password']);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $con->prepare("SELECT * FROM us WHERE username=:user and password=:password");
$query->bindParam(':user',$suser);
$query->bindParam(':password',$shashpass);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
if(!empty($result)){
// user is in database
} else {
// user is not there
}
exec will return the number of affected rows so:
$rows = $conn->exec($sql);
if($rows > 0){
//suser and shashpass are correct
}else{
//suser and shashpass are incorrect
}
//Use below PDO code
<?php
try {
$conn = new PDO("mysql:host=$servername;dbname=myDB", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected successfully";
$sql = "SELECT * FROM us WHERE username='$suser' and password='$shashpass'";
// SQL Query
$conn->exec($sql);
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
?>

PHP PDO:Login System

I am working on a PHP PDO Login system but i keep getting an error, perhaps some part of my code is incorrect.
//LOG IN VERIFICATION
if (isset($_POST['username'],$_POST['pass'])) {
try {
$con = new PDO("mysql:host=" . host . ";dbname=" . database, user, auth);
$con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (!empty($_POST['username'])&& !empty($_POST['pass'])) {
//username and password sent from Form
$usernames = trim($_POST['username']);
$password = $_POST['pass'];
$select= $con -> prepare("SELECT username,password FROM users WHERE username='$username' AND password='$password'");
$select ->execute();
$results = $select->fetch(PDO::FETCH_ASSOC);
if (count($results) > 0 && password_verify($password, $results['password'])) {
header('location:home.php');
} else{
header('location:login.php');
}
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
I suspect the error to be here
$select= $con -> prepare("SELECT username,password FROM users WHERE username='$username' AND password='$password'");
$select ->execute();
$results = $select->fetch(PDO::FETCH_ASSOC);
because i verified the connection to the database. Any help will be appreciated.
You're assigning to $usernames, not $username. However, the real problem is count($results) - you cannot count the rows this way. Which means, the count will be 0, hence the else branch is executed. See here: Row count with PDO.
Edit: In such cases, simply debug your code and var_dump(count($results)), for example. You have a simple if statement - if an unexpected branch is executed, something is wrong with the if condition.

Mysqli to PDO conversion

I recently started using PDO a few days ago and am changing all my mysqli code but I seem to have hit a brick wall. Now this code worked beautifully when I was using mysqli, but now I can't seem to print out the result. This code basically takes the input value of password, and that of the hashed password in the database, matches them and if both are equal then the user will be logged in. My problem is that I can't seem to find a way to get the password from my database. Any help would be much appreciated. Thank you.
<?php
session_start();
$user = "root";
$pass = "";
$mcon = new PDO('mysql:host=localhost;dbname=rabbit_users', $user, $pass);
try {
$mcon = new PDO('mysql:host=localhost;dbname=rabbit_users', $user, $pass);
$mcon->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
//prepare statement
$password = $_POST['password'];
$stmt = $mcon->prepare("SELECT `password` FROM members WHERE password=:password");
$stmt->bindParam(":password", $_POST['password']);
$stmt->execute();
//get_result
$data_array = $stmt->fetchAll();
$stmt->fetch(PDO::FETCH_ASSOC);
//echo passwords
print 'Password from form: ' . $password . '<br />';
print 'Password from DB: ' . $data_array['password'] . '<br />';
//verify password
if (password_verify($password, $data_array['password'])) {
print 'success';
exit();
}else{
print 'Try again m9';
exit();
}
fetchAll returns an array containing all of the result set rows. So you can access to password with $data_array[0]['password'] if you used it.
You may want use fetch instead.
$data_array = $stmt->fetch(PDO::FETCH_ASSOC);

Can I include one pdo connection

Im a just moving to using PDO for my development and I see in most tutorials that the connection is opend for each db query like in Jeffery Ways example below
$id = 5;
try {
$conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch()) {
print_r($row);
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
Can I still do a connection in an external file and include it at the top of my page like with previous procedural coding and then do my queries below in the page?
<?php include 'includes/db.php';?>
You probably misunderstood what he says. To open one connection and use it throughout the whole application is not that something you "can" but actually you should.
So - yes, you are doing it right.
Also note that this thing with
try {
...
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
that Jeffery taught you is wrong. Never use a try catch to echo an error message. PHP will handle it better
So, your code should be like this
include 'includes/db.php';
$stmt = $pdo->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch()) {
print_r($row);
}
while db.php has to contain something like this
<?php
$dsn = "mysql:host=localhost;dbname=test;charset=utf8mb4";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$pdo = new PDO($dsn, $username, $password, $opt);
Also note that when using this PDO object, you have to be aware of the variable scope.
Further reading: https://phpdelusions.net/pdo
The short answer is yes,
if you are farmilier with OOPHP it might be worth creating a wrapper class to help with running queries but just creating the connection in a file and including it will get the job done
in the above example you can put
try {
$conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
into your db.php and the run the queries
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
wherever you need.
it may also be worth mentioning that you dont have to use prepared statements with PDO which can speed things up in coding however if you wish to do that i would highly recomend a database wrapper class
non prepared statement
<?php
try {
$conn = new PDO('mysql:host=localhost;dbname=myDatabase', $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$query = "
SELECT
col_1,
col_2
FROM
table_1
WHERE
col_3 = " . $conn->quote($_POST['input']); //the quotr is important, it escapes dangerous characters to prevent SQL injection
//this will run the query for an insert this is all thats needed
$statement = $conn->query($query);
//fetch single col
$col = $statement->fetch(PDO::FETCH_ASSOC);
//fetch all collums
$cols = $statement->fetchAll(PDO::FETCH_ASSOC);
the advantage of this way is that you can build up the query SQL in a more simple to follow manner, i should not that i havent tested this code but in theory it should be fine as this is how i do database handling
Edit:
Your Common Sense brings up a good point about the echo 'ERROR: ' . $e->getMessage(); being a bad idea and this is a prime example of why you should NEVER blindly copy and paste code
Yes, example:
db.php
<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
?>
FROM:
http://www.php.net/manual/en/pdo.error-handling.php
Then just include db.php. I name my connection $PDO, seems more implicit, especially when you are building a prepared statement on that.

Categories