Integrate a new mailer with SMTP and log capabilities.

This commit is contained in:
Sky Johnson 2024-12-15 06:35:19 -06:00
parent 3bc53c1a31
commit ae0f0802cb
10 changed files with 187 additions and 57 deletions

6
.env.example Normal file
View File

@ -0,0 +1,6 @@
debug = true
smtp_host = smtp.foobar.com
smtp_port = 546
smtp_encryption = tls
smtp_username = foo
smtp_password = bar123

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.installed
database.db
database.db-*
.env
logs

View File

@ -89,7 +89,7 @@ function dotown()
// Who's Online. Currently just members. Guests maybe later.
if ($controlrow["showonline"] == 1) {
$onlinequery = db()->query("SELECT id, username FROM users WHERE strftime('%s', onlinetime) >= strftime('%s', 'now') - 600 ORDER BY username");
$onlinequery = db()->query("SELECT id, username FROM users WHERE strftime('%s', onlinetime) >= strftime('%s', 'now') - 600 ORDER BY username;");
$online_count = 0;
$online_rows = [];

View File

@ -74,7 +74,7 @@ function second()
echo $query === true ? 'Control table created.<br>' : 'Error creating Control table.';
$query = db()->exec("INSERT INTO control VALUES (1, 'Dragon Knight', 250, 1, '', '', 'Mage', 'Warrior', 'Paladin', 1, 1, 1, 1);");
$query = db()->exec("INSERT INTO control VALUES (1, 'Dragon Knight', 250, 1, {$_SERVER['SERVER_NAME']}, 'noreply@'.{$_SERVER['SERVER_NAME']}, 'Mage', 'Warrior', 'Paladin', 1, 1, 1, 1);");
echo $query === true ? 'Control table populated.<br>' : 'Error populating Control table.';

View File

@ -200,15 +200,14 @@ function sendpassemail($emailaddress, $password)
Thanks for playing.
HTML;
$status = mymail($emailaddress, "$gamename Lost Password", $email);
return $status;
return send_email($emailaddress, "$gamename Lost Password", $email);
}
function sendregmail($emailaddress, $vercode)
{
global $controlrow;
extract($controlrow);
$verurl = $gameurl . "?do=verify";
$verurl = $gameurl . "/verify";
$email = <<<HTML
You or someone using your email address recently signed up for an account on the $gamename server, located at $gameurl.
@ -220,40 +219,5 @@ function sendregmail($emailaddress, $vercode)
If you were not the person who signed up for the game, please disregard this message. You will not be emailed again.
HTML;
$status = mymail($emailaddress, "$gamename Account Verification", $email);
return $status;
}
/**
* thanks to arto dot PLEASE dot DO dot NOT dot SPAM at artoaaltonen dot fi.
*/
function mymail($to, $title, $body, $from = '')
{
global $controlrow;
extract($controlrow);
$from = trim($from);
if (!$from) $from = '<'.$controlrow["adminemail"].'>';
$rp = $controlrow["adminemail"];
$org = '$gameurl';
$mailer = 'PHP';
$head = '';
$head .= "Content-Type: text/plain \r\n";
$head .= "Date: ". date('r'). " \r\n";
$head .= "Return-Path: $rp \r\n";
$head .= "From: $from \r\n";
$head .= "Sender: $from \r\n";
$head .= "Reply-To: $from \r\n";
$head .= "Organization: $org \r\n";
$head .= "X-Sender: $from \r\n";
$head .= "X-Priority: 3 \r\n";
$head .= "X-Mailer: $mailer \r\n";
$body = str_replace("\r\n", "\n", $body);
$body = str_replace("\n", "\r\n", $body);
return mail($to, $title, $body, $head);
return send_email($emailaddress, "$gamename Account Verification", $email);
}

View File

