PHP Session Handler不写入数据库

I need help with the class below - its not writing to the database and I have no idea why. I know the "read" method is called, but not the "write" method :S

This is the code I'm using:

require '../application/database.php';
$db = new Database('localhost', 'root', '', 'gemgale');

require '../application/session.php';
$session = new Session($db);

session_set_save_handler(
    array(&$session, 'open'),
    array(&$session, 'close'),
    array(&$session, 'read'),
    array(&$session, 'write'),
    array(&$session, 'destroy'),
    array(&$session, 'clean')
);
session_start();
var_dump($session);
$_SESSION['something'] = "gem";
var_dump($_SESSION);
#$session->delete();
#var_dump($_SESSION);

and this is the class ...

class Session
{
    ###########################################################################
    private $expiry = 3600;
    private $securityCode = "gnvriev847e8grdinvrdg5e8g4r7fr7rdvreh8^£*^£FGgyhf";
    private $tableName = "session_data";
    ###########################################################################
    private $dbh;

    function __construct(Database $db)
    {
        $this->dbh = $db->getConnection();

        ini_set('session.cookie_lifetime', 0);
        ini_set('session.gc_maxlifetime', $this->expiry);
    }

    function open($save_path, $session_name)
    {
        return true;
    }

    function close()
    {
        return true;
    }

    function read($session_id)
    {
        echo $session_id;
        print "READING";
        $time = time();
        $hua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        $hua = $hua . $this->securityCode;
        $hua = md5($hua);
        try {
            $stmt = $this->dbh->prepare("
            SELECT session_data
            FROM :tableName
            WHERE session_id = :sesID
              AND session_expire > :time
              AND http_user_agent = :hua
            LIMIT 1
        ");
            $stmt->bindParam("tableName", $this->tableName);
            $stmt->bindParam("sesID", $session_id);
            $stmt->bindParam("time", $time);
            $stmt->bindParam("hua", $hua);
            $stmt->execute();
        } catch (PDOException $e) {
            echo $e->getMessage();
            return false;
        }
        $rs = $stmt->fetch();
        if (!$rs)
            return '';
        else
            return $rs['session_data'];

    }

    function write($session_id, $session_data)
    {
        print "WRITING";
        $expiry = time() + $this->expiry;
        $hua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        $hua = $hua . $this->securityCode;
        $hua = md5($hua);
        try {
            $stmt = $this->dbh->prepare("
                INSERT INTO :tableName (
                  session_id,
                  http_user_agent,
                  session_data,
                  session_expiry
                )
                VALUES (
                  :sessID,
                  :hua,
                  :sdata,
                  :expiry
                )
                ON DUPLICATE KEY UPDATE
                  session_data = :sdata,
                  session_expire = :expiry
            ");

            $stmt->bindParam("tableName", $this->tableName);
            $stmt->bindParam("sessID", $session_id, PDO::PARAM_STR);
            $stmt->bindParam("hua", $hua);
            $stmt->bindParam("sdata", $session_data, PDO::PARAM_STR);
            $stmt->bindParam("expiry", $expiry);
            $stmt->execute();
        } catch (PDOException $e) {
            echo $e->getMessage();
            return false;
        }
        if ($stmt->rowCount() > 1)
            return true;
        else
            return '';

    }


    function destroy($session_id)
    {
        try {
            $stmt = $this->dbh->prepare("
                DELETE FROM :tableName
                WHERE session_id = :id
            ");
            $stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
            $stmt->bindParam("id", $session_id, PDO::PARAM_STR);
            $stmt->execute();
        } catch (PDOException $e) {
            echo $e->getMessage();
            return false;
        }
        return true;
    }


    function clean($maxLifeTime)
    {
        try {
            $x = time() - $maxLifeTime;
            $stmt = $this->dbh->prepare("
                DELETE FROM :tableName
                WHERE session_expire < :x
            ");
            $stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
            $stmt->bindParam("x", $x, PDO::PARAM_INT);
            $stmt->execute();
        } catch (PDOException $e) {
            die($e->getMessage());
        }
        return true;
    }

    function delete()
    {
        $oldID = session_id();
        session_regenerate_id();
        $this->destroy($oldID);
        session_unset();
        session_destroy();
    }


    function getActive()
    {
        $this->clean($this->expiry);
        try {
            $stmt = $this->dbh->prepare("
                SELECT COUNT(session_id) as count
                FROM :tableName
            ");
            $stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
            $stmt->execute();
            $rs = $stmt->fetch();
            return $rs['count'];
        } catch (PDOException $e) {
            die($e->getMessage());
        }
    }

}

Hope you guys can help :)

Thanks, Gem

One, you don't need to pass by reference. Do this instead:

session_set_save_handler(
   array($session, 'open'),
   array($session, 'close'),
   array($session, 'read'),
   array($session, 'write'),
   array($session, 'destroy'),
   array($session, 'clean')
);

To test if the save/write is working, you could try this:

session_start();
$_SESSION['something'] = "gem";
session_write_close();
echo "- Foo";

This should trigger a write to the session store and flush anything to be written. In this case it should display WRITING- Foo if your write method is being called.

If the DB is not being written, but the method is being called, there are other issues.

The first thing I'd look at is the :tableName you're replacing in the prepared statement. You cannot prepare-replace column names or tables. Change your statement to this:

 $stmt = $this->dbh->prepare("
            INSERT INTO ".$this->tableName."  (
              session_id,
              http_user_agent,
              session_data,
              session_expiry
            )
            VALUES (
              :sessID,
              :hua,
              :sdata,
              :expiry
            )
            ON DUPLICATE KEY UPDATE
              session_data = :sdata,
              session_expire = :expiry
        ");

If you do substitue in variables for table names or columns, make sure you whitelist them before using to be safe against opening an injection hole.