0

I'm still fairly new to the prepared statements because it was brought to my attention by another user. I've been able to create a registration function that properly prepares the statement, binds it and then executes it. It goes into the database just fine. However, I'm not sure I understand how the login part would work. I'm trying to fetch a row and the result I keep getting is "1" but not the row + data inside the row. Any advice?

Database: Picture of database

login.php (where the form is located)

<form id="loginform" class="form-horizontal" role="form" action="" method="post">

    <div style="margin-bottom: 25px" class="input-group">
        <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
        <input id="login-username" type="text" class="form-control" name="Lusername" placeholder="Username or Email">                                        
    </div>

    <div style="margin-bottom: 25px" class="input-group">
        <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
        <input id="login-password" type="password" class="form-control" name="Lpassword" placeholder="Password">
   </div>

   <div class="input-group">
       <div class="checkbox">
           <label>
           <input id="login-remember" type="checkbox" name="remember" value="1"> Remember me
           </label>
       </div>
   </div>

   <div style="margin-top:10px" class="form-group">
   <!-- Button -->

       <div class="col-sm-12 controls">
       <button id="btn-login" type="submit" class="btn btn-success"><i class="icon-hand-right"></i>Submit</button>
       </div>
   </div>
</form>    

script:

    <script type="text/javascript">
        $(function() {
            $("#loginform").bind('submit',function() {
                var username = $('#login-username').val();
                var password = $('#login-password').val();
                $.post('scripts/loginFunction.php',{username:username, password:password}, function(data){
                    $('#signupsuccess').show();
                }).fail(function(){{
                    $('#signupalert').show();
                }});
                return false;
            });
        });
    </script>

loginFunction.php

<?php
require 'connection.php';
$username = $_POST['username'];
$password = $_POST['password'];

if($conn->connect_error){
    die("Connection failed: " . $conn->connect_error);
}

$stmt = $conn->prepare("SELECT `Username`, `Password` FROM `users` WHERE `Username` = ?");
$stmt->bind_param('s',$username);
$stmt->execute();
$stmt->store_result();
echo $stmt->num_rows;
/*if($stmt->num_rows == 1){
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    print_r($row);
    // here is where you could verify the password
    if(password_verify($password, $row['Password'])) {
        // good password
        echo 'all good!';
    }
} else {
    //echo "failed to find row";
}*/
?>

loginFunction.php that does work and queries the database properly

require 'connection.php';
$username = $_POST['username'];
$password = $_POST['password'];

if($conn->connect_error){
    die("Connection failed: " . $conn->connect_error);
}
$query = "SELECT * FROM users WHERE username='$username'";
$result = $conn->query($query);
if($result->num_rows == 1){
    $row = mysqli_fetch_array($result);
    if(password_verify($password, $row['Password'])){
        echo "Login successful!";
    }
    else{
        echo "Login failed.";
    }
}

EDIT: Here is the code you should use. Note how $stmt is carried throughout:

