Initialer Commit: Kundenverwaltung (PHP/Smarty)

Bestehende Codebasis als Ausgangsstand aufgenommen.

- .gitignore: Kundendaten (uploads_*), Smarty-Compile-Cache
  (templates_c), Laufzeit-Temp und Datenbank-Dumps ausgeschlossen;
  Verzeichnisstruktur ueber .gitkeep erhalten
- .gitattributes: Zeilenenden normalisiert (LF im Repo),
  Binaerformate markiert
- db-backup.php: MySQL-Zugangsdaten kommen jetzt wie im Rest der
  Anwendung aus der externen Konfiguration statt hartkodiert aus der
  Datei; Passwort wird ueber eine temporaere Optionsdatei statt per
  Kommandozeile uebergeben, Fehler von mysqldump/gzip werden gemeldet,
  Aufraeumen aelterer Backups berechnet Jahr und Monat konsistent

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 16:41:18 +02:00
co-authored by Claude Opus 5
commit e2124220e5
2225 changed files with 1070301 additions and 0 deletions
+131
View File
@@ -0,0 +1,131 @@
<?php
/*
* Datenbank-Backup (Cronjob).
*
* Die Zugangsdaten kommen - wie im Rest der Anwendung - aus der externen
* Konfigurationsdatei (CONFIG_PATH/CONFIG_FILE, siehe incs/constants.php)
* und stehen nicht mehr hartkodiert in dieser Datei.
*
* ACHTUNG: constants.php leitet CONFIG_FILE aus dem aktuellen Arbeits-
* verzeichnis ab. Der Cronjob muss deshalb im Installationsverzeichnis
* gestartet werden:
*
* cd /home/intranet/kunden && php db-backup.php
*/
require_once(__DIR__."/incs/constants.php");
require_once(__DIR__."/incs/settings.php");
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir."/".$object) == "dir") rrmdir($dir."/".$object); else unlink($dir."/".$object);
}
}
reset($objects);
rmdir($dir);
}
}
/* Wert fuer eine MySQL-Optionsdatei maskieren */
function cnfquote($val) {
return '"'.str_replace(array("\\", '"'), array("\\\\", '\\"'), $val).'"';
}
function fail($msg) {
fwrite(STDERR, "db-backup: ".$msg."\n");
exit(1);
}
if(readsettings() != "valid")
fail("Konfiguration ".CONFIG_PATH.CONFIG_FILE." nicht lesbar oder unvollstaendig.");
$path = "/home/intranet/backup/datenbank/";
/* $mysql_db kommt aus der Konfiguration, "angebot" wurde hier schon
* immer zusaetzlich gesichert. */
$backup_dbs = array_values(array_unique(array_filter(array($mysql_db, "angebot"))));
/* Das Passwort nicht als Kommandozeilenargument uebergeben - es waere
* sonst fuer jeden lokalen Benutzer in der Prozessliste sichtbar. */
$cnf = tempnam(sys_get_temp_dir(), "dbbak");
if($cnf === false)
fail("Temporaere Optionsdatei konnte nicht angelegt werden.");
chmod($cnf, 0600);
if(file_put_contents($cnf,
"[client]\n".
"host = ".cnfquote($mysql_server)."\n".
"user = ".cnfquote($mysql_user)."\n".
"password = ".cnfquote($mysql_pw)."\n") === false)
{
unlink($cnf);
fail("Temporaere Optionsdatei konnte nicht geschrieben werden.");
}
$day = date("d");
$month = date("M");
$year = date("Y");
$stamp = date("d-m-Y");
/* Verzeichnis von vor zwei Monaten aufraeumen. Monat UND Jahr aus dem
* selben Zeitpunkt ableiten, sonst wird zum Jahreswechsel ein falscher
* Pfad geloescht. */
$llast = strtotime("-2 month");
$llastdir = $path.date("Y", $llast)."-".date("M", $llast);
if(!is_dir($path))
fail("Backup-Verzeichnis ".$path." existiert nicht.");
$target = $path.$year."-".$month."/".$day;
if(!is_dir($target) && !mkdir($target, 0700, true))
{
unlink($cnf);
fail("Zielverzeichnis ".$target." konnte nicht angelegt werden.");
}
if(is_dir($llastdir) && $llastdir != $path.$year."-".$month)
rrmdir($llastdir);
$dumps = array();
$failed = 0;
foreach($backup_dbs as $db)
{
$sql = $target."/".$db."_".$stamp.".sql";
$cmd = "mysqldump --defaults-extra-file=".escapeshellarg($cnf).
" --result-file=".escapeshellarg($sql)." ".escapeshellarg($db);
exec($cmd." 2>&1", $out, $rc);
if($rc !== 0)
{
fwrite(STDERR, "db-backup: mysqldump fuer '".$db."' fehlgeschlagen: ".implode(" ", $out)."\n");
@unlink($sql);
$failed++;
continue;
}
exec("gzip -9 -f ".escapeshellarg($sql)." 2>&1", $out2, $rc2);
if($rc2 !== 0)
{
fwrite(STDERR, "db-backup: gzip fuer '".$db."' fehlgeschlagen: ".implode(" ", $out2)."\n");
$failed++;
continue;
}
$dumps[] = $sql.".gz";
}
unlink($cnf);
/* "current" auf die Dumps von heute zeigen lassen */
rrmdir($path."current");
if(!mkdir($path."current", 0700, true))
fail("Verzeichnis ".$path."current konnte nicht angelegt werden.");
foreach($dumps as $dump)
link($dump, $path."current/".basename($dump));
exit($failed ? 1 : 0);
?>