Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > PHP/MySQL > BOOK: Professional PHP 5 ISBN: 978-0-7645-7282-1
Password Reminder
Register
Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Professional PHP 5 ISBN: 978-0-7645-7282-1
This is the forum to discuss the Wrox book Professional PHP5 by Ed Lecky-Thompson, Heow Eide-Goodman, Steven D. Nowicki, Alec Cove; ISBN: 9780764572821
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional PHP 5 ISBN: 978-0-7645-7282-1 section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
 
 
Thread Tools Display Modes
  #1 (permalink)  
Old January 30th, 2005, 09:20 PM
Registered User
 
Join Date: Jan 2005
Location: , , .
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
Default Database Abstraction Layer

I am trying to merge together Chapter 8 and 15 to create a user login stored on a database. I do not know why chapter 15 did not use the database abstraction layer introduced in chapter 8, but it's giving me nightmares. On page 174, there is code that says

$value = $id = $this->conn->nextID($tableName . "_id");

that I do not understand. Is that assuming I have a table with the name ending in _id? Is this something specific to Postgres? I'm using MySQL and have never ran into anything like this.

If someone knows of a more robust or better written user authentication class, I'd love to see it.
  #2 (permalink)  
Old February 10th, 2005, 01:22 PM
Registered User
 
Join Date: Feb 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to Norm 2782
Default

It's a trick to get the ID for the row that will be generated by your query. It will return the ID so you know what ID your new row's got. <s>If you see absolutely no user for this, you can delete that little if-statement. You have to have a tablename ending with _id for this to work</s> PEAR DB will automaticly create the needed tables. (Sorta explained @ page 168 / 169)
Hope this helps :)

Norm 2782, why are you here?
- Normality
  #3 (permalink)  
Old April 29th, 2005, 07:38 AM
Registered User
 
Join Date: Apr 2005
Location: , , .
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default

In Chapter 8(page 160) the book says "We will look at some alternate ways of implementing a 'select()' method later in this chapter that will be far more efficient for dealing with large recordsets" but I can't find it anywhere in the chapter? Can somebody enlighten me?

  #4 (permalink)  
Old April 29th, 2005, 05:57 PM
Registered User
 
Join Date: Apr 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I have done both chapter 8 and 15 over to mysql but I'm stuck on this error on the testing of the user session.

Fatal error: Call to private method UserSession::_session_write_method() from context '' in Unknown on line 0

Warning: Unknown: A session is active. You cannot change the session module's ini settings at this time. in Unknown on line 0

here is the Database class
Code:
<?php

require_once('config.php');
require_once('DB.php');

define (DEBUG, 1);

class Database {

    private $conn;

    private function __construct($dns = null) 
    {
        global $cfg;

        //If nothing was passed in, use the value from $cfg
        if($dns == null)
        {
            $dns = $cfg['db']['dns'];
        }

        // Open a connection using the info in $dns
        $this->conn = DB::connect($dns);

        if(DB::isError($this->conn))
        {
            throw new Exception($this->conn->getMessage(), $this->conn->getCode());
        }

        // Always fetch data as an associative array
        $this->conn->setFetchMode(DB_FETCHMODE_ASSOC);

    }

    static public function instance()
    {
        static $objDB;

        if(!isset($objDB))
        {
            $objDB = new Database();
        }

        return $objDB;
    }

    function __destruct()
    {
        $this->conn->disconnect();
    }

