<?php

/* sfDatabaseSessionStorage
 *
 * @Author: Nguyen Phu Quang
 *
 */
class sfDatabaseSessionStorage extends sfSessionStorage {

  public static $new_session = true;
  public static $is_bot = false;

  private static $mysql_dsn;
  private static $mysql_user;
  private static $mysql_password;
  public static $pdo;

  /**
   * Initialize this Storage.
   *
   * @param Context A Context instance.
   * @param array   An associative array of initialization parameters.
   */
  public function initialize($context, $parameters = null) {

    $parameters['auto_start'] = false;
    parent::initialize($context, $parameters);
    if (preg_match('@bot\.html|ia_archiver|msnbot|Slurp;@', @$_SERVER['HTTP_USER_AGENT']))
      self::$is_bot = true;

    self::$mysql_dsn = $parameters['session_dsn'];
    self::$mysql_user = $parameters['session_user'];
    self::$mysql_password = $parameters['session_password'];

    // use this object as the session handler
    session_set_save_handler(array($this, 'sessionOpen'),
                             array($this, 'sessionClose'),
                             array($this, 'sessionRead'),
                             array($this, 'sessionWrite'),
                             array($this, 'sessionDestroy'),
                             array($this, 'sessionGC'));
    session_start();
  }

  public function sessionOpen($path, $name) {
     self::$pdo = new PDO(self::$mysql_dsn, self::$mysql_user, self::$mysql_password);
  }

  public function sessionClose() {
    return true;
  }

  public function sessionDestroy($id) {
    self::$pdo->exec('delete from sessions where ss_id="'.$id.'"');
  }

  public function sessionGC($lifetime) {
    $last = time() - $lifetime;
    self::$pdo->exec("delete from sessions where ss_time<$last");
    self::$pdo->exec("delete from online_guest where og_time<$last");
    self::$pdo->exec("delete from online_user where ou_time<$last");
    return true;
  }

  /**
   * Read a session.
   *
   * @param string A session ID.
   *
   * @return data from database if the session was read else returns string empty
   *
   */
  public function sessionRead($id) {
    if (self::$is_bot) return '';
    $stmt = self::$pdo->query("select ss_data from sessions where ss_id='$id' limit 1");
    if ($stmt && $row = $stmt->fetch(PDO::FETCH_NUM)) {
      self::$new_session = false;
      if ($row[0]=='vol_lock') {
        sfContext::getInstance()->getResponse()->setCookie('vol_lock', 1, time()+86400*5);
        $row[0] = '';
      }
      return $row[0];
    }
    return '';
  }

  /**
   * Write session data.
   *
   * @param string A session ID.
   * @param string A serialized chunk of session data.
   *
   * @return bool true, if the session was written, otherwise an exception is thrown.
   */
  public function sessionWrite($id, $data) {
    if (self::$is_bot) return true;
    $time = time();
    $user = sfContext::getInstance()->getUser();
    $userId = $user->getUserId();
    $userName = $user->getUserName();
    $fullname = $user->getUserFullname();

    if (self::$new_session==false) {
      self::$pdo->exec("update sessions set ss_userid=$userId, ss_username='$userName', ss_user_fullname='$fullname', ".
      "ss_time=$time, ss_data='$data' where ss_id='$id'");
    } else {
      self::$pdo->exec("insert into sessions values('$id', $userId, '$userName', '$userFullname', $time, '$data')");
      self::$new_session = false;
    }
    return true;
  }

  public static function kickUserByName($user_name, $lock=false) {
    $user_name = self::$pdo->quote($user_name);
    $stmt = self::$pdo->query('select ss_userid from sessions where ss_username='.$user_name.' limit 1');
    if ($stmt && $row = $stmt->fetch(PDO::FETCH_NUM)) {
      if ($lock==false) {
        self::$pdo->exec('delete from sessions where ss_username='.$user_name);
      } else {
        self::$pdo->exec('update sessions set ss_data="vol_lock" where ss_username='.$user_name);
      }
      self::$pdo->exec('delete from online_user where ou_userid='.$row[0]);
    }
  }

  /**
   * Kick out an user
   *
   * @param string $session_id
   */
  public static function kickUser($session_id) {
    self::connect_session_db();
    $stmt = self::$pdo->query('select ss_userid from sessions where ss_id="'.$session_id.'"');
    if ($stmt && $row = $stmt->fetch(PDO::FETCH_NUM) && $row[0] != 0) {
      self::$pdo->exec('delete from sessions where ss_id="'.$session_id.'"');
      self::$pdo->exec('delete from online_user where ou_userid='.$row[0]);
    }
  }
}
