forked from TildeClub/site
Compare commits
4 Commits
master
...
deepend-ti
Author | SHA1 | Date |
---|---|---|
|
536d5bdcd5 | |
|
5a323d7170 | |
|
017756bb6e | |
|
ac9a03aebf |
|
@ -0,0 +1,24 @@
|
|||
# Geocities-inspired Guestbook
|
||||
|
||||
A modern take on the classic Geocities guestbook, built with PHP and SQLite. This guestbook allows for multi-user functionality, user-specific themes, and adheres to current coding standards.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-user Support**: Each user can have their own guestbook by simply accessing [https://tilde.club/guestbook/?user=username](https://tilde.club/guestbook/?user=username).
|
||||
- **Custom Themes**: Users can specify their own CSS theme by placing a `.css` file in their directory and specifying it with the `theme` parameter in the URL.
|
||||
- **Referrer Validation**: The guestbook checks the referrer to ensure that entries are being made from the correct user's page.
|
||||
- **SQLite Backend**: Uses SQLite for a lightweight and serverless database solution.
|
||||
|
||||
## Customization
|
||||
|
||||
### Themes
|
||||
|
||||
Users can specify their own theme by placing a `.css` file in their directory. This theme can be applied by adding the `theme` parameter to the URL, e.g., [https://tilde.club/guestbook/?user=username&theme=cssname](https://tilde.club/guestbook/?user=username&theme=cssname).
|
||||
|
||||
A default `dark.css` theme is provided in the repository as an example.
|
||||
|
||||
### Adding Entries
|
||||
|
||||
User need to link to the guestbook from their tilde page to https://tilde.club/guestbook/?user=username or
|
||||
https://tilde.club/guestbook/?user=username&theme=themecssname and then your viewers can
|
||||
simply fill out the form on your guestbook page and submit.
|
|
@ -0,0 +1,30 @@
|
|||
/* Default styles */
|
||||
body {
|
||||
background-color: #FFF8DC;
|
||||
font-family: "Comic Sans MS";
|
||||
font-size: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
background-color: #f7f7f7;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.entry-name {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.entry-email {
|
||||
font-style: italic;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.entry-message {
|
||||
margin-top: 10px;
|
||||
font-size: 1.1em;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* Reset some default styles */
|
||||
body, h1, p, form {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #2c3e50;
|
||||
color: #ecf0f1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font-size: 2em;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
form {
|
||||
background-color: #34495e;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
input[type="text"], textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #7f8c8d;
|
||||
border-radius: 5px;
|
||||
background-color: #ecf0f1;
|
||||
color: #2c3e50;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
background-color: #e74c3c;
|
||||
color: #ecf0f1;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
input[type="submit"]:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
|
||||
/* Styles for the guestbook entries */
|
||||
.entry {
|
||||
background-color: #34495e;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.entry-name {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.entry-email {
|
||||
font-style: italic;
|
||||
color: #95a5a6;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.entry-message {
|
||||
margin-top: 10px;
|
||||
font-size: 1.1em;
|
||||
color: #ecf0f1;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Get the username and theme from the URL
|
||||
$username = $_GET['user'] ?? 'default';
|
||||
$theme = $_GET['theme'] ?? 'default';
|
||||
|
||||
// Check if the referrer matches the expected pattern for the user
|
||||
$referrer = $_SERVER['HTTP_REFERER'] ?? '';
|
||||
$expectedPattern = "/https?:\/\/tilde\.club\/~" . preg_quote($username, '/') . "\//";
|
||||
|
||||
if (!preg_match($expectedPattern, $referrer)) {
|
||||
die("Access denied: Invalid referrer.");
|
||||
}
|
||||
|
||||
try {
|
||||
$db = new PDO('sqlite:./guestbook.db');
|
||||
|
||||
// Set error mode to exceptions
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Check if the guestbook table exists
|
||||
$tableCheck = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='guestbook'")->fetch();
|
||||
|
||||
// If the table doesn't exist, create it
|
||||
if (!$tableCheck) {
|
||||
$query = "CREATE TABLE guestbook (id INTEGER PRIMARY KEY, username TEXT, name TEXT, email TEXT, message TEXT)";
|
||||
$db->exec($query);
|
||||
}
|
||||
|
||||
$username = filter_var($username, FILTER_SANITIZE_STRING);
|
||||
|
||||
if (isset($_POST['name'], $_POST['email'], $_POST['message'])) {
|
||||
$name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
|
||||
$email = filter_var($_POST['email'], FILTER_SANITIZE_STRING);
|
||||
$message = filter_var($_POST['message'], FILTER_SANITIZE_STRING);
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO guestbook (username, name, email, message) VALUES (:username, :name, :email, :message)");
|
||||
$stmt->execute([':username' => $username, ':name' => $name, ':email' => $email, ':message' => $message]);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("SELECT * FROM guestbook WHERE username = :username ORDER BY id DESC");
|
||||
$stmt->execute([':username' => $username]);
|
||||
$entries = $stmt->fetchAll();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Welcome to <?= htmlspecialchars($username) ?>'s Guestbook!</title>
|
||||
<?php
|
||||
if ($theme !== 'default') {
|
||||
echo '<link rel="stylesheet" href="' . ($_SERVER['HTTPS'] ? 'https' : 'http') . '://tilde.club/~' . htmlspecialchars($username) . '/' . htmlspecialchars($theme) . '.css">';
|
||||
} else {
|
||||
// Default theme
|
||||
echo '<link rel="stylesheet" href="https://tilde.club/guestbook/default.css">';
|
||||
}
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<h1 align="center">Welcome to <?= htmlspecialchars($username) ?>'s Guestbook!</h1>
|
||||
<p>Please leave a message below to let us know what you think of our page.</p>
|
||||
<form action="index.php?user=<?= htmlspecialchars($username) ?>&theme=<?= htmlspecialchars($theme) ?>" method="post">
|
||||
<p>Name: <input type="text" name="name" size="30"></p>
|
||||
<p>Email: <input type="text" name="email" size="30"></p>
|
||||
<p>Message:</p>
|
||||
<p><textarea name="message" rows="6" cols="50"></textarea></p>
|
||||
<p><input type="submit" value="Submit"></p>
|
||||
</form>
|
||||
<h2>Guestbook Entries</h2>
|
||||
<div class="entries">
|
||||
<?php
|
||||
if ($entries) {
|
||||
foreach ($entries as $entry) {
|
||||
echo '<div class="entry">';
|
||||
echo '<h3>' . htmlspecialchars($entry['name']) . ' <span>(' . htmlspecialchars($entry['email']) . ')</span></h3>';
|
||||
echo '<p>' . htmlspecialchars($entry['message']) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
} else {
|
||||
echo '<p>No guestbook entries were found for ' . htmlspecialchars($username) . '.</p>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue