4

So I'm using php-login-minimal to handle logins on my almost complete website.

The login system works perfectly on desktop, but on tablet or mobile it acts as though it's working and logging me in but ultimately I end up at the same page asking me to log in.

I don't understand why it would work on desktop but not mobile. The webpage is the same page that is loaded for both, as I am using a responsive design to scale the content to fit whatever screen is being used, but the logging in system doesn't return an error or anything to help me out.

I've noticed in the Login.php script that there is a line of code elseif (isset($_POST["login"])) { but none of the form elements have the name "login" other than the submit button, do you guys reckon that could be an issue?

I was also thinking about adapting the code a little bit to specify login in the URL (www.example.com/index?login) and see if that works, but I don't want to change the code as I don't fully understand it all yet.

Thanks for any help though guys!

My Login Form

<form method="post" action="index.php" name="loginForm" id="loginForm">
      <label for="login_input_username">Username</label>
      <input id="login_input_username" class="login_input" type="text" name="user_name" required /><span class="linebreak"></span>
      <label for="login_input_password">Password</label>
      <input id="login_input_password" class="login_input" type="password" name="user_password" autocomplete="off" required /><span class="linebreak"></span>

      <span class="loginregister"><input type="submit"  name="login" value="Log in" /></span></form>

The Login Code
index.php

<?php

if (version_compare(PHP_VERSION, '5.3.7', '<')) {
    exit("Sorry, Simple PHP Login does not run on a PHP version smaller than 5.3.7 !");
} else if (version_compare(PHP_VERSION, '5.5.0', '<')) {
    // if you are using PHP 5.3 or PHP 5.4 you have to include the password_api_compatibility_library.php
    // (this library adds the PHP 5.5 password hashing functions to older versions of PHP)
    require_once("libraries/password_compatibility_library.php");
}

// include the configs / constants for the database connection
require_once("config/db.php");

// load the login class
require_once("classes/Login.php");

// create a login object. when this object is created, it will do all login/logout stuff automatically
// so this single line handles the entire login process. in consequence, you can simply ...
$login = new Login();

// ... ask if we are logged in here:
if ($login->isUserLoggedIn() == true) {
    // the user is logged in. you can do whatever you want here.
    // for demonstration purposes, we simply show the "you are logged in" view.
    include("views/logged_in.php");

} else {
    // the user is not logged in. you can do whatever you want here.
    // for demonstration purposes, we simply show the "you are not logged in" view.
    include("views/not_logged_in.php");
}

classes/Login.php

<?php

/**
 * Class login
 * handles the user's login and logout process
 */
class Login
{
    /**
     * @var object The database connection
     */
    private $db_connection = null;
    /**
     * @var array Collection of error messages
     */
    public $errors = array();
    /**
     * @var array Collection of success / neutral messages
     */
    public $messages = array();

    /**
     * the function "__construct()" automatically starts whenever an object of this class is created,
     * you know, when you do "$login = new Login();"
     */
    public function __construct()
    {
        // create/read session, absolutely necessary
        session_start();

        // check the possible login actions:
        // if user tried to log out (happen when user clicks logout button)
        if (isset($_GET["logout"])) {
            $this->doLogout();
        }
        // login via post data (if user just submitted a login form)
        elseif (isset($_POST["login"])) {
            $this->dologinWithPostData();
        }
    }

    /**
     * log in with post data
     */
    private function dologinWithPostData()
    {
        // check login form contents
        if (empty($_POST['user_name'])) {
            $this->errors[] = "Username field was empty.";
        } elseif (empty($_POST['user_password'])) {
            $this->errors[] = "Password field was empty.";
        } elseif (!empty($_POST['user_name']) && !empty($_POST['user_password'])) {

            // create a database connection, using the constants from config/db.php (which we loaded in index.php)
            $this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

            // change character set to utf8 and check it
            if (!$this->db_connection->set_charset("utf8")) {
                $this->errors[] = $this->db_connection->error;
            }

            // if no connection errors (= working database connection)
            if (!$this->db_connection->connect_errno) {

                // escape the POST stuff
                $user_name = $this->db_connection->real_escape_string($_POST['user_name']);

                // database query, getting all the info of the selected user (allows login via email address in the
                // username field)
                $sql = "SELECT user_name, user_email, user_password_hash
                        FROM users
                        WHERE user_name = '" . $user_name . "' OR user_email = '" . $user_name . "';";
                $result_of_login_check = $this->db_connection->query($sql);

                // if this user exists
                if ($result_of_login_check->num_rows == 1) {

                    // get result row (as an object)
                    $result_row = $result_of_login_check->fetch_object();

                    // using PHP 5.5's password_verify() function to check if the provided password fits
                    // the hash of that user's password
                    if (password_verify($_POST['user_password'], $result_row->user_password_hash)) {

                        // write user data into PHP SESSION (a file on your server)
                        $_SESSION['user_name'] = $result_row->user_name;
                        $_SESSION['user_email'] = $result_row->user_email;
                        $_SESSION['user_login_status'] = 1;
                        print "<script type=\"text/javascript\">";
                        print "window.top.location.href='index.php'";
                        print "</script>";
                        exit;

                    } else {
                        $this->errors[] = "Wrong password. Try again.";
                    }
                } else {
                    $this->errors[] = "This user does not exist.";
                }
            } else {
                $this->errors[] = "Database connection problem.";
            }
        }
    }

