Termine auf Prepared Statements umgebaut

Kalender, Terminliste, Terminformular und Terminzettel laufen ueber
db_abfrage() mit Platzhaltern; das Anlegen einer mehrtaegigen Terminreihe
liegt in einer Transaktion. Die Logik steckt jetzt in incs/termin.php,
sites/termin*.php rufen sie nur noch auf.

Dabei behoben:
- SQL-Injektion ueber die Suchbegriffe der Terminliste, ueber die
  Mehrfachauswahl (Ankreuzfelder del<N>/erl<N> gingen roh in DELETE bzw.
  UPDATE), ueber die Wiedervorlage-Tage (INTERVAL $folgedays DAY) und ueber
  ?action=terminshow&id=... in maketerminarray(), maketerminadresse(),
  maketelnrn() und makegooglestring()
- gespeichertes XSS: Beschreibung, Notiz, Termintyp, Ort, Kundenname und
  Mitarbeiterfarbe im Kalender, in der Terminliste und im Formular
- "or $err=error(...)" stand innerhalb des Abfrage-Strings, dadurch wurden
  die Nebenzeilen einer Terminreihe beim Loeschen nie entfernt
- die Abfrage zum Folgetermin las eine Spalte typ_id, die es in termin nicht
  gibt; Typ und Wiedervorlage fehlten deshalb beim Bearbeiten
- ein Folgetermin wurde mit termtime='' und termdauer='' angelegt, ein
  Termin ohne Folgetermin mit followed_by='' - im strikten Modus Fehler
- ein Termin ohne Datum landete auf dem 01.01.1970 und gab dabei
  "NICHTTERMINIERT!!" mitten in die Seite aus
- die Ueberschneidungspruefung verglich ab dem zweiten Tag gegen das Ende
  des ersten Tages
- eine unbekannte Registerkarte der Terminliste ergab ein leeres WHERE und
  damit einen SQL-Fehler; jetzt gilt die Standardansicht
