Rechnungsmodul auf Prepared Statements umgebaut

- incs/rechnung.php: alle Abfragen mit Platzhaltern. saveRechnung() setzte
  $_POST ungeprueft in SQL (Injection; ein Apostroph im Text brach das
  Speichern ab). Speichern, Kopieren und Loeschen laufen in Transaktionen,
  bei Fehlern bleibt nichts Halbes zurueck. Formularwerte ueber
  formularText/-Zahl/-Ganzzahl (strikter Modus).
- copyRech() trug die Rechnungsnummer ohne typ_id ein (Fehler im strikten
  Modus) und zaehlte typuebergreifend; jetzt wie beim Anlegen pro Typ
  (neueRechnungsnummer()). Artikel und Eigenschaften per INSERT ... SELECT.
- Adressblock-Formatierung aus makeadressblock() und
  makeadressblockUmschlag() in formatiereAdressblock() zusammengefuehrt.
- ajax/autosave.php und ajax/preview.php teilen sich saveTmpRechnung();
  ueberzaehlige Entwuerfe werden samt Artikeln entfernt (vorher FK-Fehler).
- sites/rechnungadd.php: Storno ohne SQL-Injection ueber $_GET["id"],
  Auswahllisten ueber db_zuordnung(), tote Kommissions-Abfrage entfernt.
- Rechnungssuche (createRechQry/createKdnRechQry) liefert SQL und Parameter
  getrennt; Suchbegriffe waren ungeprueft im SQL.
- saveLog() mit Platzhaltern, Protokolltext ueber db_sql_text().
- db.php: db_zuordnung(), db_sql_text(); Helfer liefern Strings wie
  mysqli_query(), damit alter Code sich gleich verhaelt.

