|
@@ -1,7 +1,10 @@
|
|
|
<?php
|
|
<?php
|
|
|
|
|
|
|
|
|
|
+declare(strict_types=1);
|
|
|
|
|
+
|
|
|
require_once __DIR__ . "/../config.php";
|
|
require_once __DIR__ . "/../config.php";
|
|
|
require_once __DIR__ . "/../includes/version.php";
|
|
require_once __DIR__ . "/../includes/version.php";
|
|
|
|
|
+require_once __DIR__ . "/../includes/updater.php";
|
|
|
|
|
|
|
|
if (empty($_SESSION["admin_logged_in"])) {
|
|
if (empty($_SESSION["admin_logged_in"])) {
|
|
|
header("Location: login.php");
|
|
header("Location: login.php");
|
|
@@ -17,10 +20,20 @@ if (!defined("UPDATE_WORK_DIR")) {
|
|
|
if (!defined("UPDATE_BACKUP_DIR")) {
|
|
if (!defined("UPDATE_BACKUP_DIR")) {
|
|
|
define("UPDATE_BACKUP_DIR", DATA_DIR . "updates/backups/");
|
|
define("UPDATE_BACKUP_DIR", DATA_DIR . "updates/backups/");
|
|
|
}
|
|
}
|
|
|
|
|
+if (!defined("UPDATE_PRESERVE_PATHS")) {
|
|
|
|
|
+ define("UPDATE_PRESERVE_PATHS", ["config.php", "data/", ".git/"]);
|
|
|
|
|
+}
|
|
|
|
|
+if (!defined("UPDATE_REQUIRED_PACKAGE_PATHS")) {
|
|
|
|
|
+ define("UPDATE_REQUIRED_PACKAGE_PATHS", ["index.php", "admin/", "includes/"]);
|
|
|
|
|
+}
|
|
|
|
|
+if (!defined("UPDATE_USER_AGENT")) {
|
|
|
|
|
+ define("UPDATE_USER_AGENT", "Simple-PHP-Updater/" . APP_VERSION);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-$appRoot = realpath(__DIR__ . "/..");
|
|
|
|
|
$messages = [];
|
|
$messages = [];
|
|
|
$errors = [];
|
|
$errors = [];
|
|
|
|
|
+$manifest = null;
|
|
|
|
|
+$updateAvailable = false;
|
|
|
|
|
|
|
|
function updaterEscape($value): string
|
|
function updaterEscape($value): string
|
|
|
{
|
|
{
|
|
@@ -42,398 +55,57 @@ function updaterValidateCsrfToken(string $token): bool
|
|
|
hash_equals($_SESSION["updater_csrf_token"], $token);
|
|
hash_equals($_SESSION["updater_csrf_token"], $token);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function updaterVersionToCompare(string $version): string
|
|
|
|
|
-{
|
|
|
|
|
- return ltrim(trim($version), "vV");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterIsVersion(string $version): bool
|
|
|
|
|
-{
|
|
|
|
|
- return preg_match('/^v\d+\.\d+\.\d+$/', $version) === 1;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterEnsureDirectory(string $dir): void
|
|
|
|
|
-{
|
|
|
|
|
- if (!is_dir($dir) && !mkdir($dir, 02775, true) && !is_dir($dir)) {
|
|
|
|
|
- throw new RuntimeException("Directory cannot be created: " . $dir);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @chmod($dir, 02775);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterRemoveDirectory(string $dir): void
|
|
|
|
|
-{
|
|
|
|
|
- if (!is_dir($dir)) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $items = new RecursiveIteratorIterator(
|
|
|
|
|
- new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
|
|
|
|
|
- RecursiveIteratorIterator::CHILD_FIRST,
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach ($items as $item) {
|
|
|
|
|
- if ($item->isDir()) {
|
|
|
|
|
- rmdir($item->getPathname());
|
|
|
|
|
- } else {
|
|
|
|
|
- unlink($item->getPathname());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- rmdir($dir);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterHttpGet(string $url, int $timeout = 30): string
|
|
|
|
|
-{
|
|
|
|
|
- if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
|
|
|
|
- throw new RuntimeException("Invalid URL: " . $url);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $context = stream_context_create([
|
|
|
|
|
- "http" => [
|
|
|
|
|
- "method" => "GET",
|
|
|
|
|
- "timeout" => $timeout,
|
|
|
|
|
- "ignore_errors" => true,
|
|
|
|
|
- "header" => "User-Agent: PSA-Orderform-Updater/" . APP_VERSION . "\r\n",
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+try {
|
|
|
|
|
+ $appRoot = realpath(__DIR__ . "/..");
|
|
|
|
|
+ $updater = new SimpleUpdater([
|
|
|
|
|
+ "manifest_url" => UPDATE_MANIFEST_URL,
|
|
|
|
|
+ "work_dir" => UPDATE_WORK_DIR,
|
|
|
|
|
+ "backup_dir" => UPDATE_BACKUP_DIR,
|
|
|
|
|
+ "current_version" => APP_VERSION,
|
|
|
|
|
+ "app_root" => $appRoot === false ? "" : $appRoot,
|
|
|
|
|
+ "user_agent" => UPDATE_USER_AGENT,
|
|
|
|
|
+ "preserve_paths" => UPDATE_PRESERVE_PATHS,
|
|
|
|
|
+ "required_package_paths" => UPDATE_REQUIRED_PACKAGE_PATHS,
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
- $body = @file_get_contents($url, false, $context);
|
|
|
|
|
- $status = 0;
|
|
|
|
|
- $responseHeaders = function_exists("http_get_last_response_headers")
|
|
|
|
|
- ? http_get_last_response_headers()
|
|
|
|
|
- : [];
|
|
|
|
|
- if (is_array($responseHeaders)) {
|
|
|
|
|
- foreach ($responseHeaders as $header) {
|
|
|
|
|
- if (preg_match('/^HTTP\/\S+\s+(\d+)/', $header, $matches)) {
|
|
|
|
|
- $status = (int) $matches[1];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if ($body === false || ($status >= 400 && $status < 600)) {
|
|
|
|
|
- throw new RuntimeException(
|
|
|
|
|
- "HTTP request failed" . ($status > 0 ? " with status " . $status : "") . ".",
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ $manifest = $updater->fetchManifest();
|
|
|
|
|
+ $updateAvailable = $updater->updateAvailable($manifest);
|
|
|
|
|
+ } catch (Throwable $exception) {
|
|
|
|
|
+ $errors[] = $exception->getMessage();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return $body;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterFetchManifest(): array
|
|
|
|
|
-{
|
|
|
|
|
- $url = trim((string) UPDATE_MANIFEST_URL);
|
|
|
|
|
- if ($url === "") {
|
|
|
|
|
- throw new RuntimeException("UPDATE_MANIFEST_URL is not configured.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $body = updaterHttpGet($url, 15);
|
|
|
|
|
- $manifest = json_decode($body, true);
|
|
|
|
|
- if (!is_array($manifest)) {
|
|
|
|
|
- throw new RuntimeException("Manifest response is not valid JSON.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $version = trim((string) ($manifest["version"] ?? $manifest["latest"] ?? ""));
|
|
|
|
|
- $packageUrl = trim((string) ($manifest["package_url"] ?? ""));
|
|
|
|
|
- $sha256 = strtolower(trim((string) ($manifest["sha256"] ?? "")));
|
|
|
|
|
- $size = isset($manifest["size"]) ? (int) $manifest["size"] : 0;
|
|
|
|
|
- $publishedAt = trim((string) ($manifest["published_at"] ?? ""));
|
|
|
|
|
-
|
|
|
|
|
- if (!updaterIsVersion($version)) {
|
|
|
|
|
- throw new RuntimeException("Manifest version is invalid.");
|
|
|
|
|
- }
|
|
|
|
|
- if (!filter_var($packageUrl, FILTER_VALIDATE_URL)) {
|
|
|
|
|
- throw new RuntimeException("Manifest package URL is invalid.");
|
|
|
|
|
- }
|
|
|
|
|
- if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) {
|
|
|
|
|
- throw new RuntimeException("Manifest checksum is invalid.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- "version" => $version,
|
|
|
|
|
- "package_url" => $packageUrl,
|
|
|
|
|
- "sha256" => $sha256,
|
|
|
|
|
- "size" => $size,
|
|
|
|
|
- "published_at" => $publishedAt,
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterDownloadPackage(array $manifest, string $targetFile): void
|
|
|
|
|
-{
|
|
|
|
|
- updaterEnsureDirectory(dirname($targetFile));
|
|
|
|
|
-
|
|
|
|
|
- $data = updaterHttpGet($manifest["package_url"], 120);
|
|
|
|
|
- if ($data === "") {
|
|
|
|
|
- throw new RuntimeException("Downloaded package is empty.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (file_put_contents($targetFile, $data, LOCK_EX) === false) {
|
|
|
|
|
- throw new RuntimeException("Downloaded package cannot be written.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if ($manifest["size"] > 0 && filesize($targetFile) !== $manifest["size"]) {
|
|
|
|
|
- unlink($targetFile);
|
|
|
|
|
- throw new RuntimeException("Downloaded package size mismatch.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $actualHash = strtolower(hash_file("sha256", $targetFile) ?: "");
|
|
|
|
|
- if ($actualHash !== $manifest["sha256"]) {
|
|
|
|
|
- unlink($targetFile);
|
|
|
|
|
- throw new RuntimeException("Package checksum mismatch.");
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterValidateZipEntry(string $entry): bool
|
|
|
|
|
-{
|
|
|
|
|
- $entry = str_replace("\\", "/", $entry);
|
|
|
|
|
- $normalized = trim($entry, "/");
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- $normalized === "" ||
|
|
|
|
|
- str_contains($entry, "\0") ||
|
|
|
|
|
- str_starts_with($entry, "/") ||
|
|
|
|
|
- preg_match('/^[A-Za-z]:\//', $entry)
|
|
|
|
|
- ) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- foreach (explode("/", $normalized) as $segment) {
|
|
|
|
|
- if ($segment === "" || $segment === "." || $segment === "..") {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterExtractPackage(string $zipFile, string $stageDir): void
|
|
|
|
|
-{
|
|
|
|
|
- if (!class_exists("ZipArchive")) {
|
|
|
|
|
- throw new RuntimeException("PHP ZipArchive extension is not available.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- updaterRemoveDirectory($stageDir);
|
|
|
|
|
- updaterEnsureDirectory($stageDir);
|
|
|
|
|
-
|
|
|
|
|
- $zip = new ZipArchive();
|
|
|
|
|
- if ($zip->open($zipFile) !== true) {
|
|
|
|
|
- throw new RuntimeException("Downloaded package is not a readable ZIP file.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $hasAppFile = false;
|
|
|
|
|
- for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
|
|
|
- $name = (string) $zip->getNameIndex($i);
|
|
|
|
|
- if (!updaterValidateZipEntry($name)) {
|
|
|
|
|
- $zip->close();
|
|
|
|
|
- throw new RuntimeException("ZIP contains an unsafe path: " . $name);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- $name === "index.php" ||
|
|
|
|
|
- str_starts_with($name, "admin/") ||
|
|
|
|
|
- str_starts_with($name, "includes/")
|
|
|
|
|
- ) {
|
|
|
|
|
- $hasAppFile = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!$hasAppFile) {
|
|
|
|
|
- $zip->close();
|
|
|
|
|
- throw new RuntimeException("ZIP does not look like an app-root release package.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!$zip->extractTo($stageDir)) {
|
|
|
|
|
- $zip->close();
|
|
|
|
|
- throw new RuntimeException("ZIP package cannot be extracted.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $zip->close();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterRelativePath(string $path, string $baseDir): string
|
|
|
|
|
-{
|
|
|
|
|
- return ltrim(str_replace("\\", "/", substr($path, strlen($baseDir))), "/");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterShouldSkipPath(string $relativePath): bool
|
|
|
|
|
-{
|
|
|
|
|
- $relativePath = trim(str_replace("\\", "/", $relativePath), "/");
|
|
|
|
|
-
|
|
|
|
|
- return $relativePath === "" ||
|
|
|
|
|
- $relativePath === "config.php" ||
|
|
|
|
|
- $relativePath === "data" ||
|
|
|
|
|
- str_starts_with($relativePath, "data/") ||
|
|
|
|
|
- $relativePath === ".git" ||
|
|
|
|
|
- str_starts_with($relativePath, ".git/");
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterCopyWithBackup(string $stageDir, string $appRoot, string $backupDir): array
|
|
|
|
|
-{
|
|
|
|
|
- updaterEnsureDirectory($backupDir);
|
|
|
|
|
-
|
|
|
|
|
- $copied = 0;
|
|
|
|
|
- $backedUp = 0;
|
|
|
|
|
- $skipped = 0;
|
|
|
|
|
-
|
|
|
|
|
- $items = new RecursiveIteratorIterator(
|
|
|
|
|
- new RecursiveDirectoryIterator($stageDir, FilesystemIterator::SKIP_DOTS),
|
|
|
|
|
- RecursiveIteratorIterator::SELF_FIRST,
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach ($items as $item) {
|
|
|
|
|
- $relativePath = updaterRelativePath($item->getPathname(), $stageDir);
|
|
|
|
|
- if (updaterShouldSkipPath($relativePath)) {
|
|
|
|
|
- $skipped++;
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $targetPath = $appRoot . DIRECTORY_SEPARATOR . $relativePath;
|
|
|
|
|
-
|
|
|
|
|
- if ($item->isDir()) {
|
|
|
|
|
- updaterEnsureDirectory($targetPath);
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- updaterEnsureDirectory(dirname($targetPath));
|
|
|
|
|
-
|
|
|
|
|
- if (file_exists($targetPath)) {
|
|
|
|
|
- $backupPath = $backupDir . DIRECTORY_SEPARATOR . $relativePath;
|
|
|
|
|
- updaterEnsureDirectory(dirname($backupPath));
|
|
|
|
|
- if (!copy($targetPath, $backupPath)) {
|
|
|
|
|
- throw new RuntimeException("Cannot back up file: " . $relativePath);
|
|
|
|
|
|
|
+ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
|
|
|
|
+ if (!updaterValidateCsrfToken((string) ($_POST["csrf_token"] ?? ""))) {
|
|
|
|
|
+ $errors[] = "Invalid token. Please reload the page and try again.";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $manifest = $updater->fetchManifest();
|
|
|
|
|
+ $force = !empty($_POST["force_redeploy"]);
|
|
|
|
|
+ $updateAvailable = $updater->updateAvailable($manifest);
|
|
|
|
|
+
|
|
|
|
|
+ if (!$updateAvailable && !$force) {
|
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
|
+ "No newer update is available. Enable force redeployment to deploy this package anyway.",
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $result = $updater->deploy($manifest);
|
|
|
|
|
+ $messages[] = "Deployment finished.";
|
|
|
|
|
+ $messages[] = "Files copied: " . $result["copied"];
|
|
|
|
|
+ $messages[] = "Files backed up: " . $result["backed_up"];
|
|
|
|
|
+ $messages[] = "Old backup directories removed: " . $result["removed_backups"];
|
|
|
|
|
+ $messages[] = "Skipped preserved paths: " . $result["skipped"];
|
|
|
|
|
+ $messages[] = "Backup directory: " . $result["backup_dir"];
|
|
|
|
|
+ } catch (Throwable $exception) {
|
|
|
|
|
+ $errors[] = $exception->getMessage();
|
|
|
}
|
|
}
|
|
|
- $backedUp++;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!copy($item->getPathname(), $targetPath)) {
|
|
|
|
|
- throw new RuntimeException("Cannot deploy file: " . $relativePath);
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- @chmod($targetPath, fileperms($item->getPathname()) & 0777);
|
|
|
|
|
- $copied++;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- "copied" => $copied,
|
|
|
|
|
- "backed_up" => $backedUp,
|
|
|
|
|
- "skipped" => $skipped,
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterCleanupOldBackups(string $keepBackupDir): int
|
|
|
|
|
-{
|
|
|
|
|
- $backupRoot = rtrim((string) UPDATE_BACKUP_DIR, "/\\");
|
|
|
|
|
- if (!is_dir($backupRoot)) {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $keepRealPath = realpath($keepBackupDir);
|
|
|
|
|
- $backupRootRealPath = realpath($backupRoot);
|
|
|
|
|
- if ($keepRealPath === false || $backupRootRealPath === false) {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $removed = 0;
|
|
|
|
|
- $items = new DirectoryIterator($backupRootRealPath);
|
|
|
|
|
- foreach ($items as $item) {
|
|
|
|
|
- if ($item->isDot() || !$item->isDir()) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $path = $item->getPathname();
|
|
|
|
|
- if (realpath($path) === $keepRealPath) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- updaterRemoveDirectory($path);
|
|
|
|
|
- if (is_dir($path)) {
|
|
|
|
|
- throw new RuntimeException("Old backup directory could not be removed: " . $path);
|
|
|
|
|
- }
|
|
|
|
|
- $removed++;
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return $removed;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function updaterDeploy(array $manifest, string $appRoot): array
|
|
|
|
|
-{
|
|
|
|
|
- $runId = date("Ymd-His");
|
|
|
|
|
- $workDir = rtrim((string) UPDATE_WORK_DIR, "/\\") . DIRECTORY_SEPARATOR . $runId;
|
|
|
|
|
- $stageDir = $workDir . DIRECTORY_SEPARATOR . "stage";
|
|
|
|
|
- $zipFile = $workDir . DIRECTORY_SEPARATOR . "package.zip";
|
|
|
|
|
- $backupDir = rtrim((string) UPDATE_BACKUP_DIR, "/\\") .
|
|
|
|
|
- DIRECTORY_SEPARATOR .
|
|
|
|
|
- $runId .
|
|
|
|
|
- "-" .
|
|
|
|
|
- $manifest["version"];
|
|
|
|
|
-
|
|
|
|
|
- updaterEnsureDirectory($workDir);
|
|
|
|
|
- updaterDownloadPackage($manifest, $zipFile);
|
|
|
|
|
- updaterExtractPackage($zipFile, $stageDir);
|
|
|
|
|
- $result = updaterCopyWithBackup($stageDir, $appRoot, $backupDir);
|
|
|
|
|
-
|
|
|
|
|
- updaterRemoveDirectory($workDir);
|
|
|
|
|
- $removedBackups = updaterCleanupOldBackups($backupDir);
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- "backup_dir" => $backupDir,
|
|
|
|
|
- "copied" => $result["copied"],
|
|
|
|
|
- "backed_up" => $result["backed_up"],
|
|
|
|
|
- "removed_backups" => $removedBackups,
|
|
|
|
|
- "skipped" => $result["skipped"],
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-$manifest = null;
|
|
|
|
|
-$updateAvailable = false;
|
|
|
|
|
-
|
|
|
|
|
-try {
|
|
|
|
|
- $manifest = updaterFetchManifest();
|
|
|
|
|
- $updateAvailable =
|
|
|
|
|
- version_compare(
|
|
|
|
|
- updaterVersionToCompare($manifest["version"]),
|
|
|
|
|
- updaterVersionToCompare(APP_VERSION),
|
|
|
|
|
- ">",
|
|
|
|
|
- );
|
|
|
|
|
} catch (Throwable $exception) {
|
|
} catch (Throwable $exception) {
|
|
|
$errors[] = $exception->getMessage();
|
|
$errors[] = $exception->getMessage();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
|
|
|
|
- if (!updaterValidateCsrfToken((string) ($_POST["csrf_token"] ?? ""))) {
|
|
|
|
|
- $errors[] = "Invalid token. Please reload the page and try again.";
|
|
|
|
|
- } elseif ($appRoot === false) {
|
|
|
|
|
- $errors[] = "Application root cannot be resolved.";
|
|
|
|
|
- } else {
|
|
|
|
|
- try {
|
|
|
|
|
- $manifest = updaterFetchManifest();
|
|
|
|
|
- $force = !empty($_POST["force_redeploy"]);
|
|
|
|
|
- $updateAvailable =
|
|
|
|
|
- version_compare(
|
|
|
|
|
- updaterVersionToCompare($manifest["version"]),
|
|
|
|
|
- updaterVersionToCompare(APP_VERSION),
|
|
|
|
|
- ">",
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- if (!$updateAvailable && !$force) {
|
|
|
|
|
- throw new RuntimeException(
|
|
|
|
|
- "No newer update is available. Enable force redeployment to deploy this package anyway.",
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $result = updaterDeploy($manifest, $appRoot);
|
|
|
|
|
- $messages[] = "Deployment finished.";
|
|
|
|
|
- $messages[] = "Files copied: " . $result["copied"];
|
|
|
|
|
- $messages[] = "Files backed up: " . $result["backed_up"];
|
|
|
|
|
- $messages[] = "Old backup directories removed: " . $result["removed_backups"];
|
|
|
|
|
- $messages[] = "Skipped preserved paths: " . $result["skipped"];
|
|
|
|
|
- $messages[] = "Backup directory: " . $result["backup_dir"];
|
|
|
|
|
- } catch (Throwable $exception) {
|
|
|
|
|
- $errors[] = $exception->getMessage();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
?>
|
|
?>
|
|
|
<!DOCTYPE html>
|
|
<!DOCTYPE html>
|
|
|
<html lang="de">
|
|
<html lang="de">
|