PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.8.0
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.8.0
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 year ago BackgroundProcessing 1 year ago Dto 1 year ago Entity 1 year ago Exceptions 1 year ago Interfaces 2 years ago Job 1 year ago Request 2 years ago Service 1 year ago Storage 2 years ago Task 1 year ago AfterRestore.php 3 years ago BackupDeleter.php 1 year ago BackupDownload.php 2 years ago BackupFileIndex.php 1 year ago BackupHeader.php 2 years ago BackupProcessLock.php 2 years ago BackupRepairer.php 3 years ago BackupRetentionHandler.php 2 years ago BackupScheduler.php 1 year ago BackupServiceProvider.php 2 years ago BackupValidator.php 1 year ago FileHeader.php 1 year ago FileHeaderAttribute.php 2 years ago WithBackupIdentifier.php 1 year ago wpstgBackupHeader.txt 3 years ago
BackupValidator.php
265 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 $version = $metadata->getBackupVersion();
145 if (version_compare($version, BackupHeader::MIN_BACKUP_VERSION, '>=')) {
146 return true;
147 }
148
149 $start = $metadata->getHeaderStart();
150 $file->fseek($start - 1);
151
152 if (!$file->valid()) {
153 return true;
154 }
155
156 $line = $file->readAndMoveNext();
157 if (in_array($line, $this->lineBreaks)) {
158 $line = $file->readAndMoveNext(); // first line is break line, that's fine, move to next then!
159 }
160
161 if (!$this->strings->startsWith($line, 'wpstg_')) {
162 $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);
163 $this->error = $error;
164 debug_log($error);
165
166 return false;
167 }
168
169 return true;
170 }
171
172 /**
173 * @return bool
174 * @throws BackupRuntimeException
175 */
176 public function checkIfSplitBackupIsValid(BackupMetadata $metadata): bool
177 {
178 $this->partSizeIssues = [];
179 $this->missingPartIssues = [];
180
181 // Early bail if not split backup
182 if (!$metadata->getIsMultipartBackup()) {
183 return true;
184 }
185
186 $this->backupDir = wp_normalize_path($this->backupsFinder->getBackupsDirectory());
187
188 $splitMetadata = $metadata->getMultipartMetadata();
189
190 foreach ($splitMetadata->getPluginsParts() as $part) {
191 $this->validatePart($part, 'plugins');
192 }
193
194 foreach ($splitMetadata->getThemesParts() as $part) {
195 $this->validatePart($part, 'themes');
196 }
197
198 foreach ($splitMetadata->getUploadsParts() as $part) {
199 $this->validatePart($part, 'uploads');
200 }
201
202 foreach ($splitMetadata->getMuPluginsParts() as $part) {
203 $this->validatePart($part, 'muplugins');
204 }
205
206 foreach ($splitMetadata->getOthersParts() as $part) {
207 $this->validatePart($part, 'others');
208 }
209
210 foreach ($splitMetadata->getOthersParts() as $part) {
211 $this->validatePart($part, 'otherWpRoot');
212 }
213
214 foreach ($splitMetadata->getDatabaseParts() as $part) {
215 $this->validatePart($part, 'database');
216 }
217
218 return empty($this->partSizeIssues) && empty($this->missingPartIssues);
219 }
220
221 /**
222 * @param BackupMetadata $metadata
223 * @return bool
224 */
225 public function isUnsupportedBackupVersion(BackupMetadata $metadata): bool
226 {
227 $isCreatedOnPro = $metadata->getCreatedOnPro();
228 $version = $metadata->getWpstgVersion();
229 if (!$isCreatedOnPro) {
230 return false;
231 }
232
233 return version_compare($version, RestoreRequirementsCheckTask::BETA_VERSION_LIMIT_PRO, '<');
234 }
235
236 /**
237 * @param string $part contains part name
238 * @param string $type (plugins|themes|uploads|muplugins|others|database)
239 *
240 * @return void
241 */
242 private function validatePart(string $part, string $type)
243 {
244 $path = $this->backupDir . str_replace($this->backupDir, '', wp_normalize_path(untrailingslashit($part)));
245 if (!file_exists($path)) {
246 $this->missingPartIssues[] = [
247 'name' => $part,
248 'type' => $type
249 ];
250
251 return;
252 }
253
254 $metadata = new BackupMetadata();
255 $metadata = $metadata->hydrateByFilePath($path);
256
257 if (filesize($path) !== $metadata->getMultipartMetadata()->getPartSize()) {
258 $this->partSizeIssues[] = $part;
259 return;
260 }
261
262 $this->existingParts[] = $part;
263 }
264 }
265