PHP独立Session数据库存储操作类分享

  直接上代码:

  

复制代码 代码如下:

  class DbSession

  {

  const TYPE_INT = 1;

  const TYPE_STR = 2;

  /**

  * Database configration

  *

  * @var array

  */

  private $_config = array(

  ‘host' => '127.0.0.1′,

  ‘port' => 3306,

  ‘username' => ‘root',

  ‘password' => ‘root',

  ‘dbname' => ‘db_mylab',

  ‘tablename' => ‘t_sessions',

  ‘cookie_prefix' => ‘mylab_',

  ‘cookiepath' => ‘/',

  ‘cookiedomain' => ”,

  ‘cookie_timeout' => 900

  );

  /**

  * Table fields type array

  *

  * @var array

  */

  private  $_db_fields = array(

  ‘crc32sid'      => self::TYPE_INT,

  ‘sessionhash'   => self::TYPE_STR,

  ‘idhash'        => self::TYPE_STR,

  ‘userid'        => self::TYPE_INT,

  ‘ipaddress'     => self::TYPE_STR,

  ‘lastactivity'  => self::TYPE_STR,

  ‘location'      => self::TYPE_STR,

  ‘loggedin'      => self::TYPE_INT,

  ‘heartbeat'     => self::TYPE_STR

  );

  /**

  * db obj

  *

  * @var mysqli object

  */

  private $_mysqli = null;

  /**

  * Weather the session was created or existed previously

  *

  * @var bool

  */

  private $_created = false;

  /**

  * Array of changes.

  *

  * @var array

  */

  private $_changes = array();

  /**

  * @var bool

  */

  private $_db_inited = false;

  /**

  * session host

  *

  * @var string

  */

  private $_session_host = ”;

  /**

  * session idhash

  *

  * @var string

  */

  private $_session_idhash = ”;

  private $_dbsessionhash = ”;

  private $_vars = array();

  public function __construct()

  {

  $this->_dbsessionhash = addslashes($this->get_cookie(‘sessionhash'));

  $this->_session_host = substr($_SERVER[‘REMOTE_ADDR'], 0, 15);

  #This should *never* change during a session

  $this->_session_idhash = md5($_SERVER[‘HTTP_USER_AGENT'] . self::fetch_substr_ip(self::fetch_alt_ip()) );

  $this->_init_config();

  $this->init_db();

  $gotsession = false;

  if ($this->_dbsessionhash)

  {

  $sql = ‘

  SELECT *

  FROM ‘ . $this->_config[‘tablename'] . ‘

  WHERE   crc32sid = ‘ . sprintf(‘%u', crc32($this->_dbsessionhash)) . ‘

  AND sessionhash = '‘ . $this->_dbsessionhash . ‘'

  AND idhash = '‘ . $this->_session_idhash . ‘'

  AND heartbeat > '‘ . date(‘Y-m-d H:i:s' ,TIMENOW – $this->_config[‘cookie_timeout']) . ‘'‘;

  //echo $sql;exit;

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

  $session = $result->fetch_array(MYSQLI_ASSOC);

  if ($session AND ($this->fetch_substr_ip($session[‘ipaddress']) == $this->fetch_substr_ip($this->_session_host)))

  {

  $gotsession = true;

  $this->_vars = $session;

  $this->_created = false;

  }

  }

  if ($gotsession == false)

  {

  $this->_vars = $this->fetch_session();

  $this->_created = true;

  $gotsession = true;

  }

  if ($this->_created == false)

  {

  $this->set(‘lastactivity', date(‘Y-m-d H:i:s', TIMENOW));

  $this->set(‘location', $_SERVER[‘REQUEST_URI']);

  }

  }

  /**

  * Builds an array that can be used to build a query to insert/update the session

  *

  * @return    array    Array of column name => prepared value

  */

  private function _build_query_array()

  {

  $return = array();

  foreach ($this->_db_fields AS $fieldname => $cleantype)

  {

  switch ($cleantype)

  {

  case self::TYPE_INT:

  $cleaned = is_numeric($this->_vars["$fieldname"]) ? $this->_vars["$fieldname"] : intval($this->_vars["$fieldname"]);

  break;

  case self::TYPE_STR:

  default:

  $cleaned = "'" . addslashes($this->_vars["$fieldname"]) . "'";

  }

  $return["$fieldname"] = $cleaned;

  }

  return $return;

  }

  /**

  * Sets a session variable and updates the change list.

  *

  * @param    string    Name of session variable to update

  * @param    string    Value to update it with

  */

  public function set($key, $value)

  {

  if ($this->_vars["$key"] != $value)

  {

  $this->_vars["$key"] = $value;

  $this->_changes["$key"] = true;

  }

  }

  public function get($key)

  {

  return $this->_vars["$key"];

  }

  public function unsetchangedvar($var)

  {

  if (isset($this->_changes["$var"]))

  {

  unset($this->_changes["$var"]);

  }

  }

  /**

  * Fetches a valid sessionhash value, not necessarily the one tied to this session.

  *

  * @return    string    32-character sessionhash

  */

  static function fetch_sessionhash()

  {

  return hash(‘md5′ , TIMENOW . rand(1, 100000) . uniqid() );

  }

  private function _init_config()

  {

  $registry = Zend_Registry::getInstance();

  $config = $registry->get(‘config');

  $this->_config[‘host'] = $config->database->params->host;

  $this->_config[‘port'] = $config->database->params->port;

  $this->_config[‘username'] = $config->database->params->username;

  $this->_config[‘password'] = $config->database->params->password;

  $this->_config[‘dbname'] = $config->database->params->dbname;

  $this->_config[‘tablename'] = $config->database->session->tablename;

  }

  /**

  * initialize database connection

  */

  public function init_db()

  {

  if ($this->_db_inited)

  {

  return true;

  }

  //mysqli_report(MYSQLI_REPORT_OFF);

  $this->_mysqli = new mysqli(

  $this->_config[‘host'],

  $this->_config[‘username'],

  $this->_config[‘password'],

  $this->_config[‘dbname'],

  $this->_config[‘port']

  );

  /* check connection */

  if (mysqli_connect_errno())

  {

  // printf("Connect failed: %sn", mysqli_connect_error());

  // echo ‘in ‘, __FILE__, ‘ on line ‘, __LINE__;

  echo "{ success: false, errors: { reason: ‘ Connect failed: " . addslashes( mysqli_connect_error() ) . "' }}";

  exit();

  }

  $this->_mysqli->query(‘set names latin1′);

  $this->_db_inited = true;

  return true;

  }

  /**

  * Fetches an alternate IP address of the current visitor, attempting to detect proxies etc.

  *

  * @return      string

  */

  static function fetch_alt_ip()

  {

  $alt_ip = $_SERVER[‘REMOTE_ADDR'];

  if (isset($_SERVER[‘HTTP_CLIENT_IP']))

  {

  $alt_ip = $_SERVER[‘HTTP_CLIENT_IP'];

  }

  else if (isset($_SERVER[‘HTTP_FROM']))

  {

  $alt_ip = $_SERVER[‘HTTP_FROM'];

  }

  return $alt_ip;

  }

  /**

  * Returns the IP address with the specified number of octets removed

  *

  * @param    string    IP address

  *

  * @return    string    truncated IP address

  */

  static function fetch_substr_ip($ip, $length = null)

  {

  return implode(‘.', array_slice(explode(‘.', $ip), 0, 4 – $length));

  }

  /**

  * Fetches a default session. Used when creating a new session.

  *

  * @param    integer    User ID the session should be for

  *

  * @return    array    Array of session variables

  */

  public function fetch_session($userid = 0)

  {

  $sessionhash = self::fetch_sessionhash();

  $this->set_cookie(‘sessionhash', $sessionhash);

  return array(

  ‘crc32sid'      => sprintf(‘%u', crc32($sessionhash)),

  ‘sessionhash'   => $sessionhash,

  ‘idhash'        => $this->_session_idhash,

  ‘userid'        => $userid,

  ‘ipaddress'     => $this->_session_host,

  ‘lastactivity'  => date(‘Y-m-d H:i:s', TIMENOW),

  ‘location'      => $_SERVER[‘REQUEST_URI'],

  ‘loggedin'      => $userid ? 1 : 0,

  ‘heartbeat'     => date(‘Y-m-d H:i:s', TIMENOW)

  );

  }

  public function get_cookie($cookiename)

  {

  $full_cookiename = $this->_config[‘cookie_prefix'] . $cookiename;

  if (isset($_COOKIE[$full_cookiename]))

  {

  return $_COOKIE[$full_cookiename];

  }

  else

  {

  return  false;

  }

  }

  public function set_cookie($name, $value = ”, $permanent = 1, $allowsecure = true)

  {

  if ($permanent)

  {

  $expire = TIMENOW + 60 * 60 * 24 * 365;

  }

  else

  {

  $expire = 0;

  }

  if ($_SERVER[‘SERVER_PORT'] == '443′)

  {

  // we're using SSL

  $secure = 1;

  }

  else

  {

  $secure = 0;

  }

  // check for SSL

  $secure = ((REQ_PROTOCOL === ‘https' AND $allowsecure) ? true : false);

  $name = $this->_config[‘cookie_prefix'] . $name;

  $filename = ‘N/A';

  $linenum = 0;

  if (!headers_sent($filename, $linenum))

  { // consider showing an error message if there not sent using above variables?

  if ($value == ” AND strlen($this->_config[‘cookiepath']) > 1 AND strpos($this->_config[‘cookiepath'], ‘/') !== false)

  {

  // this will attempt to unset the cookie at each directory up the path.

  // ie, cookiepath = /test/abc/. These will be unset: /, /test, /test/, /test/abc, /test/abc/

  // This should hopefully prevent cookie conflicts when the cookie path is changed.

  $dirarray = explode(‘/', preg_replace(‘#/+$#', ”, $this->_config[‘cookiepath']));

  $alldirs = ”;

  foreach ($dirarray AS $thisdir)

  {

  $alldirs .= "$thisdir";

  if (!empty($thisdir))

  { // try unsetting without the / at the end

  setcookie($name, $value, $expire, $alldirs, $this->_config[‘cookiedomain'], $secure);

  }

  $alldirs .= "/";

  setcookie($name, $value, $expire, $alldirs, $this->_config[‘cookiedomain'], $secure);

  }

  }

  else

  {

  setcookie($name, $value, $expire, $this->_config[‘cookiepath'], $this->_config[‘cookiedomain'], $secure);

  }

  }

  else if (!DEBUG)

  {

  echo "can't set cookies";

  }

  }

  private function _save()

  {

  $cleaned = $this->_build_query_array();

  if ($this->_created)

  {

  //var_dump($cleaned);

  # insert query

  $this->_mysqli->query(‘

  INSERT IGNORE INTO ‘ . $this->_config[‘tablename'] . ‘

  (‘ . implode(‘,', array_keys($cleaned)) . ‘)

  VALUES

  (‘ . implode(‘,', $cleaned). ‘)

  ‘);

  }

  else

  {

  # update query

  $update = array();

  foreach ($cleaned AS $key => $value)

  {

  if (!empty($this->_changes["$key"]))

  {

  $update[] = "$key = $value";

  }

  }

  if (sizeof($update) > 0)

  {

  $sql = ‘UPDATE ‘ . $this->_config[‘tablename'] . ‘

  SET ‘ . implode(‘, ‘, $update) . ‘

  WHERE crc32sid = ‘ . sprintf(‘%u', crc32($this->_dbsessionhash)) . ‘

  AND sessionhash = '‘ . $this->_dbsessionhash . ‘'‘;

  //echo $sql;

  $this->_mysqli->query($sql);

  }

  }

  }

  public function getOnlineUserNum()

  {

  $sql = ‘

  SELECT count(*) as cnt

  FROM ‘ . $this->_config[‘tablename'] . ‘

  WHERE loggedin = 1

  AND heartbeat > '‘ . date(‘Y-m-d H:i:s' ,TIMENOW – $this->_config[‘cookie_timeout']) . ‘'‘;

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

  $row = $result->fetch_array(MYSQLI_ASSOC);

  return $row[‘cnt'];

  }

  private function _gc()

  {

  $rand_num = rand(); # randow integer between 0 and getrandmax()

  if ($rand_num < 100)

  {

  $sql = ‘DELETE FROM ‘ . $this->_config[‘tablename'] . ‘

  WHERE heartbeat < '‘ . date(‘Y-m-d H:i:s' ,TIMENOW – $this->_config[‘cookie_timeout']) . ‘'‘;

  $this->_mysqli->query($sql);

  }

  }

  public function __destruct()

  {

  $this->_save();

  $this->_gc();

  $this->_mysqli->close();

  }

  }