Покритикуйте код (Занесение сессии в Mysql)

proWoke

Новичок
Вот код написал, заносит сессию в базу данных. Для каждой группы сессий своя таблица. Скажите ошибки, пожалуйста. Хотя обсуждать особо и ничего, но всё-таки.

PHP:
<?
 
function _open() {
	global $id_connect;
	if ($id_connect = mysql_connect("localhost","root","1") or die("Mysql error: ".mysql_error())) {
	 return mysql_select_db("session") or die("Mysql error: ".mysql_error());
	} else {
	 return false;
	}
}

function _close() {
	global $id_connect;
	return mysql_close($id_connect) or die("Mysql error: ".mysql_error());
}

function _read($id_session) {
	global $id_connect;
	$session_name = session_name();
	mysql_query("CREATE TABLE IF NOT EXISTS `$session_name` (
	`id` VARCHAR(30) PRIMARY KEY,
	`info` TEXT,
	`time` INT(10) 
	)") or die("Mysql error: ".mysql_error());
	$sql = "SELECT `info` FROM `$session_name` WHERE `id`='$id_session'";
	if ($query = mysql_query($sql,$id_connect)) {
	 $result = @mysql_fetch_assoc($query); 
	 return $result['info'];
	}			
}

function _write($id_session, $value) {
	global $id_connect;
	$session_name = session_name();
	$time = time();
	$key = mysql_real_escape_string($id_session);
	$value = mysql_real_escape_string($value);
	$time = mysql_real_escape_string($time);
	mysql_query("REPLACE INTO `$session_name` VALUES('$key','$value','$time')",$id_connect) or die("Mysql error: ".mysql_error());		
}

function _destroy($id_session) {
	global $id_connect;
	$session_name = session_name();
	$sql = "DELETE FROM `$session_name` WHERE `id`='$id_session'";
	return mysql_query($sql,$id_connect) or die("Mysql error: ".mysql_error());			
}

function _clean($maxlifetime) {
		global $id_connect;
		$session_name = session_name();
		$oldrecord = time() - $maxlifetime;
		$sql = "DELETE FROM `$session_name` WHERE `time` < '$oldrecord'";
		mysql_query($sql,$id_connect) or die("Mysql error: ".mysql_error());
}
 

AmdY

Пью пиво
Команда форума
а разве он работает, насколько я помню, данные нужно сериализовать при записи _write

пару лет назад писал обёртку, надо бы отрефакторить и в блог добавить.
PHP:
class Session {
    private $dbh; // хендл на соединение с базой данных
    private $sessionLife = 3600; // время жизни сессии
    
    // в конструкторе устанавливаем обработчик, устанавливаем время жизни сессионной куки и стартуем сессию
    public function __construct() {
        session_set_save_handler(
            array($this, '_open'),
            array($this, '_close'),
            array($this, '_read'),
            array($this, '_write'),
            array($this, '_destroy'),
            array($this, '_gc')
        );
        session_set_cookie_params($this->sessionLife);
        session_start();
    }
    // при старте сессии открываем соединение с базой данных
    private function _open($dir, $name) {
        $this->dbh = mysql_connect('localhost', 'root', '');
        if (!$this->dbh) die('Bad database connect');
        if (!mysql_select_db('test')) die('Bad db table name');
        return true;
    }
    // при окончани работы закрываем соединение
    public function _close() {
        mysql_close($this->dbh);
    }
    // считываем данные из базы данных и десериализируем их
    private function _read($id) {
        $sql = 'SELECT `data` 
            FROM `session` 
            WHERE `session_id`=\''.mysql_real_escape_string($id).'\'
            LIMIT 1
        ';
        $data = mysql_query($sql, $this->dbh);
        if (!$data) die(mysql_errno() . ": " . mysql_error() . "\n");
        $data = mysql_fetch_assoc($data);
        if (isset($data['data'])) {
            return unserialize( $data['data'] );
        } else {
            return array();
        }
    }
    // при записи сериализируем данные и засовываем их в базу данных
    public function _write($id, $data) {
        $sql = 'REPLACE INTO `session`(`session_id`, `data`, `date_updated`)
            VALUES (\''.mysql_real_escape_string($id).'\', 
            \''.mysql_real_escape_string(serialize($data)).'\', 
            UNIX_TIMESTAMP() )
        ';
        if (mysql_query($sql, $this->dbh)) {
            return true;
        } else {
            die(mysql_errno() . ": " . mysql_error() . "\n");
        }
    }
    // при убийстве очищаем масив с данными, убиваем куку и чистим базу
    public function _destroy($id) {
        $_SESSION = array();
        unset($_COOKIE[session_name()]);
        setcookie(session_name(), '', time()-42000, '/');
        $sql = 'DELETE FROM `session` 
            WHERE `session_id`=\''.mysql_real_escape_string($id).'\'
            LIMIT 1
        ';
        if (mysql_query($sql, $this->dbh)) {
            return true;
        } else {
            die(mysql_errno() . ": " . mysql_error() . "\n");
        }
    }
    // убираем старые сессии
    public function _gc($time) {
        $sql = "DELETE FROM `session` 
            WHERE `date_updated` < UNIX_TIMESTAMP() - {$this->sessionLife}
        ";
        if (mysql_query($sql, $this->dbh)) {
            return true;
        } else {
            die(mysql_errno() . ": " . mysql_error() . "\n");
        }
    }

}
ini_set('session.gc_probability', 100);
$session = new Session();
кстати, по моему у grigori на сайте видел тоже реализацию. пожешь и его посмотреть.
 

