/private/backupTenant.php

https://github.com/ciniki/core · PHP · 186 lines · 110 code · 13 blank · 63 comment · 28 complexity · 1494ff4321274381c935f8719519e938 MD5 · raw file

  1. <?php
  2. //
  3. // Description
  4. // -----------
  5. // This method will backup a tenant to the ciniki-backups folder
  6. //
  7. // Arguments
  8. // ---------
  9. // ciniki:
  10. // tnid: The ID of the tenant on the local side to check sync.
  11. //
  12. //
  13. function ciniki_core_backupTenant(&$ciniki, $tenant) {
  14. //
  15. // Check the backup directory exists
  16. //
  17. if( isset($ciniki['config']['ciniki.core']['zip_backup_dir']) ) {
  18. $zip_backup_dir = $ciniki['config']['ciniki.core']['zip_backup_dir'] . '/'
  19. . $tenant['uuid'][0] . '/' . $tenant['uuid'];
  20. } else {
  21. $zip_backup_dir = $ciniki['config']['ciniki.core']['backup_dir'] . '/'
  22. . $tenant['uuid'][0] . '/' . $tenant['uuid'];
  23. }
  24. if( isset($ciniki['config']['ciniki.core']['final_backup_dir']) ) {
  25. $final_backup_dir = $ciniki['config']['ciniki.core']['final_backup_dir'] . '/'
  26. . $tenant['uuid'][0] . '/' . $tenant['uuid'];
  27. }
  28. $tenant['backup_dir'] = $ciniki['config']['ciniki.core']['backup_dir'] . '/'
  29. . $tenant['uuid'][0] . '/' . $tenant['uuid'] . '/data';
  30. if( !file_exists($tenant['backup_dir']) ) {
  31. if( mkdir($tenant['backup_dir'], 0755, true) === false ) {
  32. return array('stat'=>'fail', 'err'=>array('code'=>'ciniki.core.9', 'msg'=>'Unable to create backup directory'));
  33. }
  34. }
  35. if( !file_exists($zip_backup_dir) ) {
  36. if( mkdir($zip_backup_dir, 0755, true) === false ) {
  37. return array('stat'=>'fail', 'err'=>array('code'=>'ciniki.core.10', 'msg'=>'Unable to create backup directory'));
  38. }
  39. }
  40. //
  41. // Get the list of modules for the tenant
  42. //
  43. $strsql = "SELECT package, module, flags "
  44. . "FROM ciniki_tenant_modules "
  45. . "WHERE tnid = '" . ciniki_core_dbQuote($ciniki, $tenant['id']) . "' "
  46. . "AND status > 0 "
  47. . "";
  48. $rc = ciniki_core_dbHashQuery($ciniki, $strsql, 'ciniki.tenants', 'module');
  49. if( $rc['stat'] != 'ok' ) {
  50. return $rc;
  51. }
  52. $modules = $rc['rows'];
  53. $skip_modules = array('ciniki.tenants',
  54. 'ciniki.calendars',
  55. 'ciniki.systemdocs',
  56. 'ciniki.cron',
  57. 'ciniki.newsaggregator',
  58. 'ciniki.mail',
  59. 'ciniki.filedepot',
  60. 'ciniki.services',
  61. );
  62. //
  63. // Backup the modules
  64. //
  65. foreach($modules as $mod) {
  66. if( in_array($mod['package'] . '.' . $mod['module'], $skip_modules) ) {
  67. continue;
  68. }
  69. /*
  70. //
  71. // Backup the objects in XML format first.
  72. // Check if there is a custom backup for this module, otherwise use the default backup.
  73. //
  74. $rc = ciniki_core_loadMethod($ciniki, $mod['package'], $mod['module'], 'private', 'backupTenantModuleObjects');
  75. if( $rc['stat'] == 'ok' ) {
  76. $fn = $rc['function_call'];
  77. $rc = $fn($ciniki, $tenant);
  78. if( $rc['stat'] != 'ok' ) {
  79. error_log('BACKUP-ERR[' . $tenant['name'] . ']: ' . $rc['err']['code'] . ' - ' . $rc['err']['msg']);
  80. }
  81. } else {
  82. //
  83. // Backup the module
  84. //
  85. $rc = ciniki_core_backupTenantModuleObjects($ciniki, $tenant, $mod['package'], $mod['module']);
  86. if( $rc['stat'] != 'ok' ) {
  87. error_log('BACKUP-ERR[' . $tenant['name'] . ']: ' . $rc['err']['code'] . ' - ' . $rc['err']['msg']);
  88. }
  89. }
  90. */
  91. //
  92. // Check if there is another backup script for the module to create a human readable backup
  93. //
  94. $rc = ciniki_core_loadMethod($ciniki, $mod['package'], $mod['module'], 'private', 'backupModule');
  95. if( $rc['stat'] == 'ok' ) {
  96. $fn = $mod['package'] . '_' . $mod['module'] . '_backupModule';
  97. $rc = $fn($ciniki, $tenant);
  98. if( $rc['stat'] != 'ok' ) {
  99. error_log('BACKUP-ERR[' . $tenant['name'] . ']: ' . $rc['err']['code'] . ' - ' . $rc['err']['msg']);
  100. }
  101. }
  102. }
  103. //
  104. // Close database connections
  105. //
  106. foreach($ciniki['databases'] as $db_name => $db) {
  107. if( isset($db['connection']) ) {
  108. mysqli_close($db['connection']);
  109. unset($ciniki['databases'][$db_name]['connection']);
  110. }
  111. }
  112. //
  113. // Create the zip file
  114. //
  115. date_default_timezone_set('UTC');
  116. $date = date('Ymd-Hi');
  117. $zip = new ZipArchive;
  118. if( $zip->open($zip_backup_dir . "/backup-$date.zip", ZipArchive::CREATE) === TRUE ) {
  119. $rc = ciniki_core_backupZipAddDir($ciniki, $zip, $tenant['backup_dir'], "/backup-$date");
  120. if( $rc['stat'] != 'ok' ) {
  121. return $rc;
  122. }
  123. $zip->close();
  124. } else {
  125. error_log($zip->getStatusString());
  126. error_log('BACKUP-ERR[' . $tenant['name'] . ']: Unable to create zip file: ' . $zip_backup_dir . '/backup.zip');
  127. }
  128. //
  129. // If there is a final spot for backups, then move the zip file
  130. // Note: Due to sshfs mount problems at rackspace, the following code was added to create backups on local storage and then copy via sftp.
  131. // In ciniki-api.ini setup final_backup_dir = ssh2.sftp://user:pass@ftpserver:22/fullpathtobackups
  132. // Must have libssh2-php installed as a package on server
  133. //
  134. if( isset($final_backup_dir) ) {
  135. if( !file_exists($final_backup_dir) ) {
  136. if( mkdir($final_backup_dir, 0755, true) === false ) {
  137. return array('stat'=>'fail', 'err'=>array('code'=>'ciniki.core.11', 'msg'=>'Unable to create backup directory: ' . $final_backup_dir));
  138. }
  139. }
  140. copy("$zip_backup_dir/backup-$date.zip", "$final_backup_dir/backup-$date.zip");
  141. unlink("$zip_backup_dir/backup-$date.zip");
  142. }
  143. $cur_date = $date;
  144. //
  145. // Clear old zip files
  146. //
  147. if( isset($final_backup_dir) ) {
  148. $zip_backup_dir = $final_backup_dir;
  149. }
  150. $dh = opendir($zip_backup_dir);
  151. $today = date('Ymd');
  152. $today_datetime = strtotime($today);
  153. while( ($file = readdir($dh)) !== false ) {
  154. if( $file == "backup-$cur_date.zip" ) {
  155. continue;
  156. }
  157. //
  158. // Clear other backups from the same day.
  159. //
  160. if( preg_match("/backup-$today-.*zip/", $file) ) {
  161. unlink($zip_backup_dir . '/' . $file);
  162. }
  163. if( preg_match("/backup-([0-9]+)-([0-9]+)/", $file, $matches) ) {
  164. $file_date = strtotime($matches[1]);
  165. if( ($today_datetime - $file_date) > 86000 ) {
  166. unlink($zip_backup_dir . '/' . $file);
  167. }
  168. }
  169. }
  170. closedir($dh);
  171. return array('stat'=>'ok');
  172. }
  173. ?>