Getestet: alter und neuer Code lesen dieselbe migrierte Datenbank, 150 von
155 Pruefungen (10.936 Werte) identisch, die uebrigen 5 sind der
Injection-Suchbegriff (alt: SQL-Fehler). Schreibtests fuer Entwurf,
Anlegen, Nummernkreise, Aendern, Rollback, Kopieren, Adresse, Storno und
Loeschen im strikten Modus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 10:41:43 +02:00
co-authored by Claude Opus 5
parent a130ed56a3
commit d8fff4aeb6
11 changed files with 666 additions and 1243 deletions
+44 -133
View File
@@ -42,58 +42,25 @@ elseif($_GET["copy"] == 1 && $_GET["id"])
doneNreturn("Erfolgreich geändert");
}
}
elseif($_GET["storno"] == "YES" && $_GET["id"]){
$querystr = "UPDATE rechnung SET
storno = 1, stornodate = NOW() WHERE id = '".$_GET["id"]."'";
mysqli_query($dbconn,$querystr) or $err=error("Fehler beim aktualisieren der Rechnung<br />".mysqli_error($dbconn));
doneNreturn("Erfolgreich geändert");
}
elseif($_GET["storno"] == "NO" && $_GET["id"]){
$querystr = "UPDATE rechnung SET
storno = 0 WHERE id = '".$_GET["id"]."'";
mysqli_query($dbconn,$querystr) or $err=error("Fehler beim aktualisieren der Rechnung<br />".mysqli_error($dbconn));
doneNreturn("Erfolgreich geändert");
elseif(($_GET["storno"] == "YES" || $_GET["storno"] == "NO") && $_GET["id"]){
$err = stornoRechnung($dbconn, $_GET["id"], $_GET["storno"] == "YES");
if(!$err)
doneNreturn("Erfolgreich geändert");
}
elseif($_GET["mail"] == 1 && $_GET["id"])
{
$kdnres=makeadressarray($dbconn, $_GET["adressid"]);
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,anrede FROM anrede");
while($res=mysqli_fetch_assoc($qry))
{
$typnames[$res["id"]] = $res["anrede"];
}
$smarty->assign("anrs",$typnames);
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,titel FROM titel");
while($res=mysqli_fetch_assoc($qry))
{
$typnames[$res["id"]] = $res["titel"];
}
$smarty->assign("titels",$typnames);
$mails=array();
$mailids=array();
$qry = mysqli_query($dbconn,"SELECT kontakt.id, kontakt, partner_id, typ FROM kontakt LEFT JOIN kontakttyp ON kontakttyp.id = kontakt.typ_id WHERE partner_id='".mysql_escape_string($kdnres["partner_id"])."' AND typ_id = 1");
while($res=mysqli_fetch_assoc($qry))
{
$mails[] = $res["kontakt"];
$mailids[] = $res["id"];
}
$smarty->assign("mails",$mails);
$smarty->assign("mailids",$mailids);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,bezeichn FROM artikeltyp");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["bezeichn"];
}
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnames);
list($anrs, $titels) = anredenUndTitel($dbconn);
$smarty->assign("anrs",$anrs);
$smarty->assign("titels",$titels);
$mails = db_zuordnung($dbconn, "SELECT id, kontakt FROM kontakt WHERE partner_id = ? AND typ_id = 1", array($kdnres["partner_id"] ?? 0)) ?: array();
$smarty->assign("mails",array_values($mails));
$smarty->assign("mailids",array_keys($mails));
$typen = db_zuordnung($dbconn, "SELECT id, bezeichn FROM artikeltyp") ?: array();
$smarty->assign("typids",array_keys($typen));
$smarty->assign("typs",array_values($typen));
$rechnung=makerechnungsarray($dbconn, $_GET["id"], 0);
$smarty->assign("rechnung",$rechnung);
$smarty->assign("adresse",$kdnres);
@@ -197,72 +164,29 @@ else
if($kdnres["adresstyp"] == "Kommission")
{
$smarty->assign("kommission",$kdnres);
$qry = mysqli_query($dbconn,"SELECT plz, ortsteil, ort, str, adresstyp.typ AS adresstyp, hnr, vname, partner_id, nname, vname2, nname2, firma, adresse.id, land, anrede_id, titel_id, anrede2_id, titel2_id
FROM adresse
LEFT JOIN strasse ON str_id = strasse.id
LEFT JOIN ort ON ort_id = ort.id
LEFT JOIN land ON land_id = land.id
JOIN adresstyp ON adresse.typ_id = adresstyp.id
WHERE adresse.typ_id='1' AND adresse.partner_id = '".$kdnres["partner_id"]."'
ORDER BY typ_id ASC") or $err = error("Fehler beim abrufen der Daten ".mysqli_error($dbconn));
//$kdnres=mysqli_fetch_assoc($qry);
}
if($kdnres["partner_id"])
{
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,anrede FROM anrede");
while($res=mysqli_fetch_assoc($qry))
{
$typnames[$res["id"]] = $res["anrede"];
}
$smarty->assign("anrs",$typnames);
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,titel FROM titel");
while($res=mysqli_fetch_assoc($qry))
{
$typnames[$res["id"]] = $res["titel"];
}
$smarty->assign("titels",$typnames);
list($anrs, $titels) = anredenUndTitel($dbconn);
$smarty->assign("anrs",$anrs);
$smarty->assign("titels",$titels);
$liste = db_zuordnung($dbconn, "SELECT id, bezeichn FROM artikeltyp") ?: array();
$smarty->assign("typids",array_keys($liste));
$smarty->assign("typs",array_values($liste));
$liste = db_zuordnung($dbconn, "SELECT id, einheit FROM einheit") ?: array();
$smarty->assign("einhids",array_keys($liste));
$smarty->assign("einhs",array_values($liste));
$liste = db_zuordnung($dbconn, "SELECT id, wahrung FROM wahrung") ?: array();
$smarty->assign("wahrids",array_keys($liste));
$smarty->assign("wahrs",array_values($liste));
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,bezeichn FROM artikeltyp");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["bezeichn"];
}
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnames);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,einheit FROM einheit");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["einheit"];
}
$smarty->assign("einhids",$typids);
$smarty->assign("einhs",$typnames);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,wahrung FROM wahrung");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["wahrung"];
}
$smarty->assign("wahrids",$typids);
$smarty->assign("wahrs",$typnames);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,mwst FROM mwst");
while($res=mysqli_fetch_assoc($qry))
foreach(db_zeilen($dbconn, "SELECT id, mwst FROM mwst") ?: array() as $res)
{
if($res["mwst"] != "999")
{
@@ -283,31 +207,18 @@ else
$smarty->assign("artmwstids",$typids2);
$smarty->assign("artmwsts",$typnames2);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,ziel FROM zahlziel");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["ziel"];
}
$smarty->assign("zzielids",$typids);
$smarty->assign("zziels",$typnames);
$typids=array();
$typnames=array();
$qry=mysqli_query($dbconn, "SELECT id,kto,name FROM buchungsKontos");
while($res=mysqli_fetch_assoc($qry))
{
$typids[] = $res["id"];
$typnames[] = $res["kto"]." (".$res["name"].")";
}
$smarty->assign("buchKtoids",$typids);
$smarty->assign("buchKtos",$typnames);
$qry=mysqli_query($dbconn,"SELECT tmp_rechnung.id,adresse_id, vname, nname, str, hnr FROM tmp_rechnung JOIN adresse ON adresse_id = adresse.id JOIN strasse ON str_id = strasse.id WHERE tmp_rechnung.typ_id='".mysql_escape_string($_GET["type"])."' AND user_id = '".mysql_escape_string($_SESSION["user"])."' ORDER BY datetime DESC LIMIT 1") or $err=error("Fehler beim Suchen nach nicht gespeicherten Daten<br />".mysqli_error($dbconn));
if($res = mysqli_fetch_assoc($qry))
$liste = db_zuordnung($dbconn, "SELECT id, ziel FROM zahlziel") ?: array();
$smarty->assign("zzielids",array_keys($liste));
$smarty->assign("zziels",array_values($liste));
$liste = db_zuordnung($dbconn, "SELECT id, CONCAT(kto, ' (', name, ')') FROM buchungsKontos") ?: array();
$smarty->assign("buchKtoids",array_keys($liste));
$smarty->assign("buchKtos",array_values($liste));
$res = db_zeile($dbconn, "SELECT tmp_rechnung.id, adresse_id, vname, nname, str, hnr FROM tmp_rechnung JOIN adresse ON adresse_id = adresse.id JOIN strasse ON str_id = strasse.id WHERE tmp_rechnung.typ_id = ? AND user_id = ? ORDER BY datetime DESC LIMIT 1", array((string)$_GET["type"], $_SESSION["user"]));
if($res === false)
$err = error("Fehler beim Suchen nach nicht gespeicherten Daten<br />".mysqli_error($dbconn));
if($res)
{
$smarty->assign("draft",$res["id"]);
$smarty->assign("draftname",$res["vname"]." ".$res["nname"]);