PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.0
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 1 day ago FileList 1 day ago Restore 1 day ago Backup.php 1 day ago BackupDownloader.php 1 day ago BackupSizeCalculator.php 1 day ago BackupSpeedIndex.php 1 day ago BaseFileList.php 1 day ago BaseListing.php 1 day ago Delete.php 1 day ago Edit.php 1 day ago Explore.php 1 day ago ExploreCache.php 1 day ago FileInfo.php 1 day ago FileList.php 1 day ago Listing.php 1 day ago Parts.php 1 day ago Restore.php 1 day ago ScheduleList.php 1 day ago Upload.php 1 day 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