我有一个问题,我的php会话一直在超时。我为本地企业制作了一个订购系统,以查看新的在线订单。当餐厅登录到后端系统时,会话会在一段时间后保持过期。我需要至少持续15个小时的会话,但如果可能的话,请保持永久。
我使用codeignitor 3.1构建了系统,我使用的是php会话,而不是codeignitor会话。我已将以下内容添加到index.php文件
ini_set("session.gc_maxlifetime", 2000000);
ini_set("session.gc_divisor", "1");
ini_set("session.gc_probability", "1");
ini_set("session.cookie_lifetime", "0");
ini_set("session.save_path", '/cookie.txt');
phpinfo();
session_start();
Using phpinfo i can see the values change as below
session.cookie_lifetime 0 0
session.cookie_path / /
session.cookie_secure Off Off
session.entropy_file no value no value
session.entropy_length 0 0
session.gc_divisor 1 1000
session.gc_maxlifetime 2000000 1440
session.gc_probability 1 1
我阅读了许多文章,但无法使我的会话保持活跃。 我正在Windows 10 pc上使用xampp进行测试。 感谢您的帮助。我是一名业余开发人员,因此是业余爱好。
答案 0 :(得分:1)
保持会话状态的最佳方法是将会话保持在数据库中。 为此,您需要编写自己的会话处理程序 我写了一个图书馆,可以帮助您持续学习 阅读源代码并熟悉其工作原理!
在这里,我将解释它的工作原理。 您的模型类,用于访问这样的数据库
//ModelAbstract.php
/*
* Copyright (c) 2012 Ali Ghalambaz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
abstract class ModelAbstract
{
private static $active = array();
protected $connection = null;
public function __construct($auth,$connect_it = true,$name = 'noname' ,$user = null, $engine = null)
{
if($connect_it)
$this->connection = self::connect($auth,$name = 'noname' ,$user, $engine);
}
protected static function connect($auth,$name = 'noname' ,$user = null, $engine = null)
{
$dsn = self::mysql($auth['name'],$auth['host']);
try {
$options = array(
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
\PDO::ATTR_CASE,\PDO::CASE_NATURAL,
\PDO::ATTR_DEFAULT_FETCH_MODE=>\PDO::FETCH_ASSOC,
\PDO::ATTR_ERRMODE =>\PDO::ERRMODE_EXCEPTION
);
$con = new \PDO($dsn, $auth['user'],$auth['pass'],$options);
self::$active['connection'] = $con;
self::$active['name'] = $name;
self::$active['user'] = $user;
self::$active['engine'] = $engine;
return $con;
} catch (\PDOException $e) {
echo ('No Link to Database - Try again later - '.$e->getMessage());
}
return null;
}
private static function mysql($db_name, $host = 'local', $port = 3306)
{
return "mysql:host=$host;port=$port;dbname=$db_name;charset=UTF8";
}
protected static function getActiveConnections()
{
return self::$active;
}
}
您可以使用更简单的数据库连接。 之后需要这样的会话处理程序类
//MysqlSessionHandler.php
/*
* Credits
*
* This class was created by David Powers for the Managing PHP Persistent
* Sessions course on lynda.com. It's based on PDOSessionHandler in the
* Symfony HttpFoundation component (https://github.com/symfony/
* HttpFoundation/blob/master/Session/Storage/Handler/PdoSessionHandler.php).
* David Powers gratefully acknowledges the work of the original author, and
* releases this version under the same MIT license.
*
* Copyright (c) 2004-2015 Fabien Potencier
* Copyright (c) 2015 David Powers
* Copyright (c) 2017 Ali Ghalambaz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/**
* Class MysqlSessionHandler
* @package Foundationphp\Sessions
*
* Custom session handler to store session data in MySQL/MariaDB
*/
abstract class MysqlSessionHandler extends ModelAbstract implements \SessionHandlerInterface
{
/**
* @var int Unix timestamp indicating when session should expire
*/
protected $expiry;
/**
* @var \PDO MySQL database connection
*/
protected $db;
/**
* @var Properties
*/
protected $properties;
/**
* An array to support multiple reads before closing (manual, non-standard usage)
*
* @var array Array of statements to release application-level locks
*/
protected $unlockStatements = [];
/**
* Constructor
*
* Requires a MySQL PDO database connection to the sessions table.
* By default, the session handler uses transactions, which requires
* the use of the InnoDB engine. If the sessions table uses the MyISAM
* engine, set the optional second argument to false.
*
* @param Properties $properties
* @param bool $useTransactions Determines whether to use transactions (default)
*/
public function __construct(Properties $properties,$useTransactions = true)
{
parent::__construct($properties->getDb());
$this->properties = $properties;
$this->db = $this->connection;
$this->properties->setUseTransactions($useTransactions);
$this->expiry = time() + (int) ini_get('session.gc_maxlifetime');
}
/**
* Opens the session
*
* @param string $save_path
* @param string $name
* @return bool
*/
public function open($save_path, $name)
{
return true;
}
/**
* Reads the session data
*
* @param string $session_id
* @return string
*/
public function read($session_id)
{
try {
if ($this->expiry) {
// MySQL's default isolation, REPEATABLE READ, causes deadlock for different sessions.
$this->db->exec('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
$this->db->beginTransaction();
} else {
$this->unlockStatements[] = $this->getLock($session_id);
}
$sql = "SELECT ".$this->properties->getColExpiry().",".$this->properties->getColData()."
FROM ".$this->properties->getTableSess()." WHERE ".$this->properties->getColSid()." = :sid";
// When using a transaction, SELECT FOR UPDATE is necessary
// to avoid deadlock of connection that starts reading
// before we write.
if ($this->properties->isUseTransactions()) {
$sql .= ' FOR UPDATE';
}
$selectStmt = $this->db->prepare($sql);
$selectStmt->bindParam(':sid', $session_id);
$selectStmt->execute();
$results = $selectStmt->fetch(\PDO::FETCH_ASSOC);
if ($results) {
if ($results[$this->properties->getColExpiry()] < time()) {
// Return an empty string if data out of date
return '';
}
return $results[$this->properties->getColData()];
}
// We'll get this far only if there are no results, which means
// the session hasn't yet been registered in the database.
if ($this->properties->isUseTransactions()) {
$this->initializeRecord($selectStmt);
}
// Return an empty string if transactions aren't being used
// and the session hasn't yet been registered in the database.
return '';
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollBack();
}
throw $e;
}
}
/**
* Writes the session data to the database
*
* @param string $session_id
* @param string $data
* @return bool
*/
public function write($session_id, $data)
{
try {
$sql = "INSERT INTO ".$this->properties->getTableSess()." (".$this->properties->getColSid().",
".$this->properties->getColExpiry().", ".$this->properties->getColData().")
VALUES (:sid, :expiry, :data)
ON DUPLICATE KEY UPDATE
".$this->properties->getColExpiry()." = :expiry,
".$this->properties->getColData()." = :data";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':expiry', $this->expiry, \PDO::PARAM_INT);
$stmt->bindParam(':data', $data);
$stmt->bindParam(':sid', $session_id);
$stmt->execute();
return true;
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollback();
}
throw $e;
}
}
/**
* Closes the session and writes the session data to the database
*
* @return bool
*/
public function close()
{
if ($this->db->inTransaction()) {
$this->db->commit();
} elseif ($this->unlockStatements) {
while ($unlockStmt = array_shift($this->unlockStatements)) {
$unlockStmt->execute();
}
}
if ($this->properties->isCollectGarbage()) {
$sql = "DELETE FROM ".$this->properties->getTableSess()." WHERE ".$this->properties->getColExpiry()." < :time";
$stmt = $this->db->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
$this->properties->setCollectGarbage(false);
}
return true;
}
/**
* Destroys the session
*
* @param int $session_id
* @return bool
*/
public function destroy($session_id)
{
$sql = "DELETE FROM ".$this->properties->getTableSess()." WHERE ".$this->properties->getColSid()." = :sid";
try {
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':sid', $session_id);
$stmt->execute();
} catch (\PDOException $e) {
if ($this->db->inTransaction()) {
$this->db->rollBack();
}
throw $e;
}
return true;
}
/**
* Garbage collection
*
* @param int $maxlifetime
* @return bool
*/
public function gc($maxlifetime)
{
$this->properties->setCollectGarbage(true);
return true;
}
/**
* Executes an application-level lock on the database
*
* @param $session_id
* @return \PDOStatement Prepared statement to release the lock
*/
protected function getLock($session_id)
{
$stmt = $this->db->prepare('SELECT GET_LOCK(:key, 50)');
$stmt->bindValue(':key', $session_id);
$stmt->execute();
$releaseStmt = $this->db->prepare('DO RELEASE_LOCK(:key)');
$releaseStmt->bindValue(':key', $session_id);
return $releaseStmt;
}
/**
* Registers new session ID in database when using transactions
*
* Exclusive-reading of non-existent rows does not block, so we need
* to insert a row until the transaction is committed.
*
* @param \PDOStatement $selectStmt
* @return string
*/
protected function initializeRecord(\PDOStatement $selectStmt)
{
try {
$sql = "INSERT INTO ".$this->properties->getTableSess()." (".$this->properties->getColSid().", ".$this->properties->getColExpiry().", ".$this->properties->getColData().")
VALUES (:sid, :expiry, :data)";
$insertStmt = $this->db->prepare($sql);
$insertStmt->bindParam(':sid', $session_id);
$insertStmt->bindParam(':expiry',$this->expiry , \PDO::PARAM_INT);
$insertStmt->bindValue(':data', '');
$insertStmt->execute();
return '';
} catch (\PDOException $e) {
// Catch duplicate key error if the session has already been created.
if (0 === strpos($e->getCode(), '23')) {
// Retrieve existing session data written by the current connection.
$selectStmt->execute();
$results = $selectStmt->fetch(\PDO::FETCH_ASSOC);
if ($results) {
return $results[$this->properties->getColData()];
}
return '';
}
// Roll back transaction if the error was caused by something else.
if ($this->db->inTransaction()) {
$this->db->rollback();
}
throw $e;
}
}
}
和属性类(如果需要)
//Properties.php
/*
* Copyright (c) 2017 Ali Ghalambaz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
class Properties
{
/**
* @return string
*/
public function getCookie()
{
return $this->cookie;
}
/**
* @param string $cookie
* @return Properties
*/
public function setCookie($cookie)
{
$this->cookie = $cookie;
return $this;
}
/**
* @return string
*/
public function getTableSess()
{
return $this->table_sess;
}
/**
* @param string $table_sess
* @return Properties
*/
public function setTableSess($table_sess)
{
$this->table_sess = $table_sess;
return $this;
}
/**
* @return string
*/
public function getTableUsers()
{
return $this->table_users;
}
/**
* @param string $table_users
* @return Properties
*/
public function setTableUsers($table_users)
{
$this->table_users = $table_users;
return $this;
}
/**
* @return string
*/
public function getTableAutologin()
{
return $this->table_autologin;
}
/**
* @param string $table_autologin
* @return Properties
*/
public function setTableAutologin($table_autologin)
{
$this->table_autologin = $table_autologin;
return $this;
}
/**
* @return string
*/
public function getColSid()
{
return $this->col_sid;
}
/**
* @param string $col_sid
* @return Properties
*/
public function setColSid($col_sid)
{
$this->col_sid = $col_sid;
return $this;
}
/**
* @return string
*/
public function getColExpiry()
{
return $this->col_expiry;
}
/**
* @param string $col_expiry
* @return Properties
*/
public function setColExpiry($col_expiry)
{
$this->col_expiry = $col_expiry;
return $this;
}
/**
* @return string
*/
public function getColUkey()
{
return $this->col_ukey;
}
/**
* @param string $col_ukey
* @return Properties
*/
public function setColUkey($col_ukey)
{
$this->col_ukey = $col_ukey;
return $this;
}
/**
* @return string
*/
public function getSessUkey()
{
return $this->sess_ukey;
}
/**
* @param string $sess_ukey
* @return Properties
*/
public function setSessUkey($sess_ukey)
{
$this->sess_ukey = $sess_ukey;
return $this;
}
/**
* @return string
*/
public function getColUsername()
{
return $this->col_name;
}
/**
* @param string $col_name
* @return Properties
*/
public function setColUsername($col_name)
{
$this->col_name = $col_name;
return $this;
}
/**
* @return string
*/
public function getColData()
{
return $this->col_data;
}
/**
* @param string $col_data
* @return Properties
*/
public function setColData($col_data)
{
$this->col_data = $col_data;
return $this;
}
/**
* @return string
*/
public function getColToken()
{
return $this->col_token;
}
/**
* @param string $col_token
* @return Properties
*/
public function setColToken($col_token)
{
$this->col_token = $col_token;
return $this;
}
/**
* @return string
*/
public function getColCreated()
{
return $this->col_created;
}
/**
* @param string $col_created
* @return Properties
*/
public function setColCreated($col_created)
{
$this->col_created = $col_created;
return $this;
}
/**
* @return string
*/
public function getColUsed()
{
return $this->col_used;
}
/**
* @param string $col_used
* @return Properties
*/
public function setColUsed($col_used)
{
$this->col_used = $col_used;
return $this;
}
/**
* @return string
*/
public function getSessPersist()
{
return $this->sess_persist;
}
/**
* @param string $sess_persist
* @return Properties
*/
public function setSessPersist($sess_persist)
{
$this->sess_persist = $sess_persist;
return $this;
}
/**
* @return string
*/
public function getSessUname()
{
return $this->sess_uname;
}
/**
* @param string $sess_uname
* @return Properties
*/
public function setSessUname($sess_uname)
{
$this->sess_uname = $sess_uname;
return $this;
}
/**
* @return string
*/
public function getSessAuth()
{
return $this->sess_auth;
}
/**
* @param string $sess_auth
* @return Properties
*/
public function setSessAuth($sess_auth)
{
$this->sess_auth = $sess_auth;
return $this;
}
/**
* @return string
*/
public function getSessRevalid()
{
return $this->sess_revalid;
}
/**
* @param string $sess_revalid
* @return Properties
*/
public function setSessRevalid($sess_revalid)
{
$this->sess_revalid = $sess_revalid;
return $this;
}
/**
* @return mixed
*/
public function getDb()
{
return $this->db;
}
/**
* @param $db_user
* @param $db_pass
* @param $db_name
* @param string $db_host
* @return Properties
*/
public function setDb($db_user,$db_pass,$db_name,$db_host = 'localhost')
{
$this->db = array('user'=>$db_user,'pass'=>$db_pass,'name'=>$db_name,'host'=>$db_host);
return $this;
}
/**
* @return bool
*/
public function isUseTransactions()
{
return $this->useTransactions;
}
/**
* @param bool $useTransactions
* @return Properties
*/
public function setUseTransactions($useTransactions)
{
$this->useTransactions = $useTransactions;
return $this;
}
/**
* @return bool
*/
public function isCollectGarbage()
{
return $this->collectGarbage;
}
/**
* @param bool $collectGarbage
* @return Properties
*/
public function setCollectGarbage($collectGarbage)
{
$this->collectGarbage = $collectGarbage;
return $this;
}
/**
* @var string Name of the autologin cookie
*/
protected $cookie = 'remember_me_auth';
/**
* @var string Default table where session data is stored
*/
protected $table_sess = 'tbl_acl_sessions';
/**
* @var string Name of database table that stores user credentials
*/
protected $table_users = 'tbl_acl_users';
/**
* @var string Name of database table that stores autologin details
*/
protected $table_autologin = 'tbl_acl_autologin';
/**
* @var string Default column for session ID
*/
protected $col_sid = 'sid';
/**
* @var string Default column for expiry timestamp
*/
protected $col_expiry = 'expiry';
/**
* @var string Name of table column that stores user's ID - a unique 8-character alphanumeric string
*/
protected $col_ukey = 'id';
protected $sess_ukey ='userkey';
/**
* @var string Name of table column that stores the user's username
*/
protected $col_name = 'username';
/**
* @var string Default column for session data
*/
protected $col_data = 'data';
/**
* @var string Name of table column that stores 32-character single-use tokens
*/
protected $col_token = 'token';
/**
* @var string Name of table column that stores when the record was created as a MySQL timestamp
*/
protected $col_created = 'created';
/**
* @var string Name of table column that stores a Boolean recording whether the token has been used
*/
protected $col_used = 'used';
/**
* @var string Session variable that persists data
*/
protected $sess_persist = 'remember_me';
/**
* @var string Session variable that stores the username
*/
protected $sess_uname = 'username';
/**
* @var string Session name that indicates user has been authenticated
*/
protected $sess_auth = 'authenticated';
/**
* @var string Session name that indicates user has been revalidated
*/
protected $sess_revalid = 'revalidated';
protected $db ;
/**
* @var bool Determines whether to use transactions
*/
protected $useTransactions;
/**
* @var bool True when PHP has initiated garbage collection
*/
protected $collectGarbage = false;
/**
* @var int Number of days the autologin cookie remains valid
*/
protected $lifetimeDays = 1000;
/**
* @return int
*/
public function getLifetimeDays()
{
return $this->lifetimeDays;
}
/**
* @param int $lifetimeDays
* @return Properties
*/
public function setLifetimeDays($lifetimeDays)
{
$this->lifetimeDays = $lifetimeDays;
return $this;
}
}
还需要创建一个数据库表来保存会话数据
-- ----------------------------
-- Table structure for tbl_acl_sessions
-- ----------------------------
CREATE TABLE `tbl_acl_sessions` (
`sid` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`expiry` int(10) UNSIGNED NOT NULL,
`data` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`sid`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
并没有完全自定义。但希望能有所帮助!