From 6d199e2f5333bfafd923ce7afdd5ec88c463a967 Mon Sep 17 00:00:00 2001 From: Terranom674 Date: Sun, 16 Aug 2026 13:34:42 +0200 Subject: [PATCH] Add one-click self updater --- include/self_update.inc.php | 234 ++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 include/self_update.inc.php diff --git a/include/self_update.inc.php b/include/self_update.inc.php new file mode 100644 index 0000000..0a81fb0 --- /dev/null +++ b/include/self_update.inc.php @@ -0,0 +1,234 @@ + time(), + 'current' => $current, + 'remote' => null, + 'update_available' => false, + 'error' => 'GitHub konnte nicht erreicht oder die Versionsnummer nicht gelesen werden.', + ); + } + else + { + $remote = trim($m[1]); + $data = array( + 'checked_at' => time(), + 'current' => $current, + 'remote' => $remote, + 'update_available' => version_compare($remote, $current, '>'), + 'error' => null, + ); + } + + if (function_exists('conf_update_param')) + { + conf_update_param($cache_key, json_encode($data)); + } + return $data; +} + +function bratonien_tools_self_update_check() +{ + if (function_exists('is_webmaster') && !is_webmaster()) + { + throw new RuntimeException('Nur der Webmaster darf Plugin-Updates ausführen.'); + } + + $info = bratonien_tools_remote_update_info(true); + if (!empty($info['error'])) + { + throw new RuntimeException($info['error']); + } + + if (!empty($info['update_available'])) + { + return array('message' => 'Update verfügbar: '.$info['current'].' → '.$info['remote'].'.'); + } + + return array('message' => 'Bratonien Tools ist aktuell (Version '.$info['current'].').'); +} + +function bratonien_tools_self_update_run() +{ + global $template; + + if (function_exists('is_webmaster') && !is_webmaster()) + { + throw new RuntimeException('Nur der Webmaster darf Plugin-Updates ausführen.'); + } + if (!class_exists('ZipArchive')) + { + throw new RuntimeException('PHP ZipArchive ist nicht verfügbar. Das automatische Update kann so nicht entpackt werden.'); + } + if (!is_writable(dirname(rtrim(BRATONIEN_TOOLS_PATH, '/')))) + { + throw new RuntimeException('Der Piwigo-Pluginordner ist für den Webserver nicht beschreibbar.'); + } + + $info = bratonien_tools_remote_update_info(true); + if (!empty($info['error'])) + { + throw new RuntimeException($info['error']); + } + if (empty($info['update_available'])) + { + return array('message' => 'Kein Update nötig. Installiert ist bereits Version '.$info['current'].'.'); + } + + $work_root = rtrim(PHPWG_ROOT_PATH, '/').'/_data/bratonien-updater'; + if (!is_dir($work_root) && !@mkdir($work_root, 0755, true)) + { + throw new RuntimeException('Temporäres Update-Verzeichnis konnte nicht angelegt werden.'); + } + + $run_dir = $work_root.'/'.date('Ymd-His').'-'.bin2hex(random_bytes(3)); + if (!@mkdir($run_dir, 0755, true)) + { + throw new RuntimeException('Temporäres Update-Verzeichnis konnte nicht angelegt werden.'); + } + + $zip_data = ''; + if (!function_exists('fetchRemote') || !fetchRemote('https://codeload.github.com/Terranom674/Piwigo_Bratonien_Tools/zip/refs/heads/main', $zip_data) || strlen((string)$zip_data) < 1000) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Das Update-Archiv konnte nicht von GitHub geladen werden.'); + } + + $zip_file = $run_dir.'/update.zip'; + if (@file_put_contents($zip_file, $zip_data) === false) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Das Update-Archiv konnte nicht gespeichert werden.'); + } + + $extract_dir = $run_dir.'/extract'; + @mkdir($extract_dir, 0755, true); + $zip = new ZipArchive(); + if ($zip->open($zip_file) !== true || !$zip->extractTo($extract_dir)) + { + if ($zip instanceof ZipArchive) { @$zip->close(); } + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Das Update-Archiv konnte nicht entpackt werden.'); + } + $zip->close(); + + $source = $extract_dir.'/Piwigo_Bratonien_Tools-main'; + $source_main = $source.'/main.inc.php'; + if (!is_file($source_main)) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Das geladene Archiv enthält kein gültiges Bratonien-Tools-Plugin.'); + } + + $remote_main = @file_get_contents($source_main); + if (!$remote_main || !preg_match('/Plugin Name:\s*Bratonien Tools/i', $remote_main) || !preg_match('/Version:\s*([\w.-]+)/i', $remote_main, $vm)) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Die geladene Plugin-Version konnte nicht verifiziert werden.'); + } + $package_version = trim($vm[1]); + if ($package_version !== $info['remote']) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Versionsprüfung fehlgeschlagen: Erwartet '.$info['remote'].', erhalten '.$package_version.'.'); + } + + $plugin_dir = rtrim(BRATONIEN_TOOLS_PATH, '/'); + $backup_root = rtrim(PHPWG_ROOT_PATH, '/').'/_data/bratonien-plugin-backups'; + if (!is_dir($backup_root) && !@mkdir($backup_root, 0755, true)) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Backup-Verzeichnis konnte nicht angelegt werden.'); + } + $backup_dir = $backup_root.'/'.basename($plugin_dir).'-'.$info['current'].'-'.date('Ymd-His'); + + if (!@rename($plugin_dir, $backup_dir)) + { + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Die bestehende Plugin-Version konnte nicht gesichert werden.'); + } + + if (!@rename($source, $plugin_dir)) + { + @rename($backup_dir, $plugin_dir); + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Die neue Plugin-Version konnte nicht aktiviert werden. Das Backup wurde wiederhergestellt.'); + } + + try + { + if (defined('PLUGINS_TABLE')) + { + pwg_query("UPDATE ".PLUGINS_TABLE." SET version='".pwg_db_real_escape_string($package_version)."' WHERE id='".pwg_db_real_escape_string(BRATONIEN_TOOLS_ID)."'"); + } + + if (function_exists('conf_delete_param')) + { + conf_delete_param('bratonien_self_update_status'); + } + elseif (function_exists('conf_update_param')) + { + conf_update_param('bratonien_self_update_status', ''); + } + + if (is_object($template) && method_exists($template, 'delete_compiled_templates')) + { + $template->delete_compiled_templates(); + } + } + catch (Throwable $e) + { + // The files are already updated. Keep them and report the post-update issue. + bratonien_tools_self_update_rrmdir($run_dir); + throw new RuntimeException('Plugin-Dateien wurden aktualisiert, aber die Nachbereitung meldet: '.$e->getMessage()); + } + + bratonien_tools_self_update_rrmdir($run_dir); + return array('message' => 'Bratonien Tools wurde auf Version '.$package_version.' aktualisiert. Backup: '.$backup_dir); +} + +function bratonien_tools_self_update_rrmdir($path) +{ + if (!is_dir($path)) return; + $items = scandir($path); + foreach ($items as $item) + { + if ($item === '.' || $item === '..') continue; + $full = $path.'/'.$item; + if (is_dir($full) && !is_link($full)) bratonien_tools_self_update_rrmdir($full); + else @unlink($full); + } + @rmdir($path); +}