rewrote logic in newsletter scripts, refactored code, moved file locations,

This commit is contained in:
eclipse 2025-03-03 12:11:49 +01:00
parent 973d4b0345
commit d9b8177038
11 changed files with 187 additions and 154 deletions

View File

@ -1,7 +1,7 @@
title: Termine title: Termine
author: Tobias Radloff author: Tobias Radloff
summary: Lesungen und Veranstaltungen summary: Lesungen und Veranstaltungen
template: termine.noformat template: termine
lang: de lang: de
category: Termine category: Termine
slug: termine slug: termine

View File

@ -5,62 +5,51 @@ require(dirname(__FILE__) . '/settings.php');
$successURL = '/newsletter/confirmed.html'; $successURL = '/newsletter/confirmed.html';
$errorURL = '/newsletter/confirm-error.html'; $errorURL = '/newsletter/confirm-error.html';
$err = 'Bestätigung fehlgeschlagen';
// Adds new subscriber to database. Returns an error message on failure, TRUE on success. // Adds new subscriber to database. Returns an error message on failure, TRUE on success.
function AddSubscriberToDB($subscriberAddress, $subscriberName = NULL) { function AddSubscriberToDB($subscriberAddress, $subscriberName = NULL) {
global $general;
try {
$pdo = getPDO(); $pdo = getPDO();
// create table if it doesn't exist already
$query = $pdo->prepare($general['sql']['create_table']);
if ( ! $query->execute() ) {
error_log('Datenbankfehler beim Prüfen/Erzeugen der Tabelle.');
return "Ein Fehler ist aufgetreten.";
}
// check if record exists // check if record exists
$query = $pdo->prepare($general['sql']['read_record']); $check = NotAlreadySubscribed($subscriberAddress, $pdo);
if ( ! $query->execute([':e' => $subscriberAddress]) ) { if ( gettype($check) == 'string' ) {
error_log("Datenbankfehler: Adresscheck für Emailadresse {$subscriberAddress} ergab einen Fehler."); return $check;
return 'Datenbankfehler.';
}
if ( $query->fetch() ) {
error_log("Datenbankfehler: Emailadresse {$subscriberAddress} ist bereits eingetragen.");
return "Emailadresse ist bereits eingetragen.";
} }
// create record // create record
global $general;
$query = $pdo->prepare($general['sql']['create_record']); $query = $pdo->prepare($general['sql']['create_record']);
if ( ( ! $query->execute([':e' => $subscriberAddress, ':n' => $subscriberName]) ) or ( $query->fetch() ) ) { if ( ( ! $query->execute([':e' => $subscriberAddress, ':n' => $subscriberName]) ) or ( $query->fetch() ) ) {
error_log("Datenbankfehler: Einfügen von Emailadresse {$subscriberAddress} ergab einen Fehler."); // error_log("Datenbankfehler: Einfügen von Emailadresse {$subscriberAddress} ergab einen Fehler.");
return 'Datenbankfehler.'; return 'Fehler beim Eintragen in die Datenbank';
}
} catch(\PDOException $e) {
error_log("Datenbankfehler: {$e->getMessage()}");
return $e->getMessage();
} }
return TRUE; return TRUE;
} }
if (isset($_GET['c']) && isset($_GET['e'])) {
// check if hash and email parameters are both set
if ( ! (isset($_GET['c']) and isset($_GET['e'])) ) {
GracefulExit($errorURL, "{$err}: Fehlende Emailadresse oder Hash");
}
// check if hash is correct
$c = filter_var($_GET['c'], FILTER_SANITIZE_STRING); $c = filter_var($_GET['c'], FILTER_SANITIZE_STRING);
$e = filter_var($_GET['e'], FILTER_SANITIZE_STRING); $e = filter_var($_GET['e'], FILTER_SANITIZE_STRING);
if ( GetConfirmationHash($e) != $c ) {
GracefulExit($errorURL, "{$err}: Fehlerhafter Hash");
}
if ( GetConfirmationHash($e) === $c ) { // add email to database
try {
$result = AddSubscriberToDB($e); $result = AddSubscriberToDB($e);
if ($result === TRUE) { if ( gettype($result) == 'string' ) {
GracefulExit($errorURL, "{$err}: {$result}");
}
} catch(\PDOException $e) {
GracefulExit($errorURL, "{$err}: {$e->getMessage()}");
}
// success
GracefulExit($successURL, 'Bestätigung erfolgt: Newsletter-Anmeldung bestätigt'); GracefulExit($successURL, 'Bestätigung erfolgt: Newsletter-Anmeldung bestätigt');
} elseif (gettype($result == 'string')) {
GracefulExit($errorURL, "Bestätigung fehlgeschlagen: {$result}");
} else {
GracefulExit($errorURL, 'Bestätigung fehlgeschlagen: Unbekannter Fehler');
}
} else {
GracefulExit($errorURL, 'Bestätigung fehlgeschlagen: Fehlerhafter Hash');
}
} else {
GracefulExit($errorURL, 'Bestätigung fehlgeschlagen: Fehlende Emailadresse oder Hash');
}
?> ?>

