PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 4.9.2
WP STAGING – WordPress Backup, Restore, Migration & Clone v4.9.2
4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Backup / Job / Jobs / JobBackup.php
wp-staging / Backup / Job / Jobs Last commit date
JobBackup.php 2 months ago JobRestore.php 9 months ago
JobBackup.php
262 lines
1 <?php
2
3 /**
4 * Orchestrates the complete backup creation workflow for WordPress sites
5 *
6 * Manages the multi-stage backup process including database export, file scanning,
7 * archiving, validation, and cleanup across multiple HTTP requests.
8 */
9
10 namespace WPStaging\Backup\Job\Jobs;
11
12 use WPStaging\Backup\Dto\Job\JobBackupDataDto;
13 use WPStaging\Backup\Task\Tasks\JobBackup\BackupMuPluginsTask;
14 use WPStaging\Backup\Task\Tasks\JobBackup\BackupOtherFilesTask;
15 use WPStaging\Backup\Task\Tasks\JobBackup\BackupPluginsTask;
16 use WPStaging\Backup\Task\Tasks\JobBackup\BackupRequirementsCheckTask;
17 use WPStaging\Backup\Task\Tasks\JobBackup\CleanupValidationFilesTask;
18 use WPStaging\Backup\Task\Tasks\JobBackup\BackupThemesTask;
19 use WPStaging\Backup\Task\Tasks\JobBackup\BackupUploadsTask;
20 use WPStaging\Backup\Task\Tasks\JobBackup\DatabaseBackupTask;
21 use WPStaging\Backup\Task\Tasks\JobBackup\FilesystemScannerTask;
22 use WPStaging\Backup\Task\Tasks\JobBackup\FinalizeBackupTask;
23 use WPStaging\Backup\Task\Tasks\JobBackup\FinishBackupTask;
24 use WPStaging\Backup\Task\Tasks\JobBackup\IncludeDatabaseTask;
25 use WPStaging\Backup\Task\Tasks\JobBackup\RecalibrateFilesCountTask;
26 use WPStaging\Backup\Task\Tasks\JobBackup\ScheduleBackupTask;
27 use WPStaging\Backup\Task\Tasks\JobBackup\SignBackupTask;
28 use WPStaging\Backup\Task\Tasks\JobBackup\ValidateBackupTask;
29 use WPStaging\Framework\Job\Dto\TaskResponseDto;
30 use WPStaging\Framework\Job\AbstractJob;
31 use WPStaging\Framework\Job\Task\AbstractTask;
32
33 class JobBackup extends AbstractJob
34 {
35 /** @var JobBackupDataDto $jobDataDto */
36 protected $jobDataDto;
37
38 /** @var array The array of tasks to execute for this job. Populated at init(). */
39 protected $tasks = [];
40
41 public static function getJobName()
42 {
43 return 'backup_job';
44 }
45
46 protected function getJobTasks()
47 {
48 return $this->tasks;
49 }
50
51 protected function execute()
52 {
53 //$this->startBenchmark();
54
55 try {
56 $response = $this->getResponse($this->currentTask->execute());
57 } catch (\Exception $e) {
58 $title = $this->currentTask->getTaskTitle();
59 if (empty($title)) {
60 $title = 'Backup job';
61 }
62
63 $this->currentTask->getLogger()->critical($title . ' failed! Error: ' . $e->getMessage());
64 $response = $this->getResponse($this->currentTask->generateResponse(false));
65 }
66
67 //$this->finishBenchmark(get_class($this->currentTask));
68
69 return $response;
70 }
71
72 /**
73 * Persist the job DTO after every task step, not just when a task fully finishes.
74 *
75 * Parent `getResponse` only persists when the current task has completed
76 * (moveToNextTask branch) or when the queue is finished. For any mid-task step
77 * that returns `isRunning=true` — e.g. DatabaseBackupTask's DDL phase writing
78 * the tables list into the DTO, RowsExporter advancing `lastInsertId`, or
79 * FilesystemScannerTask updating its running totals — state persistence relies
80 * on the WordPress `shutdown` hook firing for this request. On some hosts that
81 * hook doesn't run reliably (aggressive request termination, Object Cache Pro
82 * drop-in ordering, plugins that die() earlier in shutdown), and the next
83 * request hydrates a stale DTO — which surfaces as cryptic "Could not create
84 * the tables DDL" errors mid-backup.
85 *
86 * Before writing the job DTO we mirror what `AbstractJob::persist()` does for
87 * the running-task bookkeeping: sync the task's current `queueOffset` onto
88 * the DTO and persist the task's own steps DTO. `AbstractTask::setJobDataDto()`
89 * seeks the task queue back to this offset on the next request, so leaving it
90 * stale would make tasks like `FilesystemScannerTask` rewind the queue and
91 * reprocess items each resume. We do NOT call `AbstractJob::persist()` here
92 * because its `isFinished && !isCleaned` branch runs `cleanup()`, which
93 * removes the job cache file we just wrote — the shutdown hook is the
94 * correct place for that cleanup.
95 *
96 * Writing a few extra hundred bytes per step is cheap compared to re-running
97 * a multi-GB backup, so persist unconditionally here.
98 *
99 * @param TaskResponseDto $response
100 * @return TaskResponseDto
101 */
102 protected function getResponse(TaskResponseDto $response)
103 {
104 $response = parent::getResponse($response);
105
106 if ($this->currentTask instanceof AbstractTask) {
107 $this->jobDataDto->setQueueOffset($this->currentTask->getQueue()->getOffset());
108 $this->currentTask->persistStepsDto();
109 }
110
111 $this->persistJobDataDto();
112
113 return $response;
114 }
115
116 /**
117 * @return void
118 */
119 protected function init()
120 {
121 $this->setRequirementTask();
122
123 if ($this->jobDataDto->getRepeatBackupOnSchedule() && !$this->jobDataDto->getIsCreateScheduleBackupNow()) {
124 $this->addSchedulerTask();
125 $this->addFinishBackupTask();
126 return;
127 }
128
129 if ($this->jobDataDto->getIsCreateBackupInBackground()) {
130 if ($this->jobDataDto->getRepeatBackupOnSchedule()) {
131 $this->addSchedulerTask();
132 }
133
134 $this->addFinishBackupTask();
135 return;
136 }
137
138 $this->setScannerTask();
139 if ($this->jobDataDto->getIsExportingOtherWpContentFiles()) {
140 $this->tasks[] = BackupOtherFilesTask::class;
141 }
142
143 if ($this->jobDataDto->getIsExportingPlugins()) {
144 $this->tasks[] = BackupPluginsTask::class;
145 }
146
147 if ($this->jobDataDto->getIsExportingMuPlugins()) {
148 $this->tasks[] = BackupMuPluginsTask::class;
149 }
150
151 if ($this->jobDataDto->getIsExportingThemes()) {
152 $this->tasks[] = BackupThemesTask::class;
153 }
154
155 if ($this->jobDataDto->getIsExportingUploads()) {
156 $this->tasks[] = BackupUploadsTask::class;
157 }
158
159 $this->addBackupOtherWpRootFilesTasks();
160
161 $this->addDatabaseTasks();
162
163 $this->addFinalizeTask();
164 if ($this->jobDataDto->getRepeatBackupOnSchedule()) {
165 $this->addSchedulerTask();
166 }
167
168 if (!$this->jobDataDto->getIsMultipartBackup()) {
169 $this->tasks[] = RecalibrateFilesCountTask::class;
170 }
171
172 /**
173 * Validation is a must to ensure the backup is valid.
174 * But it cannot be done during backup listing otherwise it will consume a lot of memory and may result in timeout.
175 * So validation should be done before signing of backup. So we can stop the process and keep backup invalid state in case if validation fails.
176 */
177 $this->addValidationTasks();
178
179 $this->tasks[] = SignBackupTask::class;
180
181 $this->addStoragesTasks();
182 $this->addFinishBackupTask();
183 }
184
185 protected function addDatabaseTasks()
186 {
187 if (!$this->jobDataDto->getIsExportingDatabase()) {
188 return;
189 }
190
191 $this->tasks[] = DatabaseBackupTask::class;
192 $this->tasks[] = IncludeDatabaseTask::class;
193 }
194
195 protected function addCompressionTask()
196 {
197 // Used in PRO version
198 }
199
200 /**
201 * @return void
202 */
203 protected function addStoragesTasks()
204 {
205 // Used in PRO version
206 }
207
208 /**
209 * @return void
210 */
211 protected function addBackupOtherWpRootFilesTasks()
212 {
213 // Used in PRO version
214 }
215
216 /**
217 * @return void
218 */
219 protected function addFinalizeTask()
220 {
221 $this->tasks[] = FinalizeBackupTask::class;
222 }
223
224 protected function addValidationTasks()
225 {
226 $this->tasks[] = ValidateBackupTask::class;
227 $this->tasks[] = CleanupValidationFilesTask::class;
228 }
229
230 /**
231 * @return void
232 */
233 protected function addFinishBackupTask()
234 {
235 $this->tasks[] = FinishBackupTask::class;
236 }
237
238 /**
239 * @return void
240 */
241 protected function addSchedulerTask()
242 {
243 $this->tasks[] = ScheduleBackupTask::class;
244 }
245
246 /**
247 * @return void
248 */
249 protected function setRequirementTask()
250 {
251 $this->tasks[] = BackupRequirementsCheckTask::class;
252 }
253
254 /**
255 * @return void
256 */
257 protected function setScannerTask()
258 {
259 $this->tasks[] = FilesystemScannerTask::class;
260 }
261 }
262