Session variables not being remembered

I have some PHP code that works fine on my local server (via XAMPP), and it runs fine on a Unix server on my campus, but when I use it on DreamHost servers, for some reason I am having numerous issues.

For one, the $_SESSION is not being remembered at all upon form submission.Another issue is that the header redirect does not work (nothing happens).
Both of these work fine locally and on one server I tested, but not my VPS on DreamHost. I have been trying numerous things for hours and not found a solution.

login.php:

<!DOCTYPE html>
<html>
  <head>
    <title>Log In - password hash example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="../css/normalize.css">
    <link rel="stylesheet" href="../css/main.css">
  </head>

  <?php

    include ("functions.php");
    session_start();
    require_once("../includes/open_db.php");


    //need to save whether log in is new or existing
    if (isset($_POST['type'])) {
      $_SESSION['type'] = $_POST['type'];
      unset($_POST['type']);
    }

     //want to keep username if it has been entered
    if (isset($_POST['username'])) {
      $username_check = htmlspecialchars($_POST['username']);
    }
    else {
      $username_check = "";
    }

    //check username availability
    if (isset($_POST['check_username']) && isset($_POST['username'])) {
      $check = true;  //will need to know if username needs to be put back
      if (existing_username($db, $username_check)) {
        echo "<script type='text/javascript'>alert('Username unavailable.');</script>";
      }
      else {
        echo "<script type='text/javascript'>alert('Username is available.');</script>";
      }
      unset($_POST['check_username']);
      unset($_POST['username']);
    }
    else {
      $check = false; //no name in the input box
    }

    //log in existing user
    if ($_SESSION['type'] == 'existing') {
      if (isset($_POST['username']) && isset($_POST['password'])) {
        $username = htmlspecialchars($_POST['username']);
        $password = htmlspecialchars($_POST['password']);
        if (verify_login($db, $username, $password)) {
          $_SESSION['message'] = 'You have successfully logged in';
          $_SESSION['current_user'] = $_POST['username'];
          header('Location: login_message.php');
        }
        else {
          $_SESSION['message'] = 'Login failed';
          header('Location: login_message.php');
        }
      }
    }
    else {  //create new user
     if (isset($_POST['username']) && isset($_POST['password'])) {
        $username = htmlspecialchars($_POST['username']);
        $password = htmlspecialchars($_POST['password']);
        if (validPassword($password)) {
          $password2 = htmlspecialchars($_POST['password2']);
          if ($password !== $password2) {
            echo "<script type='text/javascript'>alert('Passwords do not match.');</script>";
          }
          else  //passwords match
          {
            if (existing_username($db, $username)) {
              echo "<script type='text/javascript'>alert('username unavailable');</script>";
            }
            else {  //username available
              $encrypt_password = password_hash($password, PASSWORD_DEFAULT);
              if (addUser($db, $username, $encrypt_password)){
                $_SESSION['message'] = 'Your account has been created and you are logged in';
                $_SESSION['current_user'] = $_POST['username'];
                header('Location: login_message.php');
              }
            else {
              echo "<script type='text/javascript'>alert('Unable to create account.');</script>";
            }
          }//!existing_username
        }//passwords match
      }//valid password
      else {    //invalid password
        echo "<script type='text/javascript'>alert('Password must be at least 8 characters and "
        . "contain at least one number, one uppercase letter, and one lowercase letter');</script>";
      }
    }//isset
  }//else (new user)
?>
  <body>
    <header>
        <?php
          if ($_SESSION['type'] == "existing"){
            echo "<h1>User Log-In</h1>";
          }
          else {
            echo "<h1>Enter new account information</h1>";
          }
        ?>

    </header>
    <main>
        <form action="" method="post">
          <label for="username" class="login_label">Username</label>
          <?php
              echo "<input type='text' name='username' value=$username_check>";
              if ($_SESSION['type'] == "new") {
                echo '<input type="submit" name="check_username" value="Check Username Availability" id="check_button">';
              }
              echo '<br/>';
          ?>
          <label for="password" class="login_label">Password</label>
          <!-- would normally make the input type="password", but want to see what we type -->
          <input type="text" name="password" value=""><br />
          <?php
             if ($_SESSION['type'] == "new"){
                echo "<label for='password2' class='login_label'>Retype password</label>";
                //would normally make the input type="password", but want to see what we type
                echo "<input type='text' name='password2' value=''><br />";
             }
           ?>
          <input type="submit" value="Log-in">
        </form>
    </main>
  </body>
</html>