    /**
     * perform the logout
     */
    public function doLogout()
    {
        // delete the session of the user
        $_SESSION = array();
        session_destroy();
        // return a little feeedback message
        $this->messages[] = "You have been logged out.";

    }

    /**
     * simply return the current state of the user's login
     * @return boolean user's login status
     */
    public function isUserLoggedIn()
    {
        if (isset($_SESSION['user_login_status']) AND $_SESSION['user_login_status'] == 1) {
            return true;
        }
        // default return
        return false;
    }
}

The not_logged_in.php file (logged_in.php is similar, just the form cannot be changed from display:none as the link used to do that changes to a logout link:

<?php
// show potential errors / feedback (from login object)
if (isset($login)) {
    if ($login->errors) {
        foreach ($login->errors as $error) {
            echo $error;
        }
    }
    if ($login->messages) {
        foreach ($login->messages as $message) {
            echo $message;
        }
    }
}
?>

<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<link href="styles/main.css" rel="stylesheet" type="text/css">
<meta name="viewport" content="device-width, initial-scale=1, maximum-scale=1">
<script type="text/javascript">
function showForm(){
    document.getElementById('login').style.display = "block";
}

function hideForm(){
    document.getElementById('login').style.display = "none";
}
</script>
</head>

<body>
<header>
<div class="logo" id="logo">
<a href="#">Website Title</a>
</div>
<?php include("navigation.php"); ?>
</header>
<div id="login" class="login" style="display:none">
<div id="forms" class="forms">
<form method="post" action="index.php" name="loginForm" id="loginForm">
      <label for="login_input_username">Username</label>
      <input id="login_input_username" class="login_input" type="text" name="user_name" required /><span class="linebreak"></span>
      <label for="login_input_password">Password</label>
      <input id="login_input_password" class="login_input" type="password" name="user_password" autocomplete="off" required /><span class="linebreak"></span>

      <span class="loginregister"><input type="submit"  name="login" value="Log in" /></span></form><form action="#"><span class="loginregister"><input type="submit" value="Register"></span></form>


</div>
</div>
radiocaf
  • 151
  • 3
  • 12
  • 1
    *Hm...* these `'" . $user_name . "'` contain spaces and may be interpreted as extra spaces being added. Try to remove them `'" .$user_name. "'` or `'".$user_name."'` and check for errors/warnings/notices http://php.net/manual/en/function.error-reporting.php and http://php.net/manual/en/mysqli.error.php for all queries. – Funk Forty Niner Nov 06 '15 at 16:08
  • I have just tried that and had no change in the issue. Changed the two `'" . $user_name . "'` I found the `$sql` query. – radiocaf Nov 06 '15 at 16:22
  • 1
    did you use error reporting, and if so, anything back from it? Add error reporting to the top of your file(s) right after your opening PHP tag for example ` – Funk Forty Niner Nov 06 '15 at 16:23
  • I will try that now, I was about to tell you I had it already, but I didn't on the index.php page, I only had it on an page that is called with `include`. I will report back shortly. – radiocaf Nov 06 '15 at 16:27
  • 1
    also check to make sure that session cookies can be stored in your mobile devices and that JS is enabled; try and remove the JS prints and replace with a few echos. I'm out of ideas at this point. But make sure that the session was started inside all pages using sessions. – Funk Forty Niner Nov 06 '15 at 16:30
  • Right away, after adding it to the index.php page and loading up I got: `Warning: session_start(): Cannot send session cache limiter - headers already sent`, I also get a similar one on mobile that says session cookie headers in place of session cache limiter. – radiocaf Nov 06 '15 at 16:31
  • 1
    well there you go, that's why your code is failing. You might have your form on top of your PHP, right? – Funk Forty Niner Nov 06 '15 at 16:31
  • My exact code is: Index.php includes the usual db_connect.php, then includes the Login.php class, and then based on if the user is logged in, will display one of two versions of the page content by including logged_in.php or not_logged_in.php, it is these two content pages that have the login form on them. Included in the body of the html. Would you mind showing me what I am doing wrong? I can update the question with any additional code you need to see. – radiocaf Nov 06 '15 at 16:36

2 Answers2

3

After OP used error reporting, as I suggested in comments:

"Right away, after adding it to the index.php page and loading up I got: Warning: session_start(): Cannot send session cache limiter - headers already sent, I also get a similar one on mobile that says session cookie headers in place of session cache limiter. – radiocaf"

Your index.php file (and possibly other files) is throwing you that warning because you might have your HTML form on top of PHP, or a space, or cookie, or even a BOM (byte order mark).

Your files' encoding may contain a byte order mark, which is often the leading cause to a headers sent warning. The UTF-8 encoding lets you save files as "with" or "without" the byte order mark; you need to save them as "without BOM".

That is considered as output, as are spaces before an opening <?php tag, or a cookie etc.

To check what the file's encoding is, you can check inside a code editor's options under the encoding option.

One of which is Notepad++ https://notepad-plus-plus.org/ and there are others also.

Place your PHP first, then your form if that is the case.

Consult the following on Stack about that warning:

Additionally, a quick fix would be to use ob_start(); at the top of your PHP files.

I.e.:

<?php 
ob_start();
// rest of your PHP
?>

then your HTML

or

<?php 
ob_start();
?>
  • then your HTML

  • then the rest of your PHP/SQL.

Plus, as originally stated in comments:

" these '" . $user_name . "' contain spaces and may be interpreted as extra spaces being added. Try to remove them '" .$user_name. "' or '".$user_name."'"

Community
  • 1
  • 1
Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
  • Thank you, I shall look into this now, may take me a while to work out but for the meantime I have edited the question to show the form as it is written into the two content php files. This may help you suggest where exactly I'm going wrong. – radiocaf Nov 06 '15 at 16:43
  • 1
    @radiocaf You're welcome. I made a few more edits to my answer, gathering additional information/links as to why your code is failing. It may be a file encoding issue also. Please reload my answer in order to see what was added and read it in its entirety, especially the part about the BOM, byte order mark. – Funk Forty Niner Nov 06 '15 at 16:49
  • From what I can tell, Dreamweaver is set to not include BOM, but without knowing how to check each file individually, I can't say for sure, but it's new document preferences are not set to include Unicode Signature (BOM). I've added ob_start(); to my index.php file figuring that would solve the issue as index.php calls the other files, but nothing has changed, so I'm going through the files adding it right under – radiocaf Nov 06 '15 at 16:53
  • @radiocaf well there's one of those files or a combination of others that is causing that output and you need to find out which file that is. Double check all your files' encoding. Possibly an include file. Could be anything. – Funk Forty Niner Nov 06 '15 at 16:54
  • @radiocaf have a look at this also http://php.net/manual/en/function.headers-sent.php you can place that in your files and determine which one(s) is causing it. Run each of your files one at a time while commenting out your includes. If no headers is sent, then start uncommenting out one include at a time until you get the warning. That's the best I can offer you, in order to troubleshoot the exact file(s) that is causing it. There isn't much else I can do at this point (sorry), and believe I have given enough information to fix this. Good luck, *cheers* – Funk Forty Niner Nov 06 '15 at 17:04
  • You have been awesome, thank you Fred, as soon as I get it fixed, your answer will be voted as the solution. I know it's the solution, I'm just too dumb to get to it quickly, ha! I forgot to post the second part of the errors I got from Error_Reporting, which was `(output started at /home/radiocaf/public_html/index.php:8) in /home/radiocaf/public_html/classes/Login.php on Line 29` – radiocaf Nov 06 '15 at 17:09
  • @radiocaf You're most welcome. From what I can see in your Login.php file, try to place `session_start();` under your opening ` – Funk Forty Niner Nov 06 '15 at 17:13
  • 1
    Yeah, I thought it would be in Login.php, turns out it was my index.php page, at the top, right before the `` tags, all they were there for was to colour the header (the address bar and such) on mobile devices, they can't be there so I gotta find somewhere they can go. I've now learned that an output is (basically) anything that isn't wrapped in ``, like `` tags, would be okay. Quite a silly mistake really but I suppose silly mistakes are how you learn! :) Thanks again! – radiocaf Nov 06 '15 at 17:43
  • 1
    @radiocaf ah... there we go and you're most welcome; now knowing the "source" of the problem, I'm glad to see that it was finally resolved and was glad to have been of help, *cheers* - Mistakes happen, we're only human, remember that ;-) – Funk Forty Niner Nov 06 '15 at 19:28
1

I've noticed in the Login.php script that there is a line of code elseif (isset($_POST["login"])) { but none of the form elements have the name "login" other than the submit button, do you guys reckon that could be an issue?

This is not the issue. If the submit button has the name 'login', it is posted as 'login', so this is set.

The PHP changes Fred recommends in his comments I would follow- though it wouldn't make sense that these would impact the mobile users only. More likely, this has to do with how the session is being saved.

Does the redirect to index.php work for mobile? If so, can you var_dump($_SESSION); at the top of index.php and see what it says on mobile after you attempt to login?

Mikel Bitson
  • 3,583
  • 1
  • 18
  • 23
  • The redirect (I assume you are referring to `print "window.top.location.href='index.php'";` in the Login.php file) works, but then one could argue that this may not be working and I am only being redirected back to index.php because the form action is index.php. Removing the spaces didn't work. – radiocaf Nov 06 '15 at 16:25
  • 1
    Did you try the dump on session to debug? – Mikel Bitson Nov 06 '15 at 17:07