2013-09-17 6 views
1

Я строю простые cms, чтобы помочь расширить мои знания PHP, но, к сожалению, мои файлы cookie, похоже, не работают. Файл, который я считаю, это суть проблемы приведена ниже:Cookie, похоже, не работает?

<?php 

    // First we execute our common code to connection to the database and start the session 
    require("common.php");  

    // Detect if the user has a cookie available. If a cookie is availbale, and a valid 
    // session is found then redirect the user to the appropriate QUEST landing page 
    if(isset($_COOKIE["qcore"])) 
    { 
     $query = " 
       SELECT TOP 1 
         u.* 
       FROM dbo.[User] AS u 
         INNER JOIN dbo.UserSession AS us 
          ON us.UserId = u.UserId 
       WHERE us.SessionId = :sessiontoken"; 

      // The parameter values 
      $query_params = array( 
       ':sessiontoken' => $_COOKIE["qcore"] 
      ); 

     try 
     { 
      // Execute the query against the database 
      $stmt = $db->prepare($query); 
      $result = $stmt->execute($query_params);    
     } 
     catch(PDOException $ex) 
     { 
      // Note: On a production website, you should not output $ex->getMessage(). 
      // It may provide an attacker with helpful information about your code. 
      die("Failed to run query: " . $ex->getMessage()); 
     } 

     // Retrieve the user data from the database. If $row is false, then the session has 
     // likely expired and the user will be presented with the login form again. 
     $row = $stmt->fetch(); 

     // This statement checks if data was available when retreiving user information 
     // using our session token. 
     if($row) 
     { 
      // Here I am preparing to store the $row array into the $_SESSION by 
      // removing the salt and password values from it. Although $_SESSION is 
      // stored on the server-side, there is no reason to store sensitive values 
      // in it unless you have to. Thus, it is best practice to remove these 
      // sensitive values first. 
      unset($row['Salt']); 
      unset($row['Password']); 

      // This stores the user's data into the session at the index 'user'. 
      // We will check this index on the private members-only page to determine whether 
      // or not the user is logged in. We can also use it to retrieve 
      // the user's details. 
      $_SESSION['user'] = $row; 

      // Redirect the user to the private members-only page. 
      // This will need to be changed once we have the QUEST logic flow sorted out 
      // to be the landing quest page. 
      header("Location: private.php"); 
      die("Redirecting to: private.php"); 
     } 
     else 
     { 
      // If no data is found then the session has expired, or been terminated 
      // and we need to remove the cookie to present the login form to the user 
      // To do this we set the cookie expiration date to one hour ago 
      setcookie("qcore", "", time()-3600); 
     } 
    } 

    // This variable will be used to re-display the user's username to them in the 
    // login form if they fail to enter the correct password. It is initialized here 
    // to an empty value, which will be shown if the user has not submitted the form. 
    $submitted_username = ''; 

    // This if statement checks to determine whether the login form has been submitted 
    // If it has, then the login code is run, otherwise the form is displayed 
    if(!empty($_POST)) 
    { 
     // This query retreives the user's information from the database using 
     // their username. SELECT TOP 1 prevents people from being able to edit 
     // their HTTP POST to fetch the entire table. 
     $query = " 
      SELECT TOP 1 
       * 
      FROM dbo.[User] 
      WHERE 
       Username = :username 
     "; 

     $query_params = array( 
      ':username' => $_POST['username'] 
     ); 

     try 
     { 
      // Execute the query against the database 
      $stmt = $db->prepare($query); 
      $result = $stmt->execute($query_params);    
     } 
     catch(PDOException $ex) 
     { 
      // Note: On a production website, you should not output $ex->getMessage(). 
      // It may provide an attacker with helpful information about your code. 
      die("Failed to run query: " . $ex->getMessage()); 
     } 

     // This variable tells us whether the user has successfully logged in or not. 
     // We initialize it to false, assuming they have not. 
     // If we determine that they have entered the right details, then we switch it to true. 
     $login_ok = false; 

     // Retrieve the user data from the database. If $row is false, then the username 
     // they entered is not registered. 
     $row = $stmt->fetch(); 

     if($row) 
     { 
      // Using the password submitted by the user and the salt stored in the database, 
      // we now check to see whether the passwords match by hashing the submitted password 
      // and comparing it to the hashed version already stored in the database. 
      $check_password = hash('sha256', $_POST['password'] . $row['Salt']); 
      for($round = 0; $round < 65536; $round++) 
      { 
       $check_password = hash('sha256', $check_password . $row['Salt']); 
      } 

      if($check_password === $row['Password']) 
      { 
       // If they do, then we flip this to true 
       $login_ok = true; 
      } 
     } 

     // If the user logged in successfully, then we send them to the private members-only page 
     // Otherwise, we display a login failed message and show the login form again 
     if($login_ok) 
     { 
      // Here I am preparing to store the $row array into the $_SESSION by 
      // removing the salt and password values from it. Although $_SESSION is 
      // stored on the server-side, there is no reason to store sensitive values 
      // in it unless you have to. Thus, it is best practice to remove these 
      // sensitive values first. 
      if(!empty($_POST)) 
      { 
       unset($row['Salt']); 
       unset($row['Password']); 
      } 
      // This stores the user's data into the session at the index 'user'. 
      // We will check this index on the private members-only page to determine whether 
      // or not the user is logged in. We can also use it to retrieve 
      // the user's details. 
      $_SESSION['user'] = $row; 

      // Generate a session token which is used locally as a key between the users cookie 
      // and their UserID, this prevents the user from being able to edit their cookie 
      // to login as another user. 
      $sessiontoken = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647)); 

      // Save our cookie 'qcore' with the users session id 
      setcookie("qcore", $sessiontoken); 

      // Insert a new session ID record, or update if one already exists. One should never 
      // exist but this is added as a precaution in case a session has expired whilst the login 
      // form was being filled out (EXTREMELY unlikely), but hey, why not. 
      $query = " 
       DECLARE @userid AS INTEGER = :userid 
       DECLARE @sessionid AS varchar(500) = :sessionid 

       IF EXISTS (SELECT TOP 1 * 
          FROM dbo.UserSession 
          WHERE UserId = @userid ) 
           UPDATE dbo.UserSession 
           SET  SessionId = @sessionid 
           WHERE UserId = @userid 
       ELSE 
          INSERT INTO dbo.UserSession ( 
            UserId , 
            SessionId 
          ) VALUES (
            @userid , 
            @sessionid)"; 

      $query_params = array( 
       ':userid' => $row['UserId'], 
       ':sessionid' => $sessiontoken 
      );  

      try 
      { 
       // Execute the query to insert a new user session or update 
       // an existing one 
       $stmt = $db->prepare($query); 
       $result = $stmt->execute($query_params); 
      } 
      catch(PDOException $ex) 
      { 
       // Note: On a production website, you should not output $ex->getMessage(). 
       // It may provide an attacker with helpful information about your code. 
       // die("Failed to run query: " . $ex->getMessage()); 
       die("Failed to run query: " . $ex->getMessage()); 
      } 

      // Redirect the user to the private members-only page. 
      // This will need to be changed once we have the QUEST logic flow sorted out 
      // to be the landing quest page. 
      header("Location: private.php"); 
      die("Redirecting to: private.php"); 
     } 
     else 
     { 
      // Tell the user they failed 
      print("Login Failed."); 

      // Show them their username again so all they have to do is enter a new 
      // password. The use of htmlentities prevents XSS attacks. You should 
      // always use htmlentities on user submitted values before displaying them 
      // to any users (including the user that submitted them). For more information: 
      // http://en.wikipedia.org/wiki/XSS_attack 
      $submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8'); 
     } 
    } 

