Lit SITE

Lit SITE will pull together Lit LIST, and Lit FORM. Plus, we will add in the features from The SITE, The ACCOUNT and The PASSWORD.

You can open a completed version of the project in your browser here.

If you want to download completed versions of the PHP scripts for this project, you can find them here.

Here are the steps we will do to get the Lit SITE working:

Much of the work done for Lit LIST and Lit FORM can be used directly here, so we will build on what you have done so far.

Project Set-up. Set up a directory in the htdocs folder to hold your project. The recommended name is n413_litsite.

Copy all the files from your Lit FORM project into your project folder. Or you can use the completed set of Lit FORM files from here. Either set should contain a complete set of the CodeIgniter files.

Open config/config.php and update the "base_url" value with the new project path. It should be:

$config['base_url'] = 'http://localhost:8888/n413_litsite/';
//or for XAMPP:
//$config['base_url'] = 'http://localhost/n413_litsite/';

If you downloaded a new set of files, be sure the config/database.php files have been updated with the correct paths and database connection credentials, port numbers, etc. (See Lit LIST.)

We will use the same database tables ("list", "form_responses", "users_hash", and "litlist") used in The LIST, The FORM, The PASSWORD, and Lit LIST project. If you don't already have those tables set up, see the intructions here. Or you can download the SQL script to create the tables here.

Home Page. The Litjams controller already has a default index() method, but it currently points to "The List" page. We can set it up for a Home Page with a few edits:

  • Update the page title to "AMP JAMS | Lit SITE".
  • Update "this_page" to "home".
  • Change the $data["records"] key to $data["row"].
  • Change the litlist_model method to get_random_row().
  • Update the main view to "index".

It should look like this:

(controllers/Litjams.php)
...
public function index(){ $data["page_title"] = "AMP JAMS | Lit SITE"; $data["this_page"] = "home"; $data["row"] = $this->litlist_model->get_random_row(); $this->load->view('templates/head', $data); $this->load->view('index', $data); }
...

Create the model method for get_random_row() in models/Litlist_model.php:

(models/Litlist_model)
...
public function get_random_row(){ $sql = "SELECT * FROM `litlist` ORDER BY RAND() LIMIT 1"; $query = $this->db->query($sql); return $query->row_array(); }
...

This gets a random row from the "litlist" table and returns it to the Controller.

Now, copy index.php from The SITE and move it to your views folder. Make the following changes:

  • Delete the first PHP section.
  • Adjust the margin-top spacing by changing the "headline" div from "mt-5" to "mt-3" and delete the "content" div "mt-5" class.
  • Change the first headline to "Lit JAM Site".
  • Change the subtitle to "The Top-Ten List".
  • Change the "spacer" div width to "col-2".
  • Edit the <a> tags and convert the URLs to CodeIgniter format using "site_url()".
  • Change the "image" div width from "col-6" to "col-3".
  • Edit the <img> tag "src" URL and convert it to CodeIgniter format using "base_url()". Edit the URL so it points to the correct "detail" page. (See the script below.)
  • Remove the <h2> headline from the "image" div, and create a new "col-5"dive to hold the headline. Give the headline a margin-top of 200px and wrap it in an <a> tag just like the link for the image.
  • In the <script> tags, delete the two Javascript variables for "this_page" and "page_title".

The script should look like this:

(views/index.php)
<div class="container-fluid"> <div id="headline" class="row mt-3"> <div class="col-12 text-center"> <h1>Lit JAM Site</h1> </div> <!-- /col-12 --> </div> <!-- /row --> <div class="row"> <div id="subtitle" class="col-12 text-center"> <h3>The Top-Ten List</h3> </div> <!-- /col-12 --> </div> <!-- /row --> <div id="content" class="row"> <div class="col-2"></div><!-- spacer --> <div class="col-2 mt-5"> <!-- navigation --> <a href="<?=site_url()?>/litjams/litlist" ><h4>Top Ten List</h4></a> <a href="<?=site_url()?>/litjams/litform" ><h4>Contact Us</h4></a> </div> <div class="col-3 text-center"> <!-- image --> <a href="<?=site_url()?>/litjams/detail/<?= echo $row["id"]?>"> <img src="<?=base_url()?>assets/images/<?php=$row["image"]?>" width="100%"; /> </a> </div> <!-- /image --> <div class="col-5"> <!-- caption --> <a href="<?=site_url()?>/litjams/detail/<?= echo $row["id"]?>"> <h2 style="margin-top:200px;"><?=$row["item"]?></h2> </a> </div> </div> <!-- /row --> </div> <!-- /container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //ready </script> </html>

Test this in your browser, and you should see a Home Page that looks like this.

The left-side navigation links should take you to the expected pages, and clicking on the image or the caption should take you to the detail page for the randomly featured list item.

Messages Page. Adapt the Messages page from The ACCOUNT for use with the CodeIgniter setup.

Controller. The first step is to add a method for messages into the Litjams controller. Start by copying the litlist() method and pasting it at the end of the controller script (but inside the Litjams class curly brace). Make the following modifications:

  • Change the name of the method to "messages".
  • Change the page title to "AMP JAMS | Lit Messages"
  • Change "this_page" to "messages"
  • Change the "records" key to "messages" and change the data fetching method to
    $this->litform_model->get_messages(); (This method will need to be written next.)
  • Change the 'litlist' view to 'messages'.

The Litjams controller method should look like this:

(controllers/Litjams.php)
...
public function messages(){ $data["page_title"] = "AMP JAMS | Lit Messages"; $data["this_page"] = "messages"; $data["messages"] = $this->litform_model->get_messages(); $this->load->view('templates/head', $data); $this->load->view('messages', $data); }
...

Model.For the next step, write the get_messages() method for fetching the messages from the database. Open the Litform_model model and add a new method at the end of the script (but inside the Litform_model class curly brace). Next, open messages.php from The ACCOUNT and copy-paste the SQL query into the new method. Make the query and return the result as shown below:

(models/Litform_model.php)
...
public function get_messages(){ $sql = "SELECT * FROM `form_responses` ORDER BY timestamp DESC"; $query = $this->db->query($sql); return $query->result_array(); }
...

View. Open views/templates/head.php. Review the method for adding a right-side list to the nav-bar in The ACCOUNT and add the right-side list structure to the nav-bar in head.php. Change the URL to a CodeIgniter-style link for the Messages page, as shown below:

