Deployment-Vorbereitung: Domain-Split und Legacy-/Debug-Seiten entfernt

- index.php zeigt bei abweichendem Host (APP_HOST-Env) die Landingpage
  statt des Dashboards, damit kaffeeliste.de und app.kaffeeliste.de aus
  demselben Webspace bedient werden koennen. Ohne gesetztes APP_HOST
  (lokale Entwicklung) unveraendertes Verhalten.
- landing.php verlinkt Login/Registrierung ueber APP_HOST fest auf die
  App-Domain, damit Besucher der Marketingdomain dort landen.
- functionsLDAP.php entfernt (nur ueber die tote IIS/AUTH_USER-Branch
  erreichbar, vollstaendig durch app/saas-auth.php ersetzt); zugehoerige
  tote AD/LDAP-Variablen aus config.php und der AUTH_USER-Zweig aus
  functions.php entfernt.
- mailausgebe.php, umfrage.php, umfrageergebnisse.php entfernt: aus der
  Navigation nicht erreichbare Debug-/Einzweck-Seiten ohne echte
  Berechtigungspruefung (mailausgebe.php dumpte alle Mitglieder-E-Mails,
  umfrageergebnisse.php hatte nur einen auskommentierten Basic-Auth-
  Block). scripts/http-smoke.php entsprechend bereinigt.
