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
+12 -10
View File
@@ -1,18 +1,20 @@
<?php
// LOG
/*
* Änderungsprotokoll. $qrystr und $undoqry sind reiner Text zur
* Nachvollziehbarkeit (siehe db_sql_text()), sie werden nie ausgeführt.
* $type ist ein Eintrag aus accesstype ("anlegen", "ändern", "löschen").
*/
function saveLog($dbconn,$qrystr,$undoqry,$type)
{
$qry=mysqli_query($dbconn,"SELECT id FROM accesstype WHERE typ = '$type'") or $err=error("Fehler beim Eintragen der Aktion in die LOG:<br />".mysqli_error($dbconn));
$res=mysqli_fetch_array($qry);
$qry=mysqli_query($dbconn,"INSERT INTO log SET
typ_id= '$res[0]',
datetime=NOW(),
qry='".mysql_escape_string($qrystr)."',
undo_qry='".mysql_escape_string($undoqry)."',
user_id='".mysql_escape_string($_SESSION["user"])."'")
or $err=error("Fehler beim LOGGEN der Aktion:<br />".mysqli_error($dbconn));
$err = 0;
$typId = db_wert($dbconn, "SELECT id FROM accesstype WHERE typ = ?", array($type));
if($typId === false)
return error("Fehler beim Eintragen der Aktion in die LOG:<br />".mysqli_error($dbconn));
db_abfrage($dbconn, "INSERT INTO log SET typ_id = ?, datetime = NOW(), qry = ?, undo_qry = ?, user_id = ?",
array((int)$typId, $qrystr, $undoqry, $_SESSION["user"]))
or $err = error("Fehler beim LOGGEN der Aktion:<br />".mysqli_error($dbconn));
return $err;
}