AmdY

Пью пиво
Команда форума
и в настоящей разработке НИКОГДА НЕ ДОЛЖНО ТОРЧАТЬ or die("Mysql error: ".mysql_error());
 

proWoke

Новичок
и в настоящей разработке НИКОГДА НЕ ДОЛЖНО ТОРЧАТЬ or die("Mysql error: ".mysql_error());
Ну он сам сериализует, когда записывает.
Такие сообщения только в файл если заносить да?
В твоём коде и есть ООП? Я не про семантику а про саму суть.
 

AmdY

Пью пиво
Команда форума
да, сообщение можно в лог класть. а ошибки может видеть только разработчик на этапе разработки, а пользователи нужно выводить Нормальное сообщение, да ещё в дизайне сайта. Дл это лучше использовать исключения.
PHP:
try {
//много кода
    //mysql_query($sql,$id_connect) or throw new Exception("Mysql error: ".mysql_error());
   if (!mysql_query($sql,$id_connect))  throw new Exception("Mysql error: ".mysql_error()); // так вроде должно работать
} catch(Exception $e) {
    if ($isRoot) echo $e->getMessage();
    else echo "Произошла ошибка"; // readfile('error_page.html');
}
По поводу сериализации получается я тупанул, сериализировал сериализированные данные :(
 

fixxxer

К.О.
Партнер клуба
>> mysql_query($sql,$id_connect) or throw new Exception("Mysql error: ".mysql_error());

хрен это будет работать (увы)
 

DiMA

php.spb.ru
Команда форума
В пхп сессиях, простых как три копейки, хорошо то, что за юзера, пишущего код, все продумали. При открытии обычной сессии - она лочится, что не дает соседним потокам с тем же номером сессии открыть параллельно туже сессию. Иначе это приведет к тому, что в проекте будут регулярно теряться некоторые произвольные переменные сессии. От незначительных, до важных типа некоторых флажков о совершенных действиях юзером или установки/снятии авторизации. При использовании не файловых (стандартных) сессий никаких локов уже нет, что кардинально все меняет. Поэтому обсуждения полезности кусков говнокода, по сравнению с реальными потерями данными смысла не имеет.
 

weregod

unserializer
это когда в тз есть требование на запуск длительных операций из браузера, но нет бюджета на итеративную реализацию этих самых длительных операций
 

DiMA

php.spb.ru
Команда форума
в длительных операциях, что называется крон-скриптами, нет юзерских сессиий
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
есть session_write_close(), с ней замечательно разруливаются ситуации вроде одновременных ajax-запросов,
а если нужна синхронизация данных между процессами - это уже не сессии
 

weregod

unserializer
Сверху