简体   繁体   English

刷新后登录会话被破坏

[英]login session destroyed after refresh

I have made a log in script with some Google help but the problem is every time i refresh the page it gets log out and redirect me to the log in page. 我已经在Google的一些帮助下完成了登录脚本,但问题是每次我刷新页面时,它都会注销并重定向到登录页面。 So basically i want this that a user is logged in after entering his details and not get logged out after a single refresh. 因此,基本上,我希望用户输入详细信息后登录,并且一次刷新后不注销。 my code is: 我的代码是:

<?php

if(!isset($_SESSION)){
session_start();
}

$username = mysqli_real_escape_string($con, $_POST['username']);
$password = mysqli_real_escape_string($con, $_POST['password']);

if ($username && $password)

{


$result = mysqli_query($con, "SELECT * FROM admin WHERE username='$username' ");

$numrows = mysqli_num_rows($result);

if($numrows !=0)
{
    while($row = mysqli_fetch_assoc($result))
    {
        $dbusername = $row["username"];
        $dbpassword = $row["password"]; 

    }
        if($username==$dbusername && $password==$dbpassword)
        {

            $_SESSION['username'] = $dbusername;
        }
        else
            echo "Incorrect Password";
}       
else
    header("location: login.php"); 


}
else    
header("location: login.php"); 
?>

mysqli_real_escape_string() REQUIRES you to have an active/established connection to the DB. mysqli_real_escape_string() 要求您必须将数据库的主动/建立的连接。 Since you're doing the m_r_e_s() call BEFORE you connect, you'll simply get back boolean FALSE to signify failure. 由于在连接之前正在执行m_r_e_s()调用,因此只需返回布尔FALSE即可表示失败。 So you're trashing your "quoted" values. 因此,您浪费了“引用”值。

Boolean false values inserted into a string just get converted into empty strings, so your queries start looking like 插入字符串中的布尔假值只会转换为空字符串,因此查询看起来像

SELECT ... WHERE username=''
                           ^---see the boolean false in there?

Your code sequence should be: 您的代码序列应为:

session_start();
connect_to_db();
prepare_variables();
do_query();

And since you're using mysqli, why are you manually escaping variables anyways? 而且由于您使用的是mysqli,为什么仍要手动转义变量? You could just use a prepared statement + placeholders and bypass the problem entirely. 您可以只使用准备好的语句+占位符,然后完全绕开该问题。

LEARNING POINT # 1: SESSIONS 学习要点1:会议

