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