diff --git a/README.md b/README.md index b111785..fe8fca5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ +Here is an updated version of your README file for release version 1.0. I've included additional details regarding how the tool works, its features and functions, technologies used, data storage methods, and specific Nginx and Apache configurations. + +--- + # Christmas Invitation Management Tool -## Version 0.1 +## Version 1.0 Welcome to the **Christmas Invitation Management Tool**! This web application is designed to help manage the guest list for our upcoming holiday celebration. It provides an intuitive interface to add, edit, and organize guest information efficiently. @@ -20,6 +24,9 @@ Welcome to the **Christmas Invitation Management Tool**! This web application is - [Saving Changes](#saving-changes) - [Undoing Actions](#undoing-actions) - [Exporting the Guest List](#exporting-the-guest-list) +- [Web Server Configuration](#web-server-configuration) + - [Nginx Configuration](#nginx-configuration) + - [Apache Configuration](#apache-configuration) - [Security](#security) - [Contributing](#contributing) - [License](#license) @@ -41,7 +48,7 @@ These instructions will help you set up and run the project on your local machin ### Prerequisites - **Web Server**: Apache, Nginx, or any web server capable of running PHP scripts. -- **PHP**: Version 5.3.0 or higher with OpenSSL extension enabled. +- **PHP**: Version 7.0 or higher with OpenSSL extension enabled. - **Browser**: A modern web browser (Google Chrome, Mozilla Firefox, Microsoft Edge). ### Installation @@ -49,7 +56,7 @@ These instructions will help you set up and run the project on your local machin 1. **Clone the repository:** ```bash - https://github.com/grahfmusic/online-christmas-list.git + git clone https://github.com/grahfmusic/online-christmas-list.git ``` 2. **Navigate to the project directory:** @@ -123,6 +130,59 @@ These instructions will help you set up and run the project on your local machin - **As PDF**: Click **"Save as PDF"** to download a PDF version. - **As Spreadsheet**: Click **"Save as Spreadsheet"** to download an Excel file. +## Web Server Configuration + +### Nginx Configuration + +To set up Nginx to properly handle PHP requests and serve this tool, add the following configuration block to your Nginx server block: + +```nginx +server { + listen 80; + server_name yourdomain.com; + + root /path/to/christmas-invitation-tool; + index index.html index.php; + + location / { + try_files $uri $uri/ =404; + } + + location ~ \\.php$ { + include snippets/fastcgi-php.conf; + fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + } + + location ~ /guest_list\\.dat$ { + deny all; + } +} +``` + +### Apache Configuration + +To set up Apache to properly handle PHP requests and serve this tool, add the following configuration to your virtual host: + +```apache + + ServerName yourdomain.com + DocumentRoot /path/to/christmas-invitation-tool + + + Options Indexes FollowSymLinks + AllowOverride All + Require all granted + + + + Require all denied + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + +``` + ## Security - **Data Encryption**: Guest data is encrypted on the server using AES-256-CBC encryption. diff --git a/christmas-invite-tool.html b/index.html similarity index 95% rename from christmas-invite-tool.html rename to index.html index f5ac51f..6517c62 100644 --- a/christmas-invite-tool.html +++ b/index.html @@ -1,742 +1,744 @@ - - - - - - - Christmas 2024 Invitation - - - - - - - - - - - - -
-
-

Christmas 2024 Celebration Invitation

-

Join us for a joyful holiday gathering!

-
-
-
-
-

Attending

- -
- - -
- -
-
-
Name
-
Company
-
Comments
-
-
-
    - -
-
-
-

Not Attending

- -
- - -
- -
-
-
Name
-
Company
-
Comments
-
-
-
    - -
-
-
-
-
- - - - - - -
- -
-
- - - - + + + + + + + Christmas 2024 Invitation + + + + + + + + + + + + +
+
+
CCA Software Christmas RSVP List Tool v1.0
+
Created by Dean Thomson (2024)
+
+
+
+
+

Attending

+ +
+ + +
+ +
+
+
Name
+
Company
+
Comments
+
+
+
    + +
+
+
+

Not Attending

+ +
+ + +
+ +
+
+
Name
+
Company
+
Comments
+
+
+
    + +
