【问题标题】:Session keeps logging me out会话不断让我退出
【发布时间】:2015-11-20 05:37:27
【问题描述】:

好的,所以在我的主登录 php 页面上我有这个:

<?php
session_start();
require 'connect.php';

if(mysqli_connect_errno()) {
    echo 'Failed to Connect to MySQL' . mysqli_connect_errno();
}

if(isset($_POST['submit'])) {
    //Variables
    $user = $_POST['username'];
    $pass =  md5 ($_POST['password']);

    //prevent MySQL Inject
    $user = stripslashes($user);
    $pass = stripslashes($pass);

    $query = mysqli_query($con, "SELECT * FROM tech WHERE username = '$user' and password = '$pass'") or die("Can not query the DB");
    $count = mysqli_num_rows($query);

    if($count == 1) {
        $_SESSION['username'] = $user;
        $url = 'home.php';
        echo '<META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'">';
    } else {
        echo 'Username and Password do not match! Try Again';
        $url = 'carelogin.php';
        echo '<META HTTP-EQUIV=Refresh CONTENT="2; URL='.$url.'">';
        session_destroy();
    }
}
?>

然后,在最顶部的每一页上,我都有这个。

<?php
session_start();
require_once 'connect.php';

if(!isset($_SESSION['username'])) {
    echo "<h1>You are not an authorised user</h1>";
    $url = 'carelogin.php';
    echo '<META HTTP-EQUIV=Refresh CONTENT="1; URL='.$url.'">';
} else {
}
?>

如果我单击 REFRESH 或者我前进或后退,在任何这些页面上没有触摸我的鼠标大约 30 秒后,它会一直让我退出。我不明白。我已经设置了所有会话,但在 30 秒内我就退出了。

请有人修改我的代码,让我在点击退出之前一直保持登录状态,谢谢大家!

