Zum Inhalt

Modul: Datenschutz / Nutzungsvereinbarung

Stand

Code-Analyse vom 2026-04-22 gegen sachpool.de, WebEdition 9.2.3, PHP 8.3. Template-ModDate: 2026-01-26.

Zweck

Nach dem Login muss jeder Vermittler eine Datenschutz-/Nutzungsvereinbarung akzeptieren, bevor er den internen Bereich nutzen darf. Die Zustimmung wird mit Zeitstempel und IP-Adresse persistiert — DSGVO-konforme Nachweisbarkeit der Einwilligung.

Technische Integration

Ein einziges Template:

Tpl-ID Pfad ModDate
173 sachpool-portal/datenschutzdialog/datenschutzdialog.tmpl 2026-01-26

Einbindung auf allen Seiten im Login-Bereich über den Master-Wrap:

<we:ifRegisteredUser>
  <we:include type="template" id="173" comment="datenschutz-dialog.tmpl" once="true" />
</we:ifRegisteredUser>

Datenmodell: Tabelle Vereinbarung

Feld Typ Rolle
id int PK Datensatz-ID
art int Art der Vereinbarung — hart kodiert 1 = Datenschutz
benutzer_id int Personen-ID aus $sach_persid
benutzer varchar Vermittlernummer aus $sach_user
ip varchar IP zum Zeitpunkt der Einwilligung ($_SERVER['REMOTE_ADDR'])
datum varchar Zeitstempel YYYY-MM-DD HH:MM:SS (als String!)
exported int 0 = PDF noch nicht erstellt; wird von externem Tool aktualisiert

Keine Text-/Versions-Speicherung

Der eingewilligte Text selbst wird nicht mitgespeichert — er existiert nur im Template (kann sich zwischen Versionen ändern, ohne dass alte Zustimmungen ungültig werden). → HANDLUNGSEMPFEHLUNGEN.md

Mehrere Vereinbarungs-Arten möglich

Das Feld art deutet auf weitere Werte (z. B. art=2 = Courtagevereinbarung) hin — ein ehemaliger Block für Courtagevereinbarung ist im Template als <we:comment>START DER CORTAGEVEREINBARUNG</we:comment> (sic!) auskommentiert.

Workflow

1. Guard

<we:ifVarEmpty name="sach_user">
  <!-- Template-Inhalt -->
</we:ifVarEmpty>

ifVarEmpty invertiert genutzt

Der Tag-Name ist irreführend — der Code läuft nur wenn $sach_user gesetzt ist. WebEdition-Eigenheit oder Bug im Include-Kontext. Funktioniert, aber unübersichtlich.

2. Check auf bestehende Zustimmung

$wedb = SachPoolDB::getInstance();
$query = 'SELECT art FROM Vereinbarung WHERE benutzer = "' . $sach_user . '"';
$result = $wedb->query($query);
$rows = mysqli_fetch_assoc($result);
if (isset($rows["art"]) && $rows["art"] == 1) {
    $einwilligung = true;
}

3. Dialog-Anzeige bei fehlender Zustimmung

Bootstrap-Modal mit dem kompletten DSGVO-Text (Vertrag zwischen Vermittler und Sachpool), Session-Felder aus Kontakt_* werden als sach_* global gesetzt und im Vertragstext eingesetzt (Firmenname, Adresse, IHK-Nr., etc.).

Button-Zeile:

  • Abbrechen/_login/index.php?we_webUser_logout=1 (Logout!)
  • Senden → POST ? (gleiche URL) mit dv-akzeptiert=on

4. Persistierung bei Zustimmung

if (isset($sach_akzeptiert) && $sach_akzeptiert == "on") {
    $einwilligung = true;
    $query = 'INSERT INTO Vereinbarung (art, benutzer_id, benutzer, ip, datum, exported)
              VALUES (1, "' . $sach_persid . '", "' . $sach_user . '",
                      "' . $_SERVER['REMOTE_ADDR'] . '",
                      "' . date('Y-m-d H:i:s') . '", 0)';
    $wedb->query($query);
}

exported = 0 → Signal für den externen PDF-Export-Prozess, dass dieser Datensatz noch nicht als PDF generiert wurde.

PDF-Export (extern)

Der PDF-Export selbst ist nicht im Template. Das Template markiert neue Einwilligungen nur mit exported = 0. Ein externer Prozess (Cron oder manueller Trigger — im Code nicht sichtbar) liest diese Datensätze, generiert PDFs und setzt exported = 1.

Entwicklungsroadmap aus der Word-Doku: Wunsch ist, dass Sachpool selbst PDF-Export übernimmt (statt externes Tool).

Variablen aus Session → Global

Aus dem eingeloggten User werden via <we:setVar from="sessionfield" ... prepareSQL="true"> übernommen:

  • Kontakt_Anrede$sach_anrede
  • Kontakt_Firma$sach_firma
  • Kontakt_Strasse$sach_strasse
  • Kontakt_Nr$sach_nr
  • Kontakt_Plz$sach_plz
  • Kontakt_Ort$sach_ort
  • Kontakt_Registernummer$sach_ihk_nr
  • Kontakt_IHK$sach_ihk_ort

Vorausgesetzt (aus authorization.tmpl): - $sach_user — Vermittlernummer - $sach_persid — Personen-ID - $sach_forename, $sach_surname

Bekannte Altlasten

→ interne Datei HANDLUNGSEMPFEHLUNGEN.md im Repo-Root

  • 🟡 Kein Versions-Tracking — alte Zustimmungen gelten bei Textänderung weiter
  • 🟡 Keine CSRF-Token — Zustimmung per CSRF unterschiebbar (rechtlich bedenklich)
  • 🟡 SQL-Konkatenation in INSERT/SELECT, $sach_user/$sach_persid ohne expliziten Escape
  • 🟡 Kein Unique-Index — Doppelklick = doppelter Eintrag
  • 🟡 $_SERVER['REMOTE_ADDR'] ohne X-Forwarded-For-Handling (Proxy-Setup liefert falsche IP)
  • 🟡 ifVarEmpty invertiert genutzt, verwirrende Semantik
  • 🟢 Großer auskommentierter Courtagevereinbarungs-Block im Template (toter Code, Tippfehler „CORTAGE")
  • 🟢 Debug-Block mit $debug = false inkl. var_dump($_POST) im Produktivcode

Siehe auch