-3

I am ripping my eyes out trying to produce a decent registration, login and logout in PHP with OO coding, using PDO for MYSQL.

I am getting the error:

Notice: Undefined variable: db in D:\xampp\htdocs\dan\classes\DB.class.php on line 34

Fatal error: Call to a member function query() on a non-object in D:\xampp\htdocs\dan\classes\DB.class.php on line 34

Here is my database class file..

class DB {

protected $db_name = 'test';
protected $db_user = 'root';
protected $db_pass = '' ;
protected $db_host = 'localhost';

//***************** OPEN connection to database *****************
// Ensure called on every page that needs db connection
public function connect() {
    try {
        // Call PDO class
        $db = new PDO('mysql:host='.$this->db_host.';dbname='.$this->db_name, $this->db_user, $this->db_pass);
    }
    catch(PDOException $e) {
        // If error, nice error message here
        echo $e->getMessage();
    }
    return true;
}

//******** SELECT rows from database *****************
// Returns a full row or rows from $table using $where as the where clause
// Return value is associative array with column names as keys
public function select($table, $where)
{
    $query = $db->query('SELECT * FROM $table WHERE $where');
    $result = $query->fetchAll(PDO::FETCH_ASSOC);
    $num_rows = $result->rowCount();

    // if only one result, return that single result
    if($num_rows == 1)
        {return $result[0];}
    
    // but if numerous results, return the array
    return $result;
}

//*********** UPDATE a row in database *****************
// Takes array of data, where keys in array are column names
// Value is the data to be inserted into columns
// $table is the name of the table and $where is the SQL WHERE clause
public function update($data, $table, $where) {
    foreach ($data as $column => $value) {
        $sql = "UPDATE $table SET $column = $value WHERE $where";
        try{
            $db->query($sql);
        }
        catch(PDOException $ex){
            echo "error, ".$ex->getMessage();
        }
    }
    return true;
}

//***************** INSERT a new row into database *****************
// Takes array of data, keys in array are column names
// Values are data to be inserted into columns
// $table is the name of table
public function insert($data, $table) {
    $columns = "";
    $values = "";
    
    foreach ($data as $column => $value) {
        $columns .= ($columns == "") ? "" : ", ";
        $columns .= $column;
        $values .= ($values == "") ? "" : ", ";
        $values .= $value;
    }
    
    $sql = "INSERT INTO $table ($columns) VALUES ($values)";
    try{
        $db->query($sql);
    }
    catch(PDOException $ex){
        echo "error, ".$ex->getMessage();
    }

    
    // return the ID of the user in the database
    return $db->lastInsertId();
}

}

And here is my User class:

// User.class.php
// User object represents a person

require_once 'DB.class.php'; // note: outside of class


class User {
public $id;
public $username;
public $hashedPassword;
public $email;
public $joinDate;

// Constructor is called whenever new object is created
// Takes an associative array with db row as argument, keys are columns in table
function __construct($data) {
    $this->id                   = (isset($data['id']))          ? $data['id']           : "";
    $this->username             = (isset($data['username']))    ? $data['username']     : "";
    $this->hashedPassword   = (isset($data['password']))    ? $data['password'] : "";
    $this->email                = (isset($data['email']))       ? $data['email']        : "";
    $this->joinDate         = (isset($data['joinDate']))    ? $data['joinDate'] : "";
}

public function save($isNewUser = FALSE) {
    // create new db object
    $db = new DB();

    // if the user is already registered, just an update
    if(!$isNewUser) {
        // set the data array
        $data = array(
        "username"  => "'$this->username'",
        "password"  => "'$this->hashedPassword'",
        "email"         => "'$this->email'"
        );
        
        // update the row in database
        $db->update($data, 'users', 'id = ' . $this->id);
    }
    // if user being registered
    else {
        $data = array(
        "username"  => "'$this->username'",
        "password"  => "'$this->hashedPassword'",
        "email"         => "'$this->email'",
        "join_date"  => "'".date("Y-m-d H:i:s",time())."'"
        );
        
        $this->id = $db->insert($data, 'users');
        $this->joinDate = time();
    }
    return true;
}


} // end of class

And here is my UserTools class:

