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