PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.2
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.2
4.11.2 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 / Ajax / ExploreCache.php
wp-staging / Backup / Ajax Last commit date
Backup 2 weeks ago FileList 2 weeks ago Restore 2 weeks ago Backup.php 2 weeks ago BackupDownloader.php 2 weeks ago BackupSizeCalculator.php 2 weeks ago BackupSpeedIndex.php 2 weeks ago BaseFileList.php 2 weeks ago BaseListing.php 2 weeks ago Delete.php 2 weeks ago Edit.php 1 week ago Explore.php 2 weeks ago ExploreCache.php 2 weeks ago FileInfo.php 2 weeks ago FileList.php 2 weeks ago Listing.php 2 weeks ago Parts.php 2 weeks ago Restore.php 2 weeks ago ScheduleList.php 2 weeks ago Upload.php 2 weeks ago
ExploreCache.php
266 lines
1 <?php
2
3 namespace WPStaging\Backup\Ajax;
4
5 use WPStaging\Backup\BackupFileIndex;
6 use WPStaging\Backup\Entity\BackupMetadata;
7 use WPStaging\Backup\FileHeader;
8 use WPStaging\Core\WPStaging;
9 use WPStaging\Framework\Filesystem\FileObject;
10 use WPStaging\Framework\Filesystem\Filesystem;
11 use WPStaging\Framework\Filesystem\PathIdentifier;
12 use WPStaging\Framework\Utils\Cache\Cache;
13
14
15
16
17
18
19
20
21 class ExploreCache
22 {
23
24 const LIFETIME = 3600;
25
26
27 const MAX_CACHE_SIZE = 20 * 1024 * 1024;
28
29
30 private $cache;
31
32
33 private $pathIdentifier;
34
35
36 private $filesystem;
37
38 public function __construct(Cache $cache, PathIdentifier $pathIdentifier, Filesystem $filesystem)
39 {
40 $this->cache = $cache;
41 $this->pathIdentifier = $pathIdentifier;
42 $this->filesystem = $filesystem;
43 }
44
45
46
47
48
49
50
51
52 public function getOrBuild(string $backupFile, BackupMetadata $metadata)
53 {
54 $this->configureCache($backupFile);
55
56 $cached = $this->read($backupFile);
57 if ($cached !== null) {
58 return $cached;
59 }
60
61 $tree = $this->buildTree($backupFile, $metadata);
62 if ($tree === null) {
63 return null;
64 }
65
66 $this->write($backupFile, $tree);
67
68 return $tree;
69 }
70
71
72
73
74 private function configureCache(string $backupFile)
75 {
76 $this->cache->setLifetime(self::LIFETIME);
77 $this->cache->setFilename('backup_explore_' . md5($backupFile));
78 }
79
80
81
82
83
84
85
86 private function read(string $backupFile)
87 {
88 if (!$this->cache->isValid(false)) {
89 return null;
90 }
91
92 $filePath = $this->cache->getFilePath();
93 if (filesize($filePath) > self::MAX_CACHE_SIZE) {
94 return null;
95 }
96
97 $data = $this->cache->get();
98 if (!is_array($data) || !isset($data['mtime'], $data['tree'])) {
99 return null;
100 }
101
102 $currentMtime = @filemtime($backupFile);
103 if ($currentMtime === false || (int)$data['mtime'] !== $currentMtime) {
104 return null;
105 }
106
107 return $data['tree'];
108 }
109
110
111
112
113
114
115
116 private function write(string $backupFile, array $tree)
117 {
118 $mtime = @filemtime($backupFile);
119 if ($mtime === false) {
120 return;
121 }
122
123 $this->cache->save([
124 'mtime' => $mtime,
125 'tree' => $tree,
126 ]);
127 }
128
129
130
131
132
133
134
135
136 private function buildTree(string $backupFile, BackupMetadata $metadata)
137 {
138 $indexLineDto = $this->createIndexLineDto($metadata);
139 $fileObject = new FileObject($backupFile, FileObject::MODE_READ);
140 $fileObject->fseek((int)$metadata->getHeaderStart());
141
142
143 $tree = ['' => ['dirs' => [], 'files' => []]];
144
145 $dirChildren = [];
146 $dirHasSubdirs = [];
147
148 while ($fileObject->valid() && $fileObject->ftell() < (int)$metadata->getHeaderEnd()) {
149 $indexOffset = $fileObject->ftell();
150 $rawIndexFile = $fileObject->readAndMoveNext();
151 if (!$indexLineDto->isIndexLine($rawIndexFile)) {
152 continue;
153 }
154
155 $backupFileIndex = $indexLineDto->readIndexLine($rawIndexFile);
156 $relativePath = $this->pathIdentifier->transformIdentifiableToRelativePath($backupFileIndex->getIdentifiablePath());
157 $relativePath = $this->filesystem->normalizePath($relativePath);
158
159 if ($relativePath === '' || $relativePath === '/') {
160 continue;
161 }
162
163 $lastSlash = strrpos($relativePath, '/');
164 $parentDir = $lastSlash === false ? '' : substr($relativePath, 0, $lastSlash);
165 $fileName = $lastSlash === false ? $relativePath : substr($relativePath, $lastSlash + 1);
166
167 if ($fileName === '') {
168 continue;
169 }
170
171
172 if (!isset($tree[$parentDir])) {
173 $tree[$parentDir] = ['dirs' => [], 'files' => []];
174 }
175
176
177
178 $parts = explode('/', $relativePath);
179 $depth = count($parts);
180
181 if ($depth > 1) {
182
183 $currentPath = '';
184 for ($i = 0; $i < $depth - 1; $i++) {
185 $dirName = $parts[$i];
186 $childPath = $currentPath === '' ? $dirName : $currentPath . '/' . $dirName;
187
188 if (!isset($tree[$currentPath])) {
189 $tree[$currentPath] = ['dirs' => [], 'files' => []];
190 }
191
192
193 if (!isset($tree[$currentPath]['dirs'][$dirName])) {
194 $tree[$currentPath]['dirs'][$dirName] = [
195 'name' => $dirName,
196 'path' => $childPath,
197 'hasChildren' => false,
198 ];
199 }
200
201
202 if ($i + 1 < $depth - 1) {
203
204 $dirHasSubdirs[$childPath] = true;
205 }
206
207
208 $nextPart = $parts[$i + 1];
209 $dirChildren[$childPath][$nextPart] = true;
210
211 $currentPath = $childPath;
212 }
213 }
214
215
216 $size = (int)$backupFileIndex->getUncompressedSize();
217 $tree[$parentDir]['files'][] = [
218 'name' => $fileName,
219 'path' => $relativePath,
220 'size' => $size,
221 'offset' => (int)$indexOffset,
222 ];
223 }
224
225 $fileObject = null;
226
227
228 foreach ($tree as $folderPath => &$bucket) {
229 $dirArray = [];
230 foreach ($bucket['dirs'] as $dirName => $dirData) {
231 $dirPath = $dirData['path'];
232 $dirData['hasChildren'] = isset($dirChildren[$dirPath]) && count($dirChildren[$dirPath]) > 0;
233 $dirData['items'] = isset($dirChildren[$dirPath]) ? count($dirChildren[$dirPath]) : 0;
234 $dirArray[] = $dirData;
235 }
236
237 usort($dirArray, function ($a, $b) {
238 return strcasecmp($a['name'], $b['name']);
239 });
240
241 $bucket['dirs'] = $dirArray;
242
243 usort($bucket['files'], function ($a, $b) {
244 return strcasecmp($a['name'], $b['name']);
245 });
246 }
247
248 unset($bucket);
249
250 return $tree;
251 }
252
253
254
255
256
257 private function createIndexLineDto(BackupMetadata $metadata)
258 {
259 if ($metadata->getIsBackupFormatV1()) {
260 return new BackupFileIndex();
261 }
262
263 return WPStaging::make(FileHeader::class);
264 }
265 }
266