false, 'message' => 'Method not allowed']); exit; } require_once __DIR__ . '/SmtpMailer.php'; require_once __DIR__ . '/../includes/form-protection.php'; // Load email configuration from settings.json or fallback to smtp-config.php $emailConfig = null; $settingsPath = __DIR__ . '/../content/settings.json'; if (file_exists($settingsPath)) { $settings = json_decode(file_get_contents($settingsPath), true); if (!empty($settings['email'])) { $emailConfig = $settings['email']; } } // Fallback: legacy smtp-config.php (for existing installations) if (!$emailConfig && file_exists(__DIR__ . '/smtp-config.php')) { require_once __DIR__ . '/smtp-config.php'; $emailConfig = [ 'method' => 'smtp', 'recipientEmail' => defined('SMTP_FROM_EMAIL') ? SMTP_FROM_EMAIL : '', 'fromEmail' => defined('SMTP_FROM_EMAIL') ? SMTP_FROM_EMAIL : '', 'fromName' => defined('SMTP_FROM_NAME') ? SMTP_FROM_NAME : '', 'smtpHost' => defined('SMTP_HOST') ? SMTP_HOST : '', 'smtpPort' => defined('SMTP_PORT') ? SMTP_PORT : 587, 'smtpUsername' => defined('SMTP_USERNAME') ? SMTP_USERNAME : '', 'smtpPassword' => defined('SMTP_PASSWORD') ? SMTP_PASSWORD : '', 'smtpEncryption' => defined('SMTP_ENCRYPTION') ? SMTP_ENCRYPTION : 'tls', ]; } // Path to mail backup file $mailsFile = __DIR__ . '/../content/mails.json'; /** * Remove newlines from string (header injection protection) */ function sanitizeHeaderValue($value) { return str_replace(["\r", "\n", "\t"], '', trim($value)); } function parseConfiguredEmailList($value): array { $rawItems = is_array($value) ? $value : explode(',', (string)$value); $emails = []; foreach ($rawItems as $item) { foreach (explode(',', (string)$item) as $email) { $email = sanitizeHeaderValue($email); if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) { $emails[] = $email; } } } return array_values(array_unique($emails)); } /** * Save email locally as backup */ function saveMailBackup($filePath, $mailData) { return raijuJsonUpdate($filePath, function (array &$mails) use ($mailData): void { array_unshift($mails, $mailData); $mails = array_slice($mails, 0, 500); }); } // Get and sanitize form data $lang = $_POST['lang'] ?? 'de'; $name = sanitizeHeaderValue($_POST['name'] ?? ''); $email = sanitizeHeaderValue($_POST['email'] ?? ''); $phone = sanitizeHeaderValue($_POST['phone'] ?? ''); $occasion = sanitizeHeaderValue($_POST['occasion'] ?? ''); $date = sanitizeHeaderValue($_POST['date'] ?? ''); $message = trim($_POST['message'] ?? ''); $clientKey = raijuFormClientKey(); if (!raijuFormReserveRequest($clientKey)) { http_response_code(429); echo json_encode([ 'success' => false, 'message' => $lang === 'de' ? 'Zu viele Versuche. Bitte versuchen Sie es später erneut.' : 'Too many attempts. Please try again later.' ]); exit; } // Honeypot check. Return a neutral success response so simple bots cannot // distinguish this from a real submission, but do not store or send anything. if (!empty($_POST['website'])) { raijuFormRecordAttempt($clientKey, false); echo json_encode([ 'success' => true, 'message' => $lang === 'de' ? 'Vielen Dank für Ihre Nachricht!' : 'Thank you for your message!' ]); exit; } // Validation $errors = []; if (empty($name)) { $errors[] = $lang === 'de' ? 'Name ist erforderlich' : 'Name is required'; } if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = $lang === 'de' ? 'Gültige E-Mail ist erforderlich' : 'Valid email is required'; } if (empty($occasion)) { $errors[] = $lang === 'de' ? 'Anlass ist erforderlich' : 'Occasion is required'; } if (empty($message)) { $errors[] = $lang === 'de' ? 'Nachricht ist erforderlich' : 'Message is required'; } if (!empty($errors)) { echo json_encode(['success' => false, 'message' => implode(', ', $errors)]); exit; } if (raijuFormLooksLikeSpam([$name, $email, $phone, $occasion, $date, $message])) { raijuFormRecordAttempt($clientKey, false); echo json_encode([ 'success' => false, 'message' => $lang === 'de' ? 'Die Nachricht konnte nicht gesendet werden. Bitte prüfen Sie Ihre Eingaben.' : 'The message could not be sent. Please check your input.' ]); exit; } $tokenResult = raijuValidateFormToken($_POST['form_token'] ?? null, 'contact'); if (empty($tokenResult['valid'])) { raijuFormRecordAttempt($clientKey, false); $newToken = raijuCreateFormToken('contact'); http_response_code(400); echo json_encode([ 'success' => false, 'formToken' => $newToken, 'message' => $lang === 'de' ? 'Das Formular ist abgelaufen oder wurde zu schnell gesendet. Bitte versuchen Sie es erneut.' : 'The form expired or was submitted too quickly. Please try again.' ]); exit; } // Compose email $subject = ($lang === 'de' ? 'Anfrage über Website: ' : 'Website inquiry: ') . $occasion; $body = $lang === 'de' ? "Neue Anfrage über das Kontaktformular\n" : "New inquiry via contact form\n"; $body .= str_repeat('-', 40) . "\n\n"; $body .= ($lang === 'de' ? "Name: " : "Name: ") . $name . "\n"; $body .= ($lang === 'de' ? "E-Mail: " : "Email: ") . $email . "\n"; if ($phone) { $body .= ($lang === 'de' ? "Telefon: " : "Phone: ") . $phone . "\n"; } $body .= ($lang === 'de' ? "Anlass: " : "Occasion: ") . $occasion . "\n"; if ($date) { $formattedDate = date('d.m.Y', strtotime($date)); $body .= ($lang === 'de' ? "Gewünschtes Datum: " : "Preferred date: ") . $formattedDate . "\n"; } $body .= "\n" . ($lang === 'de' ? "Nachricht:\n" : "Message:\n"); $body .= str_repeat('-', 40) . "\n"; $body .= $message . "\n"; $body .= str_repeat('-', 40) . "\n"; // Send email when configured. Valid submissions are stored locally even when // email delivery is disabled or misconfigured, so contact requests are not lost. $sent = false; $method = $emailConfig['method'] ?? 'inactive'; $toRecipients = parseConfiguredEmailList($emailConfig['recipientEmail'] ?? ''); $bccRecipients = parseConfiguredEmailList($emailConfig['bccEmail'] ?? ''); $to = implode(', ', $toRecipients); $fromEmail = sanitizeHeaderValue($emailConfig['fromEmail'] ?? '') ?: ($toRecipients[0] ?? ''); $fromName = sanitizeHeaderValue($emailConfig['fromName'] ?? ''); $replyToEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : ''; $isEmailConfigured = $emailConfig && $method !== 'inactive' && !empty($toRecipients); if ($isEmailConfigured && $method === 'smtp') { $mailer = new SmtpMailer( $emailConfig['smtpHost'] ?? '', intval($emailConfig['smtpPort'] ?? 587), $emailConfig['smtpUsername'] ?? '', $emailConfig['smtpPassword'] ?? '', $emailConfig['smtpEncryption'] ?? 'tls' ); $sent = $mailer->send( $toRecipients, $subject, $body, $fromEmail, $fromName, $replyToEmail, $bccRecipients ); } elseif ($isEmailConfigured && $method === 'sendmail') { // PHP mail() — requires server IP to be whitelisted for sending $headers = []; $headers[] = 'From: ' . ($fromName ? "=?UTF-8?B?" . base64_encode($fromName) . "?= <$fromEmail>" : $fromEmail); if ($replyToEmail) { $headers[] = 'Reply-To: ' . $replyToEmail; } $headers[] = 'Content-Type: text/plain; charset=UTF-8'; $headers[] = 'X-Mailer: Raiju CMS'; $sent = @mail($to, '=?UTF-8?B?' . base64_encode($subject) . '?=', $body, implode("\r\n", $headers)); foreach ($bccRecipients as $bccRecipient) { $sent = @mail($bccRecipient, '=?UTF-8?B?' . base64_encode($subject) . '?=', $body, implode("\r\n", $headers)) && $sent; } } $status = $sent ? 'sent' : ($isEmailConfigured ? 'send_failed' : 'local_only'); $saved = saveMailBackup($mailsFile, [ 'id' => uniqid('mail_'), 'timestamp' => date('c'), 'lang' => $lang, 'formId' => 'contact', 'formLabel' => $lang === 'de' ? 'Kontaktformular' : 'Contact form', 'name' => $name, 'email' => $email, 'phone' => $phone, 'occasion' => $occasion, 'date' => $date, 'message' => $message, 'fields' => [ ['key' => 'name', 'label' => $lang === 'de' ? 'Name' : 'Name', 'value' => $name], ['key' => 'email', 'label' => $lang === 'de' ? 'E-Mail' : 'Email', 'value' => $email], ['key' => 'phone', 'label' => $lang === 'de' ? 'Telefon' : 'Phone', 'value' => $phone], ['key' => 'message', 'label' => $lang === 'de' ? 'Nachricht' : 'Message', 'value' => $message], ], 'status' => $status, 'read' => false, 'starred' => false ]); if (!$saved) { http_response_code(500); echo json_encode([ 'success' => false, 'message' => $lang === 'de' ? 'Die Nachricht konnte nicht gespeichert werden. Bitte versuchen Sie es später erneut.' : 'The message could not be saved. Please try again later.' ]); exit; } raijuFormRecordAttempt($clientKey, true); $newToken = raijuCreateFormToken('contact'); echo json_encode([ 'success' => true, 'status' => $status, 'formToken' => $newToken, 'message' => $lang === 'de' ? 'Vielen Dank für Ihre Nachricht!' : 'Thank you for your message!' ]);