$stmt = $conn->prepare("SELECT `Username`, `Password` FROM `users` WHERE `Username` = ?");
$stmt->bind_param('s',$username);
$stmt->execute();
$stmt->store_result();
echo $stmt->num_rows;
/*if($stmt->num_rows == 1){
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    print_r($row);
    // here is where you could verify the password
    if(password_verify($password, $row['Password'])) {
        // good password
        echo 'all good!';
    }
} else {
    //echo "failed to find row";
}*/
Chromatic
  • 87
  • 1
  • 1
  • 8
  • 2
    Don't mix `mysqli` with `mysql` use `$result->fetch_assoc()` – apokryfos Jan 24 '17 at 14:54
  • 4
    **Never store plain text passwords!** Please use PHP's [built-in functions](http://jayblanchard.net/proper_password_hashing_with_PHP.html) to handle password security. If you're using a PHP version less than 5.5 you can use the `password_hash()` [compatibility pack](https://github.com/ircmaxell/password_compat). Make sure you ***[don't escape passwords](http://stackoverflow.com/q/36628418/1011527)*** or use any other cleansing mechanism on them before hashing. Doing so *changes* the password and causes unnecessary additional coding. – Jay Blanchard Jan 24 '17 at 14:55
  • You are selecting literal strings instead of the values in the database columns. And the sql suggests that you are using plain-text passwords. You really shouldn't. Also note that unless you are on a windows server, `Username !== username`. – jeroen Jan 24 '17 at 14:55
  • 2
    To echo what @jeroen is saying: column and table names should be back-ticked, not quoted. – Jay Blanchard Jan 24 '17 at 14:56
  • To clear things up, the passwords are hashed in the registration. I use password_hash(String, PASSWORD_DEFAULT) but when I'm trying to use password_verify() it's not getting the databases string properly – Chromatic Jan 24 '17 at 14:56
  • Is `$password` the submitted password? – Jay Blanchard Jan 24 '17 at 14:58
  • I'm not sure I understand what you mean, can you give an example or at least highlight the row where I'm going wrong? I've fixed the mysqli as spotted by apokryfos – Chromatic Jan 24 '17 at 14:58
  • Yes, $password is the password that is entered by the user. – Chromatic Jan 24 '17 at 14:58
  • 1
    If you use that to select from the database you will never get a result because the hashed password is stored in the database. Get rid of `AND password = ...` then fetch the hashed password to compare to the user submitted password with `password_verify()`. For example `password_verify($_POST['password'], $hashed_password)` – Jay Blanchard Jan 24 '17 at 15:00
  • Okay, I've removed the password part but I keep getting this error: Trying to get property of non-object. It seems to be coming from this piece of code: if($result->num_rows == 1){ $result->fetch_assoc(); echo $row; } – Chromatic Jan 24 '17 at 15:02
  • Did you change `bind_param` when you removed the password from the query? – Jay Blanchard Jan 24 '17 at 15:04
  • I've updated the code above to reflect all the changes you guys have made. – Chromatic Jan 24 '17 at 15:05
  • You still have quotes around the column names. `'Username', 'Password'` – Jay Blanchard Jan 24 '17 at 15:06
  • Removed quotes, still same occurring error. When I echo $result it just gives "1" still – Chromatic Jan 24 '17 at 15:07
  • Should I be using bind_result at all? I've seen it around and have tried it but it never seemed to work correctly. – Chromatic Jan 24 '17 at 15:10
  • You don't need bind result. [Did you read this?](http://jayblanchard.net/proper_password_hashing_with_PHP.html) – Jay Blanchard Jan 24 '17 at 15:11
  • Yes I did, but I'm not sure about using PDO. Can I use their coding if I manipulate it into my variables/databases etc? – Chromatic Jan 24 '17 at 15:14
  • You don't have to use PDO - but the principle is the same from the logic standpoint. Your aren't getting any output because you never set `$row`. The code inside your if statement should be `$row = $result->fetch_assoc(); print_r($row);` – Jay Blanchard Jan 24 '17 at 15:17
  • If I do what you say, it comes back with: Fatal error: Call to a member function fetch_assoc() on boolean because $result comes back as a 1. – Chromatic Jan 24 '17 at 15:21
  • Something is wrong with your query then. Can you edit your post and add your MySQL table creation script? – Jay Blanchard Jan 24 '17 at 15:22
  • I haven't got a script to make the table. I'm just using a database that I setup like 3 days ago with various fields. I can take a screenshot of that and include that if that is any help? – Chromatic Jan 24 '17 at 15:24
  • Yes - please do that. – Jay Blanchard Jan 24 '17 at 15:25
  • Now - edit your code to reflect the latest you're using. And use `print_r($row);` not `echo` – Jay Blanchard Jan 24 '17 at 15:33
  • Now I'm getting: Trying to get property of non-object on the if statement. This whole thing is so confusing to me :/ – Chromatic Jan 24 '17 at 15:39
  • I'm sorry for your confusion, it is tough to hash through things like this. Something I obviously missed was this: `WHERE username=` should be `WHERE Username=` (capital U) And you do not need `$stmt -> store_result();` – Jay Blanchard Jan 24 '17 at 15:43
  • Still get the same error regardless of capital letter or not. – Chromatic Jan 24 '17 at 15:44
  • Is `users` the name of the table? Or does it have capitals too? – Jay Blanchard Jan 24 '17 at 15:45
  • users does not have a capital – Chromatic Jan 24 '17 at 15:45
  • Apparently $result is a boolean and not an object, so it's not getting the strings properly from the database for some odd reason. – Chromatic Jan 24 '17 at 15:57
  • Try the code I just added. – Jay Blanchard Jan 24 '17 at 16:00
  • Fatal error: Call to a member function fetch_assoc() on boolean. After adding your code – Chromatic Jan 24 '17 at 16:01
  • Made an edit, replaced `$result` with `$stmt`. – Jay Blanchard Jan 24 '17 at 16:03
  • Fatal error: Call to undefined method mysqli_stmt::fetch_assoc() after replacing the $result. – Chromatic Jan 24 '17 at 16:05
  • Alright, let's try thie new edit. – Jay Blanchard Jan 24 '17 at 16:09
  • Fatal error: Call to a member function fetch_assoc() on boolean still occurring. I officially hate PHP – Chromatic Jan 24 '17 at 16:13
  • Run the above edit and tell me the results. And maybe consider PDO because it isn't as 'lengthy' or as 'wordy' and is much more portable. – Jay Blanchard Jan 24 '17 at 16:16
  • After I run the code, in the network tab under the developer console it literally just says 1 (No quotations) – Chromatic Jan 24 '17 at 16:17
  • I am open to other ideas, I essentially do want to make a login form so if you have a recommendation for me to look at and start over from scratch in terms of the PHP, then I will. – Chromatic Jan 24 '17 at 16:19
  • It should echo 1 out to the web browser. Or are you using AJAX to send variables? If so, we may have been barking up the wrong tree and I would need to see the form your using and the AJAX call. – Jay Blanchard Jan 24 '17 at 16:19
  • Yeah, I'm using AJAX I didn't expect that to be a problem, I'll update the code above to reflect the form and the AJAX – Chromatic Jan 24 '17 at 16:22
  • If the query is coming back as a Boolean then we may not be sending the Username properly. – Jay Blanchard Jan 24 '17 at 16:27
  • Added the login form as well as the AJAX – Chromatic Jan 24 '17 at 16:27
  • How do you get `$username`? – Jay Blanchard Jan 24 '17 at 16:28
  • I just added that now, as in it was in the PHP I just didn't post it in here yet – Chromatic Jan 24 '17 at 16:29
  • OK. Here is what I am going to suggest: use PDO as I have outlined in my post above. I think you'll find it easier and more consistent to use and it will provide you with better error messages and more portability. Focus on the PHP first (leave the jQuery and AJAX out) until you're comfortable with the concepts. Then add the AJAX. You have a lot of moving parts here and without being able to view them I cannot pinpoint where the problem creeps in. – Jay Blanchard Jan 24 '17 at 16:34
  • Could you link me some PDO tutorials? And the reason why I'm using AJAX and Jquery is because it'll look more professional. Would you be happy to go into a discord server with me (Only using text chat) so we can live text rather than spamming this comment section? I have some questions that may be able to clear up the problem a lot faster. – Chromatic Jan 24 '17 at 16:38
  • [Start here](http://jayblanchard.net/demystifying_php_pdo.html). I understand why you're using AJAX, all I am saying is to get the PHP working first, then add the AJAX as an enhancement. I am not able to do chats from the environment where I am. – Jay Blanchard Jan 24 '17 at 16:39
  • If I don't use a prepared statement, it works just fine. If I create a string with $query and then use the method query() then it logs in successfully. It's literally just when I add the prepared statements that the whole thing is not happy anymore. – Chromatic Jan 24 '17 at 16:43
  • `Username = ?` => `Username = :s` – E_p Jan 24 '17 at 18:38
  • Fatal error: Call to a member function bind_param() on boolean Even after changing it. It occurs on the line $stmt->bind_param('s', $username); – Chromatic Jan 24 '17 at 18:41

1 Answers1

0

I have resolved the issue. When I went to fetch, I needed to store it in a separate variable than the one that the user is storing their entered password into. This can be reflected in the code below:

<?php
require 'connection.php';
$username = $_POST['username'];
$password = $_POST['password'];
$dbusername = ""; //These two being the new variables
$dbpassword = "";

if($conn->connect_error){
    die("Connection failed: " . $conn->connect_error);
}

$stmt = $conn->prepare("SELECT Username, Password FROM users WHERE Username = ?;");
$stmt->bind_param('s', $username);
$stmt->execute();
if($stmt->execute() == true){
    $stmt->bind_result($dbusername, $dbpassword);
    $stmt->fetch();
    if(password_verify($password, $dbpassword)) {
        echo 'successful';
    }
    else{
        echo 'failed';
    }
}
else{
    echo 'failed';
}

?>
Chromatic
  • 87
  • 1
  • 1
  • 8