Here are some learning points for you in regards to sessions and how to use them efficient and effectively. 这里有一些与会议有关的学习要点,以及如何有效地使用它们。 Please note the problem with your code is you are asking if a session was set before calling session start, so the superglobal $_SESSION is not available and therefore your logical statement always returns false, except for when you call session start in login, where you should never call session start anyway. 请注意,您代码的问题是您在询问是否在调用会话开始之前设置了会话,因此超全局$ _SESSION不可用,因此您的逻辑语句始终返回false,除非您在登录时调用会话开始时无论如何都不要调用会话开始。 Call session start 1 time in a config file(make sure you include this file in all of your "views/pages" then you can check if a session is set as normal. read this code very carefully and attempt to understand everything it is doing so that you can take advantage of the power that php's sessions offer. 在配置文件中调用会话开始1次(请确保在所有“视图/页面”中都包含此文件,然后您可以检查会话是否设置为正常。请仔细阅读此代码并尝试了解其所做的一切这样您就可以利用php会话提供的功能。

add to login.php 添加到login.php

//upon successful validation of login.
//create an object to store basic user information in. 

$user = (object) ['username'=>$username,'hash_password'=>$password,'group'=>$usergroup,'site_secret'=>$secret];//your user object

$_SESSION['user'] = $user;//store the object in the users session.

add to your config.php or any file that is included in all pages 添加到您的config.php或所有页面中包含的任何文件

GLOBAL const static $secret = (string)'someUltraSecretStringThatIsDifficultToGuess';//your site wide secret.(you should probably add this to your config file instead of the login.
session_start(); 

//you have to call session start or you don't have access to $_SESSION superglobal, 
//regardless of a user being logged in or logged out they have a session.
//as a programmer it is your job to figure out how to store data in the session

if(isset($_SESSION['user']) && is_object($_SESSION['user']) && $_SESSION['user']->site_secret == $secret)
{
    $loggedInUser = $_SESSION['user'];//if an authenticaed user session is set and is an object and contains our site secret, we assign the $loggedInUser variable to it. so we can call this variable instead of calling the session ad nauseum in our code.
}

now in your files to test if a user is loggedIn 现在在文件中以测试用户是否已登录

if($loggedInUser !== null && is_object($loggedInUser) && $loggedInUser->site_secret = $secret)
{
    //user is logged in. no reason to even call the database at this point, unless there is extra information you need.
    //if said information is going to be accessed on multiple pages, its probably wise to include it in the object when you create it during the login process. don't store overly sensitive
    //information in the object in any circumstance. things like credit card numbers, plain text passwords, security questions are big no nos.
}

now if you need to call this object from inside the function there are two ways 现在,如果您需要从函数内部调用此对象,则有两种方法

//pass by reference

function foo($loggedInUser) 
{
    //your object is available here because you passed by reference! 
    //you can check if a user is loggedIn from within functions now without a single call to the database!
}

//pass with global language feature.
function bar()
{
    global $loggedInUser; //object is available here through usage of global directive. nifty eh?
}

other considerations 其他考虑

consider adding a sitewide secret property to your loggedInUser object and check for the presence of this secret to identify a valid session. 考虑将站点范围的机密属性添加到您的loggingInUser对象中,并检查此机密是否存在以标识有效会话。 it is possible to create a variable called $loggedInUser if a user isn't logged in by passing a malformed get request. 如果未通过传递格式错误的get请求来登录用户,则可以创建一个名为$ loggedInUser的变量。 odds are that the attacker won't be able to guess your site secret though. 很有可能攻击者无法猜测您的站点秘密。 an example of this sitewide secret is shown in the first example. 在第一个示例中显示了此站点范围秘密的示例。

LEARNING POINT # 2: A crash course to Object Oriented Mysqli 学习要点#2:面向对象的Mysqli速成班

creating the connection object. 创建连接对象。

$mysqli = new mysqli("db-host","db-username","db-password","db-name");

setting the charset 设置字符集

//since your object is already created, you can now set a property on the object

$mysqli->set_charset("utf8");//set it to whatever the collation of your database is.

//side note: you should user utf_unicode_ci in your database and utf8 in php.

running a query 运行查询

$query = $mysqli->query("SELECT column1,column2,column3 FROM table1 WHERE 1 LIMIT 30");

//getting number of rows
$num_rows = $query->num_rows;//your mysqli object has morphed into $query at this point.

//working with the result set
if($num_rows > 0)
{
    while($row = $query->fetch_assoc())
    {
    echo '<li>'.$row["column1"].' | '.$row["column2"].' | '.$row["column3"].'</li>';
    }
    $query->close();//optionally close the query object NOTE: the $mysqli object is still open
    $query->free();//optionally free the result set
}
//when you are done with your $mysqli object close the connection
$mysqli->close();

prepared statements: an alternative to escaping values manually 准备好的语句:手动转义值的替代方法

$stmt = $mysqli->prepare("SELECT column1,column2,column3 FROM table1 WHERE column4 = ? column5 = ? and column6 = ?");//prepare our query.

//now we need to assign our variables to the question marks in the statement above in the correct order.
// s represents string, d represents double and i represents an integer.
$stmt->bind_param('sdi',$column4,$column5,$column6);//for illustrative purposes i name the variables the same as the column they correspond to so you can understand.

//now that we have bound our parameters to our statement wehave to execute it. if it doens't execute there is an error in our query or binding parameters

if($stmt->execute())
{
    //now we have two ways we can work with this result set. i am only going to show you what i consider the best way, `bind_result().
    $stmt->bind_result($column1,$column2,$column3);//binds in the same order of our columns.
    if($stmt->num_rows > 0) {
        //great, our query returned a result! lets work with this data now
        while($stmt->fetch())
        {
            echo '<li>'.$column1.' | '.$column2.' | '.$column3.'</li>';//we prent each row of our result. easy peasy
        }
        $stmt->close();//no need to free the result, as it is not stored by default.
    }
    //if there were no results, no need to close stmt as it was automatically closed by default.    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM