Can anybody help me find out how to create login with MVC?

Hey guys,

I am trying to create a login script, using an MVC structure, but i know i am missing something out. I normally code in php4 and procedural so it’s quite straightforward that way, however i want to try this method. Anyway below is my code and file structure:

Models/Person.class.php


<?php

class Person {
    protected $id, $email, $password, $forename, $surname, $address, $postcode, $date_added;

    public function __construct($dbrow) {
        $this->id = $dbrow['ID'];
        $this->email = $dbrow['email'];
        $this->password = $dbrow['password'];
        $this->forename = $dbrow['forename'];
        $this->surname = $dbrow['surname'];
        $this->address = $dbrow['address'];
        $this->postcode = $dbrow['postcode'];
        $this->date_added = $dbrow['date_added'];
    }

    public function getId(){
        return $this->id;
    }

    public function getEmail(){
        return $this->email;
    }

    public function getPassword(){
        return $this->password;
    }

    public function getForename(){
        return $this->forename;
    }
    
    public function getSurname(){
        return $this->surname;
    }

        public function getAddress(){
        return $this->address;
    }

    public function getPostcode(){
        return $this->postcode;
    }

    public function getDateAdded(){
        return $this->date_added;
    }
}

Models/Database.class.php


<?php
require_once('Person.class.php');
require_once('Category.class.php');

class Database {
    protected $mysqli;