【问题讨论】:

  • 你的代码真的很糟糕,很容易被sql注入
  • 你在所有浏览器都试过了吗..??
  • 使用&lt;META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'"&gt; 有什么意义?出于好奇,您从中获得了什么好处?
  • 当我使用标头时,我不断收到标头已发送的错误所以我搬到了 META
  • 我不认为代码很糟糕,我认为它非常非常基础。可怕的似乎是你会对根本不起作用的页面说的话。有点极端的人:(

标签: php mysql


【解决方案1】:

我想你会发现人们会为这类事情推荐一个框架,但是,如果你要尝试登录,你可能希望更彻底地拆分你的脚本以容纳更简洁和更可扩展的代码.此外,请确保在测试网站时使用session_start() 上方的ini_set("display_errors",1); error_reporting(E_ALL); 来提醒页面上发生的任何错误/警告(在实时环境中关闭错误报告)。

这里的代码比你所拥有的更复杂一些,但它应该可以保护你免受注入。请注意,每个文件的所有文件夹都应与 域根 相关。另请注意,您需要使用password_hash() 函数将所有密码存储在数据库中。您可以使用其中的一些,所有这些,一个都不使用,但如果您确实使用它,请务必查看 PHP 手册以了解所有这些都在做什么:

/core.processor/classes/class.DatabaseConfig.php

// This is your database. Fill out the credentials in the connect() method
// I use PDO because I think personally it's easier to use
class   DatabaseConfig
    {
        private static  $singleton;

        public  function __construct()
            {
                if(empty(self::$singleton))
                    self::$singleton    =   $this->connect();

                return self::$singleton;
            }
        // This is the method that creates the database connection
        public  function connect($host = "localhost", $username = "username", $password = "password", $database = "database")
            {
                // Create connection options
                // 1) Make PDO Exception errors, 2) Do real binding 3) By default prefer fetching associative arrays
                $opts   =   array(  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                                    PDO::ATTR_EMULATE_PREPARES => false,
                                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
                $conn   =   new PDO('mysql:host='.$host.';dbname='.$database, $username, $password,$opts);
                // Send back the database connection. You can use a "utf-8" character setting here as well...
                return $conn;
            }
    }

/core.processor/classes/class.QueryEngine.php

// This is a simple query engine. It allows for binding (or not binding)
class   QueryEngine
    {
        private $results;

        private static  $singleton;

        public  function __construct()
            {
                if(empty(self::$singleton))
                    self::$singleton    =   $this;

                return self::$singleton;
            }
        // This method sends queries to your database
        public  function query($sql = false,$bind = false)
            {
                $this->results  =   0;
                // Create database connection
                $db     =   new DatabaseConfig();
                // Attempt to connect and fetch data
                try {
                        // Bind or not bind, provided there is a bind array
                        // This is important to look up!
                        if(!empty($bind)) {
                                $query  =   $db ->connect()
                                                ->prepare($sql);
                                $query->execute($bind);
                            }
                        else {
                                $query  =   $db ->connect()
                                                ->query($sql);
                            }

                        $this->results  =   $query;
                    }
                catch (PDOException $e)
                    {
                        die($e->getMessage());
                    }

                return $this;
            }
        // This method will fetch an the associative array if used with select statement
        public  function fetch()
            {
                while($row = $this->results->fetch())
                    $result[]   =   $row;

                return (!empty($result))? $result : 0;
            }
    }

/core.processor/classes/class.HeaderProcessor.php

// This class deals with functions that should happen before the page outputs to the browswer
class   HeaderProcessor
    {
        private static  $userData;

        // This method just sits and waits for actions to happen
        // This method should expand with whatever you plan to do in the future
        public  static  function eventListener($array = array())
            {       
                if(isset($array['action'])) {
                        if($array['action'] == 'login') {
                                if(self::getLogin($array['username'],$array['password'])) {
                                        if(self::setSession(self::$userData)) {
                                                $_SESSION['password']   =   NULL;
                                            }
                                        header("Location: home.php");
                                        exit;
                                    }
                            }
                        elseif($array['action'] == 'logout') {
                                session_destroy();
                                header("Location: loggedout.php");
                                exit;
                            }
                    }
            }
        // Process login
        private static  function getLogin($user,$pass)
            {
                $query      =   new QueryEngine();
                $getUser    =   $query  ->query("SELECT * FROM `users` WHERE `username` = :0",array($user))
                                        ->fetch();

                if($getUser == 0)
                    return false;

                self::$userData =   $getUser[0];
                // Verify the password hash (this is why you need to store your passwords differently in your db
                return password_verify($pass,$getUser[0]['password']);
            }
        // Assign session variables
        private static  function setSession($userData)
            {
                $_SESSION   =   array_filter(array_merge($userData,$_SESSION));

                return true;    
            }
        // This can set options for your site, I just threw in timezone
        // as well as the class autoloader
        public  static  function initApp($settings = false)
            {
                $timezone   =   (!empty($settings['timezone']))? $settings['timezone'] : 'America/Los_Angeles';
                include_once(FUNCTIONS_DIR."/function.autoLoader.php");

                date_default_timezone_set($timezone);
            }
    }

/core.processor/functions/function.autoLoader.php

// This function will auto load your classes so you don't have to always
// include files. You could make a similar function to autoload functions
function autoLoader($class)
    {
        if(class_exists($class))
            return true;

        if(is_file($include = CLASS_DIR.'/class.'.$class.'.php'))
            include_once($include);
    }

/config.php

/*** This config is located in the root folder and goes on every page ***/

// Start session
session_start();
// Define common places
define("ROOT_DIR",__DIR__);
define("CLASS_DIR",ROOT_DIR.'/core.processor/classes');
define("FUNCTIONS_DIR",ROOT_DIR.'/core.processor/functions');
// Require the page initializer class
require_once(CLASS_DIR."/class.HeaderProcessor.php");
// Initialize the autoloader for classes
// Load timezone
// You can put any other preset in this method
HeaderProcessor::initApp();
// Here is where you put in events like login, logout, etc...
HeaderProcessor::eventListener($_POST);
// Use this function to help load up classes
spl_autoload_register('autoLoader');

/login.php

<?php
// add in the config file
require(__DIR__."/config.php");
?><!DOCTYPE html>
<html>
<meta charset="UTF-8">
<title>My Login</title>
<head>
</head>
<body>
    <form id="loginForm" method="post" action="">
        <input name="username" type="text" />
        <input name="password" type="password" />
        <input name="action" type="hidden" value="login" />
        <input type="submit" value="LOGIN" />
    </form>
</body>
</html>

【讨论】:

    【解决方案2】:

    请增加会话超时时间:

    // server should keep session data for AT LEAST 1 hour
    ini_set('session.gc_maxlifetime', 3600);
    
    // each client should remember their session id for EXACTLY 1 hour
    session_set_cookie_params(3600);
    
    session_start(); // ready to go!
    

    【讨论】:

      【解决方案3】:

      首先你需要找出你的 php 设置是什么:

      在项目的根目录下创建一个 info.php 文件,其中包含以下几行:

      <?php
      phpinfo();
      

      在浏览器上加载页面并找到以下变量:

      session.gc_maxlifetime
      

      您的会话可能已设置为在很短的时间后过期(默认值约为 24 分钟,但显示的值以秒为单位 - 1440)。在您的情况下,此值可能等于 30

      要将其更改为您喜欢的时间长度,您需要更改您的 php 设置,如下所示(确保您具有在服务器上进行写入更改的正确权限):

      找到您的 php.ini 设置文件。它可能位于您的 linux 服务器上的以下位置:

      /etc/php/7.0/apache2/php.ini
      

      您应该使用您选择的编辑器打开此文件,例如nano 在您的命令行中如下所示:

      sudo nano /etc/php/7.0/apache2/php.ini
      

      找到以下变量:

      session.gc_maxlifetime
      

      将相应的值更改为更长的时间跨度,例如 1 天,您可以计算如下:1 天 * 24 小时 * 60 分钟 * 60 秒 = 86400 秒

      如下设置:

      session.gc_maxlifetime = 86400
      

      保存文件并从命令行重新启动 apache,如下所示:

      sudo service apache2 restart
      

      重新加载您的 info.php 文件,更改应该已经生效。

      【讨论】:

        【解决方案4】:

        编辑:我删除了我的第一个建议

        或者试试我的代码

        这里它会检查你是否连接到你的数据库我把它命名为connect.inc.php

        <?php
        if(!mysql_connect('localhost', 'root', '')|| !mysql_select_db('byp_db'))
        {
        die(mysql_error());
        }
        ?>
        

        接下来我创建了我的core.inc.php,它将检查您是否已经在session,您将在其中使用loggedin() 方法

        <?php
        error_reporting(E_ALL ^ E_NOTICE); 
        ob_start();
        session_start();
        $current_file = $_SERVER['SCRIPT_NAME'];
        $http_referer = $_SERVER['HTTP_REFERER'];
        
        function loggedin() {
        
              if(isset($_SESSION['user_p_info_id'])&&!empty($_SESSION['user_p_info_id'])) {
            return true;
        
        }else {
            return false;
        }
        }
        
        function getuserfield($field){
        $query = "SELECT `$field` FROM `user_p_info` where `user_p_info_id`='".$_SESSION['user_p_info_id']."'";
        if($query_run = mysql_query($query)){
        
            if($query_result = mysql_result($query_run, 0, $field)){
                return $query_result;
            }
        
        }
        }
        ?>
        

        接下来您将创建您的登录表单

        <?php
        
        require 'connections/connect.inc.php';
        require 'connections/core.inc.php';
        
        if(isset($_POST['uname']) && isset($_POST['password'])){
        
        $uname = $_POST['uname'];
        $pword = $_POST['password'];
        
        //echo $uname;
        //echo $pword;
        if(!empty($uname)&&!empty($pword)){
        $query_login = "SELECT * FROM user_a_info where username = '$uname' and password = '$pword'";
        //echo $query_login;
        
        $query_result = mysql_query($query_login);
        $num_rows = mysql_num_rows($query_result);  
            if($num_rows == 0){
        
        ?>
        
        <script type="text/javascript"> 
        alert("Invalid Data !");  
        </script>
        
        
        <?php                   
            }else{
        
                //echo "validated";
                $user_p_info_id = mysql_result($query_result, 0, 'user_p_info_id');
                $_SESSION['user_p_info_id']=$user_p_info_id;
                header('Location: index.php');
        
        
        }
        } 
        }
        
        ?>
        
        <form action="login.php" method="POST">
        <p> USERNAME : <input type="text" name="uname" /> </p>
        <p> PASSWORD : <input type="password" name="password" /> </p>
        <p> <input type="submit" value="LOGIN" /> </p>
        </form>
        

        然后您的注销功能将如下所示

        <?php
        
        require 'core.inc.php';
        session_destroy();
        header('Location: ../index.php');
        ?>
        

        请注意,如果您想检查您是否在session 中,只需输入此条件

        <?php
        require 'connections/connect.inc.php';
        require 'connections/core.inc.php';
        
        if(loggedin()) {
        // Do something
        }
        
        ?>
        

        希望对你有帮助

        【讨论】:

        • 您为什么要使用mysql_ 进行演示? OP 至少在 mysqli_ 的正确路径上,他们只是用错了。这是使用mysql_ 倒退。
        • @Rasclatt 哦,对不起。我只是发布并演示了简单的会话登录我没有注意到这是我使用 mysql 的旧学校项目
        • @FrostyPinky 我认为 session_start() 总是必须在顶部。我想我看错了。
        • @Kmiles1990123 只需声明一次session_start() 并为其创建一个方法
        • No @Kmiles1990123 , session_start() 应该放在首位。这很好,但如前所述,您只能声明一次。
        猜你喜欢
        • 2017-11-23
        • 1970-01-01
        • 2018-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多