465 lines
14 KiB
PHP
465 lines
14 KiB
PHP
<?php
|
|
require_once 'config.php';
|
|
|
|
/**
|
|
* Write log message to file
|
|
*/
|
|
function writeLog($message, $level = 'INFO')
|
|
{
|
|
if (!LOG_ENABLED) {
|
|
return;
|
|
}
|
|
|
|
$timestamp = date('Y-m-d H:i:s');
|
|
$logMessage = "[{$timestamp}] [{$level}] {$message}" . PHP_EOL;
|
|
|
|
// Also log to error_log for immediate visibility
|
|
error_log("[MAIL] {$message}");
|
|
|
|
// Write to log file
|
|
if (defined('LOG_FILE')) {
|
|
file_put_contents(LOG_FILE, $logMessage, FILE_APPEND | LOCK_EX);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate email address
|
|
*/
|
|
function validateEmail($email)
|
|
{
|
|
return preg_match(EMAIL_REGEX, $email);
|
|
}
|
|
|
|
/**
|
|
* Encode email subject to handle umlauts and special characters (RFC 2047)
|
|
*/
|
|
function encodeEmailSubject($subject)
|
|
{
|
|
// Check if subject contains non-ASCII characters
|
|
if (preg_match('/[^\x20-\x7E]/', $subject)) {
|
|
// Use RFC 2047 encoding: =?charset?encoding?encoded-text?=
|
|
return '=?UTF-8?B?' . base64_encode($subject) . '?=';
|
|
}
|
|
return $subject;
|
|
}
|
|
|
|
/**
|
|
* Sanitize input string
|
|
*/
|
|
function sanitizeInput($input)
|
|
{
|
|
// Handle non-string values
|
|
if (is_array($input)) {
|
|
return array_map('sanitizeInput', $input);
|
|
}
|
|
if (!is_string($input)) {
|
|
$input = (string)$input;
|
|
}
|
|
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Generate XML from form data
|
|
*/
|
|
function generateXML($data)
|
|
{
|
|
$xml = new DOMDocument('1.0', 'UTF-8');
|
|
$xml->formatOutput = true;
|
|
|
|
$root = $xml->createElement('form_submission');
|
|
$xml->appendChild($root);
|
|
|
|
// Static data
|
|
$static = $xml->createElement('static');
|
|
$root->appendChild($static);
|
|
|
|
foreach (['name', 'lastname', 'title', 'telno', 'mail', 'apparatsname', 'subject', 'semester', 'dauerapparat'] as $field) {
|
|
if (isset($data[$field])) {
|
|
$element = $xml->createElement($field, htmlspecialchars($data[$field]));
|
|
$static->appendChild($element);
|
|
}
|
|
}
|
|
|
|
if (!empty($data['message'])) {
|
|
$messageEl = $xml->createElement('message', htmlspecialchars($data['message']));
|
|
$static->appendChild($messageEl);
|
|
}
|
|
|
|
// Books
|
|
if (isset($data['books']) && is_array($data['books'])) {
|
|
$booksNode = $xml->createElement('books');
|
|
$root->appendChild($booksNode);
|
|
|
|
foreach ($data['books'] as $book) {
|
|
$bookNode = $xml->createElement('book');
|
|
$booksNode->appendChild($bookNode);
|
|
|
|
foreach (['authorname', 'year', 'title', 'signature'] as $field) {
|
|
$value = isset($book[$field]) ? htmlspecialchars($book[$field]) : '';
|
|
$fieldNode = $xml->createElement($field, $value);
|
|
$bookNode->appendChild($fieldNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $xml->saveXML();
|
|
}
|
|
|
|
/**
|
|
* Generate XML for ELSA form
|
|
*/
|
|
function generateELSAXML($data)
|
|
{
|
|
$xml = new DOMDocument('1.0', 'UTF-8');
|
|
$xml->formatOutput = true;
|
|
|
|
$root = $xml->createElement('elsa_submission');
|
|
$xml->appendChild($root);
|
|
|
|
// General info
|
|
$generalInfo = $xml->createElement('general_info');
|
|
$root->appendChild($generalInfo);
|
|
|
|
$generalFields = [
|
|
'name',
|
|
'lastname',
|
|
'title',
|
|
'mail',
|
|
'subject',
|
|
'classname',
|
|
'usage_date_from',
|
|
'usage_date_to',
|
|
'availability_date'
|
|
];
|
|
|
|
foreach ($generalFields as $field) {
|
|
if (isset($data[$field])) {
|
|
$element = $xml->createElement($field, htmlspecialchars($data[$field]));
|
|
$generalInfo->appendChild($element);
|
|
}
|
|
}
|
|
|
|
if (!empty($data['message'])) {
|
|
$messageEl = $xml->createElement('message', htmlspecialchars($data['message']));
|
|
$generalInfo->appendChild($messageEl);
|
|
}
|
|
|
|
// Media sections
|
|
$mediaRoot = $xml->createElement('media');
|
|
$root->appendChild($mediaRoot);
|
|
|
|
// Add different media types (monografie, zeitschrift, herausgeber)
|
|
$mediaTypes = [
|
|
'monografien' => $data['monografien'] ?? [],
|
|
'zeitschriftenartikel' => $data['zeitschriftenartikel'] ?? [],
|
|
'herausgeberwerke' => $data['herausgeberwerke'] ?? []
|
|
];
|
|
|
|
foreach ($mediaTypes as $type => $entries) {
|
|
if (!empty($entries)) {
|
|
$section = $xml->createElement($type);
|
|
$mediaRoot->appendChild($section);
|
|
|
|
foreach ($entries as $entry) {
|
|
$entryNode = $xml->createElement('entry');
|
|
$section->appendChild($entryNode);
|
|
|
|
foreach ($entry as $key => $value) {
|
|
$fieldNode = $xml->createElement($key, htmlspecialchars($value));
|
|
$entryNode->appendChild($fieldNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $xml->saveXML();
|
|
}
|
|
|
|
/**
|
|
* Send email with XML attachment
|
|
* Uses PHP's mail() function or SMTP if configured
|
|
*/
|
|
function sendEmail($subject, $xmlContent, $toEmail = null)
|
|
{
|
|
$to = $toEmail ?? MAIL_TO;
|
|
$from = MAIL_FROM;
|
|
|
|
writeLog("==========================================================");
|
|
writeLog("Email Send Attempt");
|
|
writeLog("From: {$from}");
|
|
writeLog("To: {$to}");
|
|
writeLog("Subject: {$subject}");
|
|
writeLog("Content Length: " . strlen($xmlContent) . " bytes");
|
|
|
|
if (!MAIL_ENABLED) {
|
|
writeLog("MAIL SENDING DISABLED - Email not sent", 'WARNING');
|
|
writeLog("XML Content:\n" . $xmlContent);
|
|
writeLog("==========================================================");
|
|
return true;
|
|
}
|
|
|
|
// Try using SMTP if credentials are configured
|
|
if (SMTP_USERNAME && SMTP_PASSWORD) {
|
|
writeLog("SMTP credentials configured, attempting SMTP send");
|
|
$result = sendEmailSMTP($subject, $xmlContent, $to, $from);
|
|
|
|
if ($result) {
|
|
writeLog("Email sent successfully via SMTP", 'SUCCESS');
|
|
} else {
|
|
writeLog("Email sending via SMTP failed", 'ERROR');
|
|
}
|
|
|
|
writeLog("==========================================================");
|
|
return $result;
|
|
}
|
|
|
|
// Fallback to PHP mail() only if no SMTP credentials
|
|
writeLog("No SMTP credentials configured, using PHP mail() function");
|
|
$headers = "From: " . $from . "\r\n";
|
|
$headers .= "Content-Type: application/xml; charset=UTF-8\r\n";
|
|
$headers .= "X-Mailer: PHP/" . phpversion();
|
|
|
|
$result = mail($to, encodeEmailSubject($subject), $xmlContent, $headers);
|
|
|
|
if ($result) {
|
|
writeLog("Email sent successfully via mail()", 'SUCCESS');
|
|
} else {
|
|
writeLog("Email sending via mail() failed", 'ERROR');
|
|
}
|
|
|
|
writeLog("==========================================================");
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Send email via SMTP using PHPMailer (if available) or native PHP sockets
|
|
*/
|
|
function sendEmailSMTP($subject, $xmlContent, $to, $from)
|
|
{
|
|
// Try PHPMailer first if available
|
|
if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
|
writeLog("Initializing PHPMailer for SMTP send");
|
|
writeLog("SMTP Host: " . SMTP_HOST . ":" . SMTP_PORT);
|
|
writeLog("SMTP Encryption: " . SMTP_ENCRYPTION);
|
|
writeLog("SMTP Username: " . SMTP_USERNAME);
|
|
|
|
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
|
|
|
|
try {
|
|
// Server settings
|
|
$mail->isSMTP();
|
|
$mail->Host = SMTP_HOST;
|
|
$mail->SMTPAuth = true;
|
|
$mail->Username = SMTP_USERNAME;
|
|
$mail->Password = SMTP_PASSWORD;
|
|
$mail->SMTPSecure = SMTP_ENCRYPTION;
|
|
$mail->Port = SMTP_PORT;
|
|
$mail->CharSet = 'UTF-8';
|
|
|
|
writeLog("SMTP connection configured");
|
|
|
|
// Recipients
|
|
$mail->setFrom($from);
|
|
$mail->addAddress($to);
|
|
|
|
writeLog("Recipients configured");
|
|
|
|
// Content - XML as body
|
|
$mail->isHTML(false);
|
|
$mail->Subject = encodeEmailSubject($subject);
|
|
$mail->Body = $xmlContent;
|
|
$mail->ContentType = 'text/plain';
|
|
|
|
writeLog("Sending email via SMTP...");
|
|
$mail->send();
|
|
|
|
writeLog("SMTP send() completed successfully", 'SUCCESS');
|
|
return true;
|
|
} catch (Exception $e) {
|
|
writeLog("SMTP Exception: " . $e->getMessage(), 'ERROR');
|
|
writeLog("PHPMailer ErrorInfo: " . $mail->ErrorInfo, 'ERROR');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Helper function to read SMTP multi-line response
|
|
$readResponse = function ($socket) {
|
|
$response = '';
|
|
while ($line = fgets($socket, 515)) {
|
|
$response .= $line;
|
|
// Check if this is the last line (code followed by space, not hyphen)
|
|
if (preg_match('/^\d{3} /', $line)) {
|
|
break;
|
|
}
|
|
}
|
|
return $response;
|
|
};
|
|
|
|
// Fallback to native PHP SMTP
|
|
writeLog("PHPMailer not available, using native PHP SMTP implementation");
|
|
writeLog("SMTP Host: " . SMTP_HOST . ":" . SMTP_PORT);
|
|
writeLog("SMTP Encryption: " . SMTP_ENCRYPTION);
|
|
|
|
// Check if required transports are available
|
|
$transports = stream_get_transports();
|
|
writeLog("Available transports: " . implode(', ', $transports));
|
|
|
|
if (SMTP_ENCRYPTION === 'ssl' && !in_array('ssl', $transports)) {
|
|
writeLog("SSL transport not available. Enable OpenSSL extension in PHP.", 'ERROR');
|
|
writeLog("Try changing SMTP_ENCRYPTION to 'tls' and SMTP_PORT to 587 in config.php", 'ERROR');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// Build the connection string - always start with plain TCP for TLS
|
|
if (SMTP_ENCRYPTION === 'ssl') {
|
|
$host = 'ssl://' . SMTP_HOST;
|
|
} else {
|
|
$host = SMTP_HOST;
|
|
}
|
|
$timeout = 30;
|
|
|
|
writeLog("Connecting to {$host}:" . SMTP_PORT);
|
|
$smtp = @fsockopen($host, SMTP_PORT, $errno, $errstr, $timeout);
|
|
|
|
if (!$smtp) {
|
|
writeLog("Failed to connect: ({$errno}) {$errstr}", 'ERROR');
|
|
return false;
|
|
}
|
|
|
|
writeLog("Connected successfully");
|
|
|
|
// Read server response
|
|
$response = $readResponse($smtp);
|
|
writeLog("Server greeting: " . trim($response));
|
|
|
|
// Send EHLO
|
|
fputs($smtp, "EHLO " . SMTP_HOST . "\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("EHLO response: " . trim(str_replace("\r\n", " | ", $response)));
|
|
|
|
// Start TLS if needed and not using SSL
|
|
if (SMTP_ENCRYPTION === 'tls') {
|
|
fputs($smtp, "STARTTLS\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("STARTTLS response: " . trim($response));
|
|
|
|
if (strpos($response, '220') === 0) {
|
|
if (in_array('tls', $transports) || in_array('ssl', $transports)) {
|
|
$crypto = @stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
|
|
if ($crypto) {
|
|
writeLog("TLS encryption enabled successfully");
|
|
fputs($smtp, "EHLO " . SMTP_HOST . "\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("EHLO after TLS: " . trim(str_replace("\r\n", " | ", $response)));
|
|
} else {
|
|
writeLog("Failed to enable TLS encryption", 'WARNING');
|
|
writeLog("Continuing without encryption (not recommended)", 'WARNING');
|
|
}
|
|
} else {
|
|
writeLog("TLS/SSL transports not available. Enable OpenSSL extension.", 'WARNING');
|
|
writeLog("Continuing without encryption (not recommended)", 'WARNING');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Authenticate
|
|
fputs($smtp, "AUTH LOGIN\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("AUTH response: " . trim($response));
|
|
|
|
fputs($smtp, base64_encode(SMTP_USERNAME) . "\r\n");
|
|
$response = $readResponse($smtp);
|
|
|
|
fputs($smtp, base64_encode(SMTP_PASSWORD) . "\r\n");
|
|
$response = $readResponse($smtp);
|
|
|
|
if (strpos($response, '235') !== 0) {
|
|
writeLog("Authentication failed: " . trim($response), 'ERROR');
|
|
fclose($smtp);
|
|
return false;
|
|
}
|
|
|
|
writeLog("Authentication successful");
|
|
|
|
// Send MAIL FROM
|
|
fputs($smtp, "MAIL FROM: <{$from}>\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("MAIL FROM response: " . trim($response));
|
|
|
|
// Send RCPT TO
|
|
fputs($smtp, "RCPT TO: <{$to}>\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("RCPT TO response: " . trim($response));
|
|
|
|
// Send DATA
|
|
fputs($smtp, "DATA\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("DATA response: " . trim($response));
|
|
|
|
// Send email headers and body
|
|
$headers = "From: {$from}\r\n";
|
|
$headers .= "To: {$to}\r\n";
|
|
$headers .= "Subject: " . encodeEmailSubject($subject) . "\r\n";
|
|
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
|
|
$headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
|
|
$headers .= "\r\n";
|
|
|
|
fputs($smtp, $headers . $xmlContent . "\r\n.\r\n");
|
|
$response = $readResponse($smtp);
|
|
writeLog("Message response: " . trim($response));
|
|
|
|
// Quit
|
|
fputs($smtp, "QUIT\r\n");
|
|
$readResponse($smtp); // Read QUIT response
|
|
fclose($smtp);
|
|
|
|
if (strpos($response, '250') === 0) {
|
|
writeLog("Email sent successfully via native SMTP", 'SUCCESS');
|
|
return true;
|
|
} else {
|
|
writeLog("Email sending failed: " . trim($response), 'ERROR');
|
|
return false;
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
writeLog("Native SMTP Exception: " . $e->getMessage(), 'ERROR');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirect to URL
|
|
*/
|
|
function redirect($url)
|
|
{
|
|
header("Location: " . $url);
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get POST value with default
|
|
*/
|
|
function post($key, $default = '')
|
|
{
|
|
if (!isset($_POST[$key])) {
|
|
return $default;
|
|
}
|
|
|
|
// If the value is an array, return the first element or default
|
|
if (is_array($_POST[$key])) {
|
|
return !empty($_POST[$key]) ? sanitizeInput($_POST[$key][0]) : $default;
|
|
}
|
|
|
|
return sanitizeInput($_POST[$key]);
|
|
}
|
|
|
|
/**
|
|
* Get all POST values matching a pattern (for arrays)
|
|
*/
|
|
function postArray($key)
|
|
{
|
|
return isset($_POST[$key]) && is_array($_POST[$key]) ?
|
|
array_map('sanitizeInput', $_POST[$key]) : [];
|
|
}
|