    // returns a DB_result object
    function select($sql)
    {
        if (DEBUG) {
            echo "<h5>SELECT: $sql</h5>";
        };

        $result = $this->conn->query($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return $result;
    }

    function query($sql)
    {
        if (DEBUG)
        {
            echo "<h5>QUERY: $sql</h5>";
        };

        $result = $this->conn->query($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return $result;
    }    

    // returns 2D assoc array
    function getAll($sql)
    {
        $result = $this->conn->getAll($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return $result;        
    }

    // returns single scalar value from the first column, first record
    function getOne($sql)
    {
        $result = $this->conn->getOne($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return $result;        
    }

    // returns single scalar value from the first column, first record
    function getColumn($sql)
    {
        $result = $this->conn->getCol($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return $result;        
    }

    function update($tableName, $arUpdates, $sWhere = null)
    {
        $arSet = array();

        foreach($arUpdates as $name => $value)
        {
            if ($value != 'now()')
            {
                $arSet[] = $name . ' = ' . $this->conn->quoteSmart($value);
            }
            else 
            {
                $arSet[] = $name . ' = ' . $value;
            }
        }

        $sSet = implode(', ', $arSet);

        // make sure that table name is properly escaped
        $tableName = $this->conn->quoteIdentifier($tableName);

        $sql = "UPDATE $tableName SET $sSet";

        if($sWhere)
        {
            $sql .= " WHERE $sWhere";
        }

        if(DEBUG)
        {
            echo "<h5>UPDATE: $sql</h5>";
        }

        $result = $this->conn->query($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        // return the number of affected rows.
        return $this->conn->affectedRows();
    }

    function insert($tableName, $arValues)
    {
        $id = null;

        $sFieldList = join(', ', array_keys($arValues));

        $arValueList = array();

        foreach ($arValues as $value)
        {
            if(strtolower($value) == '#id#')
            {
                // we need to get the next value from this table's sequenct
                $value = $id = $this->conn->nextID($tableName . "_id");
            }

            if ($value != 'now()')
            {
                $arValueList[] = $this->conn->quoteSmart($value);
            }
            else 
            {
                $arValueList[] = $value;
            }

        }

        $sValueList = implode(', ', $arValueList);

        // make sure the table name is properly escaped
        $tableName = $this->conn->quoteIdentifier($tableName);

        $sql = "INSERT INTO $tableName ( $sFieldList ) VALUES ( $sValueList )";

        if(DEBUG)
        {
            echo "<h5>INSERT: $sql</h5>";
        }

        $result = $this->conn->query($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        // return the id, if there was one, or the number of affected rows.
        return $id ? $id : $this->conn->affectedRows();        
    }

    function delete($tableName, $sWhere = null)
    {
        $arSet = array();

        // make sure that table name is properly escaped
        $tableName = $this->conn->quoteIdentifier($tableName);

        $sql = "DELETE FROM $tableName";

        if($sWhere)
        {
            $sql .= " WHERE $sWhere";
        }

        if (DEBUG)
        {
            echo "<h5>DELETE: $sql</h5>";
        }

        $result = $this->conn->query($sql);

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        // return the number of affected rows.
        return $this->conn->affectedRows();
    }    

    function startTransaction()
    {
        // autoCommit returns true/false if the command succeds
        return $this->conn->autoCommit(false);
    }

    function commit()
    {
        $results = $this->conn->commit();

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        $this->conn->autoCommit(true);
        return true;    
    }

    function abort()
    {
        $result = $this->conn->rollback();

        if(DB::isError($result))
        {
            throw new Exception($result->getMessage(), $result->getCode());
        }

        return true;    
    }

    function numRows($result)
    {
        return $this->conn->numRows($result);
    }

    function fetchRow($result)
    {
        return $this->conn->fetchRow($result);
    } 

}
?>
And here is the UserSession class

Code:
<?php

require_once('DB.php');
require_once('class.Database.php');
require_once('config.php');

define(DEBUG, 1);

class UserSession {

    private $php_session_id;
    private $native_session_id;
    private $db;
    private $logged_in;
    private $user_id;
    private $session_timeout = 1200;    // 20 minute inactivity timeout
    private $session_lifespan = 7200;    // 2 hour session duration

    public function __construct()
    {
        # Connect to database
        try 
        {
            $this->db = Database::instance();
            //echo "Constructing the UserSession<br>";
        }
        catch (Exception $e)
        {
            die ("UserSession::__construct():" . $e->getMessage());
        }

        // Set up the handler
        session_set_save_handler(
            array(&$this, '_session_open_method'),
            array(&$this, '_session_close_method'),
            array(&$this, '_session_read_method'),
            array(&$this, '_session_write_method'),
            array(&$this, '_session_destroy_method'),
            array(&$this, '_session_gc_method')
        );

        // Check the cookie passed - if one is - if it looks wrong we'll scrub it right away
        $strUserAgent = $_SERVER['HTTP_USER_AGENT'];

        if($_COOKIE["PHPSESSID"])
        {
            // Security and age check
            $this->php_session_id = $_COOKIE["PHPSESSID"];

            $stmt = "SELECT id from user_session WHERE ascii_session_id = '" 
                . $this->php_session_id . "' AND ( ( now() - created < ' " 
                . $this->session_lifespan . " seconds') AND user_agent='" 
                . $strUserAgent . "' AND ( ( now() - last_impression) <= '" 
                . $this->session_timeout . " seconds') OR last_impression IS NULL)";

            //echo $stmt;

            $result = $this->db->select($stmt);

            if($result->numRows() == 0)
            {
                // Set failed flag
                $failed = true;

                // Delete from the database - we do garbage cleanup at the same time
                $whereStmt = "(ascii_session_id = '" . $this->php_session_id . "') OR ( (now() - created) > " . $this->session_lifespan . ")";
                $result = $this->db->delete("user_session", $whereStmt);

                // Clean up stray session variables
                $whereStmt = "session_id NOT IN (SELECT id FROM user_session)";
                $result = $this->db->delete("session_variable", $whereStmt);

                // Get rid of this one it will force PHP to give us anouther one
                unset($_COOKIE["PHPSESSID"]);
            };
        };

        // Set the life time for the cookie
        session_set_cookie_params($this->session_lifespan);

        // Call the session_start method to get things started
        session_start();
    }

    public function Impress()
    {
        if($this->native_session_id)
        {
            $updateArgs = array();
            $updateArgs['last_impression'] = 'now()';
            $whereStmt = "id = " . $this->native_session_id;
            $result = $this->db->update("user_session", $updateArgs, $whereStmt);
        };
    }

    public function IsLoggedIn()
    {
        return $this->logged_in;
    }

    public function GetUserID()
    {
        if($this->logged_in)
        {
            return ($this->user_id);
        }
        else
        {
            return false;
        };
    }

    public function GetUserObject()
    {
        if($this->logged_in)
        {
            if (class_exists("user"))
            {
                $objUser = new User($this->user_id);
                return $objUser;
            }
            else 
            {
                return false;
            };
        };
    }

    public function GetSessionIdentifier()
    {
        return $this->php_session_id;
    }

    public function Login($strUsername, $strPlainPassword)
    {
        $strMD5Password = md5($strPlainPassword);
        $stmt = "SELECT id FROM user WHERE username = '$strUsername' AND md5_pw = '$strMD5Password'";
        $result = $this->db->select($stmt);

        if($result->numRows() > 0)
        {
            $row = $result->fetchRow();
            $this->user_id = $row['id'];
            $this->logged_in = true;
            $updateArgs = array();
            $updateArgs['logged_in'] = 1;
            $updateArgs['user_id'] = $this->user_id;
            $whereStmt = "id = " . $this->native_session_id; 
            $result = $this->db->update("user_session", $updateArgs, $whereStmt);
            return true; 
        }
        else 
        {
            return false;
        };
    }

    public function LogOut()
    {
        if ($this->logged_in = true)
        {
            $updateArgs = array();
            $updateArgs['logged_in'] = 0;
            $updateArgs['user_id'] = 0;
            $whereStmt = "id = " . $this->native_session_id; 
            $result = $this->db->update("user_session", $updateArgs, $whereStmt);
            $this->logged_in = false;
            $this->user_id = 0;
            return true;
        }
        else 
        {
            return false;
        };
    }

    public function __get($nm)
    {
        $stmt = "SELECT variable_value FROM session_variable WHERE session_id = " . $this->native_session_id . " AND variable_name = '" . $nm . "'"; 
        $result = $this->db->select($stmt);

        if($result->numRows() > 0)
        {
            $row = $result->fetchRow();
            return (unserialize($row["variable_value"]));
        }
        else 
        {
            return false;
        };
    }

    public  function __set($nm, $val)
    {
        $strSer = serialize($val);
        $arValues = array();
        $arValues['session_id'] = $this->native_session_id;
        $arValues['variable_name'] = $nm;
        $arValues['variable_value'] = $strSer;
        $result = $this->db->insert("session_variable", $arValues);
    }

    private function _session_open_method($savePath, $session_name)
    {
        // Do nothing
        return true;
    }

    private function _session_close_method()
    {
        // $this->db->__destructor()
        return true;
    }

    private function _session_read_method($id)
    {
        // We use this to determine whether or not our session actually exists.
        $strUserAgent = $_SERVER["HTTP_USER_AGENT"];
        //$strUserAgent = "error";
        $this->php_session_id = $id;
        // Set failed flag to 1 for now
        $failed = 1;
        // See if this exists in the datbase or not
        $stmt = "SELECT id, logged_in, user_id FROM user_session WHERE ascii_session_id = '$id'";
        //echo $stmt . "<br>";
        $result = $this->db->query($stmt);

        if($result->numRows() > 0)
        {
            $row = $result->fetchRow();
            $this->native_session_id = $row["id"];

            if ($row["logged_in"] == 1)
            {
                $this->logged_in = true;
                $this->user_id = $row["user_id"];
            }
            else 
            {
                $this->logged_in = false;
            };
        }
        else 
        {
            $this->logged_in = false;
            // We need to create an entery in the database
            $arValues = array();
            $arValues['ascii_session_id'] = $id;
            $arValues['logged_in'] = 0;
            $arValues['user_id'] = 0;
            $arValues['created'] = 'now()';
            $arValues['user_agent'] = $strUserAgent;
            $result = $this->db->insert("user_session", $arValues);
            // Now get the true id
            $result = $this->db->query("SELECT id FROM user_session where ascii_session_id = '$id'");
            // This is the first fetchRow that is killing us
            $row = $result->fetchRow();
            $this->native_session_id = $row["id"];
        };

        // Just an empty string
        return "";

    }

    private function _session_write_method($id, $sess_data)
    {
        return tru;
    }

    private function _session_destroy_method($id)
    {
        $result = $this->db->query("DELETE FROM user_session WHERE ascii_session_id = '$id'");
        return $result;
    }

    private function _session_gc_method($maxlifetime)
    {
        return true;
    }

}

?>
And just so the $cfg does seem like a magic var

Code:
<?php

$cfg['db']['func_prefix'] = 'mysql';
$cfg['db']['host'] = 'localhost';
$cfg['db']['port'] = 3306;
$cfg['db']['user'] = 'root';
$cfg['db']['password'] = 'password';
$cfg['db']['name'] = 'softwareCheck';
$cfg['db']['dbtype'] = 'mysql';

$cfg['db']['dns'] = $cfg['db']['dbtype'] . "://"
                     . $cfg['db']['user'] . ":" 
                     . $cfg['db']['password'] . "@" 
                     . $cfg['db']['host'] . "/" 
                     . $cfg['db']['name'];

?>
  #5 (permalink)  
Old April 30th, 2005, 04:34 PM
Registered User
 
Join Date: Apr 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Change the functions "_session_write_method" and "_session_close_method" to public and it works. Not ideal but it will keep you moving...

 


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Handle error from database layer to applican layer khatu_jec ASP.NET 2.0 Basics 1 November 9th, 2008 03:51 PM
UI Abstraction layer navdeep General .NET 10 October 9th, 2007 07:22 PM
Database abstraction layer - OOP style w. paginati raul.ionescu PHP Databases 4 May 26th, 2006 04:19 PM
GenericObject with Database Abstraction soccer022483 BOOK: Professional PHP 5 ISBN: 978-0-7645-7282-1 1 March 28th, 2006 07:09 AM
Data Abstraction Layer kcraft Pro PHP 6 March 18th, 2006 04:29 PM



All times are GMT -4. The time now is 09:48 AM.


Powered by vBulletin®
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.