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'].'.', 'self_update' => $info, ); } return array( 'message' => 'Bratonien Tools ist aktuell (Version '.$info['current'].').', 'self_update' => $info, ); } function bratonien_tools_download_update_archive($url, &$data, &$details) { $data = ''; $details = ''; if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, CURLOPT_CONNECTTIMEOUT => 15, CURLOPT_TIMEOUT => 60, CURLOPT_USERAGENT => 'Bratonien-Tools-Updater/'.bratonien_tools_current_version(), CURLOPT_HTTPHEADER => array('Accept: application/zip, application/octet-stream;q=0.9, */*;q=0.8'), )); $response = curl_exec($ch); $errno = curl_errno($ch); $error = curl_error($ch); $http_code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $content_type = (string)curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $effective_url = (string)curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); curl_close($ch); if ($response !== false) { $data = (string)$response; } if ($errno !== 0) { $details = 'cURL-Fehler '.$errno.': '.$error; return false; } if ($http_code < 200 || $http_code >= 300) { $details = 'HTTP '.$http_code; if ($content_type !== '') { $details .= ', Content-Type '.$content_type; } if ($effective_url !== '' && $effective_url !== $url) { $details .= ', Ziel '.$effective_url; } return false; } if (strlen($data) < 1000) { $details = 'Antwort war ungewöhnlich klein ('.strlen($data).' Byte)'; if ($content_type !== '') { $details .= ', Content-Type '.$content_type; } return false; } return true; } if (!function_exists('fetchRemote')) { $details = 'Weder cURL noch Piwigos fetchRemote() sind verfügbar.'; return false; } $ok = fetchRemote($url, $data); if (!$ok) { $details = 'Piwigos fetchRemote() hat den Download ohne weitere Fehlerdetails abgebrochen.'; return false; } if (strlen((string)$data) < 1000) { $details = 'Piwigos fetchRemote() lieferte nur '.strlen((string)$data).' Byte.'; return false; } return true; } 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'].'.', 'self_update' => $info, ); } $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 = ''; $download_details = ''; $archive_url = 'https://codeload.github.com/Terranom674/Piwigo_Bratonien_Tools/zip/refs/heads/main'; if (!bratonien_tools_download_update_archive($archive_url, $zip_data, $download_details)) { bratonien_tools_self_update_rrmdir($run_dir); throw new RuntimeException( 'Das Update-Archiv konnte nicht von GitHub geladen werden.' .($download_details !== '' ? ' Details: '.$download_details : '') ); } $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. Ziel: '.$zip_file); } $extract_dir = $run_dir.'/extract'; @mkdir($extract_dir, 0755, true); $zip = new ZipArchive(); $zip_open_result = $zip->open($zip_file); if ($zip_open_result !== 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. ZipArchive-Code: '.var_export($zip_open_result, true).'.'); } $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. Erwartet wurde: '.$source_main); } $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. main.inc.php fehlt oder enthält keine lesbare Plugin-/Versionsangabe.'); } $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_root); } $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. Quelle: '.$plugin_dir.'; Ziel: '.$backup_dir); } 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. Quelle: '.$source.'; Ziel: '.$plugin_dir); } 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) { 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); $updated_info = array( 'checked_at' => time(), 'current' => $package_version, 'remote' => $package_version, 'update_available' => false, 'error' => null, ); return array( 'message' => 'Bratonien Tools wurde auf Version '.$package_version.' aktualisiert. Backup: '.$backup_dir, 'self_update' => $updated_info, ); } 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); }