You are an expert PHP developer and DevOps engineer. Your task is to generate a complete PHP-based email verification & subscription system for daily XKCD comics, implementing all functionality strictly inside a folder named `src/`. Do NOT modify or generate any files outside `src/`. The project must adhere to PHP 8.3 compatibility and use only flat files (no database). You must follow exactly the function names and file names given below. Do NOT change function signatures or file structure. The user will copy your generated files into their repository’s `src/` folder. ## 1. Project Overview - A user visits `index.php` to subscribe with their email. - They enter their email; the system sends a 6-digit numeric verification code by email. - The user enters the code on the same page to confirm and register; the verified email is appended to `registered_emails.txt`. - Every email sent (verification or XKCD or unsubscription) must be formatted in HTML with exact content formats (see “Email Content Guidelines”). - Each email sent (verification, XKCD update, unsubscription confirmation) must include an unsubscribe link pointing to `unsubscribe.php`. - Unsubscribe flow: user clicks unsubscribe link → visits `unsubscribe.php?email=<their-email>` → enters email again (form always visible) → system emails a 6-digit code → user enters code to confirm → system removes the email from `registered_emails.txt`. - A daily CRON job (triggered by `setup_cron.sh`) runs `cron.php` every 24 hours. `cron.php` picks a random XKCD comic, formats it as HTML, and emails to all registered emails from `registered_emails.txt`. Each email includes an unsubscribe link. ## 2. File Structure (all under `src/`) Generate exactly these files (and if needed, auxiliary helper files under `src/`, e.g. config or temporary storage files). Do NOT create or modify anything outside `src/`. 1. `functions.php` - Contains implementations of: - `function generateVerificationCode()` - `function registerEmail($email)` - `function unsubscribeEmail($email)` - `function sendVerificationEmail($email, $code, $context = 'subscribe')` - `function verifyCode($email, $code, $context = 'subscribe')` - `function fetchAndFormatXKCDData()` - `function sendXKCDUpdatesToSubscribers()` - Use flat files for storage: - `registered_emails.txt` for confirmed emails (one per line). - A file (e.g. `pending_codes.json`) or similar under `src/` for temporarily storing pending verification codes with timestamps and context (“subscribe” or “unsubscribe”), so that `verifyCode()` can check codes. Clean up expired codes. - Implement proper file locking (e.g. `flock`) when reading/writing these files to avoid race conditions. - Validate email format strictly (use PHP filter_var). - For security, sanitize any inputs that may be echoed in HTML (e.g. in forms), but do not over-escape URLs in unsubscribe link. 2. `index.php` - HTML page with: - A form to enter email for subscription: `<input type="email" name="email" required>` and `<button id="submit-email">Submit</button>`. - A form to enter verification code: `<input type="text" name="verification_code" maxlength="6" required>` and `<button id="submit-verification">Verify</button>`. - Both form elements must always be visible on page load (not conditionally rendered). You can disable or ignore the code input until after email step, but it must still be present in the DOM and visible. Show guidance text near code input: “After receiving code, enter it here.” - Use a hidden input or a session mechanism to keep track of which email is being verified. For simplicity, include a hidden `<input type="hidden" name="pending_email" value="...">` in the code form after sending code. But all fields remain visible; if no pending email, the hidden value may be empty. - On first POST (`$_POST['email']`): - Validate email format. - Generate a 6-digit code: call `generateVerificationCode()`. - Store code and timestamp in pending storage (`pending_codes.json` or similar) under context “subscribe”. - Call `sendVerificationEmail($email, $code, 'subscribe')`. - Show a message: “Verification code sent to your email. Please enter the code below.” Still show both forms (email + code). - Pre-fill `pending_email` hidden input with the submitted email. - On POST of verification code (`$_POST['verification_code']` and `$_POST['pending_email']` present): - Call `verifyCode($email, $code, 'subscribe')`. If matches and not expired: - Call `registerEmail($email)` to append to `registered_emails.txt` (avoid duplicates). - Show success message: “Email verified and subscribed successfully.” - Clear pending storage for that email & context. - If invalid or expired: show error message: “Invalid or expired code. Please request a new code by re-entering your email above.” Keep forms visible. - Use clean, eye-catching UI: include a `<link rel="stylesheet" href="style.css">` (create `style.css` under `src/`) with a modern theme: light grey backgrounds, light-blue accents, clear fonts, responsive layout. Use minimal inline JavaScript if needed only to disable/enable buttons, but do not hide any input—just visually indicate disabled state. 3. `unsubscribe.php` - Similar structure to `index.php` but for unsubscription: - Always visible: `<input type="email" name="unsubscribe_email" required>` with `<button id="submit-unsubscribe">Unsubscribe</button>`. - Always visible: `<input type="text" name="verification_code" maxlength="6" required>` with `<button id="submit-verification">Verify</button>`. - Use a hidden `<input type="hidden" name="pending_email" value="...">` to track the email for which code was sent. - On GET with `?email=...` or on form submission with `$_POST['unsubscribe_email']`: - Validate email format. - Check if the email exists in `registered_emails.txt`. If not registered: show “Email not found in subscribers.” - If registered: generate 6-digit code via `generateVerificationCode()`, store in pending codes under context “unsubscribe”, call `sendVerificationEmail($email, $code, 'unsubscribe')`. - Show message: “Unsubscribe confirmation code sent. Enter code below to confirm unsubscription.” Pre-fill hidden pending_email. - On POST of verification code with `pending_email`: - Validate code with `verifyCode($email, $code, 'unsubscribe')`. If valid: - Call `unsubscribeEmail($email)` to remove from `registered_emails.txt`. - Show success: “You have been unsubscribed successfully.” - Clean up pending. - If invalid/expired: show error: “Invalid or expired code. Please request a new code.” - Use same `style.css`, consistent UI. 4. `cron.php` - This script is invoked by the CRON job every 24 hours. - Behavior: - Include `functions.php`. - Call `sendXKCDUpdatesToSubscribers()`. - `sendXKCDUpdatesToSubscribers()`: - Read `registered_emails.txt` (one email per line). If empty: exit quietly. - For each email: - Call `fetchAndFormatXKCDData()`, which: - Fetch the current latest XKCD comic number by GET request to `https://xkcd.com/info.0.json`. - Determine a random comic ID between 1 and latest. - Fetch `https://xkcd.com/{randomID}/info.0.json`. - From JSON, extract fields: `img` (URL), `alt`, `title`, maybe `transcript`. Format an HTML snippet: ``` <h2>XKCD Comic: {title}</h2> <img src="{img}" alt="{alt}"> <p>{alt}</p> <!-- optional caption/alt text below image --> <p><a href="{UNSUBSCRIBE_LINK}" id="unsubscribe-button">Unsubscribe</a></p> ``` - For `{UNSUBSCRIBE_LINK}`, build using a configurable base URL + `unsubscribe.php?email={urlencoded-email}`. - Then call `mail()` to send to the subscriber with: - Subject: `Your XKCD Comic` - Headers: `MIME-Version: 1.0`, `Content-type: text/html; charset=UTF-8`, `From: no-reply@example.com` - Body: the formatted HTML. - Ensure any network errors (e.g. failure to fetch) are handled gracefully: if fetch fails, log (e.g. to `error_log`) and skip sending for this run, or retry next day. - Use PHP’s built-in `file_get_contents()` or `curl` to fetch JSON. Use `json_decode`. - Use a configuration constant or variable for `BASE_URL` so unsubscribe links point correctly. 5. `setup_cron.sh` - A shell script inside `src/` that, when executed, automatically installs a CRON job for PHP CLI to run `cron.php` every 24 hours. - It must: - Detect its directory: `DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"`. - Use `crontab -l` to list existing jobs, append a new line if not already present, e.g.: ``` # XKCD subscription daily job 0 0 * * * php "$DIR/cron.php" >> "$DIR/cron.log" 2>&1 ``` - Check idempotently: if the exact line (matching `php "$DIR/cron.php"`) is already in crontab, do not add again. - Install the updated crontab with `(crontab -l; echo "...") | crontab -`. - Print a success message: “CRON job installed: php $DIR/cron.php daily at midnight.” - Consider user’s environment: use full path to PHP if possible (`which php` fallback). - Note: file permissions: ensure `setup_cron.sh` is executable. - Do NOT write only instructions; provide the actual shell script content. 6. `style.css` - Create a CSS file to style both `index.php` and `unsubscribe.php`. - Use light-grey background (`#f5f5f5`), card-like centered form containers with white background and subtle shadow. - Use light-blue accent color (`#4a90e2`) for buttons, links, hover effects. - Use a clean sans-serif font (e.g. import from Google Fonts: “Roboto”). - Responsive: center form on desktop and mobile, padding/margins appropriate. - Ensure form elements are always visible with clear labels/placeholders. 7. `config.php` (optional but recommended) - Under `src/`, define constants: ```php <?php // Base URL where index.php and unsubscribe.php are reachable, e.g. define('BASE_URL', 'https://your-domain.com/path-to-src'); define('FROM_EMAIL', 'no-reply@example.com'); define('CODE_EXPIRY_SECONDS', 600); // e.g. 10 minutes expiry for verification codes ``` - All other files include `config.php`. 8. `registered_emails.txt` - Initially create an empty text file under `src/` (ensure read/write permissions). One email per line, no duplicates. - The AI generator should check if file exists; if not, create it when first writing. 9. `pending_codes.json` (or similar) - A JSON file storing pending codes: structure example: ```json { "subscribe": { "user1@example.com": { "code": "123456", "timestamp": 169xxx }, ... }, "unsubscribe": { "user1@example.com": { "code": "654321", "timestamp": 169xxx }, ... } } ``` - Implement in `functions.php`: - Functions to read/write this file with locking. - Clean up expired entries older than CODE_EXPIRY_SECONDS. ## 3. Function Details in `functions.php` Implement **exactly** these functions (do NOT rename): 1. `function generateVerificationCode()`: - Returns a string of 6 random digits, e.g. `sprintf('%06d', random_int(0, 999999));`. Use `random_int` for cryptographic randomness. 2. `function registerEmail($email)`: - Validate `$email` with `filter_var($email, FILTER_VALIDATE_EMAIL)`. - Open `registered_emails.txt` with exclusive lock. - Read lines, trim, check if `$email` already exists; if not, append `$email . "\n"`. - Close file properly. - Return true on success, false or throw exception on failure. 3. `function unsubscribeEmail($email)`: - Validate `$email`. - Open `registered_emails.txt` for read/write with locking. - Read all lines; filter out lines equal to `$email`. - Overwrite file with remaining emails. - Return true if removed, false if not found. 4. `function sendVerificationEmail($email, $code, $context = 'subscribe')`: - `$context` is `'subscribe'` or `'unsubscribe'`. - Subject and Body: - If `subscribe`: - Subject: `Your Verification Code` - Body: `<p>Your verification code is: <strong>{code}</strong></p>` - If `unsubscribe`: - Subject: `Confirm Un-subscription` - Body: `<p>To confirm un-subscription, use this code: <strong>{code}</strong></p>` - Always send HTML email: set headers: ``` $headers = "MIME-Version: 1.0" . "\r\n"; $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n"; $headers .= "From: " . FROM_EMAIL . "\r\n"; ``` - Use PHP `mail($email, $subject, $body, $headers);` - Return true/false based on mail() result. 5. `function verifyCode($email, $code, $context = 'subscribe')`: - Validate `$email` and `$code` format (`ctype_digit` and length == 6). - Load pending codes file (e.g. `pending_codes.json`) with lock. - Check if an entry exists for `$context][$email]`. - If exists: check if code matches and timestamp within expiry (`CODE_EXPIRY_SECONDS`). - If valid: remove entry from pending codes and save file; return true. - Else: return false. 6. `function fetchAndFormatXKCDData()`: - Fetch latest comic JSON: `file_get_contents('https://xkcd.com/info.0.json')`. Handle network errors: if false, log and return false. - `json_decode` to get `num`. - Pick random ID: `random_int(1, $latestNum)`. - Fetch JSON for that ID: `file_get_contents("https://xkcd.com/{$id}/info.0.json")`. - Decode JSON: extract `img`, `alt`, `title`. - Build unsubscribe URL: `BASE_URL . '/unsubscribe.php?email=' . urlencode($emailPlaceholder)`; in this function return the HTML snippet **with a placeholder** or accept email parameter? Actually, since formatting depends on recipient email, you can adjust signature: either have this function accept `$email` or have `sendXKCDUpdatesToSubscribers()` pass email into formatting. For clarity, implement as `fetchAndFormatXKCDData($email)`—but since stub given had no parameter, inside `sendXKCDUpdatesToSubscribers()`, after retrieving data, do string replace of placeholder. - Better: modify stub logically: inside `sendXKCDUpdatesToSubscribers()`, call a helper like `getXKCDData()` to return an associative array; then format HTML with `$email`. But the prompt: do not change function names. Therefore: implement `fetchAndFormatXKCDData($email)` instead of zero-argument? But instructions say stub is `function fetchAndFormatXKCDData()`. So within that stub: fetch JSON and return an array: `return ['title'=>..., 'img'=>..., 'alt'=>...]`. Then in `sendXKCDUpdatesToSubscribers()`, call `fetchAndFormatXKCDData()`, then inside that function or after, format HTML including unsubscribe link with actual `$email`. Clarify in comments. - Return an associative array with keys `title`, `img`, `alt`, or return HTML string plus require email param. Add a comment in code explaining: “This returns array; formatting happens in sendXKCDUpdatesToSubscribers()”. 7. `function sendXKCDUpdatesToSubscribers()`: - Read all emails from `registered_emails.txt`. - For each `$email`: - Call `fetchAndFormatXKCDData()` to get comic data. If false or error: skip for this email. - Build HTML body: ``` <h2>XKCD Comic: {title}</h2> <img src="{img}" alt="{alt}"> <p>{alt}</p> <p><a href="{BASE_URL}/unsubscribe.php?email={urlencoded email}" id="unsubscribe-button">Unsubscribe</a></p> ``` - Use headers same as HTML email. Subject: `Your XKCD Comic`. - Call mail(). Optionally sleep briefly between sends to avoid rate limits. - Log failures to `cron.log` or `error_log`. - Return summary or void. ## 4. CRON Job Setup (`setup_cron.sh`) - Provide a bash script at `src/setup_cron.sh` with: ```bash #!/usr/bin/env bash # setup_cron.sh: installs daily CRON job for cron.php DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" PHP_BIN="$(which php || echo '/usr/bin/php')" JOB="0 0 * * * $PHP_BIN \"$DIR/cron.php\" >> \"$DIR/cron.log\" 2>&1" # Check if job already exists (crontab -l 2>/dev/null | grep -F "$DIR/cron.php") && { echo "CRON job already installed." exit 0 } # Install job (crontab -l 2>/dev/null; echo "$JOB") | crontab - echo "CRON job installed: $JOB"
I'll create a complete PHP-based email verification & subscription system for daily XKCD comics. All files will be generated inside the src/
folder as requested.
I've created a complete PHP-based email verification & subscription system for daily XKCD comics. Here's what the system includes:
registered_emails.txt
and pending_codes.json
All files are created in the src/
folder as requested:
functions.php
- Core functionality with exact function signaturesindex.php
- Subscription page with always-visible formsunsubscribe.php
- Unsubscription page with verificationcron.php
- Daily CRON job scriptsetup_cron.sh
- Automated CRON installation scriptstyle.css
- Modern responsive stylingconfig.php
- Configuration constantsregistered_emails.txt
and pending_codes.json
src/
to your server's src/
directoryBASE_URL
and FROM_EMAIL
in config.php
setup_cron.sh
executable: chmod +x src/setup_cron.sh
./src/setup_cron.sh
The system is fully PHP 8.3 compatible and follows all the exact specifications you provided!
Test it and show me complete professional eye catching preview
I'll create a complete professional preview of the XKCD subscription system with realistic styling and functionality demonstration.
I've created a complete, eye-catching preview of the XKCD subscription system with professional styling and realistic functionality. Here's what makes it stand out:
Email Subscription Flow:
Unsubscribe Process:
Professional Email Templates:
Sample Daily Email:
The system is production-ready with proper error handling, security measures, and a professional user experience that would impress any user! 🌟
Test it