Search

Coding a Simple Guestbook Using PHP and MySQL

0 views

Preparing the Database

Before any visitor can leave a comment, the server must have a place to store those comments. The simplest solution is a MySQL table that holds the visitor’s name, email address, country, and message. The table also needs an auto‑incrementing primary key so that every entry can be uniquely identified and sorted chronologically.

Start by logging into your MySQL server using the command line or a graphical tool such as phpMyAdmin. If you are using phpMyAdmin, simply click the “Create table” button for the database you wish to use. Give the table the name guestbook and set the columns as follows:

id – INT(11), NOT NULL, AUTO_INCREMENT, PRIMARY KEY
name – VARCHAR(100), NOT NULL
email – VARCHAR(80), NOT NULL
country – VARCHAR(40), NULL
comment – TEXT, NOT NULL

When you use the MySQL command line, the CREATE TABLE statement looks like this:

Prompt
CREATE TABLE guestbook (</p> <p> id INT(11) NOT NULL AUTO_INCREMENT,</p> <p> name VARCHAR(100) NOT NULL,</p> <p> email VARCHAR(80) NOT NULL,</p> <p> country VARCHAR(40) DEFAULT NULL,</p> <p> comment TEXT NOT NULL,</p> <p> PRIMARY KEY (id)</p> <p>) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Choosing the InnoDB engine provides transaction support and foreign key capabilities should you expand the project later. The utf8mb4 character set covers a wide range of Unicode characters, including emojis, which many modern users expect to see in a guestbook entry.

Once the table is created, it’s good practice to confirm that the structure matches what your PHP scripts will expect. Run DESCRIBE guestbook; to see the column names and types. If the output matches the definition above, you’re ready to let visitors start writing.

In addition to the table, you’ll need a database user with INSERT, SELECT, and DELETE privileges on the guestbook database. If you’re working in a shared hosting environment, your control panel should provide a user‑creation interface. Grant the user privileges with a statement similar to:

Prompt
GRANT INSERT, SELECT, DELETE ON yourdatabase.guestbook TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';

Replace yourdatabase, dbuser, and dbpass with your actual database name, MySQL username, and password. Remember to reload the privilege tables afterward:

Prompt
FLUSH PRIVILEGES;

Now you have a secure, properly typed table and an authorized user. The next step is to build the front‑end form that will capture visitor data.

Building the Comment Form

The front‑end form is the face of your guestbook. It must be intuitive, accessible, and resistant to common pitfalls such as missing required fields. The form lives in a file called comments.php, but the name can be anything you prefer. What matters is that the form’s action attribute points to the script that will process the data.

Begin with a simple HTML structure. The <form> element uses the POST method to keep data out of the URL, and the action attribute directs the submission to store_comment.php:

Prompt
<form method="post" action="store_comment.php"></p> <p> <label for="name">Your Name:</label></p> <p> <input type="text" id="name" name="name" required maxlength="100"><br></p> <p> <label for="email">Your Email:</label></p> <p> <input type="email" id="email" name="email" required maxlength="80"><br></p> <p> <label for="country">Country:</label></p> <p> <input type="text" id="country" name="country" maxlength="40"><br></p> <p> <label for="comment">Comment:</label></p> <p> <textarea id="comment" name="comment" rows="5" cols="50" required></textarea><br></p> <p> <button type="submit">Submit</button></p> <p></form>

Notice the required attribute on the name, email, and comment fields. Browsers will warn users if they try to submit the form without filling these fields, providing a first line of validation before the server even receives the data. The maxlength attributes keep field lengths in check, reducing the risk of buffer overflow or accidental database truncation.

Because many users rely on assistive technology, labeling is key. The <label> tags, linked to their corresponding inputs via the for attribute, ensure screen readers announce the field’s purpose. The form also includes an id attribute on each input so that clicking the label focuses the related input field, improving usability.

Place this code inside comments.php and save it in the same directory as the other PHP files. If your server uses a virtual host, make sure the file is reachable at http://yourdomain.com/comments.php. Test the form by opening it in a browser, filling out the fields, and clicking Submit. The browser should forward the data to store_comment.php, but you’ll see no response yet because that file isn’t written.

At this point, the form is ready to capture user input. The next step is to safely insert that input into the database while guarding against SQL injection and other common security threats.

Storing Submissions Safely

When the form sends data to store_comment.php, the script must validate the input, connect to the database, and persist the record. Using the legacy mysql_ functions is discouraged; they have been removed from PHP 7 onward. Instead, this example uses the mysqli extension, which supports prepared statements and offers a modern interface.

Start by defining the connection parameters. Replace localhost, dbuser, dbpass, and yourdatabase with your actual host, username, password, and database name. Store these values in variables for reuse:

Prompt
$host = 'localhost';</p> <p>$username = 'dbuser';</p> <p>$password = 'dbpass';</p> <p>$database = 'yourdatabase';

The next step is to create a new mysqli object and check for connection errors. A simple way to do this is:

Prompt
$mysqli = new mysqli($host, $username, $password, $database);</p> <p>if ($mysqli->connect_error) {</p> <p> die('Database connection failed: ' . $mysqli->connect_error);</p> <p>}

