php会话保持超时

时间:2019-02-04 10:18:27

标签: php session

我有一个问题,我的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进行测试。 感谢您的帮助。我是一名业余开发人员,因此是业余爱好。

1 个答案:

答案 0 :(得分:1)

保持会话状态的最佳方法是将会话保持在数据库中。 为此,您需要编写自己的会话处理程序 我写了一个图书馆,可以帮助您持续学习 阅读源代码并熟悉其工作原理!

Source Code

在这里,我将解释它的工作原理。 您的模型类,用于访问这样的数据库

//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;

并没有完全自定义。但希望能有所帮助!