- terminshow.php pruefte den Typ mit = statt ==
- der Kalender haengt nicht mehr an der Locale de_DE (strftime)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-22 00:04:38 +02:00
co-authored by Claude Opus 5
parent 3dfbf1c9c7
commit 490c4f12a4
12 changed files with 986 additions and 950 deletions
+57 -87
View File
@@ -1,5 +1,6 @@
<?php
require_once(__DIR__."/db.php");
require_once('tcpdf/tcpdf.php');
// Unicode-Schriften statt der eingebauten PDF-Schriften Times/Helvetica: Die kennen
@@ -1332,9 +1333,10 @@ function makesingleterminpage($pdf,$termin,$adresse,$telnrn,$anfahrt,$googleadre
}
}
/* Die Daten eines Termins fuer den Terminzettel */
function maketerminarray($dbconn,$id)
{
$qry = mysqli_query($dbconn,"SELECT head, user, text, termin.id, termtime, termtyp.typ AS typ, termdauer, str, ort, hnr, plz, partner_id, land,
$res = db_zeile($dbconn,"SELECT head, user, text, termin.id, termtime, termtyp.typ AS typ, termdauer, str, ort, hnr, plz, partner_id, land,
adresse.vname AS vname, adresse.nname AS nname, titel_id, titel2_id, anrede_id, anrede2_id, vname2, nname2, zusatz,
user.vname as uservname, user.nname as usernname,
user2.vname as uservname2, user2.nname as usernname2,
@@ -1350,72 +1352,38 @@ function maketerminarray($dbconn,$id)
LEFT JOIN user AS user2 ON termin.user2 = user2.id
LEFT JOIN user AS user3 ON termin.user3 = user3.id
LEFT JOIN user AS user4 ON termin.user4 = user4.id
WHERE termin.id = $id") or $err = error("Fehler beim ermitteln der Termindaten<br />".mysqli_error($dbconn));
$res = mysqli_fetch_assoc($qry);
$qry = mysqli_query($dbconn,"SELECT anrede
FROM anrede
WHERE id = '".$res["anrede_id"]."'") or $err = error("Fehler beim ermitteln der Anrede<br />".mysqli_error($dbconn));
$res2 = mysqli_fetch_assoc($qry);
$res["anrede"] = $res2["anrede"];
$qry = mysqli_query($dbconn,"SELECT anrede
FROM anrede
WHERE id = '".$res["anrede2_id"]."'") or $err = error("Fehler beim ermitteln der Anrede2<br />".mysqli_error($dbconn));
$res2 = mysqli_fetch_assoc($qry);
$res["anrede2"] = $res2["anrede"];
$qry = mysqli_query($dbconn,"SELECT titel
FROM titel
WHERE id = '".$res["titel_id"]."'") or $err = error("Fehler beim ermitteln des Titels<br />".mysqli_error($dbconn));
$res2 = mysqli_fetch_assoc($qry);
$res["titel"] = $res2["titel"];
$qry = mysqli_query($dbconn,"SELECT titel
FROM titel
WHERE id = '".$res["titel2_id"]."'") or $err = error("Fehler beim ermitteln des Titel2<br />".mysqli_error($dbconn));
$res2 = mysqli_fetch_assoc($qry);
$res["titel2"] = $res2["titel"];
WHERE termin.id = ?", array($id));
if(!$res)
{
error("Fehler beim ermitteln der Termindaten<br />".mysqli_error($dbconn));
return array();
}
$anrs = db_zuordnung($dbconn, "SELECT id, anrede FROM anrede") ?: array();
$titels = db_zuordnung($dbconn, "SELECT id, titel FROM titel") ?: array();
$res["anrede"] = $anrs[$res["anrede_id"]] ?? "";
$res["anrede2"] = $anrs[$res["anrede2_id"]] ?? "";
$res["titel"] = $titels[$res["titel_id"]] ?? "";
$res["titel2"] = $titels[$res["titel2_id"]] ?? "";
return $res;
}
function maketerminadresse($dbconn,$termid)
{
$qry=mysqli_query($dbconn,"SELECT nname, titel_id, titel2_id, vname, nname2, vname2, str, ort, plz, hnr, land, firma, anrede_id, anrede2_id, partner_id, adresse_id
FROM termin
JOIN adresse ON termin.adresse_id = adresse.id
JOIN strasse ON strasse.id = str_id
$adresse = db_zeile($dbconn,"SELECT nname, titel_id, titel2_id, vname, nname2, vname2, str, ort, plz, hnr, land, firma, anrede_id, anrede2_id, partner_id, adresse_id
FROM termin
JOIN adresse ON termin.adresse_id = adresse.id
JOIN strasse ON strasse.id = str_id
JOIN ort ON ort.id = ort_id JOIN land ON land.id = land_id
WHERE termin.id = $termid") or $err= error("Fehler beim ermitteln der Adressdaten<br />".mysqli_error($dbconn));
$adresse = mysqli_fetch_assoc($qry);
$qry = mysqli_query($dbconn,"SELECT * FROM anrede");
while($res=mysqli_fetch_assoc($qry))
WHERE termin.id = ?", array($termid));
if(!$adresse)
{
$anrs[$res["id"]] = $res["anrede"];
error("Fehler beim ermitteln der Adressdaten<br />".mysqli_error($dbconn));
$adresse = array();
}
$qry = mysqli_query($dbconn,"SELECT * FROM titel");
while($res=mysqli_fetch_assoc($qry))
{
$titels[$res["id"]] = $res["titel"];
}
define("ADRFIELD_FIRMAANR", 0);
define("ADRFIELD_FIRMA", 1);
define("ADRFIELD_ANR1", 2);
define("ADRFIELD_TITEL1", 3);
define("ADRFIELD_NAME1", 4);
define("ADRFIELD_ANR2", 5);
define("ADRFIELD_TITEL2", 6);
define("ADRFIELD_NAME2", 7);
define("ADRFIELD_STR", 8);
define("ADRFIELD_ORT", 9);
define("ADRFIELD_LAND", 10);
// ADRFIELD_* stehen in incs/constants.php
$anrs = db_zuordnung($dbconn, "SELECT id, anrede FROM anrede") ?: array();
$titels = db_zuordnung($dbconn, "SELECT id, titel FROM titel") ?: array();
$adressfields = "";
if($adresse["firma"])
@@ -1800,50 +1768,52 @@ define("ADRFIELD_LAND", 10);
function maketelnrn($dbconn,$termid)
{
$qry=mysqli_query($dbconn,"SELECT partner_id, adresse_id
FROM termin
$telstr = "";
$adresse = db_zeile($dbconn,"SELECT partner_id, adresse_id
FROM termin
JOIN adresse ON termin.adresse_id = adresse.id
WHERE termin.id = $termid") or $err= error("Fehler beim ermitteln der Adressdaten<br />".mysqli_error($dbconn));
if($adresse = mysqli_fetch_assoc($qry))
WHERE termin.id = ?", array($termid));
if($adresse)
{
$qry = mysqli_query($dbconn,"SELECT name,typ,tel.id,nr,ort,ortsteil,plz,vwahl FROM tel LEFT JOIN teltyp ON typ_id = teltyp.id LEFT JOIN ort ON ort_id = ort.id WHERE partner_id='".$adresse["partner_id"]."' AND (tel.adresse_id = 0 OR tel.adresse_id = '".$adresse["adresse_id"]."') ORDER BY typ_id ASC");
while($res=mysqli_fetch_assoc($qry))
{
$telstr .= trim($res["typ"]).": "." (".$res["vwahl"].") ".$res["nr"]." in ".$res["ort"]."(".$res["name"].")\n";
}
$qry = mysqli_query($dbconn,"SELECT kontakt,typ FROM kontakt LEFT JOIN kontakttyp ON typ_id = kontakttyp.id WHERE partner_id='".$adresse["partner_id"]."' ORDER BY typ_id ASC");
while($res=mysqli_fetch_assoc($qry))
{
$telstr .= trim($res["typ"]).": ".$res["kontakt"]."\n";
}
$zeilen = db_zeilen($dbconn,"SELECT name, typ, tel.id, nr, ort, ortsteil, plz, vwahl FROM tel
LEFT JOIN teltyp ON tel.typ_id = teltyp.id
LEFT JOIN ort ON tel.ort_id = ort.id
WHERE partner_id = ? AND (tel.adresse_id = 0 OR tel.adresse_id = ?)
ORDER BY tel.typ_id ASC", array($adresse["partner_id"], $adresse["adresse_id"]));
foreach((array)$zeilen as $res)
$telstr .= trim($res["typ"]).": "." (".$res["vwahl"].") ".$res["nr"]." in ".$res["ort"]."(".$res["name"].")\\n";
$zeilen = db_zeilen($dbconn,"SELECT kontakt, typ FROM kontakt
LEFT JOIN kontakttyp ON kontakt.typ_id = kontakttyp.id
WHERE partner_id = ? ORDER BY kontakt.typ_id ASC", array($adresse["partner_id"]));
foreach((array)$zeilen as $res)
$telstr .= trim($res["typ"]).": ".$res["kontakt"]."\\n";
}
return $telstr;
}
function makeadrtelnrn($dbconn,$partnerid)
{
$qry = mysqli_query($dbconn,"SELECT name,typ,tel.id,nr,ort,ortsteil,plz,vwahl FROM tel LEFT JOIN teltyp ON typ_id = teltyp.id LEFT JOIN ort ON ort_id = ort.id WHERE partner_id='".$partnerid."' ORDER BY typ_id ASC");
while($res=mysqli_fetch_assoc($qry))
{
$telstr .= trim($res["typ"]).": "."(".$res["vwahl"].")".$res["nr"].",".$res["ort"]."(".$res["name"].")\n";
}
$telstr = "";
$zeilen = db_zeilen($dbconn,"SELECT name, typ, tel.id, nr, ort, ortsteil, plz, vwahl FROM tel
LEFT JOIN teltyp ON tel.typ_id = teltyp.id
LEFT JOIN ort ON tel.ort_id = ort.id
WHERE partner_id = ? ORDER BY tel.typ_id ASC", array($partnerid));
foreach((array)$zeilen as $res)
$telstr .= trim($res["typ"]).": "."(".$res["vwahl"].")".$res["nr"].",".$res["ort"]."(".$res["name"].")\\n";
return $telstr;
}
function makegooglestring($dbconn,$termid)
{
$qry=mysqli_query($dbconn,"SELECT nname, titel_id, titel2_id, vname, nname2, vname2, str, ort, plz, hnr, land, firma, anrede_id, anrede2_id
FROM termin
JOIN adresse ON termin.adresse_id = adresse.id
JOIN strasse ON strasse.id = str_id
$googlestr = "";
$adresse = db_zeile($dbconn,"SELECT nname, titel_id, titel2_id, vname, nname2, vname2, str, ort, plz, hnr, land, firma, anrede_id, anrede2_id
FROM termin
JOIN adresse ON termin.adresse_id = adresse.id
JOIN strasse ON strasse.id = str_id
JOIN ort ON ort.id = ort_id JOIN land ON land.id = land_id
WHERE termin.id = $termid") or $err= error("Fehler beim ermitteln der Adressdaten<br />".mysqli_error($dbconn));
if($adresse = mysqli_fetch_assoc($qry))
WHERE termin.id = ?", array($termid));
if($adresse)
{
$googlestr = "http://maps.googleapis.com/maps/api/staticmap";
$googlestr .= "?markers=color:blue|label:A|";