PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.0
4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 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 / BackupValidator.php
wp-staging / Backup Last commit date
Ajax 1 day ago BackgroundProcessing 1 day ago Dto 1 day ago Entity 1 day ago Exceptions 1 day ago FileHeader 1 day ago Interfaces 1 day ago Job 1 day ago Request 1 day ago Service 1 day ago Storage 1 day ago Task 1 day ago Traits 1 day ago Utils 1 day ago AfterRestore.php 1 day ago BackupDeleter.php 1 day ago BackupDownload.php 1 day ago BackupFileIndex.php 1 day ago BackupGlitchReason.php 1 day ago BackupHeader.php 1 day ago BackupNextOffer.php 1 day ago BackupRepairer.php 1 day ago BackupRetentionHandler.php 1 day ago BackupScheduler.php 1 day ago BackupServiceProvider.php 1 day ago BackupValidator.php 1 day ago BeforeUpdateRowStatus.php 1 day ago FileHeader.php 1 day ago FileHeaderAttribute.php 1 day ago UpdateProtectionPausedNotice.php 1 day ago WithBackupIdentifier.php 1 day ago
BackupValidator.php
267 lines
1 <?php
2
3 namespace WPStaging\Backup;
4
5 use WPStaging\Backup\Entity\BackupMetadata;
6 use WPStaging\Backup\Exceptions\BackupRuntimeException;
7 use WPStaging\Backup\Task\Tasks\JobRestore\RestoreRequirementsCheckTask;
8 use WPStaging\Backup\Utils\BackupPathResolver;
9 use WPStaging\Framework\Filesystem\FileObject;
10 use WPStaging\Framework\Utils\Strings;
11
12 use function WPStaging\functions\debug_log;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 class BackupValidator
29 {
30
31 const LINE_BREAKS = [
32 "\r",
33 "\n",
34 "\r\n",
35 "\n\r",
36 PHP_EOL,
37 ];
38
39
40 protected $missingPartIssues = [];
41
42
43 protected $partSizeIssues = [];
44
45
46 protected $backupFilename = '';
47
48
49 protected $existingParts = [];
50
51
52 protected $error = '';
53
54
55 private $strings;
56
57
58 private $backupPathResolver;
59
60 public function __construct(Strings $strings, BackupPathResolver $backupPathResolver)
61 {
62 $this->partSizeIssues = [];
63 $this->missingPartIssues = [];
64 $this->strings = $strings;
65 $this->backupPathResolver = $backupPathResolver;
66 }
67
68
69 public function getMissingPartIssues()
70 {
71 return $this->missingPartIssues;
72 }
73
74
75 public function getPartSizeIssues()
76 {
77 return $this->partSizeIssues;
78 }
79
80
81 public function getErrorMessage()
82 {
83 return $this->error;
84 }
85
86
87
88
89
90
91 public function validateFileIndex(FileObject $file, BackupMetadata $metadata)
92 {
93
94 if ($file->getExtension() !== 'wpstg') {
95 return true;
96 }
97
98 $start = $metadata->getHeaderStart();
99 $end = $metadata->getHeaderEnd();
100 $backupFile = $this->strings->maskBackupFilename($file->getFilename());
101 if ($end - $start < 4) {
102 $error = sprintf(esc_html('File Index of %s not found!'), $backupFile);
103 debug_log($error);
104 $this->error = $error;
105
106 return false;
107 }
108
109 if (!$this->validateFileIndexFirstLine($file, $metadata)) {
110 return false;
111 }
112
113 $file->fseek($start);
114 $count = 0;
115 while ($file->valid() && $file->ftell() < $end) {
116 $line = $file->readAndMoveNext();
117 if (empty($line) || in_array($line, self::LINE_BREAKS)) {
118 continue;
119 }
120
121 $count++;
122 }
123
124 $totalFiles = $metadata->getTotalFiles();
125 if ($count !== $totalFiles && !$metadata->getIsMultipartBackup()) {
126 $error = sprintf(esc_html('File Index of %s is invalid! Actual number of files in the backup index: %s. Expected number of files: %s.'), $backupFile, $count, $totalFiles);
127 $this->error = $error;
128 debug_log($error);
129
130 return false;
131 }
132
133 if (!$metadata->getIsMultipartBackup()) {
134 return true;
135 }
136
137 $totalFiles = $metadata->getMultipartMetadata()->getTotalFiles();
138 if ($count !== $totalFiles && $metadata->getIsMultipartBackup()) {
139 $error = sprintf(esc_html('File Index of %s multipart backup is invalid! Actual number of files in the backup index: %s. Expected number of files: %s.'), $backupFile, $count, $totalFiles);
140 $this->error = $error;
141 debug_log($error);
142
143 return false;
144 }
145
146 return true;
147 }
148
149
150
151
152
153
154 public function validateFileIndexFirstLine(FileObject $file, BackupMetadata $metadata): bool
155 {
156 $version = $metadata->getBackupVersion();
157 if (version_compare($version, BackupHeader::MIN_BACKUP_VERSION, '>=')) {
158 return true;
159 }
160
161 $start = $metadata->getHeaderStart();
162 $file->fseek($start - 1);
163
164 if (!$file->valid()) {
165 return true;
166 }
167
168 $line = $file->readAndMoveNext();
169 if (in_array($line, self::LINE_BREAKS)) {
170 $line = $file->readAndMoveNext();
171 }
172
173 $backupFile = $this->strings->maskBackupFilename($file->getFilename());
174 if (!$this->strings->startsWith($line, 'wpstg_')) {
175 $error = sprintf(esc_html('File Index of %s is invalid! The file index first line does not begin with `wpstg_`. The current first line is: %s.'), $backupFile, $line);
176 $this->error = $error;
177 debug_log($error);
178
179 return false;
180 }
181
182 return true;
183 }
184
185
186
187
188
189
190
191 public function checkIfSplitBackupIsValid(BackupMetadata $metadata, string $backupFilename): bool
192 {
193 $this->partSizeIssues = [];
194 $this->missingPartIssues = [];
195
196
197 if (!$metadata->getIsMultipartBackup()) {
198 return true;
199 }
200
201 $this->backupFilename = $backupFilename;
202
203 $splitMetadata = $metadata->getMultipartMetadata();
204
205 $partsByType = [
206 'plugins' => $splitMetadata->getPluginsParts(),
207 'themes' => $splitMetadata->getThemesParts(),
208 'uploads' => $splitMetadata->getUploadsParts(),
209 'muplugins' => $splitMetadata->getMuPluginsParts(),
210 'others' => $splitMetadata->getOthersParts(),
211 'otherWpRoot' => $splitMetadata->getOtherWpRootParts(),
212 'database' => $splitMetadata->getDatabaseParts(),
213 ];
214
215 foreach ($partsByType as $type => $parts) {
216 foreach ($parts as $part) {
217 $this->validatePart($part, $type);
218 }
219 }
220
221 return empty($this->partSizeIssues) && empty($this->missingPartIssues);
222 }
223
224
225
226
227
228 public function isUnsupportedBackupVersion(BackupMetadata $metadata): bool
229 {
230 $isCreatedOnPro = $metadata->getCreatedOnPro();
231 $version = $metadata->getWpstgVersion();
232 if (!$isCreatedOnPro) {
233 return false;
234 }
235
236 return version_compare($version, RestoreRequirementsCheckTask::BETA_VERSION_LIMIT_PRO, '<');
237 }
238
239
240
241
242
243
244 private function validatePart(string $part, string $type)
245 {
246 $path = $this->backupPathResolver->resolveBackupPartPath($part, $this->backupFilename);
247 if ($path === '' || !file_exists($path)) {
248 $this->missingPartIssues[] = [
249 'name' => $part,
250 'type' => $type,
251 ];
252
253 return;
254 }
255
256 $metadata = new BackupMetadata();
257 $metadata = $metadata->hydrateByFilePath($path);
258
259 if (filesize($path) !== $metadata->getMultipartMetadata()->getPartSize()) {
260 $this->partSizeIssues[] = $part;
261 return;
262 }
263
264 $this->existingParts[] = $part;
265 }
266 }
267