0

For learning purposes I am trying to implement a simple, PDO-based, single user login script with hashed passwords as an upgrade to MD5, which is stored in a MySQL database, following this tutorial. The script works, I am able to login and out with the correct login credentials, but every time I get the following error message:

Notice: Trying to get property of non-object in /var/www/login.php on line 23

line 23 in login.php is if ( crypt($password, $user->hash) == $user->hash ) { //

I already tried if( ! $user = $sth->fetch(PDO::FETCH_OBJ) ) {die('no rows returned');} which returns 'no rows returned', ie. no object is fetched. var_dump($user); returns bool(false).

This is how I hash the password:

$username = 'YourUsername';
$password = 'YourPassword';

// A higher "cost" is more secure but consumes more processing power
$cost = 10;

// Create a random salt
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');

// Prefix information about the hash so PHP knows how to verify it later.
// "$2a$" Means we're using the Blowfish algorithm. The following two digits are the cost parameter.
echo $salt = sprintf("$2a$%02d$", $cost) . $salt;

// Value:
// $2a$10$IkCxeZMOEYCWFDsZ2zYvFA==

// Hash the password with the salt
echo $hash = crypt($password, $salt);

// Value:
// $2a$10$IkCxeZMOEYCWFDsZ2zYvF.gMDDP.ttroo0U9YDPlp6GiXxt02.JSy

$hash is then saved in table 'users' of the MySQL database:

CREATE TABLE users(
    id INT AUTO_INCREMENT,
    username varchar(65) UNIQUE NOT NULL,
    hash varchar(123) NOT NULL,
    first_name varchar(50) NOT NULL,
    last_name varchar(50) NOT NULL,
    email_address varchar(100) NOT NULL,
    PRIMARY KEY (id)
);

INSERT INTO users ( username, hash, first_name, last_name, email_address ) 
VALUES ( 'YourUsername', '$2a$10$IkCxeZMOEYCWFDsZ2zYvF.gMDDP.ttroo0U9YDPlp6GiXxt02.JSy', 'YourName', 'YourLastName', 'test@example.com' );

This is the login.php, where the error occurs on line 23:

<?php 

include 'blog.php';

session_start();

$status = '';

if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {

    $username       = $_POST['username']; 
    $password       = $_POST['password']; 

    $sth = $conn->prepare('SELECT hash FROM users WHERE username = :username LIMIT 1');

    $sth->bindParam(':username', $username);

    $sth->execute();

    $user = $sth->fetch(PDO::FETCH_OBJ);

    // Hashing the password with its hash as the salt returns the same hash
    if ( crypt($password, $user->hash) == $user->hash ) {

        $_SESSION['username'] = $username;
        header("Location: admin/index.php");
    }
        else 
    {
        $status="Your Login Name or Password is invalid.";
    }

}

view_login("login/login", array("status" => $status));

PDO is pulled in through blog.php and db.php:

blog.php

<?php 

require 'functions.php';
require 'db.php';

// Connect to the db
$conn = Blog\DB\connect($config);
if ( !$conn ) die('Problem connecting to the db.');

db.php

<?php namespace Blog\DB;

require 'config.php';

function connect($config)
{
    try {
        $conn = new \PDO($config['DB_HOST'], 
                         $config['DB_USERNAME'], 
                         $config['DB_PASSWORD']);

        $conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        return $conn;
    } catch(Exception $e) {
        return false;
    }
}

config.php

<?php

// Database configuration
$config = array(
    'DB_HOST'       =>  'mysql:host=localhost;dbname=blog',
    'DB_USERNAME'   =>  'YourUsername', 
    'DB_PASSWORD'   =>  'YourPassword'
);

I would appreciate your advise how to fix this error.

Secondly, do you consider this a safe login method considering a single user system without registration option?

  • It seems to me that your fetch(PDO::FETCH_OBJ) is returning false or as in php.net comments returns NULL. Does query work on db? – skywalker Mar 05 '14 at 00:07
  • Sidenote: Missing quote in `'YourName', 'YourLastName,` unless it's a typo. – Funk Forty Niner Mar 05 '14 at 00:13
  • @skywalker Query works within the database, which has another table with posts that are displayed without problems. The missing quote is just a typo. The strange thing is that I am able to login and -out using the credentials, so there must be a connection. –  Mar 05 '14 at 00:20
  • I use a similar method with `crypt()` and this is what I use if it will help `if (crypt($password, $row['pass']) === $row['pass'])` @MrNerdy – Funk Forty Niner Mar 05 '14 at 00:23
  • @Fred -ii- Could you please provide the full PDO-statements? –  Mar 05 '14 at 00:31
  • 1
    I'll go one better. Have a look at [`an answer I gave`](http://stackoverflow.com/a/22152805/) using the same as noted above. @MrNerdy If you can base yourself on that, great. Maybe an upvote would be nice, but not obligatory. If I can help any way I can, great. – Funk Forty Niner Mar 05 '14 at 00:34
  • 1
    @Fred-ii- Excellent work, jeeves! +2 – Ohgodwhy Mar 05 '14 at 00:38

1 Answers1

-1

Have you tried checking your return values?

// check your return value here
$sth = $conn->prepare('SELECT hash FROM users WHERE username = :username LIMIT 1');
// check your return value here
$sth->bindParam(':username', $username);
// check your return value here
$sth->execute();
// check your return value here
$user = $sth->fetch(PDO::FETCH_OBJ);

In summary, check your return values. eg:

if( ! $sth = $conn->prepare('SELECT hash FROM users WHERE username = :username LIMIT 1') ) {
  die($conn->errorInfo());
}

if( ! $sth->bindParam(':username', $username) ) {
  die($sth->errorInfo());
}

if( ! $sth->execute() ) {
  die($sth->errorInfo());
}

if( ! $user = $sth->fetch(PDO::FETCH_OBJ) ) {
  die('no rows retrurned');
}

Replace die() calls with whatever error reporting style you like.

Sammitch
  • 30,782
  • 7
  • 50
  • 77
  • Trying your debugging code, the only message I am getting is `no rows returned`, ie. $user = $sth->fetch(PDO::FETCH_OBJ) fails. –  Mar 05 '14 at 00:50
  • @MrNerdy then your query is returning zero rows, double check that. Does `$username` contain what you expect it to? – Sammitch Mar 05 '14 at 00:52
  • `$username` contains the user-supplied username as in `$username = $_POST['username']; `. Echoing $username correctly returns the respective input, so that works. The question is why the query returns zero rows. –  Mar 05 '14 at 00:59