PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / trunk
JetBackup – Backup, Restore & Migrate vtrunk
3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / Wordpress / Init.php
backup / src / JetBackup / Wordpress Last commit date
.htaccess 1 year ago Abilities.php 1 day ago Blog.php 1 year ago Helper.php 5 months ago Init.php 5 months ago Installer.php 7 months ago MySQL.php 1 year ago UI.php 4 months ago Update.php 1 year ago Wordpress.php 1 day ago index.html 1 year ago web.config 1 year ago
Init.php
289 lines
1 <?php
2
3 namespace JetBackup\Wordpress;
4
5 use JetBackup\BackupJob\BackupJob;
6 use JetBackup\CLI\CLI;
7 use JetBackup\Destination\Destination;
8 use JetBackup\Download\Download;
9 use JetBackup\Downloader\Downloader;
10 use JetBackup\Entities\Util;
11 use JetBackup\Exception\JBException;
12 use JetBackup\Factory;
13 use JetBackup\JetBackup;
14 use JetBackup\Queue\QueueItem;
15 use JetBackup\Schedule\Schedule;
16 use JetBackup\SGB\Migration;
17 use JetBackup\UserInput\UserInput;
18
19 if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
20
21 class Init {
22
23 private static bool $_initialized = false;
24
25 private function __construct() { } // only static method
26
27 public static function isInitialized(): bool {
28 return self::$_initialized;
29 }
30
31 /**
32 * Detect whether the site is likely running on WP Cloud / Atomic (e.g., Porkbun WP Cloud).
33 *
34 * Logic:
35 * 1) IS_ATOMIC must exist and evaluate to true
36 * 2) AND at least one of ATOMIC_CLIENT_ID / ATOMIC_SITE_ID must exist (to reduce false positives)
37 */
38 public static function isWpCloudAtomic(): bool
39 {
40 // Fast fail: constant not present at all
41 if (!\defined('IS_ATOMIC')) {
42 return false;
43 }
44
45 // Some platforms may define it as bool/int/string; normalize safely
46 $isAtomic = \constant('IS_ATOMIC');
47
48 // Treat 1 / "1" / true / "true" as true
49 $isAtomic = ($isAtomic === true)
50 || ($isAtomic === 1)
51 || ($isAtomic === '1')
52 || (\is_string($isAtomic) && \strcasecmp($isAtomic, 'true') === 0);
53
54 if (!$isAtomic) {
55 return false;
56 }
57
58 // Extra signals to avoid collisions with other platforms that might define IS_ATOMIC
59 $hasClientId = \defined('ATOMIC_CLIENT_ID') && \constant('ATOMIC_CLIENT_ID') !== null && \constant('ATOMIC_CLIENT_ID') !== '';
60 $hasSiteId = \defined('ATOMIC_SITE_ID') && \constant('ATOMIC_SITE_ID') !== null && \constant('ATOMIC_SITE_ID') !== '';
61
62 return ($hasClientId || $hasSiteId);
63 }
64
65 /**
66 * Run a callable only if JetBackup init completed successfully.
67 * Never throws (logs and returns default).
68 *
69 * @param callable $callable
70 * @param array $args
71 * @param mixed $default
72 * @return mixed
73 */
74 public static function guard(callable $callable, array $args = [], $default = null) {
75 try {
76 if (!self::isInitialized()) return $default;
77 return \call_user_func_array($callable, $args);
78 } catch (\Throwable $e) {
79 error_log('[JetBackup] guarded hook failed: ' . $e->getMessage());
80 return $default;
81 }
82 }
83
84 /**
85 * @return void
86 */
87 public static function actionInit() {
88 if (!function_exists('current_user_can') || !current_user_can('manage_options')) return;
89
90 try {
91
92 load_plugin_textdomain('jetbackup', false, JetBackup::PLUGIN_NAME . DIRECTORY_SEPARATOR . 'languages');
93
94 // Cookie Env (safe)
95 add_action('wp_loaded', ['\JetBackup\Wordpress\Wordpress', 'setNonceCookie']);
96 add_action('wp_loaded', ['\JetBackup\Wordpress\Wordpress', 'setUserLanguageCookie']);
97
98 self::_createWorkingSpace();
99 self::_validateWorkingSpace();
100
101 (new Migration())->migrate();
102 Destination::createDefaultDestination();
103 Schedule::createDefaultSchedule();
104
105 BackupJob::getDefaultJob();
106 BackupJob::getDefaultConfigJob();
107
108 self::_download();
109
110 //Only register UI/AJAX/heartbeat after we know init succeeded.
111 $hookNetworkMenu = false;
112 if (Helper::isMultisite()) {
113 if (!Helper::isMainSite() || !Helper::isNetworkAdminUser()) return;
114 $hookNetworkMenu = Helper::isNetworkAdminInterface();
115 }
116
117 if ($hookNetworkMenu) add_action('network_admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
118
119 self::$_initialized = true;
120
121 add_action('admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
122 add_action('wp_ajax_jetbackup_api', ['\JetBackup\Ajax\Ajax', 'main']);
123
124 if (Factory::getSettingsAutomation()->isHeartbeatEnabled()) {
125 add_action('admin_footer', ['\JetBackup\Wordpress\UI', 'heartbeat']);
126 add_action('wp_ajax_jetbackup_heartbeat', ['\JetBackup\Ajax\Ajax', 'heartbeat']);
127 }
128
129 if (self::isWpCloudAtomic()) {
130
131 $restore = Factory::getSettingsRestore();
132 $changed = false;
133
134 if (!$restore->isRestoreWpContentOnlyEnabled()) {
135 $restore->setRestoreWpContentOnly(true);
136 $changed = true;
137 }
138
139 if (!$restore->isRestoreAlternatePathEnabled()) {
140 $restore->setRestoreAlternatePath(true);
141 $changed = true;
142 }
143
144 if ($changed) $restore->save();
145
146 }
147
148
149 } catch (\Throwable $e) {
150
151 error_log('[JetBackup] actionInit failed: ' . $e->getMessage() . "\n" . $e->getTraceAsString());
152
153 // if any hooks were added earlier, remove them
154 remove_action('admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
155 remove_action('network_admin_menu', ['\JetBackup\Wordpress\UI', 'main']);
156 remove_action('admin_footer', ['\JetBackup\Wordpress\UI', 'heartbeat']);
157 remove_action('wp_ajax_jetbackup_api', ['\JetBackup\Ajax\Ajax', 'main']);
158 remove_action('wp_ajax_jetbackup_heartbeat', ['\JetBackup\Ajax\Ajax', 'heartbeat']);
159
160 if (function_exists('is_admin') && is_admin()) {
161 add_action('admin_notices', function () use ($e) {
162 if (!current_user_can('manage_options')) return;
163 echo '<div class="notice notice-error"><p><strong>JetBackup:</strong> '
164 . esc_html('JetBackup failed to initialize and was disabled for this request. Reason: ' . $e->getMessage())
165 . '</p></div>';
166 });
167 }
168
169 return;
170 }
171 }
172
173
174
175 private static function _download():void {
176 try {
177 $userInput = new UserInput();
178 $userInput->setData($_REQUEST);
179
180 if($download_id = $userInput->getValidated('download_id', 0, UserInput::UINT)) {
181 $download = new Download($download_id);
182 if(!$download->getId()) throw new JBException('The provided download id not found');
183 $download->download();
184 }
185
186 if($queue_item_id = $userInput->getValidated('queue_item_id', 0, UserInput::UINT)) {
187 $queue_item = new QueueItem($queue_item_id);
188 if(!$queue_item->getId()) throw new JBException('The provided queue item id not found');
189 $downloader = new Downloader($queue_item->getLogFile());
190 $downloader->download();
191 }
192 } catch(JBException $e) {
193 wp_die(esc_html('JetBackup: ' . $e->getMessage()));
194 }
195 }
196
197 private static function _getWorkingSpaceLockFile(): string
198 {
199 return Factory::getLocations()->getDataDir()
200 . JetBackup::SEP
201 . Factory::getConfig()->getUniqueID()
202 . '.lock';
203 }
204
205 private static function _getWorkingSpaceLockFileValue(): string
206 {
207 $lockFile = self::_getWorkingSpaceLockFile();
208 if (!file_exists($lockFile)) return '';
209 $content = @file_get_contents($lockFile);
210 if ($content === false) return ''; // Treat as corrupted; let validator handle it
211 return trim($content);
212 }
213
214 private static function _getInstallFingerprint(): string
215 {
216 global $wpdb;
217
218 $dbName = $wpdb->dbname ?? '';
219 $prefix = $wpdb->prefix ?? '';
220
221 $secret = defined('AUTH_KEY')
222 ? AUTH_KEY
223 : Factory::getConfig()->getEncryptionKey();
224
225 return sha1($dbName . '|' . $prefix . '|' . $secret);
226 }
227
228 private static function _updateWorkingSpaceLockFile(): void
229 {
230 $lockFile = self::_getWorkingSpaceLockFile();
231 $fingerprint = self::_getInstallFingerprint();
232
233 if (file_put_contents($lockFile, $fingerprint, LOCK_EX) !== false) {
234 @chmod($lockFile, 0400);
235 }
236 }
237
238 private static function _validateWorkingSpace(): void
239 {
240 // Only lock the folder if we are using an alternate datadir
241 // Regular setup is inside wp-content which is per-install
242 if (empty(Factory::getConfig()->getAlternateDataFolder())) return;
243
244 $lockFile = self::_getWorkingSpaceLockFile();
245
246 // First run: create lock file and exit
247 if (!file_exists($lockFile)) {
248 self::_updateWorkingSpaceLockFile();
249 return;
250 }
251
252 $storedFingerprint = self::_getWorkingSpaceLockFileValue();
253 $currentFingerprint = self::_getInstallFingerprint();
254
255 if (!hash_equals($storedFingerprint, $currentFingerprint)) {
256 error_log('JetBackup: Alternate data folder reset due to mismatched installation fingerprint.');
257 Factory::getConfig()->setAlternateDataFolder('');
258 Factory::getConfig()->save();
259 }
260 }
261
262
263 private static function _createWorkingSpace() {
264
265 $folders = [
266 Factory::getLocations()->getDataDir(),
267 Factory::getLocations()->getTempDir(),
268 Factory::getLocations()->getDatabaseDir(),
269 Factory::getLocations()->getDownloadsDir(),
270 Factory::getLocations()->getBackupsDir(),
271 Factory::getLocations()->getLogsDir(),
272 ];
273
274 foreach ($folders as $folder) Util::secureFolder($folder);
275
276 }
277
278 public static function filterAdminBodyClass($classes) {
279 $screen = Helper::getCurrentScreen();
280 if ($screen && strpos($screen, 'jetbackup') !== false) $classes .= ' jetbackup';
281 return $classes;
282 }
283
284 public static function actionCLI() {
285 if (defined('WP_CLI') && WP_CLI) CLI::init();
286 }
287
288 }
289