PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / src / Models / Transfer / CodeBase.php
transferito / src / Models / Transfer Last commit date
CodeBase.php 2 months ago Database.php 10 months ago Upload.php 8 months ago
CodeBase.php
470 lines
1 <?php
2
3 namespace Transferito\Models\Transfer;
4
5 use Transferito\Models\Core\Config;
6 use ZipArchive;
7
8 if (!defined('ABSPATH')) exit;
9
10 class CodeBase {
11
12 private $htaccessFile = '.htaccess';
13
14 private $renameFileJSON = TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'renamed-files.json';
15
16 public function createExecArchive($selectedFoldersEnabled, $folderPathArray = [])
17 {
18 $archive = null;
19
20 /**
21 * Create the options for the archive
22 */
23 $archiveOptions = [
24 'stdOutFile' => 'transferito' . DIRECTORY_SEPARATOR . '.archive-process',
25 'stdErrFile' => 'transferito' . DIRECTORY_SEPARATOR . '.archive-error',
26 'filename' => bin2hex(openssl_random_pseudo_bytes(16))
27 ];
28
29 /**
30 * Check if the zip archive should be created
31 */
32 $isZipArchive = useZipArchive();
33
34 /**
35 * If the archive is less than the zip file limit
36 * Initiate method to create zip archive
37 */
38 if ($isZipArchive) {
39 $archive = $this->createExecZipArchive($archiveOptions, $selectedFoldersEnabled, $folderPathArray);
40 }
41
42 /**
43 * If the archive is greater than the zip file limit
44 * Initiate method to create tar archive
45 */
46 if (!$isZipArchive) {
47 $archive = $this->createExecTarArchive($archiveOptions, $selectedFoldersEnabled, $folderPathArray);
48 }
49
50 /**
51 * Save the PID
52 */
53 set_transient('transferito_codebase_archive_pid', $archive['pid']);
54
55 return [
56 'path' => $archive['path'],
57 'url' => $archive['url']
58 ];
59
60 }
61
62 public function createArchivePath()
63 {
64 try {
65 $filename = bin2hex(openssl_random_pseudo_bytes(8))
66 . '-'
67 . gmdate("dmY_His")
68 . '-'
69 . bin2hex(openssl_random_pseudo_bytes(8));
70
71 /**
72 * Check if the zip archive should be created
73 */
74 $isZipArchive = useZipArchive();
75
76 /**
77 * Get the correct extension based on the size changes
78 */
79 $extension = $isZipArchive ? 'zip' : 'tar';
80
81 /**
82 * Create the archive name with the correct extension
83 */
84 $archiveName = DIRECTORY_SEPARATOR . $filename . '.' . $extension;
85
86 /**
87 * Get the full path of the
88 */
89 $archiveFullPath = TRANSFERITO_UPLOAD_PATH . $archiveName;
90
91 /**
92 * If the archive is less than the zip file limit
93 * Create an empty zip archive
94 */
95 if ($isZipArchive) {
96 $zip = null;
97
98 if (class_exists('ZipArchive')) {
99 $zip = new \ZipArchive;
100 } else {
101 throw new \Exception('ZipArchive not installed');
102 }
103 $zip->open($archiveFullPath, ZipArchive::CREATE);
104 $zip->addFromString('transferito_tmp', '');
105 $zip->close();
106 }
107
108 /**
109 * If the archive is greater than the zip file limit
110 * Create an empty tar archive
111 */
112 if (!$isZipArchive) {
113 /**
114 * PharData class check
115 */
116 if ($this->pharDataExists()) {
117 throw new \Exception('The PharData class does not exist and is required to create your backup.');
118 }
119
120 $tar = new \PharData($archiveFullPath, 0, null, \Phar::TAR);
121 $tar->addFromString('transferito_tmp', '');
122 }
123
124 return [
125 'path' => $archiveFullPath,
126 'url' => TRANSFERITO_UPLOAD_URL . $archiveName
127 ];
128 } catch (\Exception $exception) {
129 return $exception->getMessage();
130 }
131 }
132
133 public function createFileList($selectedFoldersEnabled, $folderPathArray = [])
134 {
135 try {
136
137 $renamedFileCount = 1;
138
139 $settings = get_option('transferito_settings_option');
140 $excludeHtaccess = !isset($settings['transferito_include_htaccess'])
141 ? true
142 : ($settings['transferito_include_htaccess'] === false);
143
144 $fileIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(TRANSFERITO_ABSPATH), \RecursiveIteratorIterator::CHILD_FIRST);
145 $files = [];
146 $byteCount = 0;
147 $fileSuffix = 1;
148 $excludedFileArray = [
149 TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'test.txt',
150 TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'index.html',
151 TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'check-public-access.php',
152 ];
153
154 /**
155 * Exclude the htaccess access file
156 * @todo update with the correct file name
157 */
158 if ($excludeHtaccess) {
159 $excludedFileArray[] = ABSPATH . $this->htaccessFile;
160 }
161
162 /**
163 * Create the directory to house the json files
164 */
165 $fileListDirectory = TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'json';
166 wp_mkdir_p($fileListDirectory);
167
168 /**
169 * Check if the zip archive should be created
170 */
171 $isZipArchive = useZipArchive();
172
173 /**
174 * Loop through the files
175 */
176 foreach ($fileIterator as $file) {
177 if ($file->isDir()){
178 continue;
179 }
180
181 /**
182 * Assign name to variable
183 */
184 $filename = $file->getPathname();
185
186 /**
187 * Base files created, when migration has been created
188 * need to be excluded from the archive
189 */
190 if (in_array($filename, $excludedFileArray)) {
191 continue;
192 }
193
194 /**
195 * Check if the folders array exists
196 */
197 if ($selectedFoldersEnabled) {
198 $file = str_replace('/',"\\/", $filename);
199 $excludedArrayCheck = preg_grep('/^' . $file . '.*$/', $folderPathArray);
200
201 /**
202 * If the file exists in the list of excluded paths
203 */
204 if (count($excludedArrayCheck) > 0) {
205 continue;
206 }
207 }
208
209 $byteCount = $byteCount + $file->getSize();
210
211 /**
212 * If the byte count is greater than the archive limit - split the file
213 */
214 if ($byteCount >= TRANSFERITO_ZIP_LIMIT) {
215
216 file_put_contents($fileListDirectory . DIRECTORY_SEPARATOR . 'file_list_' . $fileSuffix . '.json', json_encode($files));
217
218 $byteCount = 0;
219 $fileSuffix++;
220
221 /**
222 * Destroy the file
223 */
224 unset($files);
225 $files = [];
226 }
227
228 /**
229 * Create array based paths
230 */
231 if ($isZipArchive) {
232 $updatedPath = explode(TRANSFERITO_ABSPATH, $filename)[1];
233 $files[] = [
234 'originalPath' => $filename,
235 'updatedPath' => str_replace("\\", "/", $updatedPath),
236 ];
237 }
238
239 /**
240 * Create path based array
241 */
242 if (!$isZipArchive) {
243 $fileKey = explode(TRANSFERITO_ABSPATH, $filename)[1];
244 $filenameOnlyArray = explode(DIRECTORY_SEPARATOR, $fileKey);
245 $filenameOnly = end($filenameOnlyArray);
246 $filenameLength = strlen($filenameOnly);
247
248 if ($filenameLength < 100) {
249 $files[$fileKey] = $filename;
250 } else {
251
252 $tempFilePath = TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . $renamedFileCount . '.txt';
253
254 /**
255 * Copy the file to a temp location
256 */
257 copy($filename, $tempFilePath);
258
259 /**
260 * Get the path name
261 */
262 $tempFileKey = explode(TRANSFERITO_ABSPATH, $tempFilePath)[1];
263
264 /**
265 * Assign the temp path to the file array
266 */
267 $files[$tempFileKey] = $tempFilePath;
268
269 /**
270 * Get the renamed file
271 */
272 $renamedFiles = $this->getRenameFileContents();
273
274 /**
275 * Create an array with the renamed files
276 */
277 $renamedFiles[] = [
278 'renamedFilePath' => $tempFilePath,
279 'originalFilePath' => $filename,
280 'count' => $filenameLength
281 ];
282
283 /**
284 * Add it to the renamed files
285 */
286 $this->addToRenameFile($renamedFiles);
287
288 /**
289 * Increment the rename count
290 */
291 $renamedFileCount++;
292 }
293 }
294 }
295
296 /**
297 * Create the last file
298 */
299 if (count($files) > 0) {
300 file_put_contents($fileListDirectory . DIRECTORY_SEPARATOR . 'file_list_' . $fileSuffix . '.json', json_encode($files));
301 }
302
303 return [
304 'created' => true,
305 'amount' => $fileSuffix
306 ];
307
308 } catch (\Exception $exception) {
309 return $exception->getMessage();
310 }
311 }
312
313 public function addFileToArchive($archiveFilePath, $paths)
314 {
315 set_time_limit(0);
316
317 try {
318 /**
319 * Check if the zip archive should be created
320 */
321 $isZipArchive = useZipArchive();
322
323 /**
324 * If the archive is less than the zip file limit
325 * Add to the ZIP archive
326 */
327 if ($isZipArchive) {
328 $zip = null;
329
330 if (class_exists('ZipArchive')) {
331 $zip = new \ZipArchive;
332 } else {
333 throw new \Exception('ZipArchive not installed');
334 }
335
336 if ($zip->open($archiveFilePath) === TRUE) {
337 foreach ($paths as $path) {
338 $zip->addFile($path->originalPath, $path->updatedPath);
339 }
340 // $zip->close();
341 } else {
342 throw new \Exception('We can not open your zip file.');
343 }
344 }
345
346 /**
347 * If the archive is greater than the zip file limit
348 * Add to the TAR archive
349 */
350 if (!$isZipArchive) {
351 /**
352 * PharData class check
353 */
354 try {
355 $this->pharDataExists();
356 } catch (\Exception $ex) {
357 throw new \Exception('We\'re unable to start your backup. Reason: ' . $ex->getMessage());
358 }
359
360 $array = json_decode(json_encode($paths), true);
361 $tar = new \PharData($archiveFilePath);
362 $tar->buildFromIterator(new \ArrayIterator($array));
363 }
364
365 return true;
366 } catch (\Exception $exception) {
367 return $exception->getMessage();
368 }
369 }
370
371 private function createExecZipArchive(array $archiveOptions, $selectedFoldersEnabled, $folderPathArray = [])
372 {
373 $path = substr(TRANSFERITO_ABSPATH, 0, -1);
374
375 $archiveName = '/' . $archiveOptions['filename'] . '.zip';
376 $archiveFullPath = TRANSFERITO_UPLOAD_PATH . $archiveName;
377 $settings = get_option('transferito_settings_option');
378 $excludeHtaccess = !isset($settings['transferito_include_htaccess'])
379 ? true
380 : ($settings['transferito_include_htaccess'] === false);
381
382 /**
383 * If the selected folders are enabled
384 * & the folder path array has more than 1 element
385 */
386 if ($selectedFoldersEnabled && count($folderPathArray) > 0) {
387 $folderList = implode(' ', $folderPathArray);
388 $directories = str_replace(TRANSFERITO_ABSPATH, '', $folderList);
389 $command = 'cd ' . $path . '; zip -1 -db -r ' . $archiveFullPath . ' ' . $directories . ' > ' . $archiveOptions['stdOutFile'] . ' 2>' . $archiveOptions['stdErrFile'] . ' & echo $!;';
390 } else {
391 if (!$excludeHtaccess) {
392 $command = 'cd ' . $path . '; zip -1 -x "transferito/" "transferito/**" -db -r ' . $archiveFullPath . ' . > ' . $archiveOptions['stdOutFile'] . ' 2>' . $archiveOptions['stdErrFile'] . ' & echo $!;';
393 }
394
395 if ($excludeHtaccess) {
396 $command = 'cd ' . $path . '; zip -1 -x "transferito/" "transferito/**" "' . $this->htaccessFile . '" -db -r ' . $archiveFullPath . ' . > ' . $archiveOptions['stdOutFile'] . ' 2>' . $archiveOptions['stdErrFile'] . ' & echo $!;';
397 }
398 }
399
400 /**
401 * Get the PID
402 */
403 $pid = exec($command);
404
405 return [
406 'pid' => $pid,
407 'path' => $archiveFullPath,
408 'url' => TRANSFERITO_UPLOAD_URL . $archiveName
409 ];
410 }
411
412 private function createExecTarArchive(array $archiveOptions, $selectedFoldersEnabled, $folderPathArray = [])
413 {
414 $settings = get_option('transferito_settings_option');
415 $excludeHtaccess = !isset($settings['transferito_include_htaccess'])
416 ? true
417 : ($settings['transferito_include_htaccess'] === false);
418 $path = substr(TRANSFERITO_ABSPATH, 0, -1);
419 $baseDirectory = TRANSFERITO_ABSPATH;
420 $uploadPath = str_replace(TRANSFERITO_ABSPATH, '', TRANSFERITO_UPLOAD_PATH);
421 $paths = ($selectedFoldersEnabled) ? str_replace(TRANSFERITO_ABSPATH, '', implode(' ', $folderPathArray)) : './';
422 $exclude = ($excludeHtaccess) ? "--exclude={$uploadPath} --exclude={$this->htaccessFile}" : "--exclude={$uploadPath}";
423
424
425 $archiveName = DIRECTORY_SEPARATOR . $archiveOptions['filename'] . '.tar';
426 $codebasePath = 'transferito' . $archiveName;
427
428 /**
429 * Commands
430 */
431 $tarCommand = "cd {$path}; tar --xform s:'^./':: {$exclude} -cvf {$codebasePath} {$paths} > {$archiveOptions['stdOutFile']} 2>{$archiveOptions['stdErrFile']} & echo $!;";
432
433 /**
434 * Check if the background command can be run
435 * Then execute the full command - To create the archive
436 */
437 $pid = exec($tarCommand);
438
439 return [
440 'pid' => $pid,
441 'path' => $baseDirectory . $codebasePath,
442 'url' => TRANSFERITO_UPLOAD_URL . $archiveName
443 ];
444 }
445
446 private function pharDataExists() {
447 try {
448 $sampleTarFile = TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . 'sample.tar';
449 $tar = new \PharData($sampleTarFile);
450 } catch (\Exception $exception) {
451 throw new \Exception(esc_html($exception->getMessage()));
452 }
453 }
454
455 private function getRenameFileContents()
456 {
457
458 if (file_exists($this->renameFileJSON)) {
459 return json_decode(file_get_contents($this->renameFileJSON), true);
460 }
461
462 return array();
463 }
464
465 private function addToRenameFile($files)
466 {
467 file_put_contents($this->renameFileJSON, json_encode($files));
468 }
469 }
470