(views/templates/head.php)
...
<ul id="right_navbar" class="navbar-nav ml-auto mr-5"> <li id="messages_item" class="nav-item"> <a id="messages_link" class="nav-link" href="<?=site_url()?>/litjams/messages">Messages</a> </li> </ul>
...

Copy messages.php into the views folder. Make the following modifications:

  • Delete the first block of PHP code.
  • Comment out the "if" statement and the "else" block of code so we don't need a log-in to see the messages. (As shown below)
  • The next section discusses the CodeIgniter "property" syntax for CodeIgniter sessions. Go ahead and convert the "if($_SESSION["role"]..." line to CodeIgniter property syntax:
    if($this->session->role > 0){ ... 
  • Delete the Javascript vars this_page and page_title.

Here is how the messages.php script should look:

(views/messages.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <?php if(count($messages) > 0){ echo '<h1>Contact Form Messages</h1>'; }else{ echo '<h2>There are no messages at this time.</h2>'; } ?> </div> <!-- /.col-12 --> </div> <!-- /.row --> <?php // if($this->session->role > 0){ foreach($messages as $message){ echo' <div class="row mt-3"> <div class="col-2"></div> <!-- spacer --> <div class="col-2">'.$message["name"].'<br/> <a href="mailto:'.$message["email"].'">'.$message["email"].'</a><br/> ['.$message["timestamp"].'] </div> <div class="col-6">'.$message["comment"].'</div> </div> <!-- /.row -->'; } //foreach // }else{ // echo' // <div class="row mt-3"> // <div class="col-12 text-center"><h3>You are not authorized to view the messages.</h3></div> // </div> <!-- /.row -->'; // } //else if ?> </div> <!-- /.container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //document.ready </script> </html>

Test this in your browser. It should look like this:

You should be able to navigate around the site, leave new comments in the "Contact" form, and see them in the Messages list.

Once that is working, uncomment the if-else structure that hides the messages from unauthorized viewing.

A log-in system is the next step. To get there, we should review sessions.

Sessions. It would be good to review the material on PHP sessions found in The ACCOUNT at this point. Sessions work exactly the same with CodeIgniter as they do with any other PHP project, but CodeIgniter has some features built on top of the PHP sessions structure that we will use.

The first difference you will see is that you never need to start a session. You may recall that we set up "autoload" to load the sessions library in Lit LIST. This means that everytime we run the costructor function for a class, the session library is loaded, and a session is started. Had we not done the autoload step, we would need to start sessions, just as before. CodeIgniter's method of doing this is:

$this->load->library('session');

The second difference (which you might not notice right away) is that CodeIgniter will time out sessions after 2 hours. This can be configured to a different time, but instead of the default being no time out, the default is 2 hours.

The third difference is the way variables are stored to/accessed from the $_SESSION array. CodeIgniter uses two alternate methods in addition to the standard PHP syntax:

//setting variables
    $_SESSION["user_id"] = $user_id; //standard syntax
    $this->session->set_userdata('user_id', $user_id); //CodeIgniter "userdata" syntax
    $this->session->user_id = $user_id; //CodeIgniter property syntax
    
//getting variables
    $user_id = $_SESSION["user_id"]; //standard syntax
    $user_id = $this->session->userdata('user_id'); //CodeIgniter "userdata" syntax    
    $user_id = $this->session->user_id; //CodeIgniter property syntax  

You can also pass entire sets of session data as arrays using the standard syntax or the "userdata" syntax, but not the CodeIgniter property syntax.

Where possible, we will use the property syntax, since it is concise and the "userdata" syntax is no longer used in Codeigniter version 4.

Log-In. As we begin adding authentication features to the project, organize them into a separate Controller and Model. Add a new Controller named "Auth.php" and a new Model named Auth_model.php.

Controller. Copy the controllers/Litjams.php controller and name the copy Auth.php. (The first character must be capitalized.) Open it and name the class "Auth". Make the following modifications:

  • Change the model for the first load->model() command to 'auth_model', which will be built in a later step. Delete the other load->model() command.
  • With the index method, change the page title to "AMP JAMS | Lit LOGIN".
  • Set "this_page" to "login".
  • Delete the line that calls litlist_model->get_random_row().
  • Change load->view('index', $data) to load->view('auth/login', $data).
  • Delete the other methods in the class, but be sure to leave the curly brace that closes the class.

It should look like this:

(controllers/Auth.php)
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Auth extends CI_Controller { public function __construct() { parent::__construct(); $this->load->model('auth_model'); } public function index(){ $data["page_title"] = "AMP JAMS | Lit LOGIN"; $data["this_page"] = "login"; $this->load->view('templates/head', $data); $this->load->view('auth/login', $data); } }

Model. The Model method will not be used until the login submission step, but go ahead and put the Auth_model.php file in place and write the class. Start with the existing Litform_model.php file. Copy the file and change the name to "Auth_model.php". Make the following modifications:

  • Change the class name from "Litform_model" to "Auth_model", keeping the capitalization shown here.
  • Leave the constructor function, but delete the others.
  • Add a method called "authenticate" that takes an argument called "$credentials", as shown below.

It should look like this for now:

(models/Auth_model.php)
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Auth_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function authenticate($credentials){ return true; } }

We will return to this when we are ready to process the logins.

Views. Add a link for the log-in to the right-side list of the nav-bar in views/templates/head.php. Be sure the URL is CodeIgniter-style. Since the method that does the log-in is the index method of the Auth controller, we only need to call the Auth controller to ge the login page:

(views/templates/head.php)
...
<ul id="right_navbar" class="navbar-nav ml-auto mr-5"> <li id="messages_item" class="nav-item"> <a id="messages_link" class="nav-link" href="<?=site_url()?>/litjams/messages">Messages</a> </li> <li id="login_item" class="nav-item"> <a id="login_link" class="nav-link" href="<?=site_url()?>/auth">Log-In</a> </li> </ul>
...

Next, create an "auth" directory inside the views folder. This will allow us to organize the view files. Copy login.php from The PASSWORD and add it to the auth folder. Make the following modifications:

  • Delete the first PHP block with the "include" statement.
  • Change the headline to "Amp Jam Lit Log-in".
  • Delete the Javascript vars this_page and page_title.
  • Change the URL in the jQuery $.post() statement. It should look like this:
    $.post("<?=site_url()?>/auth/authenticate", ... 
  • Change the URLs in the right_side_update() function to CodeIgniter links.

The script should look like this:

(views/auth/login.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Full Stack Amp Jam Log-in</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="login_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> User Name: <input type="text" id="username" name="username" class="form-control" value="" placeholder="Enter User Name" required/><br/> Password: <input type="password" id="password" name="password" class="form-control" value="" placeholder="Enter Password" required/><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#login_form").submit(function(event){ event.preventDefault(); $.post("<?=site_url()?>/auth/authenticate", $("#login_form").serialize(), function(data){ //handle messages here if(data.status){ $("#form-container").html(data.success); right_navbar_update(data.role); }else{ $("#form-container").html(data.failed); } }, "json" ); //post }); //submit }); //document.ready function right_navbar_update(role){ var html = ""; if (role > 0) { html = '<li id="messages_item" class="nav-item">'+ '<a id="messages_link" class="nav-link" href="<?=site_url()?>/litjams/messages">Messages</a>'+ '</li>'; } html += '<li id="logout_item" class="nav-item">'+ '<a id="logout_link" class="nav-link" href="<?=site_url()?>/auth/logout">Log-Out</a>'+ '</li>'; $("#right_navbar").html(html); } </script> </html>

You can test it in your browser now. It should look like the screeenshot on the right, but you will not be able to submit the form until the AJAX methods are added to the controller and the model.

AJAX. Add a Controller method to the Auth controller to accept the AJAX call from the log-in form. Copy the contact_post() method and paste it after the index method (but within the class). Make the following modifications:

  • Change the name to "authenticate".
  • Change $contact to $credentials.
  • Change the model method from
    $this->litform_model->contact_post($contact) to
    $this->auth_model->authenticate($credentials);

It should look like this:

(controllers/Auth.php)
...
public function authenticate(){ $credentials = $this->input->post(); $messages = $this->auth_model->authenticate($credentials); echo json_encode($messages); }
...

The login credentials posted from the login page will be sanitized and stored as an array in $credentials. This is passed to the Auth_model for authentication. Messages about the result will be passed back, and they will be encoded as JSON before being sent out to the browser.

Now we are ready to write the Model method to authenticate the password. Open n413auth.php from The PASSWORD and copy from the end of the sanitize() function on down to (but not including) the "echo" command. Paste this into the Auth_model "authenticate" method, above the "return" statement. Make the following modifications:

  • Replace the two lines that set $username and $password to empty quotes with:
    $username = $credentials["username"]; $password = $credentials["password"];
  • Delete the two "if" statements that store the $_POST variables. These variables are now passed in, having been retrieved from the $_POST array (and sanitized) by the controller.
  • Leave the SQL query, but replace the two following lines that use mysqli commands with:
    $query = $this->db->query($sql); $row = $query->row_array();
  • Wrap the "password_verify" block of code in a conditional if($row) in case no rows are returned..
  • Delete the session_start() command, since we already have a session.
  • Convert the $_SESSION statements from standard PHP syntax to CodeIgniter property syntax. This would work either way, but it is an opportunity to use the Codeigniter property syntax for the session.
  • Change the "return" from "true" to $messages.
It should look like this:
(models/Auth_model.php)
...
public function authenticate($credentials){ $messages = array(); $messages["status"] = 0; $messages["role"] = 0;; $messages["success"] = ""; $messages["failed"] = ""; $username = $credentials["username"]; $password = $credentials["password"]; $sql = "SELECT * FROM `users_hash` WHERE username = '".$username."' LIMIT 1"; $query = $this->db->query($sql); $row = $query->row_array(); if($row){ if(password_verify($password, $row["password"])){ $this->session->user_id = $row["id"]; $this->session->role = $row["role"]; } } if($this->session->user_id > 0){ $messages["status"] = "1"; $messages["role"] = $this->session->role; $messages["success"] = '<h3 class="text-center">You are now Logged In.</h3>'; }else{ $messages["failed"] = '<h3 class="text-center">The Log-in was not successful.</h3> <div class="col-12 text-center"><a href="<?=site_url()?>/auth"><button type="button" class="btn btn-primary mt-5">Try Again</button></a></div>'; } return $messages; }
...

Setting the "user_id" property to some number greater than zero creates the login.

You should now be able to test the log-in in your browser using one of the accounts in your users_hash table.

AJAX Callback. Let's review how the AJAX process works for updating the browser. Notice the jQuery $.post() function in login.php, and its four arguments:

  • URL for posting the data.
  • Data object to send.
  • Callback function (an "anonymous" function with a "data" argument).
  • Data type. This is a string that usually contains either "text" or "json", and determines how the "data" argument for the call back function is interpreted.
(views/auth/login.php)
...
$.post("<?=site_url()?>/auth/authenticate", //URL $("#login_form").serialize(), //data object function(data){ //callback function //handle messages here if(data.status){ $("#form-container").html(data.success); right_navbar_update(data.role); }else{ $("#form-container").html(data.failed); } }, "json" //data type ); //post
...

When the $messages array is "echo"ed back to the login page in the browser, it arrives at the jQuery $.post() function's callback function as the data argument. When the data type is set to "json", the data argument is converted to a Javascript variable and may be used directly. The associative keys of the PHP $messages array become property variables of a Javascript object.

The callback function can check the "status" property and use that logic to display the correct message, using jQuery to replace the form with either the "success" message or the "failed" message. In addition, if the login is sucessful, the right_navbar_update() function is called with the user's role. This will make the Messages link visible for roles with permissions.

Logout. If you log in, you need to be able to log out. Begin with the Controller method for the Logout page. Copy the index() method from the Auth controller and paste it at the bottom script (but inside the class). Make the following modifications:

  • Change the name to "logout".
  • Change the page title to "AMP JAMS | Lit LOGOUT".
  • Remove the log-in by setting the user_id to zero: $this->session->user_id = 0;
  • Destroy the session with Codeigniter's $this->session->sess_destroy(); (equivalent to PHP's session_destroy();)
  • Change "this_page" to "logout".
  • Change the 'login' view to 'logout'.

It should look like this:

(controllers/Auth.php)
...
public function logout(){ $data["page_title"] = "AMP JAMS | Lit LOGOUT"; $data["this_page"] = "logout"; $this->session->user_id = 0; //remove the log-in $this->session->sess_destroy(); //delete the session variables (for the next page load) $this->load->view('templates/head', $data); $this->load->view('auth/logout', $data); }
...

No Model methods are required here, but there is logic needed in the nav-bar. The nav-bar needs to change what it displays on the right side, depending on the log-in state. Open views/templates/head.php and find the right-side list. Drop in the PHP structure, with the logout link, as shown:

(views/templates/head.php)
...
<ul id="right_navbar" class="navbar-nav ml-auto mr-5"> <?php if($this->session->user_id > 0){ echo ' <li id="messages_item" class="nav-item"> <a id="messages_link" class="nav-link" href="'.site_url().'/litjams/messages">Messages</a> </li> <li id="logout_item" class="nav-item"> <a id="logout_link" class="nav-link" href="'.site_url().'/auth/logout">Log-Out</a> </li>'; }else{ echo ' <li id="login_item" class="nav-item"> <a id="login_link" class="nav-link" href="'.site_url().'/auth">Log-In</a> </li>'; } ?> </ul>
...

If there is a log-in, the user_id will be at least 1. If it's more than zero, we have a log-in and we show the logged-in version of the nav-bar. Otherwise, we show the logged out version.

Notice that the syntax for inserting the site_url() function is different here. We are echoing a string from PHP instead of dropping PHP into HTML.

Now we can adapt the logout.php view from The ACCOUNT. Copy it into the views/auth folder and make the following modifications:

  • Delete the first PHP section.
  • Change the headline to "Amp Jam Lit Log-out".
  • Update the <a> tag URL with a CodeIgniter link to the Login page.
  • In the <script> tags, delete the two Javascript variables for "this_page" and "page_title".

It should look like this:

(views/auth/logout.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Amp Jam Lit Log-out</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div class="col-4 text-center"> <h3>You are now Logged Out.</h3> <a href="<?=site_url()?>/auth"><button class="btn btn-primary mt-5">Log In</button></a> </div> <!-- /.col-4 --> </div> <!-- /.row --> </div> <!-- /.container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //document.ready </script> </html>

Try this now in your browser. Log in and log out. Notice whether the nav-bar behaves correctly.

One issue you should notice is that if you move away from the Login page, the "Messages" link is displayed regardless of whether the "role" for the account has privileges or not. Correct that now by adding a conditional check to the nav-bar.

Go back to the right-side menu in views/templates/head.php and restructure the logic to only show the "Messages" link if the role is greater than zero:

(views/templates/head.php)
...
<ul id="right_navbar" class="navbar-nav ml-auto mr-5"> <?php if($this->session->user_id > 0){ if($this->session->role > 0){ echo ' <li id="messages_item" class="nav-item"> <a id="messages_link" class="nav-link" href="'.site_url().'/litjams/messages">Messages</a> </li> } echo ' <li id="logout_item" class="nav-item"> <a id="logout_link" class="nav-link" href="'.site_url().'/auth/logout">Log-Out</a> </li>'; }else{ echo ' <li id="login_item" class="nav-item"> <a id="login_link" class="nav-link" href="'.site_url().'/auth">Log-In</a> </li>'; } ?> </ul>
...

Now that there is a way to log in and log out, test whether the Messages page properly hides the messages if you log out and use a direct URL to see the messages.

Registration Page. The Registration Page will provide a way for users to create new accounts with encrypted passwords. Since registration is part of the authentication process, the Auth controlller and Auth_model model will be used.

Controller. Begin with the Auth controller. Copy the index method and paste it at the end of the script (but inside the class). Make the following modifications:

  • Change the method name to "register".
  • Change the page title to "AMP JAMS | Lit REGISTER".
  • Change "this_page" to "register".
  • Change the view from 'auth/login' to 'auth/register'.
It should look like this:
(controllers/Auth.php)
...
public function register(){ $data["page_title"] = "AMP JAMS | Lit REGISTER"; $data["this_page"] = "register"; $this->load->view('templates/head', $data); $this->load->view('auth/register', $data); }
...

Nothing needs to be done with the Model for now. There will be a method added later as the AJAX process for creating the account is built.

Views. The first task for the view is to add a link to the nav-bar. Return to views/templates/head.php and insert a link for the Registration page in the right-side list, inside the "else" section, just before "Log-In":

(views/templates/head.php)
...
}else{ echo ' <li id="register_item" class="nav-item"> <a id="register_link" class="nav-link" href="'.site_url().'/auth/register">Register</a> </li> <li id="login_item" class="nav-item"> <a id="login_link" class="nav-link" href="'.site_url().'/auth">Log-In</a> </li>'; }
...

To create the Registration Form, copy register.php from The PASSWORD and add it to the auth folder. Make the following modifications:

  • Delete the first PHP block with the "include" statement.
  • Remove the style tag section and replace the 5 occurrences of the "error_msg" class with the Bootstrap text color class "text-danger".
  • Change the headline to "Amp Jam Lit Register".
  • Delete the Javascript vars this_page and page_title.
  • Change the URL in the jQuery $.post() statement. It should look like this:
    $.post("<?=site_url()?>/auth/new_account", ... 
  • Change the URLs in the right_side_update() function to CodeIgniter links.

The script should look like this:

(views/auth/register.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Amp Jam Lit Register</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="register_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> <div>User Name: <input type="text" id="username" name="username" class="form-control" value="" placeholder="Enter User Name" required/></div> <div id="username_length" class="text-danger"></div> <div id="username_exists" class="text-danger"></div> <div class="mt-3">E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/></div> <div id="email_exists" class="text-danger"></div> <div id="email_validate" class="text-danger"></div> <div class="mt-3">Password: <input type="password" id="password" name="password" class="form-control" value="" placeholder="Enter Password" required/></div> <div id="password_length" class="text-danger"></div> <div class="mt-5"><button type="submit" id="submit" class="btn btn-primary float-right">Submit</button></div> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#register_form").submit(function(event){ event.preventDefault(); $.post( "<?=site_url()?>/auth/new_account", $("#register_form").serialize(), function(data){ if(data.status){ $("#form-container").html(data.success); right_navbar_update(); }else{ if(data.errors){ // handle error messages here for (var key in data){ switch(key){ case "status": case "errors": case "success": case "failed": break; default: $("#"+key).html(data[key]); $("#"+key).css("display","block"); break; } //switch } //for-in }else{ $("#form-container").html(data.failed); //registration failed, but without errors } //if data.errors } //if data.status }, //callback function "json" ); //post }); //submit }); //document.ready function right_navbar_update(){ var html = '<li id="logout_item" class="nav-item">'+ '<a id="logout_link" class="nav-link" href="<?=site_url()?>/auth/logout">Log-Out</a>'+ '</li>'; $("#right_navbar").html(html); } </script> </html>

Test this in your browser. It should look like the screenshot on the right. You won't be able to submit the form until the AJAX structure is in place. Proceed with that now.

AJAX. The register form's $.post() function expects there to be a "new_account" method in the Auth controller. Put it there now by copying the authenticate() method and pasting it at the end of the script (but inside the class). Make the following modifications:

  • Change the name of the method to "new_account"
  • Change the name of the auth_model method to "new_account"

It should look like this:

(controllers/Auth.php)
...
public function new_account(){ $credentials = $this->input->post(); $messages = $this->auth_model->new_account($credentials); echo json_encode($messages); }
...

Continue with a new_account method in Auth_model. Open Auth_model and create a new method at the end of the script (but inside the class). Name the method new_account, with a $credentials argument:

(models/Auth_model.php)
...
public function new_account($credentials){ }
...

Much of the structure needed for inserting the new accounts is in the n413register.php script from The PASSWORD. Review the section about n413register.php in The PASSWORD to refresh your memory about the various operations in the script, especially:

Open n413register.php and copy everything from the end of the sanitize() function down to (but not including) the "echo" statement at the end. Paste the code into the new method and make the following modifications:

  • Where the variables are initialized with empty strings, set them to the values that are contained in $credentials:
    (models/Auth_model.php)
    ...
    $username = $credentials["username"]; $email = $credentials["email"]; $password = $credentials["password"];
    ...
  • Delete all the lines that begin if(isset($_POST.... The $_POST values were retrieved and sanitized in the controller.
  • Change $username = sanitize($username); to:
    $username = $this->db->escape_str($username);

    There's no need to sanitize the username, but it is important to escape special characters.

  • There is no need to sanitize $email, so change the logic of this section to:
    (models/Auth_model.php)
    ...
    if (! filter_var($email, FILTER_VALIDATE_EMAIL)){ $messages["errors"] = 1; $messages["email_validate"] = "There are problems with the e-mail address. Please correct them."; }
    ...

    This will generate an error if the $email is not formatted properly.

  • In all the queries, replace $result = mysqli_query($link, $sql); with the CodeIgniter version:
    $query = $this->db->query($sql);
  • For both the username and email queries, replace the mysqli_num_rows() logic with the CodeIgniter function:
    if($query->num_rows() > 0)
  • Replace $user_id = mysqli_insert_id($link); with the CodeIgniter version:
    $user_id = $this->db->insert_id();
  • Delete session_start(), since the session automatically starts.
  • Change the $_SESSION syntax to the CodeIgniter "property" syntax:
    $this->session->user_id = $user_id;
    $this->session->role = 0;
  • Change if(isset($_SESSION["user_id"])) to:
    if($this->session->user_id > 0)
  • In the last message string, update the URL to a CodeIgniter link. Remember to use the style for a PHP string, not an HTML PHP insert:
    (models/Auth_model.php)
    ...
    $messages["failed"] = '<h3 class="text-center">The Registration was not successful.</h3><div class="col-12 text-center"><a href="'.site_url().'/auth/register" class="text-center"><button class="btn btn-primary mt-5">Try Again</button></a></div>';
    ...
  • The last step is to add return $messages; as the last line of the method.

The finished method should look like:

(models/Auth_model.php)
...
public function new_account($credentials){ $messages = array(); $messages["status"] = 0; $messages["errors"] = 0; $messages["username_length"] = ""; $messages["password_length"] = ""; $messages["username_exists"] = ""; $messages["email_exists"] = ""; $messages["email_validate"] = ""; $messages["success"] = ""; $messages["failed"] = ""; $username = $credentials["username"]; $email = $credentials["email"]; $password = $credentials["password"]; trim($username); //delete leading and trailing spaces if(strlen($username) < 5){ $messages["errors"] = 1; $messages["username_length"] = "The username must have at least 5 characters."; }else{ $username = $this->db->escape_str($username); } if (! filter_var($email, FILTER_VALIDATE_EMAIL)){ $messages["errors"] = 1; $messages["email_validate"] = "There are problems with the e-mail address. Please correct them."; } trim($password); //delete leading and trailing spaces if(strlen($password) < 8){ $messages["errors"] = 1; $messages["password_length"] = "The password must have at least 8 characters."; }else{ $encrypted_password = password_hash($password, PASSWORD_DEFAULT); if($encrypted_password){ $password = $encrypted_password; }else{ $messages["errors"] = 1; $messages["password_length"] = "Password encryption failed. You cannot register at this time"; } } if( ! $messages["errors"] ){ $sql = "SELECT * FROM `users_hash` WHERE username = '".$username."'"; $query = $this->db->query($sql); if($query->num_rows() > 0){ $messages["errors"] = 1; $messages["username_exists"] = "This username already exists. Please select another username."; } $sql = "SELECT * FROM `users_hash` WHERE email = '".$email."'"; $query = $this->db->query($sql); if($query->num_rows() > 0){ $messages["errors"] = 1; $messages["email_exists"] = "This email is already in use. You cannot register another account with this email address."; } } if( ! $messages["errors"] ){ $sql = "INSERT INTO `users_hash` (`id`, `username`, `email`, `password`, `role`) VALUES (NULL, '".$username."', '".$email."', '".$password."', '0')"; $query = $this->db->query($sql); $user_id = $this->db->insert_id(); if($user_id){ $this->session->user_id = $user_id; $this->session->role = 0; } // if($user_id) } // if( ! $messages["errors"] ) // if($this->session->user_id > 0){ $messages["status"] = "1"; $messages["success"] = '<h3 class="text-center">You are now Registered and Logged In.</h3>'; }else{ $messages["failed"] = '<h3 class="text-center">The Registration was not successful.</h3><div class="col-12 text-center"><a href="'.site_url().'/auth/register" class="text-center"><button class="btn btn-primary mt-5">Try Again</button></a></div>'; } return $messages; }
...

Try this in your browser. You should see the message from the screenshot if things went well. You should also see records in the users_hash table for the new account.

You should see error messages if you make errors on the form. Try to make all the errors to test whether they work properly.

The Lit SITE is complete! You have built a third MVC Full Stack application. This one holds all the necessary components to build your own site!

Here are completed versions of the scripts used for this project:

Controllers and Models

(controllers/Litjams.php)
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litjams extends CI_Controller { public function __construct() { parent::__construct(); $this->load->model('litlist_model'); $this->load->model('litform_model'); } public function index(){ $data["page_title"] = "AMP JAMS | Lit SITE"; $data["this_page"] = "home"; $data["row"] = $this->litlist_model->get_random_row(); $this->load->view('templates/head', $data); $this->load->view('index', $data); } public function litlist(){ $data["page_title"] = "AMP JAMS | Lit LIST"; $data["this_page"] = "litlist"; $data["records"] = $this->litlist_model->get_litlist_items(); $this->load->view('templates/head', $data); $this->load->view('litlist', $data); } public function detail($id){ $detail = $this->litlist_model->get_litlist_detail($id); $data["page_title"] = "AMP JAMS | ".$detail["item"]; $data["this_page"] = "litlist"; $data["row"] = $detail; $this->load->view('templates/head', $data); $this->load->view('detail', $data); } public function litform(){ $data["page_title"] = "AMP JAMS | Lit FORM"; $data["this_page"] = "contact"; $this->load->view('templates/head', $data); $this->load->view('litform', $data); } public function contact_post(){ $contact = $this->input->post(); $messages = $this->litform_model->contact_post($contact); echo json_encode($messages); } public function messages(){ $data["page_title"] = "AMP JAMS | Lit Messages"; $data["this_page"] = "messages"; $data["messages"] = $this->litform_model->get_messages(); $this->load->view('templates/head', $data); $this->load->view('messages', $data); } }
(models/Litlist_model.php) 
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litlist_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function get_litlist_items(){ $sql = "SELECT * FROM `litlist`"; $query = $this->db->query($sql); return $query->result_array(); } public function get_litlist_detail($id){ $sql = "SELECT * FROM `litlist` WHERE id = '".$id."'"; $query = $this->db->query($sql); return $query->row_array(); } }
(models/Litform_model.php) 
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Litform_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function contact_post($contact){ $contact["name"] = $this->db->escape_str($contact["name"]); $contact["comment"] = $this->db->escape_str($contact["comment"]); $messages = array(); $messages["status"] = $this->db->insert('form_responses', $contact); if($messages["status"]){ $messages["success"] = '<p>Thank you for submitting your comment. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; }else{ $messages["failed"] = '<p>Sorry, but something went wrong. Please try again later. <br/> <span class="mt-5 float-right"><i>The Web Site Team</i></span></p>'; } return $messages; } }
(controllers/Auth.php)
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Auth extends CI_Controller { public function __construct() { parent::__construct(); $this->load->model('auth_model'); } public function index(){ $data["page_title"] = "AMP JAMS | Lit LOGIN"; $data["this_page"] = "login"; $this->load->view('templates/head', $data); $this->load->view('auth/login', $data); } public function authenticate(){ $credentials = $this->input->post(); $messages = $this->auth_model->authenticate($credentials); echo json_encode($messages); } public function logout(){ $data["page_title"] = "AMP JAMS | Lit LOGOUT"; $data["this_page"] = "logout"; $this->session->user_id = 0; //delete the session $this->session->sess_destroy(); //delete the session $this->load->view('templates/head', $data); $this->load->view('auth/logout', $data); } public function register(){ $data["page_title"] = "AMP JAMS | Lit REGISTER"; $data["this_page"] = "register"; $this->load->view('templates/head', $data); $this->load->view('auth/register', $data); } public function new_account(){ $credentials = $this->input->post(); $messages = $this->auth_model->new_account($credentials); echo json_encode($messages); } }
(models/Auth_model.php)
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Auth_model extends CI_Model { public function __construct() { parent::__construct(); //this causes the database library to be autoloaded //loading of any other models would happen here } public function authenticate($credentials){ $messages = array(); $messages["status"] = 0; $messages["role"] = 0;; $messages["success"] = ""; $messages["failed"] = ""; $username = $credentials["username"]; $password = $credentials["password"]; $sql = "SELECT * FROM `users_hash` WHERE username = '".$username."' LIMIT 1"; $query = $this->db->query($sql); $row = $query->row_array(); if($row){ if(password_verify($password, $row["password"])){ $this->session->user_id = $row["id"]; $this->session->role = $row["role"]; } } if($this->session->user_id > 0){ $messages["status"] = "1"; $messages["role"] = $this->session->role; $messages["success"] = '<h3 class="text-center">You are now Logged In.</h3>'; }else{ $messages["failed"] = '<h3 class="text-center">The Log-in was not successful.</h3><div class="col-12 text-center"><a href="<?=site_url()?>/auth"><button type="button"class="btn btn-primary mt-5">Try Again</button></a></div>'; } return $messages; } public function new_account($credentials){ $messages = array(); $messages["status"] = 0; $messages["errors"] = 0; $messages["username_length"] = ""; $messages["password_length"] = ""; $messages["username_exists"] = ""; $messages["email_exists"] = ""; $messages["email_validate"] = ""; $messages["success"] = ""; $messages["failed"] = ""; $username = $credentials["username"]; $email = $credentials["email"]; $password = $credentials["password"]; trim($username); //delete leading and trailing spaces if(strlen($username) < 5){ $messages["errors"] = 1; $messages["username_length"] = "The username must have at least 5 characters."; }else{ $username = $this->db->escape_str($username); } if (! filter_var($email, FILTER_VALIDATE_EMAIL)){ $messages["errors"] = 1; $messages["email_validate"] = "There are problems with the e-mail address. Please correct them."; } trim($password); //delete leading and trailing spaces if(strlen($password) < 8){ $messages["errors"] = 1; $messages["password_length"] = "The password must have at least 8 characters."; }else{ $encrypted_password = password_hash($password, PASSWORD_DEFAULT); if($encrypted_password){ $password = $encrypted_password; }else{ $messages["errors"] = 1; $messages["password_length"] = "Password encryption failed. You cannot register at this time"; } } if( ! $messages["errors"] ){ $sql = "SELECT * FROM `users_hash` WHERE username = '".$username."'"; $query = $this->db->query($sql); if($query->num_rows() > 0){ $messages["errors"] = 1; $messages["username_exists"] = "This username already exists. Please select another username."; } $sql = "SELECT * FROM `users_hash` WHERE email = '".$email."'"; $query = $this->db->query($sql); if($query->num_rows() > 0){ $messages["errors"] = 1; $messages["email_exists"] = "This email is already in use. You cannot register another account with this email address."; } } if( ! $messages["errors"] ){ $sql = "INSERT INTO `users_hash` (`id`, `username`, `email`, `password`, `role`) VALUES (NULL, '".$username."', '".$email."', '".$password."', '0')"; $query = $this->db->query($sql); $user_id = $this->db->insert_id(); if($user_id){ $this->session->user_id = $user_id; $this->session->role = 0; } // if($user_id) } // if( ! $messages["errors"] ) if($this->session->user_id > 0){ $messages["status"] = "1"; $messages["success"] = '<h3 class="text-center">You are now Registered and Logged In.</h3>'; }else{ $messages["failed"] = '<h3 class="text-center">The Registration was not successful.</h3><div class="col-12 text-center"><a href="'.site_url().'/auth/register" class="text-center"><button class="btn btn-primary mt-5">Try Again</button></a></div>'; } return $messages; } }

Views

(views/templates/head.php) 
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"> <title><?=$page_title?></title> <link href="<?=base_url()?>assets/css/bootstrap.min.css" rel="stylesheet"> <script src="<?=base_url()?>assets/js/jquery-3.4.1.min.js" type="application/javascript"></script> <script src="<?=base_url()?>assets/js/bootstrap.min.js" type="application/javascript"></script> <script src="<?=base_url()?>assets/js/bootstrap.min.js.map" type="application/javascript"></script> <script> var this_page = "<?=$this_page?>"; var page_title = "<?=$page_title?>"; function navbar_update(this_page){ $("#"+this_page+"_item").addClass('active'); $("#"+this_page+"_link").append(' <span class="sr-only">(current)</span>'); } </script> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark" style="background-color:#ee4323;"> <a class="navbar-brand" href="<?=site_url()?>">AMP JAM LIT</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li id="home_item" class="nav-item"> <a id="home_link" class="nav-link" href="<?=site_url()?>">Home</a> </li> <li id="litlist_item" class="nav-item"> <a id="litlist_link" class="nav-link" href="<?=site_url()?>/litjams/litlist">The List</a> </li> <li id="contact_item" class="nav-item"> <a id="contact_link" class="nav-link" href="<?=site_url()?>/litjams/litform">Contact</a> </li> </ul> <ul id="right_navbar" class="navbar-nav ml-auto mr-5"> <?php if($this->session->user_id > 0){ if($this->session->role > 0){ echo ' <li id="messages_item" class="nav-item"> <a id="messages_link" class="nav-link" href="'.site_url().'/litjams/messages">Messages</a> </li>'; } echo ' <li id="logout_item" class="nav-item"> <a id="logout_link" class="nav-link" href="'.site_url().'/auth/logout">Log-Out</a> </li>'; }else{ echo ' <li id="register_item" class="nav-item"> <a id="register_link" class="nav-link" href="'.site_url().'/auth/register">Register</a> </li> <li id="login_item" class="nav-item"> <a id="login_link" class="nav-link" href="'.site_url().'/auth">Log-In</a> </li>'; } ?> </ul>
(views/index.php)
<div class="container-fluid"> <div id="headline" class="row mt-3"> <div class="col-12 text-center"> <h1>Lit JAM Site</h1> </div> <!-- /col-12 --> </div> <!-- /row --> <div class="row"> <div id="subtitle" class="col-12 text-center"> <h3>The Top-Ten List</h3> </div> <!-- /col-12 --> </div> <!-- /row --> <div id="content" class="row"> <div class="col-2"></div><!-- spacer --> <div class="col-2 mt-5"> <!-- navigation --> <a href="<?=site_url()?>/litjams/litlist" ><h4>Top Ten List</h4></a> <a href="<?=site_url()?>/litjams/litform" ><h4>Contact Us</h4></a> </div> <div class="col-3 text-center"> <!-- image --> <a href="<?=site_url()?>/litjams/detail/<?=$row["id"]?>"> <img src="<?=base_url()?>assets/images/<?=$row["image"]?>" width="100%"; /> </a> </div> <!-- /image --> <div class="col-5"> <!-- caption --> <a href="<?=site_url()?>/litjams/detail/<?=$row["id"]?>"> <h2 style="margin-top:200px;"><?=$row["item"]?></h2> </a> </div> </div> <!-- /row --> </div> <!-- /container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //ready </script> </html>
(views/litlist.php) 
<style> .cursor-pointer {cursor:pointer;} </style> <div class="container-fluid"> <div id-"headline" class="row mt-5"> <div class="col-12 text-center"> <h2>LIT Top 10 List</h2> </div> <!-- /.col-12 --> </div> <!-- /.row --> <?php foreach ($records as $record){ echo ' <div class="row record-item mt-5 cursor-pointer" data-id="'.$record["id"].'" data-item="'.$record["item"].'"> <div class="col-1"></div> <!-- spacer --> <div class="col-3"><img src="'.base_url().'assets/images/'.$record["image"].'" width="100%"/></div> <div class="col-7"><b>'.$record["item"].'</b> '.$record["description"].'</div> </div> <!-- /.row -->'; } //foreach ?> </div> <!-- /.container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $(".record-item").on("click", function(){ var id = $(this).data('id'); show_detail(id); }); //on() }); //document.ready function show_detail(id){ window.location.assign("<?=site_url()?>/litjams/detail/"+id); } </script> </html>
(views/detail.php) 
<div class="container-fluid"> <div id-"headline" class="row mt-5"> <div class="col-12 text-center"> <?php if($row){ echo '<h1>'.$row["item"].'</h1>'; }else{ echo '<h2>There has been a database error.</h2>'; } ?> </div> <!-- /.col-12 --> </div> <!-- /.row --> <?php if($row){ echo ' <div class="row mt-3"> <div class="col-1"></div> <!-- spacer --> <div class="col-4"><img src="'.base_url().'assets/images/'.$row["image"].'" width="100%"/></div> <div class="col-6">'.$row["description"].'</div> </div> <!-- /.row -->'; } ?> <div class="row mt-4 mb-5"> <div class="col-12 text-center"> <a href="<?=site_url()?>/litjams/litlist"><button class="btn btn-primary">Back to The List</button></a> </div> <!-- /.col-12 --> </div> <!-- /.row --> </div> <!-- /.container-fluid --> </body> </html>
(views/litform.php) 
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Lit JAMS Contact Form</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="contact_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> Name: <input type="text" id="name" name="name" class="form-control" value="" placeholder="Enter Name" required/><br/> E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/><br/> Comment: <textarea id="comment" name="comment" class="form-control" value="" placeholder="Add your comment here:"></textarea><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#contact_form").submit(function(event){ event.preventDefault(); $.post("<?=site_url()?>/litjams/contact_post", $("#contact_form").serialize(), function(data){ //handle messages here if(data.status){ $("#form-container").html(data.success); }else{ $("#form-container").html(data.failed); } }, "json" ); //post }); //submit }); //document.ready </script> </html>
(views/messages.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <?php if(count($messages) > 0){ echo '<h1>Contact Form Messages</h1>'; }else{ echo '<h2>There are no messages at this time.</h2>'; } ?> </div> <!-- /.col-12 --> </div> <!-- /.row --> <?php if($this->session->role > 0){ foreach($messages as $message){ echo' <div class="row mt-3"> <div class="col-2"></div> <!-- spacer --> <div class="col-2">'.$message["name"].'<br/> <a href="mailto:'.$message["email"].'">'.$message["email"].'</a><br/> ['.$message["timestamp"].'] </div> <div class="col-6">'.$message["comment"].'</div> </div> <!-- /.row -->'; } //foreach }else{ echo' <div class="row mt-3"> <div class="col-12 text-center"><h3>You are not authorized to view the messages.</h3></div> </div> <!-- /.row -->'; } //else if ?> </div> <!-- /.container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //document.ready </script> </html>

Auth Views

(views/auth/login.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Full Stack Amp Jam Log-in</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="login_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> User Name: <input type="text" id="username" name="username" class="form-control" value="" placeholder="Enter User Name" required/><br/> Password: <input type="password" id="password" name="password" class="form-control" value="" placeholder="Enter Password" required/><br/> <button type="submit" id="submit" class="btn btn-primary float-right">Submit</button> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#login_form").submit(function(event){ event.preventDefault(); $.post("<?=site_url()?>/auth/authenticate", $("#login_form").serialize(), function(data){ //handle messages here if(data.status){ $("#form-container").html(data.success); right_navbar_update(data.role); }else{ $("#form-container").html(data.failed); } }, "json" ); //post }); //submit }); //document.ready function right_navbar_update(role){ var html = ""; if (role > 0) { html = '<li id="messages_item" class="nav-item">'+ '<a id="messages_link" class="nav-link" href="<?=site_url()?>/litjams/messages">Messages</a>'+ '</li>'; } html += '<li id="logout_item" class="nav-item">'+ '<a id="logout_link" class="nav-link" href="<?=site_url()?>/auth/logout">Log-Out</a>'+ '</li>'; $("#right_navbar").html(html); } </script> </html>
(views/auth/logout.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Amp Jam Lit Log-out</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div class="col-4 text-center"> <h3>You are now Logged Out.</h3> <a href="<?=site_url()?>/auth"><button class="btn btn-primary mt-5">Log In</button></a> </div> <!-- /.col-4 --> </div> <!-- /.row --> </div> <!-- /.container-fluid --> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); }); //document.ready </script> </html>
(views/auth/register.php)
<div class="container-fluid"> <div id="headline" class="row mt-5"> <div class="col-12 text-center"> <h2>Amp Jam Lit Register</h2> </div> <!-- /col-12 --> </div> <!-- /row --> <form id="register_form" method="POST" action=""> <div class="row mt-5"> <div class="col-4"></div> <!-- spacer --> <div id="form-container" class="col-4"> <div>User Name: <input type="text" id="username" name="username" class="form-control" value="" placeholder="Enter User Name" required/></div> <div id="username_length" class="text-danger"></div> <div id="username_exists" class="text-danger"></div> <div class="mt-3">E-mail: <input type="email" id="email" name="email" class="form-control" value="" placeholder="Enter E-mail" required/></div> <div id="email_exists" class="text-danger"></div> <div id="email_validate" class="text-danger"></div> <div class="mt-3">Password: <input type="password" id="password" name="password" class="form-control" value="" placeholder="Enter Password" required/></div> <div id="password_length" class="text-danger"></div> <div class="mt-5"><button type="submit" id="submit" class="btn btn-primary float-right">Submit</button></div> </div> <!-- /#form-container --> </div> <!-- /.row --> </form> </body> <script> $(document).ready(function(){ document.title = page_title; navbar_update(this_page); $("#register_form").submit(function(event){ event.preventDefault(); $.post( "<?=site_url()?>/auth/new_account", $("#register_form").serialize(), function(data){ if(data.status){ $("#form-container").html(data.success); right_navbar_update(); }else{ if(data.errors){ // handle error messages here for (var key in data){ switch(key){ case "status": case "errors": case "success": case "failed": break; default: $("#"+key).html(data[key]); $("#"+key).css("display","block"); break; } //switch } //for-in }else{ $("#form-container").html(data.failed); //registration failed, but without errors } //if data.errors } //if data.status }, //callback function "json" ); //post }); //submit }); //document.ready function right_navbar_update(){ var html = '<li id="logout_item" class="nav-item">'+ '<a id="logout_link" class="nav-link" href="<?=site_url()?>/auth/logout">Log-Out</a>'+ '</li>'; $("#right_navbar").html(html); } </script> </html>

You can open a completed version of the project in your browser here.

If you want to download completed versions of the PHP scripts and image files, you can find them here.