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