1
$query = $pdo -> prepare("SELECT * FROM Users WHERE Username =:Username");
$query->bindParam(':Username', $name);
$query->execute();

$nameRes = $query->fetch(PDO::FETCH_ASSOC);
if ($nameRes['Username']==$_POST['username']) {
    die ("Username is already in use!");
}   

$query = $pdo -> prepare("SELECT * FROM Users WHERE Email =:Email");
$query->bindParam(':Email', $email);
$query ->execute();
$emailRes = $query->fetch(PDO::FETCH_ASSOC);

if ($emailRes['Email']==$_POST['email']) {
    die ("Email is already in use!");
}

I have this code on the registration page of my app and when Username is free to use but email is not and vice versa I get this

Notice: Trying to access array offset on value of type bool

Ok the result is returning false but what to do in this situation? Note: This is on php v7.4 this same thing was working on v7.3

10
  • 3
    Just check if any rows were returned, by replacing if ($emailRes['Email']==$_POST['email']) { with if ($emailRes) { (and the same for $nameRes) Commented Feb 4, 2020 at 13:14
  • Ok that fixes it , thank you very much. But can someone explain why it used to work on previous version and is not working on this new one? Commented Feb 4, 2020 at 13:17
  • The issue is probably that your query didn't return any rows. It would work fine if a row was returned. Commented Feb 4, 2020 at 13:19
  • This seems like a weak strategy. What if someone submits the username while this username is checking whether the username exists? Commented Feb 4, 2020 at 13:24
  • 1
    Of course you could just simplify this down to one query by doing SELECT COUNT(Username) FROM Users WHERE Username =:Username OR Email =:Email Commented Feb 4, 2020 at 13:44

1 Answer 1

5

You are getting this error probably because there were no records found in the database matching your criteria.

The easiest way to solve this error is to check if the database returned anything first.

$emailRes = $query->fetch(PDO::FETCH_ASSOC);
// Below I am checking if there was anything returned
if($emailRes) {
    // proceed to use $emailRes
}

If you don't care whether the database returned anything, then you can simply provide a default value. For example:

$emailRes = $query->fetch(PDO::FETCH_ASSOC);
$email = $emailRes['Email'] ?? ''; // default: empty string

The correct way to check for existance in DB using PDO is:

$query = $pdo->prepare("SELECT COUNT(*) FROM Users WHERE Username =:Username");
$query->execute([':Username' => $name]);
if ($query->fetchColumn()) {
    throw new \Exception("Username is already in use!");
}

$query = $pdo->prepare("SELECT COUNT(*) FROM Users WHERE Email =:Email");
$query->execute([':Email' => $email]);
if ($query->fetchColumn()) {
    throw new \Exception("Email is already in use!");
}

Instead of fetching the row and doing the comparison again in PHP I am fetching a count of matching rows from the database and I use that count as a boolean in the if statement. fetchColumn() will fetch a single column from the first row and if I use COUNT(*) I know there will always be one row.

You can also do it in one query:

$query = $pdo->prepare("SELECT COUNT(*) FROM Users WHERE Username =:Username OR  Email =:Email");
$query->execute([':Username' => $name, ':Email' => $email]);
if ($query->fetchColumn()) {
    throw new \Exception("Username or email is already in use!");
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.