PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.8.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.8.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 / BackupFileIndex.php
wp-staging / Backup Last commit date
Ajax 2 years ago BackgroundProcessing 2 years ago Dto 2 years ago Entity 2 years ago Exceptions 2 years ago Interfaces 2 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 2 years ago BackupDownload.php 2 years ago BackupFileIndex.php 2 years ago BackupHeader.php 2 years ago BackupProcessLock.php 2 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 FileHeader.php 2 years ago FileHeaderAttribute.php 2 years ago WithBackupIdentifier.php 2 years ago wpstgBackupHeader.txt 3 years ago
BackupFileIndex.php
204 lines
1 <?php
2
3 namespace WPStaging\Backup;
4
5 use WPStaging\Backup\Exceptions\FileValidationException;
6 use WPStaging\Backup\Interfaces\IndexLineInterface;
7
8 class BackupFileIndex implements IndexLineInterface
9 {
10 /** @var int */
11 public $bytesStart;
12
13 /** @var int */
14 public $bytesEnd;
15
16 /** @var string */
17 public $identifiablePath;
18
19 /** @var int */
20 public $isCompressed;
21
22 public function __construct()
23 {
24 $this->bytesStart = 0;
25 $this->bytesEnd = 0;
26 $this->identifiablePath = '';
27 $this->isCompressed = 0;
28 }
29
30 /**
31 * @param string $index
32 * @return BackupFileIndex
33 */
34 public function readIndex(string $index): BackupFileIndex
35 {
36 /*
37 * We start with a string that is the backup file index, like this:
38 *
39 * wpstg_t_/twentytwentyone/readme.txt|9378469:4491
40 *
41 * We split it into two parts, using the pipe "|" character as the delimiter.
42 * The first part is the identifiable path, the second is the metadata about the file.
43 *
44 * By "Identifiable Path", we mean a path that has a prefix that identifies
45 * what kind of file it is, such as a plugin, mu-plugin, theme, etc.
46 */
47 list($identifiablePath, $entryMetadata) = explode('|', trim($index));
48
49 $entryMetadata = explode(':', trim($entryMetadata));
50
51 // This should never happen.
52 if (count($entryMetadata) < 2) {
53 // todo: Log this when we have a logger.
54 throw new \UnexpectedValueException('Invalid backup file index.');
55 }
56
57 $offsetStart = (int)$entryMetadata[0];
58 $writtenPreviously = (int)$entryMetadata[1];
59
60 if (count($entryMetadata) >= 3) {
61 $isCompressed = (int)$entryMetadata[2];
62 } else {
63 $isCompressed = 0;
64 }
65
66 $backupFileIndex = new BackupFileIndex();
67
68 // Replace the placeholder with the pipe character.
69 $backupFileIndex->identifiablePath = str_replace(['{WPSTG_PIPE}', '{WPSTG_COLON}'], ['|', ':'], $identifiablePath);
70 $backupFileIndex->bytesStart = $offsetStart;
71 $backupFileIndex->bytesEnd = $writtenPreviously;
72 $backupFileIndex->isCompressed = $isCompressed;
73
74 return $backupFileIndex;
75 }
76
77 /**
78 * For compatibility with IndexLineInterface
79 * @param string $indexLine
80 * @return IndexLineInterface
81 */
82 public function readIndexLine(string $indexLine): IndexLineInterface
83 {
84 return $this->readIndex($indexLine);
85 }
86
87 /**
88 * Creates an index entry for a file to be added to the backup's file index.
89 *
90 * @param string $identifiablePath The identifiable path to the file.
91 * @param int $bytesStart The offset in the backup file where the file starts.
92 * @param int $bytesEnd The offset in the backup file where the file ends.
93 * @param int $isCompressed Whether the file is compressed.
94 *
95 * @see PathIdentifier For definition of identifiable path.
96 *
97 * @return BackupFileIndex
98 */
99 public function createIndex(string $identifiablePath, int $bytesStart, int $bytesEnd, int $isCompressed): BackupFileIndex
100 {
101 $backupFileIndex = new BackupFileIndex();
102
103 // Replace the pipe character with a placeholder to avoid conflicts.
104 $backupFileIndex->identifiablePath = str_replace(['|', ':'], ['{WPSTG_PIPE}', '{WPSTG_COLON}'], $identifiablePath);
105 $backupFileIndex->bytesStart = $bytesStart;
106 $backupFileIndex->bytesEnd = $bytesEnd;
107 $backupFileIndex->isCompressed = $isCompressed;
108
109 return $backupFileIndex;
110 }
111
112 public function getIndex(): string
113 {
114 return "$this->identifiablePath|$this->bytesStart:$this->bytesEnd:$this->isCompressed";
115 }
116
117 public function isIndexLine(string $item): bool
118 {
119 return !empty($item) && strpos($item, ':') !== false && strpos($item, '|') !== false;
120 }
121
122 /**
123 * Compatibility for new extractor on old file format
124 * Points to start of file content
125 *
126 * @return int
127 */
128 public function getContentStartOffset(): int
129 {
130 return $this->bytesStart;
131 }
132
133 /**
134 * Compatibility for new extractor on old file format
135 * Points to start of file content (in new format, it points to File Header)
136 *
137 * @return int
138 */
139 public function getStartOffset(): int
140 {
141 return $this->bytesStart;
142 }
143
144 public function getIdentifiablePath(): string
145 {
146 return $this->identifiablePath;
147 }
148
149 /**
150 * Compatibility for new extractor on old file format
151 * Old format can either support compressed or uncompressed size
152 *
153 * @return int
154 */
155 public function getUncompressedSize(): int
156 {
157 return $this->bytesEnd;
158 }
159
160 /**
161 * Compatibility for new extractor on old file format
162 * Old format can either support compressed or uncompressed size
163 *
164 * @return int
165 */
166 public function getCompressedSize(): int
167 {
168 return $this->bytesEnd;
169 }
170
171 public function getIsCompressed(): bool
172 {
173 return $this->isCompressed === 1;
174 }
175
176 /**
177 * @param string $filePath
178 * @param string $pathForErrorLogging
179 * @return void
180 * @throws FileValidationException
181 * Doesn't support crc32 validation
182 */
183 public function validateFile(string $filePath, string $pathForErrorLogging = '')
184 {
185 if (empty($pathForErrorLogging)) {
186 $pathForErrorLogging = $filePath;
187 }
188
189 if (!file_exists($filePath)) {
190 throw new FileValidationException(sprintf('File doesn\'t exist: %s.', $pathForErrorLogging));
191 }
192
193 // Doesn't support file size validation for compressed files
194 if ($this->getIsCompressed()) {
195 return;
196 }
197
198 $fileSize = filesize($filePath);
199 if ($this->getUncompressedSize() !== $fileSize) {
200 throw new FileValidationException(sprintf('Filesize validation failed for file %s. Expected: %s. Actual: %s', $pathForErrorLogging, size_format($this->getUncompressedSize(), 2), size_format($fileSize, 2)));
201 }
202 }
203 }
204