getMessage());
return $default;
}
}
/**
* @return void
*/
public static function actionInit() {
if (!function_exists('current_user_can') || !current_user_can('manage_options')) return;
try {
load_plugin_textdomain('jetbackup', false, JetBackup::PLUGIN_NAME . DIRECTORY_SEPARATOR . 'languages');
// Cookie Env (safe)
add_action('wp_loaded', ['\JetBackup\Wordpress\Wordpress', 'setNonceCookie']);
add_action('wp_loaded', ['\JetBackup\Wordpress\Wordpress', 'setUserLanguageCookie']);
self::_createWorkingSpace();
self::_validateWorkingSpace();
(new Migration())->migrate();
Destination::createDefaultDestination();
Schedule::createDefaultSchedule();
BackupJob::getDefaultJob();
BackupJob::getDefaultConfigJob();
self::_download();
//Only register UI/AJAX/heartbeat after we know init succeeded.
$hookNetworkMenu = false;
if (Helper::isMultisite()) {
if (!Helper::isMainSite() || !Helper::isNetworkAdminUser()) return;
$hookNetworkMenu = Helper::isNetworkAdminInterface();
}
if ($hookNetworkMenu) add_action('network_admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
self::$_initialized = true;
add_action('admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
add_action('wp_ajax_jetbackup_api', ['\JetBackup\Ajax\Ajax', 'main']);
if (Factory::getSettingsAutomation()->isHeartbeatEnabled()) {
add_action('admin_footer', ['\JetBackup\Wordpress\UI', 'heartbeat']);
add_action('wp_ajax_jetbackup_heartbeat', ['\JetBackup\Ajax\Ajax', 'heartbeat']);
}
if (self::isWpCloudAtomic()) {
$restore = Factory::getSettingsRestore();
$changed = false;
if (!$restore->isRestoreWpContentOnlyEnabled()) {
$restore->setRestoreWpContentOnly(true);
$changed = true;
}
if (!$restore->isRestoreAlternatePathEnabled()) {
$restore->setRestoreAlternatePath(true);
$changed = true;
}
if ($changed) $restore->save();
}
} catch (\Throwable $e) {
error_log('[JetBackup] actionInit failed: ' . $e->getMessage() . "\n" . $e->getTraceAsString());
// if any hooks were added earlier, remove them
remove_action('admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
remove_action('network_admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
remove_action('admin_footer', ['\JetBackup\Wordpress\UI', 'heartbeat']);
remove_action('wp_ajax_jetbackup_api', ['\JetBackup\Ajax\Ajax', 'main']);
remove_action('wp_ajax_jetbackup_heartbeat', ['\JetBackup\Ajax\Ajax', 'heartbeat']);
if (function_exists('is_admin') && is_admin()) {
add_action('admin_notices', function () use ($e) {
if (!current_user_can('manage_options')) return;
echo '
JetBackup: '
. esc_html('JetBackup failed to initialize and was disabled for this request. Reason: ' . $e->getMessage())
. '
';
});
}
return;
}
}
private static function _download():void {
try {
$userInput = new UserInput();
$userInput->setData($_REQUEST);
if($download_id = $userInput->getValidated('download_id', 0, UserInput::UINT)) {
$download = new Download($download_id);
if(!$download->getId()) throw new JBException('The provided download id not found');
$download->download();
}
if($queue_item_id = $userInput->getValidated('queue_item_id', 0, UserInput::UINT)) {
$queue_item = new QueueItem($queue_item_id);
if(!$queue_item->getId()) throw new JBException('The provided queue item id not found');
$downloader = new Downloader($queue_item->getLogFile());
$downloader->download();
}
} catch(JBException $e) {
wp_die(esc_html('JetBackup: ' . $e->getMessage()));
}
}
private static function _getWorkingSpaceLockFile(): string
{
return Factory::getLocations()->getDataDir()
. JetBackup::SEP
. Factory::getConfig()->getUniqueID()
. '.lock';
}
private static function _getWorkingSpaceLockFileValue(): string
{
$lockFile = self::_getWorkingSpaceLockFile();
if (!file_exists($lockFile)) return '';
$content = @file_get_contents($lockFile);
if ($content === false) return ''; // Treat as corrupted; let validator handle it
return trim($content);
}
private static function _getInstallFingerprint(): string
{
global $wpdb;
$dbName = $wpdb->dbname ?? '';
$prefix = $wpdb->prefix ?? '';
$secret = defined('AUTH_KEY')
? AUTH_KEY
: Factory::getConfig()->getEncryptionKey();
return sha1($dbName . '|' . $prefix . '|' . $secret);
}
private static function _updateWorkingSpaceLockFile(): void
{
$lockFile = self::_getWorkingSpaceLockFile();
$fingerprint = self::_getInstallFingerprint();
if (file_put_contents($lockFile, $fingerprint, LOCK_EX) !== false) {
@chmod($lockFile, 0400);
}
}
private static function _validateWorkingSpace(): void
{
// Only lock the folder if we are using an alternate datadir
// Regular setup is inside wp-content which is per-install
if (empty(Factory::getConfig()->getAlternateDataFolder())) return;
$lockFile = self::_getWorkingSpaceLockFile();
// First run: create lock file and exit
if (!file_exists($lockFile)) {
self::_updateWorkingSpaceLockFile();
return;
}
$storedFingerprint = self::_getWorkingSpaceLockFileValue();
$currentFingerprint = self::_getInstallFingerprint();
if (!hash_equals($storedFingerprint, $currentFingerprint)) {
error_log('JetBackup: Alternate data folder reset due to mismatched installation fingerprint.');
Factory::getConfig()->setAlternateDataFolder('');
Factory::getConfig()->save();
}
}
private static function _createWorkingSpace() {
$folders = [
Factory::getLocations()->getDataDir(),
Factory::getLocations()->getTempDir(),
Factory::getLocations()->getDatabaseDir(),
Factory::getLocations()->getDownloadsDir(),
Factory::getLocations()->getBackupsDir(),
Factory::getLocations()->getLogsDir(),
];
foreach ($folders as $folder) Util::secureFolder($folder);
}
public static function filterAdminBodyClass($classes) {
$screen = Helper::getCurrentScreen();
if ($screen && strpos($screen, 'jetbackup') !== false) $classes .= ' jetbackup';
return $classes;
}
public static function actionCLI() {
if (defined('WP_CLI') && WP_CLI) CLI::init();
}
}