mirror of
https://github.com/itflow-org/itflow
synced 2026-08-05 15:17:17 +00:00
137 lines
4.9 KiB
PHP
137 lines
4.9 KiB
PHP
<?php
|
|
|
|
/*
|
|
* ITFlow - Command line restore
|
|
*
|
|
* Replaces the database (and the uploads folder, for a full backup) with the contents of
|
|
* an encrypted ITFlow backup archive.
|
|
*
|
|
* This is the only restore path with no size limit. The setup wizard's restore has to
|
|
* receive the archive through a browser upload, which PHP caps at upload_max_filesize /
|
|
* post_max_size - a real full backup is usually larger than both.
|
|
*
|
|
* Usage:
|
|
* php scripts/restore_cli.php --file=/path/to/itflow_20260731-020000_full_XXXX.zip
|
|
*
|
|
* Options:
|
|
* --file=PATH The backup archive. Required.
|
|
* --key=KEY Encryption key. Defaults to $config_backup_key from config.php.
|
|
* --inspect Show what is in the archive and exit without changing anything.
|
|
* --yes Skip the confirmation prompt (for unattended use).
|
|
*/
|
|
|
|
chdir(dirname(__FILE__));
|
|
|
|
if (php_sapi_name() !== 'cli') {
|
|
die("This script must be run from the command line.\n");
|
|
}
|
|
|
|
if (!file_exists("../config.php")) {
|
|
fwrite(STDERR, "config.php not found.\n\n");
|
|
fwrite(STDERR, "A restore needs a working database connection, so ITFlow has to be installed first.\n");
|
|
fwrite(STDERR, "Run the setup wizard (or scripts/setup_cli.php) to create config.php, then run this again.\n");
|
|
exit(1);
|
|
}
|
|
|
|
require_once "../config.php";
|
|
require_once "../includes/inc_set_timezone.php";
|
|
require_once "../functions.php";
|
|
|
|
$options = getopt("", ["file:", "key:", "inspect", "yes", "help"]);
|
|
|
|
if (isset($options['help']) || empty($options['file'])) {
|
|
echo "Usage: php scripts/restore_cli.php --file=/path/to/backup.zip [--key=KEY] [--inspect] [--yes]\n\n";
|
|
echo " --file=PATH The backup archive to restore. Required.\n";
|
|
echo " --key=KEY Encryption key. Defaults to \$config_backup_key from config.php.\n";
|
|
echo " --inspect Show what is in the archive and exit without changing anything.\n";
|
|
echo " --yes Skip the confirmation prompt.\n";
|
|
exit(isset($options['help']) ? 0 : 1);
|
|
}
|
|
|
|
$file = $options['file'];
|
|
|
|
if (!is_file($file)) {
|
|
fwrite(STDERR, "Backup file not found: $file\n");
|
|
exit(1);
|
|
}
|
|
|
|
// The key from config.php is the right one for a backup made by this install. A backup
|
|
// carried over from another server needs that server's key passed in.
|
|
$key = $options['key'] ?? ($config_backup_key ?? '');
|
|
|
|
if ($key === '') {
|
|
fwrite(STDERR, "No encryption key.\n\n");
|
|
fwrite(STDERR, "config.php has no \$config_backup_key, so pass the key from the install that made\n");
|
|
fwrite(STDERR, "this backup with --key=... It is shown in Maintenance > Backup on that install.\n");
|
|
exit(1);
|
|
}
|
|
|
|
$error = null;
|
|
$meta = backupInspectArchive($file, $key, $error);
|
|
|
|
if ($meta === false) {
|
|
fwrite(STDERR, "Cannot read this backup: $error\n");
|
|
exit(1);
|
|
}
|
|
|
|
echo "Backup archive: " . basename($file) . "\n";
|
|
echo "Size: " . backupFormatBytes(filesize($file)) . "\n";
|
|
echo "Type: " . backupTypeLabel($meta['type']) . "\n";
|
|
echo "Taken: " . $meta['generated'] . "\n";
|
|
echo "ITFlow version: " . $meta['app_version'] . "\n";
|
|
echo "Database version:" . " " . $meta['database_version'] . "\n";
|
|
echo "Contains: " . implode(", ", $meta['entries']) . "\n";
|
|
|
|
$current_db_version = backupCurrentDatabaseVersion($mysqli);
|
|
echo "This install is at database version $current_db_version.\n";
|
|
|
|
if (isset($options['inspect'])) {
|
|
echo "\n--inspect given, nothing was changed.\n";
|
|
exit(0);
|
|
}
|
|
|
|
if ($meta['database_version'] !== 'Unknown' && version_compare($meta['database_version'], $current_db_version, '>')) {
|
|
echo "\nWARNING: this backup is from a NEWER database version than the code in this directory.\n";
|
|
echo "Update ITFlow to a matching version before restoring, or the app will error after the restore.\n";
|
|
}
|
|
|
|
echo "\n";
|
|
echo "This will REPLACE the database";
|
|
if (in_array('uploads.zip', $meta['entries'], true)) {
|
|
echo " and everything in the uploads folder";
|
|
}
|
|
echo ".\n";
|
|
echo "The current database is dumped first and put back automatically if the restore fails.\n";
|
|
|
|
if (!isset($options['yes'])) {
|
|
echo "\nType 'restore' to continue: ";
|
|
$answer = trim(fgets(STDIN) ?: '');
|
|
if ($answer !== 'restore') {
|
|
echo "Aborted, nothing was changed.\n";
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
echo "\n";
|
|
|
|
$restore_error = null;
|
|
$ok = backupRestoreArchive($mysqli, $file, $key, $restore_error, function ($message) {
|
|
echo " $message\n";
|
|
});
|
|
|
|
if (!$ok) {
|
|
fwrite(STDERR, "\nRestore failed: $restore_error\n");
|
|
exit(1);
|
|
}
|
|
|
|
logAudit("Backup", "Restore", "Restored from " . escapeSql(basename($file)) . " via the command line");
|
|
|
|
echo "\nDone.\n";
|
|
echo "\nNext steps:\n";
|
|
echo " 1. Log in with the credentials that were in use when the backup was taken.\n";
|
|
echo " 2. If the backup is older than the code in this directory, finish the database update:\n";
|
|
echo " php " . realpath(__DIR__) . "/update_cli.php --update_db\n";
|
|
echo " 3. Check Maintenance > Cron - the schedule came back with the database.\n";
|
|
|
|
exit(0);
|