?> 
<h1>Login</h1> 
<form action="login.php" method="post"> 
    Username:<br /> 
    <input type="text" name="username" value="<?php echo $submitted_username; ?>" /> 
    <br /><br /> 
    Password:<br /> 
    <input type="password" name="password" value="" /> 
    <br /><br /> 
    <input type="submit" value="Login" /> 
</form> 
<a href="register.php">Register</a> 

И я подозреваю, что что-то просто происходит не так в этой области, после retreiving сеанса, но я понятия не имею, что может быть вызвать:

// This statement checks if data was available when retreiving user information 
// using our session token. 
if($row) 
{ 
+0

Есть ли var_dump ($ _ COOKIE ['qcore']) 'показывать ожидаемое значение? – Barmar

+0

Я предполагаю, что вы не используете MySQL. Поскольку MySQL не имеет ТОП-1. – invisal

+0

Нет, Microsoft SQL (размещен на Azure) – Codingo

ответ

1

Это известная проблема с IIS (Azure работает IIS Я считаю?)

Ссылка: http://support.microsoft.com/kb/q176113

Когда приложение CGI отправляет заголовок Set-Cookie с ответом «302 Object Moved» и заголовком местоположения, Internet Information Server (IIS) игнорирует заголовок файла cookie.

Такое поведение является нарушением спецификации CGI, в котором говорится, «все заголовки, которые не директивы сервера посылаются непосредственно клиенту. На данный момент, эта спецификация определяет три директивы сервера ...»

На связанной странице есть обходной путь, который выглядит так, будто он мало участвует в этом проекте. Сожалею. У меня нет реального опыта работы с продуктами microsoft, поэтому лучше всего я могу порекомендовать попробовать другой стек.

+0

Ничего себе, стыдно, я снова это написал! Но, спасибо, я посмотрю! – Codingo

Смежные вопросы