11: Writing a Basic Dynamic Website (Part 3)
Learning Target
- Connect to a database using PHP
- Create and access records in a database
- Use sessions and authentication to protect data
Instructions
Part 1: Prerequisites
Step 1: Complete the prior assignment and ensure it is working.
Be sure everything else is working before you move on.
Step 2: Update some things from the prior assignment.
You will need to update this line in your contact.php file:
<form method="POST" action="index.php?page=contact">
To this:
<form method="POST" action="index.php?page=submit_contact">
Why? In order to make the logic easier to understand, the submission logic has been moved to a separate page. Otherwise, the contact.php page starts to get long and complex.
Step 3: Required fields...sort of
Though you are welcome to use your own field names, if you do you will need to account for that in future steps.
These instructions will use these field names from the contact form:
- name
- topic
- phone
- address
- city
- state
- zip
- message
Part 2: Create the Submission Page
Step 1: Create a new file to handle the submission logic
Create a new file within the pages subfolder:
sudo nano pages/submit_contact.php
This page will:
-
- receive form data
- save it to the database
- show a confirmation message
Step 2: Write the coded needed to handle a submission
First, connect to the database. If this fails, we end the code execution.
<?php
// Load database config
$db = require __DIR__ . "/../config/database.php";
// Connect to database
$conn = new mysqli(
$db["host"],
$db["username"],
$db["password"],
$db["database"]
);
// Stop if the connection fails
if ($conn->connect_error) {
die("Database connection failed.");
}
Second, gather the information sent by the Contact form in the POST data.
$name = $conn->real_escape_string($_POST["name"] ?? "");Third, insert this information into the database and close the connection
$topic = $conn->real_escape_string($_POST["topic"] ?? "");
$phone = $conn->real_escape_string($_POST["phone"] ?? "");
$address = $conn->real_escape_string($_POST["address"] ?? "");
$city = $conn->real_escape_string($_POST["city"] ?? "");
$state = $conn->real_escape_string($_POST["state"] ?? "");
$zip = $conn->real_escape_string($_POST["zip"] ?? "");
$message = $conn->real_escape_string($_POST["message"] ?? "");
$submitted_at = date("Y-m-d H:i:s");
Lastly, give the user a visual indication of what happened
// Insert into database
$sql = "INSERT INTO messages
(submitted_at, name, topic, phone, address, city, state, zip, message)
VALUES
('$submitted_at', '$name', '$topic', '$phone', '$address', '$city', '$state', '$zip', '$message')";
// Assume it is going to fail
$success = false;
// See if it works
if ($conn->query($sql) === TRUE) {
$success = true;
}
// Either way, always close the connection to the database
$conn->close();
?>
<h2>Submission Result</h2>
<?php if ($success): ?>
<p>Your message has been received.</p>
<?php else: ?>
<p>There was an error saving your message.</p>
<?php endif; ?>
<p><a href="index.php?page=contact">Back to Contact Page</a></p>
Step 3: Be sure the user is allowed to visit this page
In index.php, update the allowed pages array:
$allowed_pages = ["home", "about", "contact", "messages", "submit_contact"];
Step 4: Check that the front-end is working!
You will need to do these steps
- Open your website in a browser
- Go to the contact page
- Fill out the form
- Click submit
- Be taken to the confirmation page
- See either:
- “Your message has been received.”
- or an error message of some type
- If it works, be sure it is reliable by repeating this a couple times
Step 5: Check that the back-end is working!
You will need to do these steps:
- Open MariaDB
- Switch to your database
- Check that messages have been recorded
sudo mariadb
USE mysite_db;
SELECT * FROM messages;
You should see the messages you submitted in your testing.
Part 3: Viewing Submitted Messages on your Website
You want people to be able to see the messages that are sent, but not just anyone. We will need to:
- Create an authorized user who can see all messages
- Create a messages page that is protected from the public
Step 1: Open the PHP Interactive Shell
php -a
For security reasons, we never store actual passwords in the database. Instead, we store a hashed version of the password.
A hash is a one-way transformation:
- You can create a hash from a password
- The same password always creates the same hash
- But you cannot realistically reverse the hash back into the same password
When a user logs in:
- They enter their password
- PHP hashes it internally and compares it to the stored hash
- If they match, the login is successful
Even if someone gains access to the database, they cannot easily recover the original passwords.
Step 2: Generate a password hash
Choose a password and then hash it.
echo password_hash("YourPassword", PASSWORD_DEFAULT);
Copy the ugly-looking string of characters into a notepad document and save it as a backup in your H: drive. Then, exit the PHP Interactive Shell:
exit
Step 3: Insert the user into the database
Open MySQL, choose your database and then insert a new user with the password hash you created.
sudo mariadb
USE mysite_db;
INSERT INTO users (username, password_hash)
VALUES ('admin', 'PASTE_HASH_HERE');
Then, verify it worked!
SELECT * FROM users;
Part 4: Create the Protected Messages Page
We will want to require a login before we let people see this page.
Step 1: Allow the page in index.php
Open your index page:
sudo nano index.php
Then, add "messages" to the list of allowed pages.
At the very top of the page, before anything else, start a PHP session:
session_start();
This allows us to keep track of who is (or is not) logged in.
Step 2: Create the messages page
Create a new page called messages.php using Nano.
You can use this code as a starting point. You many need to make adjustments for your own site if you used different variables or id's in your other pages.
<?php
$db = require __DIR__ . "/../config/database.php";
$conn = new mysqli( $db["host"], $db["username"], $db["password"], $db["database"]);
if ($conn->connect_error) { die("Database connection failed.");}
$login_error = "";
// Handle login form submissionif ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = $conn->real_escape_string($_POST["login_username"] ?? "");
$result = $conn->query("SELECT * FROM users WHERE username = '$username' LIMIT 1");
if ($result && $result->num_rows === 1) {
$user = $result->fetch_assoc();
if (password_verify($_POST["login_password"], $user["password_hash"])) { $_SESSION["logged_in"] = true; } else { $login_error = "Invalid login."; }
} else { $login_error = "Invalid login."; }}
// If not logged in, show login formif (!isset($_SESSION["logged_in"])) {?>
<h2>Login</h2>
<?phpif ($login_error !== "") { echo "<p>$login_error</p>";}?>
<form method="POST"> <p>Username:<br><input name="login_username"></p> <p>Password:<br><input type="password" name="login_password"></p> <p><button type="submit">Login</button></p></form>
<?php
// if logged in, show the messages
} else {
// Show messages echo "<h2>Messages</h2>";
$result = $conn->query("SELECT * FROM messages ORDER BY submitted_at DESC");
echo "<table border='1'>";
while ($row = $result->fetch_assoc()) { echo "<tr>"; echo "<td>" . htmlspecialchars($row["submitted_at"]) . "</td>"; echo "<td>" . htmlspecialchars($row["name"]) . "</td>"; echo "<td>" . htmlspecialchars($row["message"]) . "</td>"; echo "</tr>"; }
echo "</table>";}
$conn->close();?>
Step 5: Test Login Protection
Check that you cannot see messages before logging in. Visit the messages page directly:
index.php?page=messages
If things are working properly you should see the login form.
Try several times to login using incorrect or mismatched username and password. See what happens.
Correct username and wrong password -or-
Correct password and wrong username -or-
Wrong username and wrong password:
- Should show "Invalid login"
Step 6: Test Message View
Visit the messages page:
index.php?page=messages
Enter the correct username and password.
Check that you see a full list of messages.
Common mistakes
- Forgot
session_start() - Did not add "messages" to allowed pages
- Username in DB does not match login input
- Password hash not copied completely or correctly
- Config file path incorrect