4
0

backup-functions.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. trait BackupFunctions
  3. {
  4. public function getOrganizrBackupLocation()
  5. {
  6. $defaultPath = $this->config['dbLocation'] . 'backups' . DIRECTORY_SEPARATOR;
  7. $userPath = $this->config['backupLocation'];
  8. if ($this->config['backupLocation'] !== '') {
  9. if (file_exists($userPath)) {
  10. return $userPath;
  11. }
  12. }
  13. return $defaultPath;
  14. }
  15. public function fileArray($files)
  16. {
  17. foreach ($files as $file) {
  18. if (file_exists($file)) {
  19. $list[] = $file;
  20. }
  21. }
  22. if (!empty($list)) {
  23. return $list;
  24. }
  25. }
  26. public function deleteBackup($filename)
  27. {
  28. $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
  29. $path = $this->getOrganizrBackupLocation();
  30. $filename = $path . $filename;
  31. if ($ext == 'zip') {
  32. if (file_exists($filename)) {
  33. $this->setLoggerChannel('Backup')->info('Deleted Backup [' . pathinfo($filename, PATHINFO_BASENAME) . ']');
  34. $this->setAPIResponse(null, pathinfo($filename, PATHINFO_BASENAME) . ' has been deleted', null);
  35. return (unlink($filename));
  36. } else {
  37. $this->setAPIResponse('error', 'File does not exist', 404);
  38. return false;
  39. }
  40. } else {
  41. $this->setAPIResponse('error', pathinfo($filename, PATHINFO_BASENAME) . ' is not approved to be deleted', 409);
  42. return false;
  43. }
  44. }
  45. public function downloadBackup($filename)
  46. {
  47. $path = $this->getOrganizrBackupLocation();
  48. $filename = $path . $filename;
  49. if (file_exists($filename)) {
  50. header('Content-Type: application/zip');
  51. header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
  52. header('Content-Length: ' . filesize($filename));
  53. flush();
  54. readfile($filename);
  55. exit();
  56. } else {
  57. $this->setAPIResponse('error', 'File does not exist', 404);
  58. return false;
  59. }
  60. }
  61. public function backupOrganizr($type = 'config')
  62. {
  63. $directory = $this->getOrganizrBackupLocation();
  64. @mkdir($directory, 0770, true);
  65. switch ($type) {
  66. case 'config':
  67. break;
  68. case 'full':
  69. break;
  70. default:
  71. }
  72. $this->setLoggerChannel('Backup')->notice('Backing up Organizr');
  73. $zipName = $directory . 'backup[' . date('Y-m-d_H-i') . ' - ' . $this->random_ascii_string(2) . '][' . $this->version . '].zip';
  74. $zip = new ZipArchive;
  75. $zip->open($zipName, ZipArchive::CREATE);
  76. if ($this->config['driver'] == 'sqlite3') {
  77. $zip->addFile($this->config['dbLocation'] . $this->config['dbName'], basename($this->config['dbLocation'] . $this->config['dbName']));
  78. }
  79. $rootPath = $this->root . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR;
  80. $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
  81. foreach ($files as $name => $file) {
  82. // Skip directories (they would be added automatically)
  83. if (!$file->isDir()) {
  84. if (!stripos($name, 'data' . DIRECTORY_SEPARATOR . 'cache') && !stripos($name, 'backups')) {
  85. // Get real and relative path for current file
  86. $filePath = $file->getRealPath();
  87. $relativePath = substr($filePath, strlen($rootPath));
  88. // Add current file to archive
  89. $zip->addFile($filePath, $relativePath);
  90. }
  91. }
  92. }
  93. $zip->close();
  94. $this->setLoggerChannel('Backup')->notice('Backup process finished');
  95. $this->setAPIResponse('success', 'Backup has been created', 200);
  96. $this->deleteBackupsLimit();
  97. return true;
  98. }
  99. public function deleteBackupsLimit()
  100. {
  101. $backups = $this->getBackups();
  102. if ($backups) {
  103. $list = array_reverse($backups['files']);
  104. $killCount = count($list) - $this->config['keepBackupsCountCron'];
  105. if ($killCount >= 1) {
  106. foreach ($list as $count => $backup) {
  107. $count++;
  108. if ($count <= $killCount) {
  109. $this->log('Cron')->notice('Deleting organizr backup file as it is over limit', ['file' => $backup['name']]);
  110. $this->deleteBackup($backup['name']);
  111. }
  112. }
  113. }
  114. }
  115. return true;
  116. }
  117. public function getBackups()
  118. {
  119. $path = $this->getOrganizrBackupLocation();
  120. @mkdir($path, 0770, true);
  121. $files = array_diff(scandir($path), array('.', '..'));
  122. $fileList = [];
  123. $totalFiles = 0;
  124. $totalFileSize = 0;
  125. foreach ($files as $file) {
  126. $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
  127. if (file_exists($path . $file) && $ext == 'zip') {
  128. $size = filesize($path . $file);
  129. $totalFileSize = $totalFileSize + $size;
  130. $totalFiles = $totalFiles + 1;
  131. try {
  132. $fileList['files'][] = [
  133. 'name' => $file,
  134. 'size' => $this->human_filesize($size, 0),
  135. 'date' => gmdate("Y-m-d\TH:i:s\Z", (filemtime($path . $file)))
  136. ];
  137. } catch (Exception $e) {
  138. $this->setAPIResponse('error', 'Backup list failed', 409, $e->getMessage());
  139. return false;
  140. }
  141. }
  142. }
  143. $fileList['total_files'] = $totalFiles;
  144. $fileList['total_size'] = $this->human_filesize($totalFileSize, 2);
  145. $fileList['files'] = $totalFiles > 0 ? array_reverse($fileList['files']) : null;
  146. $this->setAPIResponse('success', null, 200, array_reverse($fileList));
  147. return array_reverse($fileList);
  148. }
  149. }