190) {
return 'Please enter a shorter email address.';
}
$parts = explode('@', $email);
if (count($parts) !== 2) {
return 'Please enter a valid email address.';
}
[$local, $domain] = $parts;
if ($local === '' || $domain === '') {
return 'Please enter a valid email address.';
}
if (is_disposable_email_domain($domain)) {
return 'Please use your real email address. Temporary or disposable inboxes are not allowed.';
}
if (!has_valid_email_dns($domain)) {
return 'Please use an email with a real mail domain.';
}
return null;
}
function clean_text_input($value, int $max_length = 255): string {
$value = trim((string) $value);
$value = strip_tags($value);
$value = preg_replace('/[ -]/u', '', $value) ?? '';
if (function_exists('mb_substr')) {
return mb_substr($value, 0, $max_length);
}
return substr($value, 0, $max_length);
}
function normalize_timezone_input($value): ?string {
$timezone = clean_text_input($value, 100);
if ($timezone === '') {
return null;
}
return in_array($timezone, timezone_identifiers_list(), true) ? $timezone : null;
}
// --- Helper function to fetch webinar details ---
function get_webinar_details($id) {
if (empty($id)) return null;
try {
$stmt = db()->prepare("SELECT id, title, description, scheduled_at, presenter FROM webinars WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
error_log("Database error fetching webinar ID $id: " . $e->getMessage());
return null;
}
}
// --- Only allow POST requests ---
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
echo json_encode(['success' => false, 'error' => 'Invalid request method.']);
exit;
}
$webinar_id = filter_input(INPUT_POST, 'webinar_id', FILTER_VALIDATE_INT) ?: 1;
$webinar = get_webinar_details($webinar_id);
if (!$webinar) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Webinar not found.']);
exit;
}
// --- DATA CAPTURE ---
$email_input = (string) filter_input(INPUT_POST, 'email', FILTER_UNSAFE_RAW);
$email = normalize_email_address($email_input);
$email_error = validate_registration_email($email);
$first_name = clean_text_input(filter_input(INPUT_POST, 'first_name', FILTER_UNSAFE_RAW), 120);
$last_name = clean_text_input(filter_input(INPUT_POST, 'last_name', FILTER_UNSAFE_RAW), 120);
$company = clean_text_input(filter_input(INPUT_POST, 'company', FILTER_UNSAFE_RAW), 180);
$how_did_you_hear = clean_text_input(filter_input(INPUT_POST, 'how_did_you_hear', FILTER_UNSAFE_RAW), 120);
$timezone = normalize_timezone_input(filter_input(INPUT_POST, 'timezone', FILTER_UNSAFE_RAW));
$allowed_sources = [
'Social Media',
'LinkedIn',
'Reddit',
'Threads',
'Advertisement',
'ChatGPT',
'Flatlogic Community Discord',
'Other',
];
// --- VALIDATION ---
if (!$first_name || !$last_name || $email === '' || $how_did_you_hear === '') {
echo json_encode(['success' => false, 'error' => 'Please fill out all required fields.']);
exit;
}
if ($email_error !== null) {
echo json_encode(['success' => false, 'error' => $email_error]);
exit;
}
if (!in_array($how_did_you_hear, $allowed_sources, true)) {
echo json_encode(['success' => false, 'error' => 'Please choose how you heard about this webinar from the list.']);
exit;
}
try {
// --- CHECK IF ALREADY REGISTERED OR SOFT-DELETED -- -
$stmt = db()->prepare("SELECT id, deleted_at FROM attendees WHERE webinar_id = ? AND email = ?");
$stmt->execute([$webinar_id, $email]);
$existing_user = $stmt->fetch(PDO::FETCH_ASSOC);
$send_email = false;
if ($existing_user) {
if ($existing_user['deleted_at'] !== null) {
// --- USER IS SOFT-DELETED, SO REACTIVATE AND UPDATE ---
$sql = "UPDATE attendees SET first_name = ?, last_name = ?, company = ?, how_did_you_hear = ?, timezone = ?, deleted_at = NULL, created_at = NOW(), consented = 1 WHERE id = ?";
$stmt = db()->prepare($sql);
$stmt->execute([$first_name, $last_name, $company, $how_did_you_hear, $timezone, $existing_user['id']]);
$send_email = true;
} else {
// --- USER IS ACTIVE, SO REJECT ---
echo json_encode(['success' => false, 'error' => 'You are already registered for this webinar.']);
exit;
}
} else {
// --- REGISTER NEW USER ---
$password_hash = password_hash($email . time(), PASSWORD_DEFAULT);
$sql = "INSERT INTO attendees (webinar_id, first_name, last_name, email, company, how_did_you_hear, password, timezone, consented)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)";
$stmt = db()->prepare($sql);
$stmt->execute([$webinar_id, $first_name, $last_name, $email, $company, $how_did_you_hear, $password_hash, $timezone]);
$send_email = true;
}
$schedule = webinar_schedule_data($webinar);
$event_title = $schedule['title'];
$event_description = $schedule['calendar_description'];
$start_time_utc = webinar_utc_stamp($schedule['start']);
$end_time_utc = webinar_utc_stamp($schedule['end']);
$google_link = 'https://www.google.com/calendar/render?action=TEMPLATE' .
'&text=' . urlencode($event_title) .
'&dates=' . $start_time_utc . '/' . $end_time_utc .
'&details=' . urlencode($event_description) .
'&location=' . urlencode('Online') .
'&ctz=UTC';
if ($send_email) {
// --- SEND CONFIRMATION EMAIL ---
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
$logo_url = $protocol . '://' . $host . '/assets/pasted-20251030-095744-1b7c02ab.png';
$subject = "Confirmation: You're Registered for {$event_title}";
$safe_first_name = htmlspecialchars($first_name, ENT_QUOTES, 'UTF-8');
$safe_title = htmlspecialchars($event_title, ENT_QUOTES, 'UTF-8');
$safe_date_long = htmlspecialchars($schedule['date_long'], ENT_QUOTES, 'UTF-8');
$safe_berlin_label = htmlspecialchars($schedule['berlin_label'], ENT_QUOTES, 'UTF-8');
$safe_new_york_label = htmlspecialchars($schedule['new_york_label'], ENT_QUOTES, 'UTF-8');
$safe_los_angeles_label = htmlspecialchars($schedule['los_angeles_label'], ENT_QUOTES, 'UTF-8');
$body_html = <<
Webinar Registration Confirmation
You're Registered!
|
Hello {$safe_first_name},
Thank you for registering for the {$safe_title} webinar.
We're excited to have you join us for this professional vibe-coding session.
Webinar Details:
{$safe_date_long} | {$safe_berlin_label} | {$safe_new_york_label} | {$safe_los_angeles_label}
You'll learn the fastest way to go from an idea to a working app you own, running on your server, with your database, using real frameworks.
Your personal webinar access link will be emailed to you 1 day before the event.
Add to Calendar
|
|
© 2025 AppWizzy. All rights reserved.
You can visit our website for more information.
|
|
HTML;
MailService::sendMail($email, $subject, $body_html);
}
$ics_content = implode("\r\n", [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//Flatlogic//' . $event_title . '//EN',
'BEGIN:VEVENT',
'URL:' . 'http://' . $_SERVER['HTTP_HOST'],
'DTSTART:' . $start_time_utc,
'DTEND:' . $end_time_utc,
'SUMMARY:' . $event_title,
'DESCRIPTION:' . str_replace(PHP_EOL, '\\n', $event_description),
'LOCATION:Online',
'END:VEVENT',
'END:VCALENDAR'
]);
$outlook_link = 'data:text/calendar;charset=utf-8,' . rawurlencode($ics_content);
echo json_encode([
'success' => true,
'webinar_title' => $event_title . '
Professional Vibe-Coding Webinar',
'google_link' => $google_link,
'outlook_link' => $outlook_link,
'schedule_line' => $schedule['timezone_line']
]);
}
catch (Exception $e) {
http_response_code(500);
echo json_encode(['success' => false, 'error' => 'An unexpected server error occurred. Please try again.']);
}