From 74911e473c900510f391653d0d7756d34a69200d Mon Sep 17 00:00:00 2001 From: Terranom674 Date: Tue, 18 Aug 2026 22:22:51 +0200 Subject: [PATCH] Use dedicated WebDAV gallery roots and suppress duplicate sources --- runtime/reconcile-webdav.php | 82 ++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/runtime/reconcile-webdav.php b/runtime/reconcile-webdav.php index 9e57af0..f6c4262 100644 --- a/runtime/reconcile-webdav.php +++ b/runtime/reconcile-webdav.php @@ -35,12 +35,54 @@ function webdav_shell_value($value) return escapeshellarg((string)$value); } +function webdav_remove_generated_tree($path, $allowedRoot) +{ + $path = rtrim((string)$path, '/'); + $allowedRoot = rtrim((string)$allowedRoot, '/'); + if ($path === '' || $allowedRoot === '' || strpos($path, $allowedRoot.'/') !== 0 || !file_exists($path)) return; + if (is_link($path) || is_file($path)) + { + @unlink($path); + return; + } + $items = scandir($path); + if (is_array($items)) + { + foreach ($items as $item) + { + if ($item === '.' || $item === '..') continue; + webdav_remove_generated_tree($path.'/'.$item, $allowedRoot); + } + } + @rmdir($path); +} + +function webdav_source_fingerprint($baseUrl, $user, array $roots) +{ + $normalized = array(); + foreach ($roots as $root) + { + $normalized[] = array( + 'fileid'=>(int)($root['fileid'] ?? 0), + 'path'=>trim((string)($root['webdav_path'] ?? ''), '/'), + ); + } + usort($normalized, function($a, $b) + { + $cmp = $a['fileid'] <=> $b['fileid']; + return $cmp !== 0 ? $cmp : strcmp($a['path'], $b['path']); + }); + return hash('sha256', strtolower(rtrim((string)$baseUrl, '/'))."\n".strtolower(trim((string)$user))."\n".json_encode($normalized)); +} + $pluginRoot = dirname(__DIR__); $piwigoRoot = dirname($pluginRoot, 2); $dbConfig = $piwigoRoot.'/local/config/database.inc.php'; $configDir = '/etc/bratonien-tools/nc-connector'; $stateRoot = '/var/lib/bratonien-tools/nc-connector'; $publicSourceRoot = rtrim($piwigoRoot, '/').'/_data/bratonien-tools/nc-webdav-source'; +$publicGalleryRoot = rtrim($piwigoRoot, '/').'/_data/bratonien-tools/nc-webdav-gallery'; +$legacyGalleryRoot = rtrim($piwigoRoot, '/').'/galleries'; try { @@ -62,15 +104,19 @@ try $hexKey = trim((string)$keyResult->fetch_assoc()['value']); $table = $prefixeTable.'bratonien_tools_nc_connections'; - $rows = $db->query("SELECT id,name,adapter,config_json,secret_blob FROM `{$table}` ORDER BY id"); + $rows = $db->query("SELECT id,name,adapter,config_json,secret_blob FROM `{$table}` ORDER BY id DESC"); if (!$rows) fail_webdav_reconcile('Connector-Verbindungen konnten nicht gelesen werden: '.$db->error); - if (!is_dir($configDir) && !mkdir($configDir, 0700, true)) fail_webdav_reconcile('Runtime-Konfigurationsverzeichnis konnte nicht angelegt werden.'); + foreach (array($configDir=>$configDir, $publicSourceRoot=>$publicSourceRoot, $publicGalleryRoot=>$publicGalleryRoot) as $dir=>$unused) + { + if (!is_dir($dir) && !mkdir($dir, $dir === $configDir ? 0700 : 0755, true)) fail_webdav_reconcile('Runtime-Verzeichnis konnte nicht angelegt werden: '.$dir); + } @chmod($configDir, 0700); - if (!is_dir($publicSourceRoot) && !mkdir($publicSourceRoot, 0755, true)) fail_webdav_reconcile('WebDAV-Platzhalterbereich konnte nicht angelegt werden.'); @chmod($publicSourceRoot, 0755); + @chmod($publicGalleryRoot, 0755); $known = array(); + $seenFingerprints = array(); while ($row = $rows->fetch_assoc()) { @@ -81,7 +127,6 @@ try if ((string)($config['source_mode'] ?? '') !== 'webdav-placeholder') continue; if (empty($config['parallel_test'])) continue; - $known[$id] = true; try { $baseUrl = rtrim(trim((string)($config['nextcloud_url'] ?? '')), '/'); @@ -94,13 +139,35 @@ try $password = $credentials['nextcloud_password']; if ($user === '' || $password === '') fail_webdav_reconcile('Nextcloud-Zugangsdaten fehlen.'); + $fingerprint = webdav_source_fingerprint($baseUrl, $user, $roots); + if (isset($seenFingerprints[$fingerprint])) + { + fwrite(STDERR, "NC WebDAV #{$id}: identische Quelle bereits durch Verbindung #".$seenFingerprints[$fingerprint]." abgedeckt; doppelte Runtime wird unterdrueckt.\n"); + foreach (glob($configDir.'/webdav-connection-'.$id.'.*') ?: array() as $stale) @unlink($stale); + webdav_remove_generated_tree($legacyGalleryRoot.'/bratonien-webdav-'.$id, $legacyGalleryRoot); + webdav_remove_generated_tree($publicGalleryRoot.'/connection-'.$id, $publicGalleryRoot); + continue; + } + $seenFingerprints[$fingerprint] = $id; + $known[$id] = true; + $stateDir = rtrim((string)($config['state_dir'] ?? ''), '/'); if ($stateDir === '') $stateDir = $stateRoot.'/connection-'.$id; if (!is_dir($stateDir) && !mkdir($stateDir, 0750, true)) fail_webdav_reconcile('State-Verzeichnis konnte nicht angelegt werden.'); @chmod($stateDir, 0750); + $legacyDefault = $legacyGalleryRoot.'/bratonien-webdav-'.$id; $galleryRoot = rtrim((string)($config['parallel_gallery_root'] ?? ''), '/'); - if ($galleryRoot === '') $galleryRoot = rtrim($piwigoRoot, '/').'/galleries/bratonien-webdav-'.$id; + if ($galleryRoot === '' || $galleryRoot === $legacyDefault || strpos($galleryRoot, $legacyGalleryRoot.'/bratonien-webdav-') === 0) + { + $galleryRoot = $publicGalleryRoot.'/connection-'.$id; + } + if (!is_dir($galleryRoot) && !mkdir($galleryRoot, 0755, true)) fail_webdav_reconcile('WebDAV-Galeriebereich konnte nicht angelegt werden.'); + @chmod($galleryRoot, 0755); + + // Alte technische Wrapper unter ./galleries duerfen nicht als Piwigo-Alben auftauchen. + webdav_remove_generated_tree($legacyDefault, $legacyGalleryRoot); + $sourceDir = $publicSourceRoot.'/connection-'.$id; if (!is_dir($sourceDir) && !mkdir($sourceDir, 0755, true)) fail_webdav_reconcile('WebDAV-Platzhalterquelle konnte nicht angelegt werden.'); @chmod($sourceDir, 0755); @@ -143,10 +210,6 @@ try 'GALLERY_ROOT='.webdav_shell_value($galleryRoot), 'STATE_DIR='.webdav_shell_value($stateDir), 'STATUS_FILE='.webdav_shell_value($statusFile), - // Der WebDAV-Zweig registriert seinen fertigen Shadow Tree selbst. - // Damit ist er nicht von der Aktivitaets-Gate einer bestehenden - // lokalen Verbindung abhaengig. Bestehende Verbindungen bleiben - // unveraendert und koennen parallel weiterlaufen. 'PIWIGO_SYNC_ENABLED=1', ); file_put_contents($configPath, implode("\n", $lines)."\n", LOCK_EX); @@ -155,6 +218,7 @@ try $config['state_dir'] = $stateDir; $config['status_file'] = $statusFile; $config['parallel_gallery_root'] = $galleryRoot; + $config['source_fingerprint'] = $fingerprint; $config['runtime'] = array( 'mode'=>'parallel-webdav', 'config'=>$configPath,