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