View File

@ -5,9 +5,9 @@ use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
$dname = dirname(__FILE__); $dname = dirname(__FILE__);
require $dname . '/Exception.php'; require $dname . '/../Exception.php';
require $dname . '/PHPMailer.php'; require $dname . '/../PHPMailer.php';
require $dname . '/SMTP.php'; require $dname . '/../SMTP.php';
// general constants // general constants
$general = [ $general = [
@ -17,7 +17,7 @@ $general = [
// string concatenated with email address to create a non-recreatable md5 hash // string concatenated with email address to create a non-recreatable md5 hash
'uniqueKey' => '***REMOVED***', // works like password salt 'uniqueKey' => '***REMOVED***', // works like password salt
// file name of confirm script // file name of confirm script
'confirmScript' => '/confirm.php', 'confirmScript' => '/newsletter/confirm.php',
// status code to be used when redirection to success or error page // status code to be used when redirection to success or error page
'statusCode' => 'HTTP/1.1 303 See Other', 'statusCode' => 'HTTP/1.1 303 See Other',
// array of SQL statements used // array of SQL statements used
@ -61,7 +61,7 @@ $mailConfirmation = [
// database information // database information
$db = [ $db = [
'sqlite' => [ 'sqlite' => [
'dsn' => 'sqlite:../newsletter.sqlite', 'dsn' => 'sqlite:../../newsletter.sqlite',
], ],
'mysql' => [ 'mysql' => [
'dsn' => '', 'dsn' => '',
@ -83,13 +83,11 @@ function getPDO($dbType = 'sqlite') {
return new \PDO($db[$dbType]['dsn']); return new \PDO($db[$dbType]['dsn']);
} }
// Sends an email to single recipient with subject and body specified in an array. Returns an error message on failure, TRUE on success. // Sends an email to single recipient with subject and body specified in an array
function SendEmail($recipientAddress, $mailContents, $link = NULL) { function SendEmail($recipientAddress, $mailContents, $link = NULL) {
global $general, $smtp; global $general, $smtp;
$mail = new PHPMailer(true); $mail = new PHPMailer(true);
try {
//Server settings //Server settings
// $mail->SMTPDebug = SMTP::DEBUG_SERVER; //Enable verbose debug output // $mail->SMTPDebug = SMTP::DEBUG_SERVER; //Enable verbose debug output
$mail->isSMTP(); $mail->isSMTP();
@ -116,14 +114,48 @@ function SendEmail($recipientAddress, $mailContents, $link = NULL) {
$mail->AltBody = $mailContents["bodyText"]; $mail->AltBody = $mailContents["bodyText"];
$mail->send(); $mail->send();
return TRUE;
} catch (Exception $e) {
error_log("Message error: {$e}");
return FALSE;
}
} }
// redirects to specified URL via GET request and conveys an optional message
function MakeSureTableExists($pdo) {
global $general;
$query = $pdo->prepare($general['sql']['create_table']);
if ( ! $query->execute() ) {
// error_log('Unbekannter Datenbankfehler beim Prüfen/Erzeugen der Tabelle.');
return "Unbekannter Datenbankfehler";
}
return TRUE;
}
// returns true if record does not yet exist in database; error string otherwise
function NotAlreadySubscribed($email, $pdo = NULL) {
if (!isset($pdo)) {
$pdo = getPDO();
}
$result = MakeSureTableExists($pdo);
if ( gettype($result) == "string" ) {
// error_log("Datenbankfehler beim Adresscheck: {$result}");
return $result;
}
global $general;
$query = $pdo->prepare($general['sql']['read_record']);
if ( ! $query->execute([':e' => $email]) ) {
// error_log("Datenbankfehler: Adresscheck für Emailadresse {$email} ergab einen Fehler.");
return "Fehler beim Zugriff auf Datenbank";
}
if ( $query->fetch() ) {
// error_log("Adresscheck: Emailadresse {$email} ist bereits eingetragen.");
return "Emailadresse {$email} ist bereits eingetragen";
}
// success
return TRUE;
}
// redirects to specified URL via GET request and conveys an optional message; then exits
function GracefulExit($location, $message = NULL) { function GracefulExit($location, $message = NULL) {
global $general; global $general;
header($general['statusCode']); header($general['statusCode']);
@ -132,5 +164,6 @@ function GracefulExit($location, $message = NULL) {
error_log($location); error_log($location);
} }
header("Location: {$location}"); header("Location: {$location}");
exit;
} }
?> ?>

View File

@ -1,28 +1,42 @@
<?php <?php
// inspired by https://www.mailgun.com/blog/email/double-opt-in-with-php-mailgun/ // inspired by https://www.mailgun.com/blog/email/double-opt-in-with-php-mailgun/
$successURL = '/newsletter/subscribed.html';
$errorURL = '/newsletter/subscribe-error.html';
require(dirname(__FILE__) . '/settings.php'); require(dirname(__FILE__) . '/settings.php');
if (isset($_POST['email'])) { $successURL = '/newsletter/subscribed.html';
$email = filter_var(trim($_POST['email'], FILTER_SANITIZE_STRING)); $errorURL = '/newsletter/subscribe-error.html';
$err = 'Anmeldung fehlgeschlagen';
if (filter_var($email, FILTER_VALIDATE_EMAIL)) { // check if email parameter is set
if ( ! isset($_POST['email']) ) {
GracefulExit($errorURL, "{$err}: Keine Emailadresse angegeben.");
}
// check if it's a well-formed email address
$email = filter_var(trim($_POST['email'], FILTER_SANITIZE_STRING));
if ( ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
GracefulExit($errorURL, "{$err}: Ungültige Emailadresse {$email}");
}
// check whether address is already subscribed
try {
$check = NotAlreadySubscribed($email);
if ( gettype($check) == 'string' ) {
GracefulExit($errorURL, "{$err}: {$check}.");
}
} catch (\PDOException $e) {
GracefulExit($errorURL, "{$err}: {$e->getMessage()}");
}
// send email with confirmation link
$confirmQuery = http_build_query(['c' => GetConfirmationHash($email), 'e' => $email]); $confirmQuery = http_build_query(['c' => GetConfirmationHash($email), 'e' => $email]);
$confirmLink = $general['siteURL'] . $general['confirmScript'] . "?" . $confirmQuery; $confirmLink = $general['siteURL'] . $general['confirmScript'] . "?" . $confirmQuery;
try {
SendEmail($email, $mailConfirmation, $confirmLink);
} catch (Exception $e) {
GracefulExit($errorURL, "{$err}: {$e->getMessage()}");
}
$result = SendEmail($email, $mailConfirmation, $confirmLink); // success
if ( $result === TRUE ) { GracefulExit($successURL, "Anmeldung erfolgreich: Email mit Bestätigungslink wurde an {$email} versandt.");
GracefulExit($successURL, 'Anmeldung wird fortgesetzt: Email mit Bestätigungslink wurde versandt.');
} else {
GracefulExit($errorURL, 'Anmeldung fehlgeschlagen: Fehler beim Versenden der Bestätigungs-Email.');
}
} else {
GracefulExit($errorURL, 'Anmeldung fehlgeschlagen: Ungültige Emailadresse.');
}
} else {
GracefulExit($errorURL, 'Anmeldung fehlgeschlagen: Keine Emailadresse angegeben.');
}
?> ?>

View File

@ -4,49 +4,45 @@ require(dirname(__FILE__) . '/settings.php');
$successURL = '/newsletter/unsubscribed.html'; $successURL = '/newsletter/unsubscribed.html';
$errorURL = '/newsletter/unsubscribe-error.html'; $errorURL = '/newsletter/unsubscribe-error.html';
$err = "Abmeldung fehlgeschlagen";
function RemoveSubscriberFromDB($subscriberAddress) { function RemoveSubscriberFromDB($subscriberAddress) {
global $general;
try {
$pdo = getPDO(); $pdo = getPDO();
// make sure record exists // make sure record exists
$query = $pdo->prepare($general['sql']['read_record']); $check = NotAlreadySubscribed($subscriberAddress, $pdo);
if ( ! $query->execute([':e' => $subscriberAddress]) ) { if ( gettype($check) == 'string' ) {
error_log("Datenbankfehler: Adresscheck für {$subscriberAddress} ergab einen Fehler."); return $check;
return 'Datenbankfehler.';
}
if ( ! $query->fetch() ) {
error_log("Datenbankfehler: Emailadresse {$subscriberAddress} nicht in Datenbank vorhanden.");
return "Emailadresse nicht bekannt.";
} }
// delete record // delete record
global $general;
$query = $pdo->prepare($general['sql']['delete_record']); $query = $pdo->prepare($general['sql']['delete_record']);
if ( ! $query->execute([':e' => $subscriberAddress])) { if ( ! $query->execute([':e' => $subscriberAddress])) {
error_log("Datenbankfehler: Löschen von Emailadresse {$subscriberAddress} ergab einen Fehler."); return "Fehler beim Löschen des Datenbankeintrags für {$subscriberAddress}.";
return 'Fehler beim Löschen des Datenbankeintrags.';
}
} catch(\PDOException $e) {
error_log("Datenbankfehler: {$e->getMessage()}");
return $e->getMessage();
} }
return TRUE; return TRUE;
} }
if (isset($_GET['e'])) { // check if hash and email parameters are both set
$e = filter_var($_GET["e"], FILTER_SANITIZE_STRING); if ( ! (isset($_GET['c']) and isset($_GET['e'])) ) {
$result = RemoveSubscriberFromDB($e); GracefulExit($errorURL, "{$err}: Fehlende Emailadresse oder Hash");
if ($result === TRUE) {
GracefulExit($successURL, "Abmeldung für {$e} erfolgreich.");
} elseif (gettype($result == 'string')) {
GracefulExit($errorURL, "Abmeldung fehlgeschlagen: {$result}");
} else {
GracefulExit($errorURL, 'Abmeldung fehlgeschlagen: Unbekannter Fehler');
} }
} else {
GracefulExit($errorURL, 'Abmeldung fehlgeschlagen: Fehlerhafte Emailadresse'); // check if hash is correct
$c = filter_var($_GET['c'], FILTER_SANITIZE_STRING);
$e = filter_var($_GET['e'], FILTER_SANITIZE_STRING);
if ( ! GetConfirmationHash($e) === $c ) {
GracefulExit($errorURL, "{$err}: Fehlerhafter Hash");
}
// remove email from database
try {
$result = RemoveSubscriberFromDB($e);
if (gettype($result) == 'string') {
GracefulExit($errorURL, "{$err}: {$result}");
}
} catch(\PDOException $e) {
GracefulExit($error, "{$err}: {$e->getMessage()}");
} }
?> ?>

View File

@ -27,11 +27,11 @@ IGNORE_FILES = ['**/.*', '__pycache__', 'favicon-from-svg.sh', '*.metadata']
EXTRA_PATH_METADATA = { EXTRA_PATH_METADATA = {
'favicon/favicon.ico': {'path': 'favicon.ico'}, 'favicon/favicon.ico': {'path': 'favicon.ico'},
'php/settings.php': {'path': 'settings.php'}, 'php/settings.php': {'path': 'newsletter/settings.php'},
'php/subscribe.php': {'path': 'subscribe.php'}, 'php/subscribe.php': {'path': 'newsletter/subscribe.php'},
'php/confirm.php': {'path': 'confirm.php'}, 'php/confirm.php': {'path': 'newsletter/confirm.php'},
'php/unsubscribe.php': {'path': 'unsubscribe.php'}, 'php/unsubscribe.php': {'path': 'newsletter/unsubscribe.php'},
'php/contact.php': {'path': 'contact.php'}, 'php/contact.php': {'path': 'kontakt/contact.php'},
'php/Exception.php': {'path': 'Exception.php'}, 'php/Exception.php': {'path': 'Exception.php'},
'php/PHPMailer.php': {'path': 'PHPMailer.php'}, 'php/PHPMailer.php': {'path': 'PHPMailer.php'},
'php/SMTP.php': {'path': 'SMTP.php'}, 'php/SMTP.php': {'path': 'SMTP.php'},

View File

@ -1,6 +1,6 @@
{% extends "page.html" %} {% extends "page.html" %}
{% block content_body %} {% block content_body %}
<form id="contact-form" method="post" action="{{ SITEURL }}/contact.php"> <form id="contact-form" method="post" action="{{ SITEURL }}/kontakt/contact.php">
<fieldset> <fieldset>
<label> <label>
Name Name

View File

@ -2,7 +2,7 @@
<h2>Abonniere meinen Newsletter</h2> <h2>Abonniere meinen Newsletter</h2>
<p>Erfahre zuerst von Neuerscheinungen, Lesungen und dem ganzen Rest. Mein Dankeschön für dich: ein unveröffentlichtes Gedicht.</p> <p>Erfahre zuerst von Neuerscheinungen, Lesungen und dem ganzen Rest. Mein Dankeschön für dich: ein unveröffentlichtes Gedicht.</p>
</hgroup> </hgroup>
<form class="newsletter-form" method="post" action="{{ SITEURL }}/subscribe.php"> <form class="newsletter-form" method="post" action="{{ SITEURL }}/newsletter/subscribe.php">
<input class="newsletter-email" type="email" name="email" placeholder="Emailadresse" autocomplete="email" aria-label="Emailadresse" required/> <input class="newsletter-email" type="email" name="email" placeholder="Emailadresse" autocomplete="email" aria-label="Emailadresse" required/>
<input class="newsletter-submit" type="submit" value="Abonnieren" /> <input class="newsletter-submit" type="submit" value="Abonnieren" />
</form> </form>

View File

@ -2,7 +2,7 @@
<h2>Newsletter-Abmeldung</h2> <h2>Newsletter-Abmeldung</h2>
<p>Komm gerne wieder, irgendwann.</p> <p>Komm gerne wieder, irgendwann.</p>
</hgroup> </hgroup>
<form class="newsletter-form" method="get" action="{{ SITEURL }}/unsubscribe.php"> <form class="newsletter-form" method="get" action="{{ SITEURL }}/newsletter/unsubscribe.php">
<input class="newsletter-email" type="email" name="e" placeholder="Emailadresse" autocomplete="email" aria-label="Emailadresse" required/> <input class="newsletter-email" type="email" name="e" placeholder="Emailadresse" autocomplete="email" aria-label="Emailadresse" required/>
<input class="newsletter-submit" type="submit" value="Abmelden" /> <input class="newsletter-submit" type="submit" value="Abmelden" />
</form> </form>

View File

@ -22,5 +22,6 @@
</div> </div>
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% include "includes/subscribe.html" %} {% {% include "includes/subscribe.html" %}
endblock content_body %} {% include "includes/unsubscribe.html" %}
{% endblock content_body %}

View File

@ -1,5 +1,5 @@
{% extends "page.html" %} {% extends "page.html" %}
{# note that this template's filename is ''termine.noformat.html'' and not ''termine.html''. This is because vscodium's autoformat breaks the ''replace'' filters in the summary line, which is bad. By setting an exlude rule for all "noformat.html" files in vscodium's settings.json file, autoformat will now ignore this file. #}
{% if page.termine is defined %} {% if page.termine is defined %}
{% set date_format = "%d.%m." %} {% set date_format = "%d.%m." %}
{% set time_format = "%H:%M" %} {% set time_format = "%H:%M" %}