// UserTools.class.php

require_once 'User.class.php';
require_once 'DB.class.php';

class UserTools {

// Log in user (REQUIRES DB)
// First checks if username and password match row in db
// If yes, set session vars and store user object within
public function login($username, $password)
{
    $db = new DB();
    $db->connect();

    // need to change to PREPARE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    $hashedPassword = md5($password);
    $result = $db->query("SELECT * FROM users WHERE username = '$username' AND password = '$hashedPassword'");
    
    if($result->rowCount() == 1)
    {
        $_SESSION['user'] = serialize(new User($result));
        $_SESSION['login_time'] = time();
        $_SESSION['logged_in'] = 1;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

// Log the user out (destroy session vars)
public function logout() {
    unset($_SESSION['user']);
    unset($_SESSION['login_time']);
    unset($_SESSION['logged_in']);
    session_destroy();
}

// Check if username exists (called during registration)  (REQUIRES DB)
public function CheckUsernameExists($username) {
    $db = new DB();
    $db->connect();
    // CHANGE TO PREPARE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    $result = $db->select("users","username=".$username);
            
    if(($result->rowCount()) == 0)
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

// Get a user
// Returns a User object, takes user id as input
public function get($id) {
    // unsure if to delete the following:
    $db = new DB();
    $db->connect();
    $result = $db->select('users', "id = $id");
    return new User($result);
}



} // end of class

Please tell me where I am going wrong. I obviously do not understand object oriented coding even after doing example after example after tutorial after book.

I just want to create a registration system that WORKS and is in a modular, OO style of code.

Community
  • 1
  • 1
DJT-CPP
  • 1
  • 4
  • Did the last comment on my answer help? Just wanting to make sure you got your problems solved so I can stop checking back since SO hasn't been notifying me of responses. ^^ – Jon Feb 03 '13 at 23:38

1 Answers1

5

db is in the local scope when you create it in the DB class. You want it to be in the class scope (ie, a class variable). Change $db in your DB class to $this->db to put it in to the class scope and have it through all your class functions.

Jon
  • 4,746
  • 2
  • 24
  • 37
  • I changed $db in the connect() function to $this-db... I changed the calls to $db in the other members to $this->db,,,, now getting error... Fatal error: Call to a member function fetchAll() on a non-object in D:\xampp\htdocs\dan\classes\DB.class.php on line 35 – DJT-CPP Feb 03 '13 at 21:48
  • That's because, with PDO, you need to `prepare` the statement and then `execute` it. -> http://www.php.net/manual/en/pdostatement.execute.php – Jon Feb 03 '13 at 21:53
  • I am reading so many conflicting things regarding PDO. Prepare, don't prepare.. I am trying to follow some tutorials and it just isn't happening, I am finding the PHP PDO docs hard to read, I feel like I am going to give up. Thankyou for your detailed response by the way I appreciate it – DJT-CPP Feb 03 '13 at 21:58
  • Well, prepare or not, `$query` won't be defined. You want to `$this->db->execute` your statement, and then use `$this->db->fetchAll`. As you have it written `$query` isn't being assigned as that is the `mysqli` way of doing it. ^^ And you are welcome for the detailed response, that's what this community is here for. – Jon Feb 03 '13 at 22:02
  • OK I changed it to prepare the statement first and now getting: Fatal error: Call to a member function rowCount() on a non-object in D:\xampp\htdocs\dan\classes\DB.class.php on line 37 – DJT-CPP Feb 03 '13 at 22:03
  • That's because the result from `fetchAll` is an array, not an object, just `count` on it instead. – Jon Feb 03 '13 at 22:05
  • PDOStatement::rowCount() does not return the number of rows affected by a SELECT statement in some databases. [Documentation](http://www.php.net/manual/en/pdostatement.rowcount.php) Use SELECT COUNT(*) and fetchColumn(). See http://stackoverflow.com/questions/14537335/pdo-version-of-mysql-num-rowsresult-0/14537636#14537636 – david strachan Feb 04 '13 at 11:02
  • Nono, `count($result)`, not `$result->rowCount()`. Please post when you edit so I am informed and can try to continue to help you. – Jon Feb 04 '13 at 11:09