+
+
+
+
+ + + + + + +
+ +
+
+ + + + diff --git a/load_guest_list.php b/load_guest_list.php index 17c2ee1..6c3c287 100644 --- a/load_guest_list.php +++ b/load_guest_list.php @@ -1,96 +1,96 @@ - 'error', 'message' => 'Unauthorized']; - echo json_encode($response); - log_error("Unauthorized access attempt."); - exit; -} - -$file = 'guest_list.json'; // The JSON file containing guest list data -$filePath = __DIR__ . DIRECTORY_SEPARATOR . $file; - -if (file_exists($filePath)) { - // Open the file with locking to prevent concurrent reads/writes - $fp = fopen($filePath, 'r'); - if ($fp) { - if (flock($fp, LOCK_SH)) { // Acquire a shared lock - // Optional: Check if file size is manageable - $fileSize = filesize($filePath); - $maxSize = 5 * 1024 * 1024; // 5 MB - if ($fileSize > $maxSize) { - http_response_code(413); // Payload Too Large - $response = ['status' => 'error', 'message' => 'Data payload is too large']; - echo json_encode($response); - log_error("Data payload too large: $filePath."); - flock($fp, LOCK_UN); - fclose($fp); - exit; - } - - $data = fread($fp, $fileSize); - flock($fp, LOCK_UN); // Release the lock - fclose($fp); - - if ($data !== false) { - // Validate JSON - json_decode($data); - if (json_last_error() !== JSON_ERROR_NONE) { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Corrupted JSON data']; - echo json_encode($response); - log_error("Corrupted JSON data in $filePath."); - exit; - } - - $response = ['status' => 'success', 'data' => json_decode($data, true)]; - } else { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Error reading data']; - log_error("Error reading data from $filePath."); - } - } else { - fclose($fp); - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Could not lock the file for reading']; - log_error("Could not lock the file for reading: $filePath."); - } - } else { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Error opening file for reading']; - log_error("Failed to open file for reading: $filePath."); - } -} else { - http_response_code(404); - $response = ['status' => 'error', 'message' => 'No saved guest list found']; - log_error("File not found: $filePath."); -} - -echo json_encode($response); -?> - + 'error', 'message' => 'Unauthorized']; + echo json_encode($response); + log_error("Unauthorized access attempt."); + exit; +} + +$file = 'guest_list.json'; // The JSON file containing guest list data +$filePath = __DIR__ . DIRECTORY_SEPARATOR . $file; + +if (file_exists($filePath)) { + // Open the file with locking to prevent concurrent reads/writes + $fp = fopen($filePath, 'r'); + if ($fp) { + if (flock($fp, LOCK_SH)) { // Acquire a shared lock + // Optional: Check if file size is manageable + $fileSize = filesize($filePath); + $maxSize = 5 * 1024 * 1024; // 5 MB + if ($fileSize > $maxSize) { + http_response_code(413); // Payload Too Large + $response = ['status' => 'error', 'message' => 'Data payload is too large']; + echo json_encode($response); + log_error("Data payload too large: $filePath."); + flock($fp, LOCK_UN); + fclose($fp); + exit; + } + + $data = fread($fp, $fileSize); + flock($fp, LOCK_UN); // Release the lock + fclose($fp); + + if ($data !== false) { + // Validate JSON + json_decode($data); + if (json_last_error() !== JSON_ERROR_NONE) { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Corrupted JSON data']; + echo json_encode($response); + log_error("Corrupted JSON data in $filePath."); + exit; + } + + $response = ['status' => 'success', 'data' => json_decode($data, true)]; + } else { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Error reading data']; + log_error("Error reading data from $filePath."); + } + } else { + fclose($fp); + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Could not lock the file for reading']; + log_error("Could not lock the file for reading: $filePath."); + } + } else { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Error opening file for reading']; + log_error("Failed to open file for reading: $filePath."); + } +} else { + http_response_code(404); + $response = ['status' => 'error', 'message' => 'No saved guest list found']; + log_error("File not found: $filePath."); +} + +echo json_encode($response); +?> + diff --git a/save_guest_list.php b/save_guest_list.php index 9107123..f81287e 100644 --- a/save_guest_list.php +++ b/save_guest_list.php @@ -1,107 +1,107 @@ - 'error', 'message' => 'Unauthorized']; - echo json_encode($response); - log_error("Unauthorized access attempt."); - exit; - } - - // Retrieve the 'data' parameter from POST request - $data = $_POST['data'] ?? null; - - if ($data) { - // Validate JSON data - $decodedData = json_decode($data, true); - if (json_last_error() !== JSON_ERROR_NONE) { - http_response_code(400); - $response = ['status' => 'error', 'message' => 'Invalid JSON data']; - echo json_encode($response); - log_error("Invalid JSON data received."); - exit; - } - - // Re-encode to ensure consistent formatting - $encodedData = json_encode($decodedData, JSON_PRETTY_PRINT); - if ($encodedData === false) { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Error encoding JSON data']; - echo json_encode($response); - log_error("Error encoding JSON data."); - exit; - } - - // Define the file path securely - $file = 'guest_list.json'; - $filePath = __DIR__ . DIRECTORY_SEPARATOR . $file; - - // Open the file with locking to prevent concurrent writes - $fp = fopen($filePath, 'c+'); - if ($fp) { - if (flock($fp, LOCK_EX)) { // Acquire an exclusive lock - ftruncate($fp, 0); // Truncate the file - $bytesWritten = fwrite($fp, $encodedData); // Write new data - fflush($fp); // Flush output before releasing the lock - flock($fp, LOCK_UN); // Release the lock - fclose($fp); - - if ($bytesWritten !== false) { - http_response_code(200); - $response = ['status' => 'success', 'message' => 'Data saved successfully']; - } else { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Error saving data']; - log_error("Failed to write data to $filePath."); - } - } else { - fclose($fp); - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Could not lock the file for writing']; - log_error("Could not lock the file for writing: $filePath."); - } - } else { - http_response_code(500); - $response = ['status' => 'error', 'message' => 'Error opening file for writing']; - log_error("Failed to open file: $filePath."); - } - } else { - http_response_code(400); - $response = ['status' => 'error', 'message' => 'No data provided']; - log_error("No data provided in POST request."); - } -} else { - http_response_code(405); - $response = ['status' => 'error', 'message' => 'Method not allowed']; - log_error("Invalid request method: {$_SERVER['REQUEST_METHOD']}."); -} - -echo json_encode($response); -?> - + 'error', 'message' => 'Unauthorized']; + echo json_encode($response); + log_error("Unauthorized access attempt."); + exit; + } + + // Retrieve the 'data' parameter from POST request + $data = $_POST['data'] ?? null; + + if ($data) { + // Validate JSON data + $decodedData = json_decode($data, true); + if (json_last_error() !== JSON_ERROR_NONE) { + http_response_code(400); + $response = ['status' => 'error', 'message' => 'Invalid JSON data']; + echo json_encode($response); + log_error("Invalid JSON data received."); + exit; + } + + // Re-encode to ensure consistent formatting + $encodedData = json_encode($decodedData, JSON_PRETTY_PRINT); + if ($encodedData === false) { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Error encoding JSON data']; + echo json_encode($response); + log_error("Error encoding JSON data."); + exit; + } + + // Define the file path securely + $file = 'guest_list.json'; + $filePath = __DIR__ . DIRECTORY_SEPARATOR . $file; + + // Open the file with locking to prevent concurrent writes + $fp = fopen($filePath, 'c+'); + if ($fp) { + if (flock($fp, LOCK_EX)) { // Acquire an exclusive lock + ftruncate($fp, 0); // Truncate the file + $bytesWritten = fwrite($fp, $encodedData); // Write new data + fflush($fp); // Flush output before releasing the lock + flock($fp, LOCK_UN); // Release the lock + fclose($fp); + + if ($bytesWritten !== false) { + http_response_code(200); + $response = ['status' => 'success', 'message' => 'Data saved successfully']; + } else { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Error saving data']; + log_error("Failed to write data to $filePath."); + } + } else { + fclose($fp); + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Could not lock the file for writing']; + log_error("Could not lock the file for writing: $filePath."); + } + } else { + http_response_code(500); + $response = ['status' => 'error', 'message' => 'Error opening file for writing']; + log_error("Failed to open file: $filePath."); + } + } else { + http_response_code(400); + $response = ['status' => 'error', 'message' => 'No data provided']; + log_error("No data provided in POST request."); + } +} else { + http_response_code(405); + $response = ['status' => 'error', 'message' => 'Method not allowed']; + log_error("Invalid request method: {$_SERVER['REQUEST_METHOD']}."); +} + +echo json_encode($response); +?> + diff --git a/scnshot.png b/scnshot.png index 05dfe9e..52560cf 100644 Binary files a/scnshot.png and b/scnshot.png differ