Mi7ai
Mi7ai

Reputation: 37

Call to a member function prepare() on null

I want to make a function to check if a user already exist in a db. The function is stored in a php file called checks.php and must return a value.

require 'database.php';
function exist_user( $username){
 $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
 $sth->bindParam(':email', $username);
 $sth->execute();
 return ($sth->rowCount() == 0) ?  true :  false;
}

My database.php file:

$server = 'localhost';
$username = 'root';
$password = '';
$database = 'auth';
try {
  $conn = new PDO("mysql:host=$server;dbname=$database;", $username, 
  $password);
} catch (PDOException $e) {
  die( "Connection failed: " . $e->getMessage());
}

I call to exist_user() in another php file called register.php:

require 'database.php';
require 'checks.php';

if (!exist_user($username)) {
  //insert in the db
else{
  //echo some message error 
}

The error poops up on this sentence: $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');

I have tried in the checks.php file:

  1. Move the code from database.php to checks.php
  2. Set error_reporting(E_ALL); ini_set('display_errors', 1); after php tag
  3. I saw different answers on this type of error but none helped me to solve this.

Upvotes: 0

Views: 139

Answers (2)

CD001
CD001

Reputation: 8472

You've got a few errors.

Firstly: $conn doesn't exist within the scope of the user_exist function; you'll need to either pass it in as a parameter or access it with the global keyword.

function exist_user($conn, $username){
    $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
    ...
}

... or ...

function exist_user($username){
    global $conn;
    $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
    ...
}

Secondly: your parameter binding is somewhat broken:

$sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
$sth->bindParam(':email', $username);

That would be attempting to literally bind a parameter called $username - you probably just want :username.

And the parameter you're binding then isn't :email but :username - i.e.

$sth = $conn->prepare('SELECT email FROM users WHERE email = :username');       
$sth->bindParam(':username', $username);

Finally: - you might get away with using return ($sth->rowCount() == 0) ? true : false; to return a success state but technically rowCount() returns the number of affected rows, not retrieved:

PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.

If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.

However if you just need to determine whether a user exists you can use something like:

function exist_user($conn, $username) {
    $sth = $conn->prepare('SELECT 1 AS user_exists FROM users WHERE email = :username');        
    $sth->bindParam(':username', $username);
    
    if($sth->execute()) {
        $result = $stc->fetch(PDO::FETCH_ASSOC);
        return !empty($result['user_exists']);
    }
    else {
        return false;
    }
}

Upvotes: 1

Jite
Jite

Reputation: 5847

The $conn object is a global object which does not exist in the function scope, a global object can either be passed in to the function as a parameter/argument or by the use of the keyword global.

function exist_user($username, $conn){
  $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
  $sth->bindParam(':email', $username);
  $sth->execute();
  return ($sth->rowCount() == 0) ?  true :  false;
}  

Or:

function exist_user($username){
  global $conn;
  $sth = $conn->prepare('SELECT email FROM users WHERE email = :$username');       
  $sth->bindParam(':email', $username);
  $sth->execute();
  return ($sth->rowCount() == 0) ?  true :  false;
}

I would recommend going with option 1, its easier to read and the global keyword is an abomination (personal opinion).

Upvotes: 0

Related Questions