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

@ -191,69 +191,33 @@ function sendpassemail($emailaddress, $password)
extract($controlrow);
$email = <<<HTML
You or someone using your email address submitted a Lost Password application on the $gamename server, located at $gameurl.
You or someone using your email address submitted a Lost Password application on the $gamename server, located at $gameurl.
We have issued you a new password so you can log back into the game.
We have issued you a new password so you can log back into the game.
Your new password is: $password
Your new password is: $password
Thanks for playing.
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.
You or someone using your email address recently signed up for an account on the $gamename server, located at $gameurl.
This email is sent to verify your registration email. In order to begin using your account, you must verify your email address.
Please visit the Verification Page ($verurl) and enter the code below to activate your account.
Verification code: $vercode
This email is sent to verify your registration email. In order to begin using your account, you must verify your email address.
Please visit the Verification Page ($verurl) and enter the code below to activate your account.
Verification code: $vercode
If you were not the person who signed up for the game, please disregard this message. You will not be emailed again.
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'
// ]);