This commit is contained in:
2026-07-17 11:37:41 +02:00
parent d2330c81cd
commit cb799c7c66
10 changed files with 47 additions and 979 deletions
+28
View File
@@ -50,6 +50,34 @@ function app_send_security_headers(): void
} }
} }
/**
* The application's own primary hostname in production (e.g.
* app.kaffeeliste.de), configured via APP_HOST. Unset in dev, where
* index.php should keep behaving exactly as before (no host split).
*/
function app_primary_host(): ?string
{
return app_env('APP_HOST');
}
/**
* Builds a URL that always points at the app's own host, even when the
* current request came in on a different domain (e.g. the marketing
* domain linking to /login.php). Falls back to a relative path when
* APP_HOST isn't configured, so local dev is unaffected.
*/
function app_primary_url(string $path): string
{
$host = app_primary_host();
if ($host === null) {
return ltrim($path, '/');
}
$scheme = app_is_https() ? 'https' : 'http';
return $scheme . '://' . $host . '/' . ltrim($path, '/');
}
function app_start_session(): void function app_start_session(): void
{ {
if (PHP_SAPI === 'cli' || session_status() === PHP_SESSION_ACTIVE) { if (PHP_SAPI === 'cli' || session_status() === PHP_SESSION_ACTIVE) {
-22
View File
@@ -8,28 +8,6 @@ if ((getenv('APP_DB_DRIVER') ?: '') === 'mysql' && !function_exists('sqlsrv_conn
require_once __DIR__ . '/lib/sqlsrv_mysql_compat.php'; require_once __DIR__ . '/lib/sqlsrv_mysql_compat.php';
} }
### ZUGANGSDATEN AD
$aduser = '';
$adpassword = '';
$domain = '';
## OU für die Suche der Benutzerkonten
#$basedn = '';
$basedn = '';
## OU für die Suche der Benutzerkonten
#$basednandereKasse = '';
## OU für die Suche der Gruppen
$basedngroup = '';
## Zugriffsgruppe für Automatisierungsclient
$zugriffsACgroup = '';
## Zugriffsgruppe für Automatische Abwesenheitsnachricht
$zugriffsAbwesenheitgroup = '';
## Zugriffsgruppe für alle Anfragen des Automatisierungsclient
$zugriffsalleACgroup = '';
## Zugriffsgruppe für Anfragen der Abwesenheitsnachrichten
$zugriffsalleAbwesenheitgroup = '';
## Zugriff auf alles
$zugriffsAdminsgroup = '';
// Verbindung zur Datenbank herstellen (ersetze die Platzhalter durch deine Daten) // Verbindung zur Datenbank herstellen (ersetze die Platzhalter durch deine Daten)
$serverName = getenv('DB_HOST') ?: ""; $serverName = getenv('DB_HOST') ?: "";
$connectionOptions = array( $connectionOptions = array(
-6
View File
@@ -15,12 +15,6 @@ if ($saasUser !== null) {
if ($devAuthEmail !== '') { if ($devAuthEmail !== '') {
$mailadress = strtolower(trim($devAuthEmail)); $mailadress = strtolower(trim($devAuthEmail));
$kennung = $mailadress; $kennung = $mailadress;
} elseif (!empty($_SERVER['AUTH_USER'])) {
$kennungtemp = $_SERVER['AUTH_USER'];
$teile = explode("\\", $kennungtemp);
$kennung = $teile[1] ?? $kennungtemp;
include_once "functionsLDAP.php";
} }
} }
-166
View File
@@ -1,166 +0,0 @@
<?php
#$kennungtemp = $_SERVER['AUTH_USER'];
#$teile = explode("\\", $kennungtemp);
#$kennung = $teile[1];
$ad = ldap_connect("ldap://{$domain}") or die('Could not connect to LDAP server.');
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
@ldap_bind($ad, "{$aduser}@{$domain}", $adpassword) or die('Could not bind to AD.');
$userdn = getDN($ad, $kennung, $basedn);
$mailadress = getADMail($ad, $kennung, $basedn);
ldap_unbind($ad);
/**
* This function searchs in LDAP tree entry specified by samaccountname and
* returns its DN or epmty string on failure.
*
* @param resource $ad
* An LDAP link identifier, returned by ldap_connect().
* @param string $samaccountname
* The sAMAccountName, logon name.
* @param string $basedn
* The base DN for the directory.
* @return string
*/
function getDN($ad, $samaccountname, $basedn)
{
$result = ldap_search($ad, $basedn, "(samaccountname={$samaccountname})", array(
'dn'
));
if (! $result)
{
return '';
}
$entries = ldap_get_entries($ad, $result);
if ($entries['count'] > 0)
{
return $entries[0]['dn'];
}
return '';
}
function getADMail($ad, $samaccountname, $basedn)
{
$attributes = array('mail');
$resultz = ldap_search($ad, $basedn, "(samaccountname={$samaccountname})", $attributes);
$entriesz = ldap_get_entries($ad, $resultz);
#return $entriesz[0]['mail'];
# $entries = ldap_get_entries($ad, $result);
if ($entriesz['count'] > 0)
{
return $entriesz[0]['mail'][0];
}
return 'nichts gefunden';
}
/**
* This function retrieves and returns Common Name from a given Distinguished
* Name.
*
* @param string $dn
* The Distinguished Name.
* @return string The Common Name.
*/
function getCN($dn)
{
preg_match('/[^,]*/', $dn, $matchs, PREG_OFFSET_CAPTURE, 3);
return $matchs[0][0];
}
/**
* This function checks group membership of the user, searching only in
* specified group (not recursively).
*
* @param resource $ad
* An LDAP link identifier, returned by ldap_connect().
* @param string $userdn
* The user Distinguished Name.
* @param string $groupdn
* The group Distinguished Name.
* @return boolean Return true if user is a member of group, and false if not
* a member.
*/
function checkGroup($ad, $userdn, $groupdn)
{
$result = ldap_read($ad, $userdn, "(memberof={$groupdn})", array(
'members'
));
if (! $result)
{
return false;
}
$entries = ldap_get_entries($ad, $result);
return ($entries['count'] > 0);
}
/**
* This function checks group membership of the user, searching in specified
* group and groups which is its members (recursively).
*
* @param resource $ad
* An LDAP link identifier, returned by ldap_connect().
* @param string $userdn
* The user Distinguished Name.
* @param string $groupdn
* The group Distinguished Name.
* @return boolean Return true if user is a member of group, and false if not
* a member.
*/
function checkGroupEx($ad, $userdn, $groupdn)
{
if ($groupdn == "")
{
return false;
}
$result = ldap_read($ad, $userdn, '(objectclass=*)', array(
'memberof'
));
if (! $result)
{
return false;
}
$entries = ldap_get_entries($ad, $result);
if ($entries['count'] <= 0)
{
return false;
}
if (empty($entries[0]['memberof']))
{
return false;
}
for ($i = 0; $i < $entries[0]['memberof']['count']; $i ++)
{
if ($entries[0]['memberof'][$i] == $groupdn)
{
return true;
}
elseif (checkGroupEx($ad, $entries[0]['memberof'][$i], $groupdn))
{
return true;
}
}
return false;
}
?>
+13
View File
@@ -1,5 +1,18 @@
<?php <?php
require_once __DIR__ . "/app/bootstrap.php";
// Marketingdomain (z. B. kaffeeliste.de) zeigt die Landingpage statt des
// Dashboards; nur der Host aus APP_HOST bekommt die eigentliche App. Ohne
// gesetztes APP_HOST (lokale Entwicklung) verhaelt sich index.php wie
// bisher immer als Dashboard.
$appHost = app_primary_host();
$requestHost = strtolower(preg_replace('/:\d+$/', '', (string)($_SERVER['HTTP_HOST'] ?? '')));
if ($appHost !== null && $requestHost !== strtolower($appHost)) {
require __DIR__ . '/landing.php';
exit;
}
include "functions.php"; include "functions.php";
require_once __DIR__ . "/app/ledger.php"; require_once __DIR__ . "/app/ledger.php";
app_require_csrf(); app_require_csrf();
+6 -6
View File
@@ -15,16 +15,16 @@
<nav class="public-nav" aria-label="Hauptnavigation"> <nav class="public-nav" aria-label="Hauptnavigation">
<strong>Kaffeeliste</strong> <strong>Kaffeeliste</strong>
<ul class="actions"> <ul class="actions">
<li><a href="login.php" class="button">Login</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('login.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button">Login</a></li>
<li><a href="register.php" class="button primary">Registrieren</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('register.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button primary">Registrieren</a></li>
</ul> </ul>
</nav> </nav>
<div class="public-hero-content"> <div class="public-hero-content">
<h1>Die Kaffeekasse, die von allein mitrechnet</h1> <h1>Die Kaffeekasse, die von allein mitrechnet</h1>
<p>Schluss mit Strichlisten auf Papier und Kopfrechnen beim Kassensturz: Kaffeeliste hält für dein Team, Büro oder deinen Verein fest, wer wie viele Striche gemacht hat, wer bezahlt hat und wer gerade offen ist jederzeit einsehbar, für jeden nachvollziehbar.</p> <p>Schluss mit Strichlisten auf Papier und Kopfrechnen beim Kassensturz: Kaffeeliste hält für dein Team, Büro oder deinen Verein fest, wer wie viele Striche gemacht hat, wer bezahlt hat und wer gerade offen ist jederzeit einsehbar, für jeden nachvollziehbar.</p>
<ul class="actions"> <ul class="actions">
<li><a href="register.php" class="button primary big">Kostenlos einrichten</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('register.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button primary big">Kostenlos einrichten</a></li>
<li><a href="login.php" class="button big">Zur App</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('login.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button big">Zur App</a></li>
</ul> </ul>
</div> </div>
</section> </section>
@@ -128,8 +128,8 @@
<p>In wenigen Minuten eingerichtet, für dein ganzes Team nutzbar.</p> <p>In wenigen Minuten eingerichtet, für dein ganzes Team nutzbar.</p>
</header> </header>
<ul class="actions"> <ul class="actions">
<li><a href="register.php" class="button primary big">Kundenkonto anlegen</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('register.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button primary big">Kundenkonto anlegen</a></li>
<li><a href="login.php" class="button big">Zur App</a></li> <li><a href="<?php echo htmlspecialchars(app_primary_url('login.php'), ENT_QUOTES, 'UTF-8'); ?>" class="button big">Zur App</a></li>
</ul> </ul>
</section> </section>
</div> </div>
-50
View File
@@ -1,50 +0,0 @@
<?php
include "functions.php";
include "header.php";
include "headerline.php";
include "nav.php";
?>
<!-- Banner -->
<section id="banner">
<div class="content">
<?php
if(checkKaffeelisteAccess($conn, $mailadress)){
echo "<h2>Kaffeeliste</h2>";
echo "Hallo " . getUserName($conn,$mailadress) . "!<br><br>";
// MitarbeiterID anhand der E-Mail-Adresse abrufen
// Mitglieder aus der Datenbank abrufen
$sqlMitglieder = "SELECT MitarbeiterID, Name, Email FROM kl_Mitarbeiter WHERE aktiv = 1 ORDER BY Name";
$stmtMitglieder = sqlsrv_query($conn, $sqlMitglieder);
while ($row = sqlsrv_fetch_array($stmtMitglieder, SQLSRV_FETCH_ASSOC)) {
$mitarbeiterID = $row['MitarbeiterID'];
$name = $row['Name'];
$email = $row['Email'];
echo "{$email};";
}
}else{
echo "<h2>Sie haben keine Zugang zu dieser Webseite</h2>";
}
?>
</div>
</section>
<?php include "footer.php";
?>
-15
View File
@@ -167,21 +167,6 @@ $checks = [
'path' => 'teilnehmerauswertung.php?user_id=1', 'path' => 'teilnehmerauswertung.php?user_id=1',
'contains' => ['Auswertung', 'Test Admin', 'Jahresübersicht', 'Letzte Einzahlungen'], 'contains' => ['Auswertung', 'Test Admin', 'Jahresübersicht', 'Letzte Einzahlungen'],
], ],
[
'label' => 'Mailausgabe',
'path' => 'mailausgebe.php',
'contains' => ['admin@test.local'],
],
[
'label' => 'Umfrage',
'path' => 'umfrage.php',
'contains' => ['Kaffeeliste', 'Danke'],
],
[
'label' => 'Umfrageergebnisse',
'path' => 'umfrageergebnisse.php',
'contains' => ['Umfrage', 'Ergebnisse'],
],
[ [
'label' => 'PDF-Export', 'label' => 'PDF-Export',
'path' => 'exportKaffeeliste.php', 'path' => 'exportKaffeeliste.php',
-344
View File
@@ -1,344 +0,0 @@
<?php
declare(strict_types=1);
include "functions.php";
include "header.php";
include "headerline.php";
include "nav.php";
?>
<!-- Banner -->
<section id="banner">
<div class="content">
<style>
/* Hartes Reset für Inputs nur im Umfrage-Formular */
html body form#coffeeSurvey input[type="checkbox"],
html body form#coffeeSurvey input[type="radio"]{
all: revert !important; /* setzt ALLES zurück */
appearance: auto !important;
-webkit-appearance: auto !important;
display: inline-block !important;
position: static !important;
opacity: 1 !important;
visibility: visible !important;
width: 16px !important;
height: 16px !important;
margin: 0 6px 0 0 !important;
transform: none !important;
}
html body form#coffeeSurvey label{
display: inline-block;
cursor: pointer;
}
</style>
<?php
$geschlossen = true;
if(checkKaffeelisteAccess($conn, $mailadress)){
echo "<h2>Kaffeeliste</h2>";
echo "Hallo " . getUserName($conn,$mailadress) . "!<br><br>";
// Beispiel: falls $conn nicht global ist, musst du es wie in deiner Seite erzeugen.
if (!isset($conn)) {
die("DB Verbindung (\$conn) fehlt.");
}
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
$errors = [];
$success = false;
$emailNorm = function_exists('mb_strtolower')
? mb_strtolower(trim((string)$mailadress), 'UTF-8')
: strtolower(trim((string)$mailadress));
if ($emailNorm === '' || !filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Keine gültige E-Mail im System gefunden (Variable \$mailadress).";
}
// Options
$drinks = [
'espresso' => 'Espresso',
'crema' => 'Café Crema',
'cappuccino' => 'Cappuccino',
'latte' => 'Latte Macchiato',
'americano' => 'Americano',
'decaf' => 'Entkoffeiniert',
'other' => 'Andere',
];
$problems = [
'forget' => 'Vergesse Eintrag',
'empty' => 'Kaffee leer',
'water' => 'Wasser auffüllen',
'too_little' => 'zu wenig Kaffeeausgabe',
'too_much' => 'zu viel Kaffeeausgabe',
'none' => 'Kein Problem',
'other' => 'Sonstiges',
];
$improvements = [
'easier_entry' => 'Einfacherer Eintrag',
'overview' => 'Übersicht über Kosten/Verbrauch',
'more_mails' => 'Mehr Info-Mails',
'adjust_amount' => 'Menge der Kaffeeausgabe anpassen',
'other' => 'Sonstiges',
];
function post($k, $def='') { return $_POST[$k] ?? $def; }
function postArr($k) { $v = $_POST[$k] ?? []; return is_array($v) ? $v : []; }
// Schon abgestimmt?
$alreadyVoted = true;
if (!$errors) {
$sqlChk = "SELECT 1 FROM dbo.CoffeeSurveyVotedEmails WHERE EmailNorm = ?";
$stmtChk = sqlsrv_query($conn, $sqlChk, [$emailNorm]);
if ($stmtChk === false) {
$errors[] = "DB-Fehler (Vote-Check): " . print_r(sqlsrv_errors(), true);
} else {
$alreadyVoted = (sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_NUMERIC) !== null);
}
}
// POST Handling
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$errors) {
if ($alreadyVoted) {
$errors[] = "Du hast bereits abgestimmt.";
} else {
$q1 = (int)post('q1_listease', 0); // 1 sehr einfach .. 5 sehr schwierig
$q2 = (int)post('q2_listsat', 0); // 1 sehr zufrieden .. 5 sehr unzufrieden
$q3 = (int)post('q3_quality', 0);
$q4 = (int)post('q4_websat', 0);
$q5 = postArr('q5_drinks'); // array
$q5_other = trim((string)post('q5_drinks_other',''));
$q6 = trim((string)post('q6_newvarieties',''));
$q7 = (string)post('q7_problem','');
$q7_other = trim((string)post('q7_problem_other',''));
$q8 = postArr('q8_improvements');
$q8_other = trim((string)post('q8_improvements_other',''));
$q9 = trim((string)post('q9_betterideas',''));
// Validate scales
foreach ([1=>$q1,2=>$q2,3=>$q3,4=>$q4] as $idx=>$val) {
if ($val < 1 || $val > 5) $errors[] = "Bitte bei Frage {$idx} einen Wert von 1 bis 5 wählen.";
}
// Validate drinks
$allowedDrinks = array_keys($drinks);
$q5 = array_values(array_unique(array_filter($q5, fn($v)=>in_array($v,$allowedDrinks,true))));
if (count($q5) === 0) $errors[] = "Bitte bei Frage 5 mindestens eine Kaffeesorte auswählen.";
if (in_array('other',$q5,true) && $q5_other === '') $errors[] = "Bitte bei Frage 5 'Andere' kurz beschreiben.";
// Validate problem
if (!array_key_exists($q7, $problems)) $errors[] = "Bitte bei Frage 7 eine Option wählen.";
if ($q7 === 'other' && $q7_other === '') $errors[] = "Bitte bei Frage 7 'Sonstiges' kurz beschreiben.";
// Validate improvements
$allowedImp = array_keys($improvements);
$q8 = array_values(array_unique(array_filter($q8, fn($v)=>in_array($v,$allowedImp,true))));
if (count($q8) === 0) $errors[] = "Bitte bei Frage 8 mindestens eine Verbesserung auswählen.";
if (in_array('other',$q8,true) && $q8_other === '') $errors[] = "Bitte bei Frage 8 'Sonstiges' kurz beschreiben.";
if (!$errors) {
$q5_csv = implode(',', $q5);
$q8_csv = implode(',', $q8);
// Transaction (sqlsrv)
sqlsrv_begin_transaction($conn);
// 1) Sperre (E-Mail) eintragen
$sqlEmail = "INSERT INTO dbo.CoffeeSurveyVotedEmails (EmailNorm) VALUES (?)";
$stmtEmail = sqlsrv_query($conn, $sqlEmail, [$emailNorm]);
if ($stmtEmail === false) {
sqlsrv_rollback($conn);
$errors[] = "Speichern fehlgeschlagen (E-Mail-Sperre). " . print_r(sqlsrv_errors(), true);
} else {
// 2) Antworten speichern (ohne E-Mail)
$sqlIns = "
INSERT INTO dbo.CoffeeSurveyResponses
(Q1_ListEase, Q2_ListSatisfaction, Q3_CoffeeQuality, Q4_WebsiteSatisfaction,
Q5_Drinks, Q5_DrinksOther, Q6_NewVarieties,
Q7_ListProblem, Q7_ListProblemOther,
Q8_Improvements, Q8_ImprovementsOther,
Q9_BetterIdeas)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
";
$params = [
$q1, $q2, $q3, $q4,
$q5_csv, ($q5_other !== '' ? $q5_other : null), ($q6 !== '' ? $q6 : null),
$q7, ($q7_other !== '' ? $q7_other : null),
$q8_csv, ($q8_other !== '' ? $q8_other : null),
($q9 !== '' ? $q9 : null),
];
$stmtIns = sqlsrv_query($conn, $sqlIns, $params);
if ($stmtIns === false) {
sqlsrv_rollback($conn);
$errors[] = "Speichern fehlgeschlagen (Antworten). " . print_r(sqlsrv_errors(), true);
} else {
sqlsrv_commit($conn);
$success = true;
$alreadyVoted = true;
}
}
}
}
}
?>
<?php if ($success): ?>
<p><b>Danke!</b> Deine Antwort wurde gespeichert.</p>
<?php endif; ?>
<?php if ($alreadyVoted && !$success && !$errors): ?>
<p><h2><b>Hinweis:</b> Du hast bereits abgestimmt.</h2></p>
<?php endif; ?>
<?php if ($errors): ?>
<div style="border:1px solid #cc0000; padding:10px; margin:10px 0;">
<b>Bitte korrigieren:</b>
<ul>
<?php foreach ($errors as $e): ?>
<li><?php echo h($e); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif;?>
<?php if ($geschlossen):
echo "<p><b>Danke!</b> Umfrage abgeschlossen.</p>";
else:
?>
<form id="coffeeSurvey" method="post" action="<?php echo h($_SERVER["PHP_SELF"]); ?>">
<label for="q1_listease">Wie einfach ist die Kaffeeliste für dich zu benutzen?</label><br>
<select name="q1_listease" id="q1_listease" required>
<option value="">Bitte wählen</option>
<?php for ($i=1;$i<=5;$i++): ?>
<?php
$text = ($i===1) ? "1 (sehr einfach)" : (($i===5) ? "5 (sehr schwierig)" : (string)$i);
$sel = ((string)post('q1_listease','') === (string)$i) ? "selected" : "";
?>
<option value="<?php echo $i; ?>" <?php echo $sel; ?>><?php echo h($text); ?></option>
<?php endfor; ?>
</select>
<br><br>
<label for="q2_listsat">Wie zufrieden bist du mit der Kaffeeliste insgesamt?</label><br>
<select name="q2_listsat" id="q2_listsat" required>
<option value="">Bitte wählen</option>
<?php for ($i=1;$i<=5;$i++): ?>
<?php
$text = ($i===1) ? "1 (sehr zufrieden)" : (($i===5) ? "5 (sehr unzufrieden)" : (string)$i);
$sel = ((string)post('q2_listsat','') === (string)$i) ? "selected" : "";
?>
<option value="<?php echo $i; ?>" <?php echo $sel; ?>><?php echo h($text); ?></option>
<?php endfor; ?>
</select>
<br><br>
<label for="q3_quality">Wie zufrieden bist du mit der Kaffeequalität insgesamt?</label><br>
<select name="q3_quality" id="q3_quality" required>
<option value="">Bitte wählen</option>
<?php for ($i=1;$i<=5;$i++): ?>
<?php
$text = ($i===1) ? "1 (sehr zufrieden)" : (($i===5) ? "5 (sehr unzufrieden)" : (string)$i);
$sel = ((string)post('q3_quality','') === (string)$i) ? "selected" : "";
?>
<option value="<?php echo $i; ?>" <?php echo $sel; ?>><?php echo h($text); ?></option>
<?php endfor; ?>
</select>
<br><br>
<label for="q4_websat">Wie zufrieden bist du mit der Webseite der Kaffeeliste insgesamt?</label><br>
<select name="q4_websat" id="q4_websat" required>
<option value="">Bitte wählen</option>
<?php for ($i=1;$i<=5;$i++): ?>
<?php
$text = ($i===1) ? "1 (sehr zufrieden)" : (($i===5) ? "5 (sehr unzufrieden)" : (string)$i);
$sel = ((string)post('q4_websat','') === (string)$i) ? "selected" : "";
?>
<option value="<?php echo $i; ?>" <?php echo $sel; ?>><?php echo h($text); ?></option>
<?php endfor; ?>
</select>
<br><br>
<label>Welche Kaffeearten/Sorten trinkst du am häufigsten? (Mehrfachauswahl)</label><br>
<?php foreach ($drinks as $val => $label): ?>
<?php $checked = in_array($val, postArr('q5_drinks'), true) ? "checked" : ""; ?>
<input type="checkbox" name="q5_drinks[]" value="<?php echo h($val); ?>" <?php echo $checked; ?>>
<?php echo h($label); ?><br>
<?php endforeach; ?>
<br>
<label for="q5_drinks_other">Andere (Text):</label><br>
<input type="text" name="q5_drinks_other" id="q5_drinks_other" value="<?php echo h((string)post('q5_drinks_other','')); ?>">
<br><br>
<label for="q6_newvarieties">Welche zusätzlichen Sorten würdest du dir wünschen? (Freitext)</label><br>
<textarea name="q6_newvarieties" id="q6_newvarieties" rows="3"><?php echo h((string)post('q6_newvarieties','')); ?></textarea>
<br><br>
<label for="q7_problem">Was ist dein häufigstes Problem mit der Kaffeeliste?</label><br>
<select name="q7_problem" id="q7_problem" required>
<option value="">Bitte wählen</option>
<?php foreach ($problems as $val => $label): ?>
<?php $sel = ((string)post('q7_problem','') === (string)$val) ? "selected" : ""; ?>
<option value="<?php echo h($val); ?>" <?php echo $sel; ?>><?php echo h($label); ?></option>
<?php endforeach; ?>
</select>
<br><br>
<label for="q7_problem_other">Sonstiges (Text):</label><br>
<input type="text" name="q7_problem_other" id="q7_problem_other" value="<?php echo h((string)post('q7_problem_other','')); ?>">
<br><br>
<label>Welche Verbesserungen wünschst du dir für die Kaffeeliste? (Mehrfachauswahl)</label><br>
<?php foreach ($improvements as $val => $label): ?>
<?php $checked = in_array($val, postArr('q8_improvements'), true) ? "checked" : ""; ?>
<input type="checkbox" name="q8_improvements[]" value="<?php echo h($val); ?>" <?php echo $checked; ?>>
<?php echo h($label); ?><br>
<?php endforeach; ?>
<br>
<label for="q8_improvements_other">Sonstiges (Text):</label><br>
<input type="text" name="q8_improvements_other" id="q8_improvements_other" value="<?php echo h((string)post('q8_improvements_other','')); ?>">
<br><br>
<label for="q9_betterideas">Was kann die Kaffeeliste noch besser machen? (Freitext)</label><br>
<textarea name="q9_betterideas" id="q9_betterideas" rows="4"><?php echo h((string)post('q9_betterideas','')); ?></textarea>
<br><br>
<input type="hidden" name="aktion" value="umfrage_absenden">
<button type="submit" <?php echo $alreadyVoted ? 'disabled' : ''; ?>>Umfrage absenden</button>
</form>
<?php
endif;?>
<?php
}else{
echo "<h2>Sie haben keine Zugang zu dieser Webseite</h2>";
}
?>
</div>
</section>
<?php include "footer.php";
?>
-370
View File
@@ -1,370 +0,0 @@
<?php
declare(strict_types=1);
include "functions.php";
include "header.php";
include "headerline.php";
include "nav.php";
?>
<!-- Banner -->
<section id="banner">
<div class="content">
<?php
if(checkKaffeelisteAccess($conn, $mailadress)){
echo "<h2>Kaffeeliste</h2>";
echo "Hallo " . getUserName($conn,$mailadress) . "!<br><br>";
// Annahme: $conn ist bereits vorhanden (sqlsrv_connect in deiner Infrastruktur)
if (!isset($conn)) {
die("DB Verbindung (\$conn) fehlt.");
}
function h($s): string {
return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
/**
* OPTIONAL: Admin-Schutz via Basic Auth (auskommentieren, wenn nicht gewünscht)
*/
/*
$ADMIN_USER = 'admin';
$ADMIN_PASS = 'changeme';
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])
|| $_SERVER['PHP_AUTH_USER'] !== $ADMIN_USER || $_SERVER['PHP_AUTH_PW'] !== $ADMIN_PASS) {
header('WWW-Authenticate: Basic realm="Umfrage Admin"');
header('HTTP/1.0 401 Unauthorized');
echo "Unauthorized";
exit;
}
*/
$drinks = [
'espresso' => 'Espresso',
'crema' => 'Café Crema',
'cappuccino' => 'Cappuccino',
'latte' => 'Latte Macchiato',
'americano' => 'Americano',
'decaf' => 'Entkoffeiniert',
'other' => 'Andere',
];
$problems = [
'forget' => 'Vergesse Eintrag',
'empty' => 'Kaffee leer',
'water' => 'Wasser auffüllen',
'too_little' => 'zu wenig Kaffeeausgabe',
'too_much' => 'zu viel Kaffeeausgabe',
'none' => 'Kein Problem',
'other' => 'Sonstiges',
];
$improvements = [
'easier_entry' => 'Einfacherer Eintrag',
'overview' => 'Übersicht über Kosten/Verbrauch',
'more_mails' => 'Mehr Info-Mails',
'adjust_amount' => 'Menge der Kaffeeausgabe anpassen',
'other' => 'Sonstiges',
];
// Helper: SQL scalar
function sql_scalar($conn, string $sql, array $params = []) {
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) return null;
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC);
return $row ? $row[0] : null;
}
// Helper: SQL all rows
function sql_all($conn, string $sql, array $params = []): array {
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) return [];
$rows = [];
while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$rows[] = $r;
}
return $rows;
}
$errors = [];
$totalResponses = (int)(sql_scalar($conn, "SELECT COUNT(*) FROM dbo.CoffeeSurveyResponses") ?? 0);
$totalVotedEmails = (int)(sql_scalar($conn, "SELECT COUNT(*) FROM dbo.CoffeeSurveyVotedEmails") ?? 0);
// Skalen-Auswertung (Avg + Count pro Wert 1..5)
function scale_stats($conn, string $col): array {
$sql = "
SELECT
AVG(CAST([$col] AS FLOAT)) AS avgVal,
SUM(CASE WHEN [$col] = 1 THEN 1 ELSE 0 END) AS c1,
SUM(CASE WHEN [$col] = 2 THEN 1 ELSE 0 END) AS c2,
SUM(CASE WHEN [$col] = 3 THEN 1 ELSE 0 END) AS c3,
SUM(CASE WHEN [$col] = 4 THEN 1 ELSE 0 END) AS c4,
SUM(CASE WHEN [$col] = 5 THEN 1 ELSE 0 END) AS c5
FROM dbo.CoffeeSurveyResponses
";
$rows = sql_all($conn, $sql);
if (!$rows) return ['avg'=>null,'c'=>[0,0,0,0,0]];
$r = $rows[0];
return [
'avg' => $r['avgVal'] !== null ? (float)$r['avgVal'] : null,
'c' => [(int)$r['c1'], (int)$r['c2'], (int)$r['c3'], (int)$r['c4'], (int)$r['c5']]
];
}
$q1 = scale_stats($conn, 'Q1_ListEase');
$q2 = scale_stats($conn, 'Q2_ListSatisfaction');
$q3 = scale_stats($conn, 'Q3_CoffeeQuality');
$q4 = scale_stats($conn, 'Q4_WebsiteSatisfaction');
// Problem (Q7) Gruppiert
$q7Rows = sql_all($conn, "
SELECT Q7_ListProblem AS keyVal, COUNT(*) AS cnt
FROM dbo.CoffeeSurveyResponses
GROUP BY Q7_ListProblem
ORDER BY cnt DESC
");
// CSV-Felder + Freitext sammeln (limit)
$limit = 500; // genug für Auswertung, falls riesig: erhöhen oder paginieren
$dataRows = sql_all($conn, "
SELECT TOP ($limit)
CreatedAt,
Q5_Drinks, Q5_DrinksOther,
Q6_NewVarieties,
Q8_Improvements, Q8_ImprovementsOther,
Q9_BetterIdeas
FROM dbo.CoffeeSurveyResponses
ORDER BY CreatedAt DESC
");
// Aggregation in PHP für Mehrfachauswahl
$drinkCounts = array_fill_keys(array_keys($drinks), 0);
$drinkOtherTexts = [];
$impCounts = array_fill_keys(array_keys($improvements), 0);
$impOtherTexts = [];
$newVarietiesTexts = [];
$betterIdeasTexts = [];
foreach ($dataRows as $r) {
// Q5 drinks CSV
$csv = trim((string)($r['Q5_Drinks'] ?? ''));
if ($csv !== '') {
$parts = array_filter(array_map('trim', explode(',', $csv)));
foreach ($parts as $p) {
if (array_key_exists($p, $drinkCounts)) $drinkCounts[$p]++;
}
}
$ot = trim((string)($r['Q5_DrinksOther'] ?? ''));
if ($ot !== '') $drinkOtherTexts[] = $ot;
// Q8 improvements CSV
$csv2 = trim((string)($r['Q8_Improvements'] ?? ''));
if ($csv2 !== '') {
$parts2 = array_filter(array_map('trim', explode(',', $csv2)));
foreach ($parts2 as $p2) {
if (array_key_exists($p2, $impCounts)) $impCounts[$p2]++;
}
}
$ot2 = trim((string)($r['Q8_ImprovementsOther'] ?? ''));
if ($ot2 !== '') $impOtherTexts[] = $ot2;
// Q6 / Q9 Freitext
$t6 = trim((string)($r['Q6_NewVarieties'] ?? ''));
if ($t6 !== '') $newVarietiesTexts[] = $t6;
$t9 = trim((string)($r['Q9_BetterIdeas'] ?? ''));
if ($t9 !== '') $betterIdeasTexts[] = $t9;
}
// Hilfsfunktion Prozent
function pct(int $n, int $total): string {
if ($total <= 0) return "0%";
return round(($n / $total) * 100, 1) . "%";
}
?>
<h1>Umfrage Ergebnisse</h1>
<p class="muted">
Antworten: <b><?php echo (int)$totalResponses; ?></b>
<?php if ($limit && $totalResponses > $limit): ?>
&nbsp;|&nbsp; Auswertung basiert auf den letzten <?php echo (int)$limit; ?> Antworten
<?php endif; ?>
</p>
<div class="grid">
<div class="box">
<h3>1) Kaffeeliste benutzen (1 sehr einfach … 5 sehr schwierig)</h3>
<p class="small">Durchschnitt: <b><?php echo $q1['avg'] !== null ? number_format($q1['avg'], 2, ',', '.') : '-'; ?></b></p>
<table>
<tr><th>Wert</th><th>Anzahl</th><th>Anteil</th></tr>
<?php for ($i=1;$i<=5;$i++): ?>
<tr>
<td><?php echo $i; ?></td>
<td><?php echo $q1['c'][$i-1]; ?></td>
<td><?php echo pct($q1['c'][$i-1], $totalResponses); ?></td>
</tr>
<?php endfor; ?>
</table>
</div>
<div class="box">
<h3>2) Zufriedenheit Kaffeeliste (1 sehr zufrieden … 5 sehr unzufrieden)</h3>
<p class="small">Durchschnitt: <b><?php echo $q2['avg'] !== null ? number_format($q2['avg'], 2, ',', '.') : '-'; ?></b></p>
<table>
<tr><th>Wert</th><th>Anzahl</th><th>Anteil</th></tr>
<?php for ($i=1;$i<=5;$i++): ?>
<tr>
<td><?php echo $i; ?></td>
<td><?php echo $q2['c'][$i-1]; ?></td>
<td><?php echo pct($q2['c'][$i-1], $totalResponses); ?></td>
</tr>
<?php endfor; ?>
</table>
</div>
<div class="box">
<h3>3) Zufriedenheit Kaffeequalität (1 sehr zufrieden … 5 sehr unzufrieden)</h3>
<p class="small">Durchschnitt: <b><?php echo $q3['avg'] !== null ? number_format($q3['avg'], 2, ',', '.') : '-'; ?></b></p>
<table>
<tr><th>Wert</th><th>Anzahl</th><th>Anteil</th></tr>
<?php for ($i=1;$i<=5;$i++): ?>
<tr>
<td><?php echo $i; ?></td>
<td><?php echo $q3['c'][$i-1]; ?></td>
<td><?php echo pct($q3['c'][$i-1], $totalResponses); ?></td>
</tr>
<?php endfor; ?>
</table>
</div>
<div class="box">
<h3>4) Zufriedenheit Webseite (1 sehr zufrieden … 5 sehr unzufrieden)</h3>
<p class="small">Durchschnitt: <b><?php echo $q4['avg'] !== null ? number_format($q4['avg'], 2, ',', '.') : '-'; ?></b></p>
<table>
<tr><th>Wert</th><th>Anzahl</th><th>Anteil</th></tr>
<?php for ($i=1;$i<=5;$i++): ?>
<tr>
<td><?php echo $i; ?></td>
<td><?php echo $q4['c'][$i-1]; ?></td>
<td><?php echo pct($q4['c'][$i-1], $totalResponses); ?></td>
</tr>
<?php endfor; ?>
</table>
</div>
</div>
<div class="box">
<h3>5) Häufigste Kaffeearten (Mehrfachauswahl)</h3>
<table>
<tr><th>Sorte</th><th>Anzahl</th><th>Anteil (bezogen auf Antworten)</th></tr>
<?php foreach ($drinks as $key => $label): ?>
<tr>
<td><?php echo h($label); ?></td>
<td><?php echo (int)$drinkCounts[$key]; ?></td>
<td><?php echo pct((int)$drinkCounts[$key], $totalResponses); ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php if (count($drinkOtherTexts) > 0): ?>
<p class="small"><b>„Andere“ Texte (letzte 30):</b></p>
<ul>
<?php foreach (array_slice($drinkOtherTexts, 0, 30) as $t): ?>
<li><?php echo h($t); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<div class="box">
<h3>7) Häufigstes Problem mit der Kaffeeliste</h3>
<table>
<tr><th>Problem</th><th>Anzahl</th><th>Anteil</th></tr>
<?php
// Map rows -> counts
$tmp = [];
foreach ($q7Rows as $r) $tmp[(string)$r['keyVal']] = (int)$r['cnt'];
foreach ($problems as $k => $label):
$c = $tmp[$k] ?? 0;
?>
<tr>
<td><?php echo h($label); ?></td>
<td><?php echo $c; ?></td>
<td><?php echo pct($c, $totalResponses); ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<div class="box">
<h3>8) Gewünschte Verbesserungen (Mehrfachauswahl)</h3>
<table>
<tr><th>Verbesserung</th><th>Anzahl</th><th>Anteil (bezogen auf Antworten)</th></tr>
<?php foreach ($improvements as $key => $label): ?>
<tr>
<td><?php echo h($label); ?></td>
<td><?php echo (int)$impCounts[$key]; ?></td>
<td><?php echo pct((int)$impCounts[$key], $totalResponses); ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php if (count($impOtherTexts) > 0): ?>
<p class="small"><b>„Sonstiges“ Texte (letzte 30):</b></p>
<ul>
<?php foreach (array_slice($impOtherTexts, 0, 30) as $t): ?>
<li><?php echo h($t); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<div class="grid">
<div class="box">
<h3>6) Zusätzliche Sorten (Freitext) letzte 30</h3>
<?php if (!$newVarietiesTexts): ?>
<p class="muted">Keine Einträge.</p>
<?php else: ?>
<ul>
<?php foreach (array_slice($newVarietiesTexts, 0, 30) as $t): ?>
<li><?php echo h($t); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<div class="box">
<h3>9) Was kann die Kaffeeliste noch besser machen? letzte 30</h3>
<?php if (!$betterIdeasTexts): ?>
<p class="muted">Keine Einträge.</p>
<?php else: ?>
<ul>
<?php foreach (array_slice($betterIdeasTexts, 0, 30) as $t): ?>
<li><?php echo h($t); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
</div>
<?php
}else{
echo "<h2>Sie haben keine Zugang zu dieser Webseite</h2>";
}
?>
</div>
</section>
<?php include "footer.php";
?>