ZipBackup.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. namespace Grav\Common\Backup;
  3. use Grav\Common\GravTrait;
  4. use Grav\Common\Filesystem\Folder;
  5. use Grav\Common\Inflector;
  6. /**
  7. * The ZipBackup class lets you create simple zip-backups of a grav site
  8. *
  9. * @author RocketTheme
  10. * @license MIT
  11. */
  12. class ZipBackup
  13. {
  14. use GravTrait;
  15. protected static $ignorePaths = [
  16. 'backup',
  17. 'cache',
  18. 'images',
  19. 'logs'
  20. ];
  21. protected static $ignoreFolders = [
  22. '.git',
  23. '.svn',
  24. '.hg',
  25. '.idea'
  26. ];
  27. public static function backup($destination = null, callable $messager = null)
  28. {
  29. if (!$destination) {
  30. $destination = self::getGrav()['locator']->findResource('backup://', true);
  31. if (!$destination)
  32. throw new \RuntimeException('The backup folder is missing.');
  33. Folder::mkdir($destination);
  34. }
  35. $name = self::getGrav()['config']->get('site.title', basename(GRAV_ROOT));
  36. $inflector = new Inflector();
  37. if (is_dir($destination)) {
  38. $date = date('YmdHis', time());
  39. $filename = trim($inflector->hyphenize($name), '-') . '-' . $date . '.zip';
  40. $destination = rtrim($destination, DS) . DS . $filename;
  41. }
  42. $messager && $messager([
  43. 'type' => 'message',
  44. 'level' => 'info',
  45. 'message' => 'Creating new Backup "' . $destination . '"'
  46. ]);
  47. $messager && $messager([
  48. 'type' => 'message',
  49. 'level' => 'info',
  50. 'message' => ''
  51. ]);
  52. $zip = new \ZipArchive();
  53. $zip->open($destination, \ZipArchive::CREATE);
  54. static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager);
  55. $messager && $messager([
  56. 'type' => 'progress',
  57. 'percentage' => false,
  58. 'complete' => true
  59. ]);
  60. $messager && $messager([
  61. 'type' => 'message',
  62. 'level' => 'info',
  63. 'message' => ''
  64. ]);
  65. $messager && $messager([
  66. 'type' => 'message',
  67. 'level' => 'info',
  68. 'message' => 'Saving and compressing archive...'
  69. ]);
  70. $zip->close();
  71. return $destination;
  72. }
  73. /**
  74. * @param $folder
  75. * @param $zipFile
  76. * @param $exclusiveLength
  77. * @param $messager
  78. */
  79. private static function folderToZip($folder, \ZipArchive &$zipFile, $exclusiveLength, callable $messager = null)
  80. {
  81. $handle = opendir($folder);
  82. while (false !== $f = readdir($handle)) {
  83. if ($f != '.' && $f != '..') {
  84. $filePath = "$folder/$f";
  85. // Remove prefix from file path before add to zip.
  86. $localPath = substr($filePath, $exclusiveLength);
  87. if (in_array($f, static::$ignoreFolders)) {
  88. continue;
  89. } elseif (in_array($localPath, static::$ignorePaths)) {
  90. $zipFile->addEmptyDir($f);
  91. continue;
  92. }
  93. if (is_file($filePath)) {
  94. $zipFile->addFile($filePath, $localPath);
  95. $messager && $messager([
  96. 'type' => 'progress',
  97. 'percentage' => false,
  98. 'complete' => false
  99. ]);
  100. } elseif (is_dir($filePath)) {
  101. // Add sub-directory.
  102. $zipFile->addEmptyDir($localPath);
  103. static::folderToZip($filePath, $zipFile, $exclusiveLength, $messager);
  104. }
  105. }
  106. }
  107. closedir($handle);
  108. }
  109. }