functions.php:

    function verify_login($db, $username, $password)
    {
      $query = "SELECT user_password FROM users WHERE username = :user";
      $statement = $db->prepare($query);
      $statement->bindValue(':user', $username);
      $statement->execute();
      $result = $statement->fetch();
      $statement->closeCursor();
      $hash = $result['user_password'];
      return password_verify($password, $hash);
    }

    function existing_username($db, $username)
    {
      $query = "SELECT COUNT(username) FROM users WHERE username = :username";
      $statement = $db->prepare($query);
      $statement->bindValue(':username', $username);
      $statement->execute();
      $exists = $statement->fetch();
      $statement->closeCursor();
      return $exists[0] == 1;
    }

    function addUser($db, $username, $password) {
      $query = "INSERT INTO users (username, user_password)
                VALUES (:username, :password)";
      $statement = $db->prepare($query);
      $statement->bindValue(':username', $username);
      $statement->bindValue(':password', $password);
      $success = $statement->execute();
      $statement->closeCursor();
      return $success;
    }

    function validPassword($password){
      $valid_pattern = '/(?=^.{8,}$)(?=.*\d)(?=.*[A-Z])(?=.*[a-z]).*$/';
      if (preg_match($valid_pattern, $password))
        return true;
      else
        return false;
    }

That’s an easy one. You are sending headers after there has already been output to the browser.
That’s one of many reasons to separate your php logic from your html, all that business can be sorted out before you even consider html.

An easy way to work around that is to call ob_start() first thing when a request starts, and echo ob_get_clean() when the request is done, so you can be sure nothing is output in between, also allowing for graceful error handling.

SamA74,

I appreciate your response. But it doesn’t solve my main problem, which is SESSION variables not being remembered.
Also, the redirects work fine on my localhost as well as on campus server we have. It is just my VPS at DreamHost that is having issues.

When you start a sentence like that you might want to rethink. The better answer is to write proper code.

1 Like

Well, that’s the same problem really. From the PHP manual page on session_start:

To use cookie-based sessions, session_start() must be called before outputing anything to the browser.

So you can’t start with some HTML and then call session_start(), you have to call session_start first thing in your file.

<?php
session_start();
?>
<html>
  <!-- etc -->

The fact this work on your local machine is probably because it has output buffering enabled in php.ini, whereas DreamHost does not.

3 Likes

Actually, it does.

The reason SESSION isn’t being “remembered” is precisely because the text/html header is being output before SESSION has had a chance.

Ensure that no headers are sent out before SESSION and it should work as expected.

2 Likes

Thank you so much, this solved my problems.
I manually had to use ob_start() (of which I wasn’t aware of the existence until now) for some stuff.

The website in question is located here: aashishbharadwaj.com/fakestore

It is a project I created for my second semester web devlopment class (nothing great).

NO, NO, NO! If you have to use ob_start() your code is not written properly. Dont use shortcut hacks to make up for bad coding. You have already been told what to do. PHP at the top of the page, HTML below.

Well, the PHP code has necessary echo statements in it. So I need to do this.

Should be easy enough in this case to move the php block to the beginning of the document.
Where you are echoing out things like scripts into the head, instead of echoing, just store them in variables and spit them out when needed.

    <?= $ThisScript ?>
</head>
<body>

Not really. If you just start with session_start() before you output anything you’ll be fine.

Edit: to clarify, the problem is not with echo, the problem is generating any output before you call session_start - the reason is that session_start sets a header cookie, and once the content starts you can’t write anything to the header anymore, as you can’t rewind and insert something in data was already sent over the wire :slight_smile:

1 Like

That is the reason. Your localhost isn’t properly installed with error reporting. That’s why it “works” on your localhost, but not on a live server that was properly configured by experts. If your localhost was properly configured, you would be seeing Headers already sent error and an error saying that session_start() has to go before outputs. On properly configured servers, your code will break and give you a bunch of errors. This means that it’s a properly configured server. When your server isn’t properly configured, no errors are reported even though there are problems with the code.

In most successful developments, you always want it to report errors either to an error log or display the error only in development environments such as a localhost. This way, you can figure out what is going on with the code and you can fix it. Once it goes on a live server, the fixed codes should never have any errors or problems unless on a different version which may remove or deprecate certain functions. In that case, find an alternative for that function.

Not really. There are many ways to going about this. For example, separate your code using different files. Use 3 files instead of 1. Many people prefer a single file nesting PHP and HTML and what not all into it. I strongly disagree with this. Sure, it may be easy for you because you are lazy. But it’s not easy when you are going to figure out what is going on in your code and why it isn’t doing what you expect it to. So what I am talking about separating the file into 3 files is something like so.

<?php
session_start();

require_once('header_file.php');

// Do something in PHP here.

require_once('your_other_html_element_like_the_rest_of_the_body.php');

Then this code can be something like your index.php file or test.php file or whatever file the user is going to access.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.