    public function sanitise($data) { // Escapes parameters before sending SQL query
        foreach($data as $key => $value){
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        return $data;
    }

    public function __construct($host, $username, $password, $dbname) {
        $this->mysqli = new mysqli($host, $username, $password, $dbname);
        if ($this->mysqli->errno){
            echo 'Unable to connect'.$this->mysqli->error;
            exit();
        }
    }

    public function login($username, $password) { // Login
        $data = $this->sanitise($data);
        $sql = 'SELECT ID, email, password FROM hussaini_members
            WHERE email = \\''.$data['email'].'\\' AND password = \\''.$data['password'].'\\'';
        $results = $this->mysqli->query($sql);
        $personArray = array();
        while($row = $results->fetch_array(MYSQLI_ASSOC)) {
            $personArray[] =  new Person($row);
        }
        return $personArray;
    }

    public function __destruct() {
        $this->mysqli->close();
    }
}

Views/login.php


<?php
$view->pageTitle = 'Login';
require_once('Models/Database.class.php');
$database = new Database('localhost', ****', '', '****');

    if(isset($_POST['submit']))
    {
          $view->login($_POST['email'], $_POST['password']);
    }
    
require_once('Views/login.phtml');

login.phtml


<?php require('template/header.phtml') ?>

<h2>Login</h2>

<div id="login">

<fieldset>
    <legend>Please login</legend>
    <form action="" method="post">
        <ul>
            <li><label for="email">Email: </label> <input type="text" maxlength="45" id="email" name="email" /></li>
            <li><label for="password">Password: </label> <input type="password" maxlength="45" id="password" name="password" /></li>
            <li><input style="float:right; margin-right:30px;" type="submit" value="Submit" name="submit"/></li>
        </ul>
    </form>
</fieldset>
</div>
<?php require('template/sidebar.phtml') ?>
<?php require('template/footer.phtml') ?>

Now the structure above shows how i am trying to implement a login script, the login function in the database.class.php file looks fine. I am using a function to escape string called sanitise…

But in the index.php (Controller), I call the function but i need to actually check to see if the details match. I think i need some return error or something in the login function??

How can i fix this so i can create a session if the details are true??

Can someone please help?

Thanks again

I just need to check to see if the details are true, and the create a session, can anyone see how i can do this?

Currently in my login.php (Controller) i am not doing this…

Any help would be much appreciated.

Thanks again

By the way i made a mistake in my first post, the “Views/login.php” should be “Views/login.phtml”, AND login.phtml should be login.php… sorry :frowning:

Hey everyone,

I have recently started coding in php5 and used an MVC structure to follow…

I am somewhat stuck with the login, in php4 i simply had everything and all the code on ONE page, where i set the session or threw back an error!

But now i want to go further, so does anyone know where or how i can write the same thing but in mvc structure style?? I am using PHP5…

Thanks

Which MVC are you useing?
you can try SMRTY,it’s easy for PHP4 PHPER.

How do you mean which MVC?

I’m writing this myself… I just followed an O’Reilly book for the structure of the files and have managed to put a design together…

I have even managed to pull stuff out of a database so i know i’m doing it right… :rolleyes:

But this doesn’t seem to work, can you see what i am doing wrong?

In your view controller, your login function could look something like this:

function login($email, $password) {
  $db = new Database(); // or however you get your database object
  $personArray = $db->login($email, $password);
  if(sizeof($personArray) == 1) { // there should only be one user in the database with those credentials... you don't actually need an array, but I see you used one in the database->login function.
    // someone successfully logged in, save this in the session
    $personArray[0]->clearPassword(); // you don't want the password in the session variable!
    $_SESSION['currentUser'] = $personArray[0];
    $_SESSION['loggedin'] = true;
    // to do: login was successful. Display a message or something.
  }
  else {
    // to do: login failed! display a message or something
  }
}

It may help to have a session manager class instead of accessing the variables directly through $_SESSION. You also need to start your session when your framework is starting up and make sure the person model is included before the session starts because the session has to create the person object from the class.

Also don’t forget to ENCRYPT your passwords in your database and any time you are checking passwords. You do not want plain text passwords in your database. You can use md5() like everyone else if you want.

Hey,

Thanks smalshot, i really appreciate your suggestions.

So i’m trying to get this working. First of all i don’t need to have the Person Array. In PHP 4 i used to simply write:


while ($row = mysql_fetch_array($result)) {
//code here...
}

I don’t know how i can do that here? I feel as if i can remove the Array and use some sort of fetch?, in this function…


    public function login($username, $password) { // Login
        $data = $this->sanitise($data);
        $sql = 'SELECT ID, email, password FROM hussaini_members
            WHERE email = \\''.$data['email'].'\\' AND password = \\''.$data['password'].'\\'';
        $results = $this->mysqli->query($sql);
        $personArray = array();
        while($row = $results->fetch_array(MYSQLI_ASSOC)) {
            $personArray[] =  new Person($row);
        }
        return $personArray;
    }

Anyway, i have tried to make the code work in my login.php controller, code is shown:


<?php
$view->pageTitle = 'Login';
require_once('Models/Database.class.php');
$database = new Database('localhost', 'root', '', 'test');

    if(isset($_POST['submit']))
    {
        function login($email, $password) {
          $personArray = $database->login($email, $password);
          if(sizeof($personArray) == 1) { 
            // someone successfully logged in, save this in the session
            $personArray[0]->clearPassword(); // No password in Session!
            $_SESSION['currentUser'] = $personArray[0];
            $_SESSION['loggedin'] = true;
            echo "You are logged in...";
          }
          else {
            echo "You are NOT logged in...";
          }
        }
    }
    
require_once('Views/login.phtml');

But on button click nothing happens, no error message, nothing.

Any ideas what i am doing wrong?

Thanks again

Your Views/login.php looked like this before:

<?php
$view->pageTitle = 'Login';
require_once('Models/Database.class.php');
$database = new Database('localhost', ****', '', '****');

    if(isset($_POST['submit']))
    {
          $view->login($_POST['email'], $_POST['password']);
    }
    
require_once('Views/login.phtml');

You can keep that the same. I meant for the login function i shared to go in the class that makes up the $view object so you can call $view->login(…) like you had already. You didn’t share that code so I assumed that $view was a class of some kind.

I hope I didn’t make that more confusing.

Hey,

Sorry the $view is wrong, i should have had that as $database…

This is my database class at the minute:


<?php
require_once('Person.class.php');

class Database {
    protected $mysqli;

    public function sanitise($data) { // Escapes parameters before sending SQL query
        foreach($data as $key => $value){
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        return $data;
    }

    public function __construct($host, $username, $password, $dbname) {
        $this->mysqli = new mysqli($host, $username, $password, $dbname);
        if ($this->mysqli->errno){
            echo 'Unable to connect'.$this->mysqli->error;
            exit();
        }
    }

    public function selectCategory() {
        $sql = 'SELECT * FROM hussaini_categories';
        $results = $this->mysqli->query($sql);
        $categoryArray = array();
        while($row = $results->fetch_array(MYSQLI_ASSOC)) {
            $categoryArray[] =  new Category($row);
        }
        return $categoryArray;
    }

    public function login($username, $password) { // Login
        $data = $this->sanitise($data);
        $sql = 'SELECT ID, email, password FROM hussaini_members
            WHERE email = \\''.$data['email'].'\\' AND password = \\''.$data['password'].'\\'';
        $results = $this->mysqli->query($sql);
        $personArray = array();
        while($row = $results->fetch_array(MYSQLI_ASSOC)) {
            $personArray[] =  new Person($row);
        }
        return $personArray;
    }

    public function __destruct() {
        $this->mysqli->close();
    }
}

So in the login function do i need to add:


function login($email, $password) {
  $db = new Database(); // or however you get your database object
  $personArray = $db->login($email, $password);

  if(sizeof($personArray) == 1) { // there should only be one user in the database with those credentials... you don't actually need an array, but I see you used one in the database->login function.
    // someone successfully logged in, save this in the session
    $personArray[0]->clearPassword(); // you don't want the password in the session variable!
    $_SESSION['currentUser'] = $personArray[0];
    $_SESSION['loggedin'] = true;
    // to do: login was successful. Display a message or something.
  }
  else {
    // to do: login failed! display a message or something
  }
}

Or should this be a separate function? Sorry i’m hard work :confused:

Currently when i hit submit in my login.php (Controller), i do this:


    if(isset($_POST['submit']))
    {
        $database->login($_POST['email'], $_POST['password']);
    }

I get this error message:

Warning: Invalid argument supplied for foreach() in G:\xampp\htdocs\Manstore\Models\Database.class.php on line 9

Which relates to the sanitise function…

Any ideas?

Thanks

OK, since you don’t have a view class, instead of creating a new function, modify your login.php controller to this:

  if(isset($_POST['submit']))
  {
    $personArray = $database->login($_POST['email'], $_POST['password']);
    if(sizeof($personArray) == 1) { 
      // someone successfully logged in, save this in the session
      $personArray[0]->clearPassword(); // No password in Session!
      $_SESSION['currentUser'] = $personArray[0];
      $_SESSION['loggedin'] = true;
      echo "You are logged in...";
    }
    else {
      echo "You are NOT logged in...";
    }
  }

As for the warning on line 9 in Database.class.php, the problem is on line 33 (the first line of your login function in the database class. You pass $data to sanitise() but $data is not defined in this function, so it’s just null. you could fix it with this:

$data = $this->sanitise(array('email'=>$username, 'password'=>$password));

All I did there was create an array for the sanitise function using the arguments for the login function.

Hey it seems to be working :slight_smile:

Thanks

However i am trying to do this to check to see if the session exists:


<?php if (isset($_SESSION['loggedin'])) { ?>
                    <p><a href="">Log Out</a> | <a href="">My Account</a> | <a href="">Shopping Cart</a> | <a href="">Checkout</a></p>
                    <?php } else { ?>
                    <p>Welcome <strong>Guest</strong>, you are not logged in. <a href="login.php">Login</a> or <a href="register.php">Register</a> now.</p>
                    <?php } ?>

But $_SESSION[‘loggedin’] always returns false…

Now in my login.php page i have this:


  if(isset($_POST['submit']))
  {
    $personArray = $database->login($_POST['email'], $_POST['password']);
    if(sizeof($personArray) == 1) {
$personArray[0]->clearPassword(); // No password in Session!
      $_SESSION['currentUser'] = $personArray[0];
      $_SESSION['loggedin'] = true;
      $message = "";
      header ("Location: index.php");
    }
    else {
      $message = "<span style=\\"color:#00cc00\\">Invalid user credentials.</span>";
    }
  }

This works exactly how it should, it gives an error if the details are wrong otherwise it redirects to index.php, so this means the session is active?

But why can’t i do the check? I do have session_start(); at the top of the page…

Thanks again :slight_smile:

And sorry for all the questions…

Which script is calling session_start() ? Do you have an index page which calls the above? If so, added session_start() to the top of that script.

The only thing I can think of that would cause that is a missing session_start() like SpacePhoenix said. Is it at the top of every page that uses or might use the session variables? Specifically, both the login.php page and the index.php page that has the if(isset($_SESSION[‘loggedin’])) part?

Well i have a header.phtml and have included the session_start() at the top of the page. I have also tried putting session_start() on the index.php and login.php even though it’s not needed there as its in the header.phtml file…

Any ideas how i could do some tests to check?

Thanks

This is what i have at the top of the header.phtml file:


<?php
session_start();
require_once('Models/Database.class.php');
$database = new Database('localhost', '***', '', '*****');
?>

I have attached my file structure, see the image…

Where do i need to put the session start?

If you are including header.phtml before you do anything else PHP related, then you should be fine. session_start() just needs to happen once every page load before you access $_SESSION so I think you’re OK there. I’m not sure what’s going on.

When I run into a problem like this I start printing out my variables at each step until I figure out where they get messed up. Try printing out your session ( print_r($_SESSION); die(); ) once after you login before you redirect. Then go to the next page manually and print out your session again right after session_start() and again right before you check if isset($_SESSION[‘loggedin’]).

hmm, well i get this when i click on login:

Array ( [currentUser] => Person Object ( [id:protected] => 2 [email:protected] => test@test.com [password:protected] => hello [forename:protected] => [surname:protected] => [address:protected] => [postcode:protected] => [date_added:protected] => ) [loggedin] => 1 )

And then when i go to the index.php page manually i get this:

Array ( )

So does this mean that the SESSION is empty?

I took out the password clear code as it was giving me an error and i wanted to get the login working but on submit button click in have the following code to initiate the session:


  if(isset($_POST['submit']))
  {
    $personArray = $database->login($_POST['email'], $_POST['password']);
    if(sizeof($personArray) == 1) {
      $_SESSION['currentUser'] = $personArray[0];
      $_SESSION['loggedin'] = true;
      $message = "";
      print_r($_SESSION); die();
      header ("Location: homepage");
    }
    else {
      $message = "<span style=\\"color:#00cc00\\">Invalid user credentials.</span>";
    }
  }

Can you see what i am doing wrong?

Thanks

Hey,

I thought i’d managed to fix it, i changed the IF statement to this:


if (isset($_SESSION))

Instead of:


if (isset($_SESSION['loggedin']))

But this always shows me as logged in for some reason so this does not work :frowning:

isset($_SESSION) will always be true because $_SESSION always exists, even if it’s an empty array.

The empty array means the session is empty. So either session_start() wasn’t called before you printed $_SESSION or something else emptied your session, OR it’s possible your browser could be blocking the session cookie (unlikely, but possible).

you could add print session_id(); before the print_r($_SESSION); session_id() should be the same every time you load the page. If you open it with a different browser, you will get a different session id. If your session id changes from page to page then you know your browser is blocking the session cookie.