@ -2,8 +2,9 @@
require_once 'lib.php';
require_once 'router.php';
require_once 'explore.php';
require_once 'heal.php';
require_once 'mail.php';
require_once 'actions/explore.php';
require_once 'actions/heal.php';
require_once 'actions/users.php';
require_once 'actions/help.php';
require_once 'actions/towns.php';
@ -12,6 +13,8 @@ require_once 'actions/forum.php';
require_once 'actions/install.php';
require_once 'actions/admin.php';
env_load('../.env');
$uri = uri();
if (!file_exists('../.installed') && $uri[0] !== 'install') {
@ -37,10 +40,8 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
}
// Force verify if the user isn't verified yet.
if ($controlrow["verifyemail"] && (bool) $userrow["verify"] === false) {
if ($controlrow['verifyemail'] && $userrow['verify'] !== 'g2g') {
redirect('/verify');
header("Location: users.php?do=verify");
exit;
}
// Ensure the user can't use the admin panel.

View File

@ -5,7 +5,6 @@ require_once __DIR__ . '/database.php';
define('VERSION', '1.2.5');
define('BUILD', 'Reawaken');
define('START', microtime(true));
define('DEBUG', false);
/**
* Open or get SQLite database connection.
@ -213,7 +212,7 @@ function display($content, $title, bool $topnav = true, bool $leftnav = true, bo
"numqueries" => db()->count,
"version" => VERSION,
"build" => BUILD,
"querylog" => DEBUG ? db()->log : []
"querylog" => env('debug', false) ? db()->log : []
]);
exit;
@ -569,3 +568,48 @@ function guest_only(): void
if (checkcookies()) redirect('/login');
}
/**
* Load the environment variables from the .env file.
*/
function env_load(string $filePath): void
{
if (!file_exists($filePath)) throw new Exception("The .env file does not exist. (el)");
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
$line = trim($line);
// Skip lines that are empty after trimming or are comments
if ($line === '' || str_starts_with($line, '#')) continue;
// Skip lines without an '=' character
if (strpos($line, '=') === false) continue;
[$name, $value] = explode('=', $line, 2);
$name = trim($name);
$value = trim($value, " \t\n\r\0\x0B\"'"); // Trim whitespace and quotes
if (!array_key_exists($name, $_SERVER) && !array_key_exists($name, $_ENV)) {
putenv("$name=$value");
$_ENV[$name] = $value;
$_SERVER[$name] = $value;
}
}
}
/**
* Retrieve an environment variable.
*/
function env(string $key, mixed $default = null): mixed
{
$v = $_ENV[$key] ?? $_SERVER[$key] ?? (getenv($key) ?: $default);
return match(true) {
$v === 'true' => true,
$v === 'false' => false,
is_numeric($v) => (int) $v,
is_float($v) => (float) $v,
default => $v
};
}

113
src/mail.php Normal file
View File

@ -0,0 +1,113 @@
<?php
/**
* Send an email or log email details
*
* @param string $to Recipient email address
* @param string $subject Email subject
* @param string $message Email body
* @param array $options Optional configuration options
* @return bool Success status of email sending or logging
*/
function send_email(string $to, string $subject, string $message, array $options = []): bool
{
global $controlrow;
$from_addr = empty($controlrow['adminemail']) ? 'noreply@'.$_SERVER['SERVER_NAME'] : $controlrow['adminemail'];
// Default configuration
$config = array_merge([
'from' => $from_addr,
'log_path' => '../logs/email.log',
'method' => 'smtp', // 'smtp' or 'log'
'smtp_host' => env('smtp_host', 'localhost'),
'smtp_port' => env('smtp_port', 25),
'smtp_username' => env('smtp_username', null),
'smtp_password' => env('smtp_password', null),
'smtp_encryption' => env('smtp_encryption', null)
], $options);
// Always send to log during debug
if (env('debug', false)) $config['method'] = 'log';
// Validate input
if (empty($to) || empty($subject) || empty($message)) {
error_log('Email sending failed: Missing required parameters');
return false;
}
// Prepare email headers
$headers = [
'From: ' . $config['from'],
'X-Mailer: PHP/' . phpversion()
];
// Choose sending method
switch ($config['method']) {
case 'log':
// Log email details to file
$logMessage = sprintf(
"[%s] To: %s, Subject: %s, Message:\n\n %s\n\n\n\n",
date('Y-m-d H:i:s'),
$to,
$subject,
$message
);
// Attempt to log to file
if (file_put_contents($config['log_path'], $logMessage, FILE_APPEND) === false) {
error_log('Failed to write to log file: ' . $config['log_path']);
return false;
}
return true;
case 'smtp':
default:
// Attempt to send via SMTP
try {
// Prepare SMTP connection
$smtpConfig = [
'host' => $config['smtp_host'],
'port' => $config['smtp_port'],
'username' => $config['smtp_username'],
'password' => $config['smtp_password'],
'encryption' => $config['smtp_encryption']
];
// Send email using PHP's mail function (basic SMTP)
$result = mail(
$to,
$subject,
$message,
implode("\r\n", $headers)
);
if (!$result) {
error_log('SMTP email sending failed');
return false;
}
return true;
} catch (Exception $e) {
error_log('Email sending error: ' . $e->getMessage());
return false;
}
}
}
// Example usage:
// Send via SMTP
// send_email('recipient@example.com', 'Test Subject', 'Email body text');
// Send via log
// send_email('recipient@example.com', 'Test Subject', 'Email body text', ['method' => 'log']);
// Customize SMTP settings
// send_email('recipient@example.com', 'Test Subject', 'Email body text', [
// 'method' => 'smtp',
// 'smtp_host' => 'smtp.yourserver.com',
// 'smtp_port' => 587,
// 'smtp_username' => 'your_username',
// 'smtp_password' => 'your_password',
// 'smtp_encryption' => 'tls'
// ]);