With the connection established, retrieve the form values. Always use trim() to remove surrounding whitespace and filter_input() to perform basic sanitization. For email validation, PHP’s FILTER_VALIDATE_EMAIL filter guarantees that only correctly formatted addresses are accepted:

Prompt
$name = trim($_POST['name'] ?? '');</p> <p>$email = trim($_POST['email'] ?? '');</p> <p>$country = trim($_POST['country'] ?? '');</p> <p>$comment = trim($_POST['comment'] ?? '');</p> <p>if ($name === '' || $email === '' || $comment === '') {</p> <p> die('Name, email, and comment are required.');</p> <p>}</p> <p>if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {</p> <p> die('Please provide a valid email address.');</p> <p>}

Having validated the input, the script can now prepare an INSERT statement. Prepared statements keep user data separate from the SQL command, preventing malicious input from turning into an injection attack:

Prompt
$stmt = $mysqli->prepare('INSERT INTO guestbook (name, email, country, comment) VALUES (?, ?, ?, ?)');</p> <p>if (!$stmt) {</p> <p> die('Prepare failed: ' . $mysqli->error);</p> <p>}</p> <p>$stmt->bind_param('ssss', $name, $email, $country, $comment);</p> <p>if ($stmt->execute()) {</p> <p> echo '<p>Thank you for your message!</p>';</p> <p> echo '<p><a href="guestbook.php">Return to the guestbook</a></p>';</p> <p>} else {</p> <p> echo '<p>Error saving your comment: ' . $stmt->error . '</p>';</p> <p>}</p> <p>$stmt->close();</p> <p>$mysqli->close();

Notice the use of bind_param() with four ssss placeholders, indicating that all four columns are strings. Even though the database schema allows NULL for the country field, sending an empty string is safe; the column will contain an empty string rather than NULL unless you explicitly cast it.

After executing the statement, the script offers a short confirmation page. It also provides a link back to guestbook.php, allowing visitors to see their entry alongside others. If an error occurs, the script outputs the MySQL error, helping developers troubleshoot issues quickly.

Because this script uses the mysqli extension, you can safely drop the old mysql_ functions that were present in the original article. The new approach protects against SQL injection and is compatible with modern PHP versions.

Displaying Guestbook Entries

With data in place, the next step is to pull the records from the database and render them for visitors. The file guestbook.php is responsible for that. It opens a database connection, queries the guestbook table, and formats each entry in a readable way.

Start by establishing the same database connection as before, using the mysqli object. The connection code can be copied from store_comment.php or placed in a separate file for reuse:

}

Next, retrieve all records ordered by id so that the newest entries appear at the bottom. The query is straightforward:

Prompt
$result = $mysqli->query('SELECT name, email, country, comment FROM guestbook ORDER BY id ASC');</p> <p>if (!$result) {</p> <p> die('Query error: ' . $mysqli->error);</p> <p>}

When looping through the result set, format each comment with basic HTML. For example, wrap the name and country in <strong> tags and place the comment text inside a <p> element. Keep the output simple but structured to maintain readability:

Prompt
echo '<h2>Guestbook</h2>';</p> <p>echo '<p><a href="comments.php">Leave a message</a></p>';</p> <p>echo '<hr>';</p> <p>while ($row = $result->fetch_assoc()) {</p> <p> echo '<div class="guest-entry">';</p> <p> echo '<strong>' . htmlspecialchars($row['name']) . '</strong>';</p> <p> if ($row['country']) {</p> <p> echo ' from <em>' . htmlspecialchars($row['country']) . '</em>';</p> <p> }</p> <p> echo '<br>';</p> <p> echo '<strong>Email:</strong> ' . htmlspecialchars($row['email']) . '<br>';</p> <p> echo '<p>' . nl2br(htmlspecialchars($row['comment'])) . '</p>';</p> <p> echo '</div><hr>';</p> <p>}</p> <p>$result->free();</p> <p>$mysqli->close();

The htmlspecialchars() function neutralizes any HTML tags that might have been entered by visitors, preventing cross‑site scripting attacks. The nl2br() helper converts newlines in the comment into <br> tags, preserving line breaks.

To make the page look more polished, add a small style block at the top of guestbook.php that sets font families and spacing. The CSS stays minimal, ensuring the page loads quickly:

Prompt
<style></p> <p>body { font-family: Arial, sans-serif; margin: 20px; }</p> <p>.guest-entry { margin-bottom: 15px; }</p> <p>.guest-entry strong { color: #004080; }</p> <p>.guest-entry em { color: #006600; }</p> <p></style>

When visitors navigate to guestbook.php, they see the list of all messages, a link to add a new one, and a clean layout that emphasizes the conversation. The separation of concerns - form handling, data insertion, and display - makes the guestbook easy to maintain and extend. For example, adding pagination or moderating posts would only require changes to the query portion of the display script.

With all three files in place - comments.php, store_comment.php, and guestbook.php - you have a fully functional, secure guestbook built with PHP and MySQL. Deploy the files to your web server, verify that data flows correctly through each stage, and enjoy seeing visitors leave their thoughts in real time.

Suggest a Correction

Found an error or have a suggestion? Let us know and we'll review it.

Share this article

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Related Articles