From 3e01f4b391255862d0246f7f025d16278d1d9958 Mon Sep 17 00:00:00 2001 From: "r.mubarakzyanov" Date: Fri, 7 Aug 2026 14:05:49 +0300 Subject: [PATCH] fix .env path --- public/userportal/api/_mail.php | 92 ++++++++++++--------------------- 1 file changed, 32 insertions(+), 60 deletions(-) diff --git a/public/userportal/api/_mail.php b/public/userportal/api/_mail.php index fcfa122..05b8308 100644 --- a/public/userportal/api/_mail.php +++ b/public/userportal/api/_mail.php @@ -3,87 +3,59 @@ require_once __DIR__ . '/../../../vendor/autoload.php'; +use Dotenv\Dotenv; use PHPMailer\PHPMailer\PHPMailer; -/** Treats the literal "null" from .env as "not set". */ -function mail_env(string $key): string +Dotenv::createImmutable([dirname(__DIR__, 2), dirname(__DIR__, 3)])->safeLoad(); + +/** Treats an empty value and the literal "null" from .env as "not set". */ +function mail_env(string $key, string $default = ''): string { - $value = (string) (getenv($key) ?: ''); - return ($value === 'null') ? '' : $value; + $value = (string) ($_ENV[$key] ?? getenv($key) ?: ''); + + return ($value === '' || $value === 'null') ? $default : $value; } -/** - * PHPMailer compares SMTPSecure with ===, so "SSL" from .env would silently fall - * back to an unencrypted socket and hang on an implicit-TLS port. Normalise, and - * infer the usual encryption from the port when MAIL_ENCRYPTION is not set. - */ -function mail_encryption(int $port): string -{ - $enc = strtolower(mail_env('MAIL_ENCRYPTION')); - if ($enc === 'ssl' || $enc === 'tls') { - return $enc; - } - if ($enc !== '' && $enc !== 'none') { - error_log("mail: unknown MAIL_ENCRYPTION '{$enc}', falling back to the port default"); - } elseif ($enc === 'none') { - return ''; - } - - return in_array($port, [465, 2465], true) ? 'ssl' : 'tls'; -} - -/** - * Never surfaces the SMTP error to the caller: it can leak host and credentials. - * The error log gets the connection details (minus the password) instead — without - * them a failure is indistinguishable from a wrong recipient address. - */ +/** Never surfaces the SMTP error to the caller: it can leak host and credentials. */ function send_mail(string $to, string $subject, string $html): bool { - if (!class_exists(PHPMailer::class)) { - error_log('mail failed: PHPMailer not installed'); - return false; - } - - $host = mail_env('MAIL_HOST') ?: 'localhost'; - $port = (int) (mail_env('MAIL_PORT') ?: 587); - $user = mail_env('MAIL_USERNAME'); - $enc = mail_encryption($port); - $mail = new PHPMailer(true); try { $mail->isSMTP(); - $mail->Host = $host; - $mail->Port = $port; - $mail->CharSet = 'UTF-8'; + $mail->Host = mail_env('MAIL_HOST', 'localhost'); + $mail->Port = (int) mail_env('MAIL_PORT', '587'); + $mail->SMTPAuth = true; + $mail->Username = mail_env('MAIL_USERNAME'); + $mail->Password = mail_env('MAIL_PASSWORD'); + $mail->SMTPSecure = mail_env('MAIL_ENCRYPTION', PHPMailer::ENCRYPTION_STARTTLS); + $mail->CharSet = 'UTF-8'; // Default is 300s: an unreachable SMTP would otherwise stall registration. - $mail->Timeout = 10; - - if ($user !== '') { - $mail->SMTPAuth = true; - $mail->Username = $user; - $mail->Password = mail_env('MAIL_PASSWORD'); - } - if ($enc !== '') { - $mail->SMTPSecure = $enc; - } + $mail->Timeout = 10; $mail->setFrom( - mail_env('MAIL_FROM_ADDRESS') ?: 'noreply@casadoc.app', - mail_env('MAIL_FROM_NAME') ?: 'CasaDoc' + mail_env('MAIL_FROM_ADDRESS', 'noreply@casadoc.app'), + mail_env('MAIL_FROM_NAME', 'CasaDoc') ); $mail->addAddress($to); $mail->isHTML(true); $mail->Subject = $subject; $mail->Body = $html; - if ($mail->send()) { - return true; - } - error_log("mail failed to {$to} via {$enc}://{$user}@{$host}:{$port}: {$mail->ErrorInfo}"); + $mail->send(); - return false; + return true; } catch (Throwable $e) { - error_log("mail failed to {$to} via {$enc}://{$user}@{$host}:{$port}: " . $e->getMessage()); + // Without the connection details a failure is indistinguishable from a + // wrong recipient address. The password is never logged. + error_log(sprintf( + 'mail failed to %s via %s@%s:%s (%s): %s', + $to, + mail_env('MAIL_USERNAME'), + mail_env('MAIL_HOST', 'localhost'), + mail_env('MAIL_PORT', '587'), + mail_env('MAIL_ENCRYPTION', 'none'), + $mail->ErrorInfo ?: $e->getMessage() + )); return false; }