PHPLOVER PHPLOVER - 6 months ago 20
PHP Question

PHP login script and SQL query always returns the same user id

I posted a question asking for help to solve a problem I have, it was closed as it was to localized. I have now narrowed down my problem.

The original question I asked can be seen PHP Login Script Returning Same user id?.

I am having a problem on my login script. Everything seems to works fine, I get no errors or anything.

Basically when I login the user_uid (users uid) retrieved from the database is always 3, for some reason it isn't getting the correct user_uid, however all the other details that are stored in the session are correct.

The query that is causing the problem is this one

$stmt = $dbh->prepare("
SELECT
*
FROM
users, users_roles, users_profiles
WHERE
user_login = :username
OR
user_email = :email

LIMIT 1");


If I remove users_roles and users_profiles from the SQL query and just retrieve from just the users table it gets the correct user_uid, must be something to do with the fact I am retrieving from multiple tables and the query is messing up somewhere.

Here's a link to SqlFiddle with my schema and SQL query http://sqlfiddle.com/#!2/3cc32/1/0

Below is the array of values echoed out, for some reason even though the user_uid is suppose to be 6 when logging in as test account phplover, it is showing user_uid '3' which is first row in table, seems to be conflicting somewhere.

After further testing it seems that it gets the correct data from users table except the user_uid, but it retrieves the information from users_profiles and users_roles for the first row in database, maybe it is getting the user_uid from users table correctly, but maybe the query is overwriting it.

I ran the query is phpMyAdmin and it still does the same thing, definitely something to do with my SQL query, how can I fix my query so it retrieves the correct user_uid?

Array
(
[user_uid] => 3 // should be 6, 3 is the user_uid of the first row in database, seems to just fetch first row :/
[user_status] => 1
[user_login] => PhpLover
[user_pass] => 5e79a29e6292e7690a6bf56484140114f1374933081d499b8cc5034685950a16668868cd0886d93f9bc634a5649a6037022a5ef62e9b5d13cda24619bbdf610b;507a7ea891f609.84619944
[user_email] => smaple@sample.com
[user_registered] => 2012-10-14 09:58:16
[user_display_name] =>
[user_failed_logins] => 0
[id] => 3 // not sure where this is coming from but should be 6 like user_uid
[user_role] => subscriber
[user_gender] =>
[user_url] =>
[user_msn] =>
[user_aim] =>
[user_yim] =>
[user_twitter] =>
[user_facebook] =>
)


Here is my login script, no need to show it as I have narrowed the problem down to my SQL query, but thought I would post it in case it helps people further understand what is happening.

<?php
// ob_start()
ob_start();

// Include config.php
require_once("".$_SERVER['DOCUMENT_ROOT']."/de-admin/config.php");

// if user is logged in redirect them to control panel
// an already logged in user cannot login whilst already logged in!
alreadyloggedin();

// top.inc.php
require_once($top_inc);
?>

<!-- Meta start -->
<title><?php echo SITE_NAME; ?> - Member Login</title>
<meta name="description" content="<?php echo SITE_NAME; ?> - Member Login, Sign in" />
<meta name="keywords" content="sign up, member, login, signin, account, membership, <?php echo SITE_NAME; ?>" />
<!-- Meta end -->

<?php
// sidebar.inc.php
require_once($sidebar_inc);

// main.inc.php
require_once($main_inc);
?>

<?php

if(isset($_POST['username_email'], $_POST['password'], $_POST[BOT_TEST], $_POST['token'])){

// check if form token is valid
IsValidFormTokenHash();

// initialize form errors array
$error = array();

// fetch form data
$username_email = trim($_POST['username_email']);
$password = trim($_POST['password']);
$bottest = $_POST[BOT_TEST];

// validate form data
if(empty($username_email)){
$error[] = 'Please enter your username or email address';
}
if(empty($password)){
$error[] = 'Please enter your password';
}
if(!empty($bottest)){
$error[] = 'Spambot detected, if your human please try again';
}
if(!empty($username_email) && !empty($password)){
try{

// connect to database
$dbh = sql_con();

// prepare query
$stmt = $dbh->prepare("
SELECT
*
FROM
users, users_roles, users_profiles
WHERE
users.user_login = :username
OR
users.user_email = :email
AND
users.user_uid = users_roles.user_uid
AND
users.user_uid = users_profiles.user_uid
LIMIT 1");

// execute query
$stmt->execute(array(':username' => $username_email, ':email' => $username_email));

if ($stmt->rowCount() > 0) {

$result = $stmt->fetch(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($result);
echo '</pre>';
$user_db_pass = $result['user_pass'];

if(!ValidatePassword($password, $user_db_pass)){
$error[] = 'Invalid Login Details';
} else {

$user_status = $result['user_status'];

if($user_status == USER_STATUS_VERIFY){
$error[] = 'You must verify your account before you can log in';
}elseif($user_status == USER_STATUS_SUSPENDED){
$error[] = 'This account has been suspended';
}elseif($user_status == USER_STATUS_SPAM){
$error[] = 'This account has been marked as potentially spam';
} else {

// user valid

// fetch user details and assign there details to there sessions
$_SESSION['user_uid'] = $result['user_uid'];
$_SESSION['user_status'] = $result['user_status'];
$_SESSION['user_login'] = $result['user_login'];
$_SESSION['user_email'] = $result['user_email'];
$_SESSION['user_registered'] = $result['user_registered'];
$_SESSION['user_display_name'] = $result['user_display_name'];
$_SESSION['user_role'] = $result['user_role'];
$_SESSION['user_gender'] = $result['user_gender'];
$_SESSION['user_url'] = $result['user_url'];
$_SESSION['user_msn'] = $result['user_msn'];
$_SESSION['user_aim'] = $result['user_aim'];
$_SESSION['user_yim'] = $result['user_yim'];
$_SESSION['user_twitter'] = $result['user_twitter'];
$_SESSION['user_facebook'] = $result['user_facebook'];

// unset (destroy) form token
UnsetFormToken();

// On successful login get URI user was on
// so we can redirect them back to URI they was on
/*if(isset($_SESSION['redirect_to'])){
// if session redirect_to is found this means
// they tried to access a membersarea()
// so we get the URI and redirect to the
// secure page they tried accessing before logged in
$redirect_to = $_SESSION['redirect_to'];
// unset the session var
unset($_SESSION['redirect_to']);
// redirect
header("Location: ".SITE_URL."$redirect_to");
exit();
} else {
header("Location: /member/control-panel");
exit();
}*/

// now logged in redirect to control panel
//header("Location: /member/control-panel");
exit;
}
}

} else {
$error[] = 'Incorrect login details';
}

// close database connection
$dbh = null;

}
catch (PDOException $e){
ExceptionErrorHandler($e);
require_once($footer_inc);
exit;
}
}

// If errors found display errors
if(!empty($error)){
$SiteErrorMessages = '';
foreach($error as $msg){
$SiteErrorMessages .= "$msg <br />";
}
}
}


// display error messages
if(isset($SiteErrorMessages)){
SiteErrorMessages();
}

// the below values is to replace placeholders in tpl
$TemplateReplacementValues = array(
'SITE_NAME' => SITE_NAME,
'FORM_TOKEN_HASH' => GenerateFormTokenHash(),
'BOT_TEST' => BotTest()
);

// signup.tpl template location
$tpl = DOCUMENT_ROOT.'inc/tpl/login.tpl';

// load signup template
PageContentTemplate($tpl, $TemplateReplacementValues);

?>

<?php
// footer.inc.php
require_once($footer_inc);

// ob_end-flush
ob_end_flush();
?>

Answer Source

Rewrite this:

FROM users, users_profiles, users_roles

to this:

FROM users
INNER JOIN users_profiles USING (user_uid)
INNER JOIN users_roles USING (user_uid)

... otherwise your query produces a CROSS JOIN (and that's very inefficient, to say the least).

You should replace INNER JOIN with LEFT OUTER JOIN here if some users records may not have corresponding records in users_profiles and users_roles (for these users the corresponding column values will be set to NULL in the returned row set).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download