t('Backup and Migrate makes the task of backing up your Drupal database and migrating data from one Drupal install to another easier. It provides a function to backup the entire database to file or download, and to restore from a previous backup. You can also schedule the backup operation. Compression of backup files is also supported.'), ), 'admin/content/backup_migrate' => array( 'title' => t('Backup Tab'), 'body' => t('Use this form to run manual backups of your database. You can fill out the fields below, or if you have any settings profiles saved you can load one. The backup files created can be imported into this or any other Drupal installation with the restore feature, or you can use a database tool such as phpMyAdmin or the mysql command line command.', array("!profileurl" => url('admin/content/backup_migrate/profile'), '!restoreurl' => url('admin/content/backup_migrate/restore'), '!phpmyadminurl' => 'http://www.phpmyadmin.net')), ), 'admin/content/backup_migrate/restore' => array( 'title' => t('Restore Tab'), 'body' => t('Use this form to upload a previously created backup file. You must make sure that your php settings allow for uploads of the size of your backip file. Compressed backups will be automatically decompressed as long as their file extensions have not been changed. The restore function will not work with databse dumps from other sources such as phpMyAdmin.'), ), 'admin/content/backup_migrate/destination' => array( 'title' => t('Destinations'), 'body' => t('Destinations are the places you can save your backup files. Files can be saved to a directory on your web server, downloaded to your desktop or emailed to a specified email account. Other modules may enable other destination types. From the Destinations tab you can create, delete and edit destinations or list the files which have already been backed up to the available destinations.'), ), 'admin/content/backup_migrate/profile' => array( 'title' => t('Profiles'), 'body' => t('Profiles are saved backup settings. Profiles store your table exclusion settings as well as your backup file name, compression and timestamp settings. You can use profiles in schedules and for manual backups.', array("!scheduleurl" => url('admin/content/backup_migrate/schedule'), '!manualurl' => url('admin/content/backup_migrate'))), ), 'admin/content/backup_migrate/schedule' => array( 'title' => t('Scheduling'), 'body' => t('You can specify schedules on which your database will be automatically backed up. Schedules are run by cron, and each schedule will run a maximum of once per cron run, so they will not run more frequently than your cron is configured to run. If you specify a number of backups to keep for a schedule, old backups will be deleted as new ones created. If specifiy a number of files to keep other backup files in that schedule\'s destination will get deleted.', array('!cronurl' => 'http://drupal.org/cron')), ), ); if (isset($help[$section])) { return $help[$section]['body']; } if ($section == 'admin/help#backup_migrate') { $out = ""; foreach ($help as $key => $section) { if ($section['title']) { if (!is_numeric($key)) { $section['title'] = l($section['title'], $key); } $out .= "
". $section['body'] ."
"; } return $out; } } /** * Implementation of hook_menu(). */ function backup_migrate_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/content/backup_migrate', 'title' => t('Backup and Migrate'), 'description' => t('Backup/restore your database or migrate data to or from another Drupal site.'), 'callback' => 'backup_migrate_ui_manual_backup', 'access' => user_access('perform backup'), 'type' => MENU_NORMAL_ITEM, ); $items[] = array( 'path' => 'admin/content/backup_migrate/export', 'title' => t('Backup'), 'description' => t('Backup the database.'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('', 'backup_migrate_ui_manual_backup', TRUE), 'access' => user_access('perform backup'), 'weight' => 0, 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/restore', 'title' => t('Restore'), 'description' => t('Restore the database from a previous backup'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('', 'backup_migrate_ui_manual_restore', TRUE), 'access' => user_access('restore from backup'), 'weight' => 1, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination', 'title' => t('Destinations'), 'description' => t('List the available backup destinations.'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_display_destinations', TRUE), 'access' => user_access('access backup files'), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/list', 'title' => t('List Destinations'), 'weight' => 1, 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/add', 'title' => t('Create Destination'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_create', TRUE), 'access' => user_access('administer backup and migrate'), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/files', 'title' => t('Destination Files'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_display_files', TRUE), 'access' => user_access('access backup files'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/delete', 'title' => t('Delete Destination'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_delete_destination', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/configure', 'title' => t('Configure Destination'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_configure', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/deletefile', 'title' => t('Delete File'), 'description' => t('Delete a backup file'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_delete_file', TRUE), 'access' => user_access('delete backup files'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/restorefile', 'title' => t('Restore from backup'), 'description' => t('Restore database from a backup file on the server'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_restore_file', TRUE), 'access' => user_access('restore from backup'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/destination/downloadfile', 'title' => t('Download File'), 'description' => t('Download a backup file'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('destinations', 'backup_migrate_ui_destination_download_file', TRUE), 'access' => user_access('access backup files'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/schedule', 'title' => t('Schedule'), 'description' => t('View existing schedules'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('schedules', 'backup_migrate_ui_schedule_display_schedules', TRUE), 'access' => user_access('administer backup and migrate'), 'weight' => 3, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/schedule/list', 'title' => t('Schedule List'), 'weight' => 1, 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/schedule/add', 'title' => t('Create Schedule'), 'description' => t('View existing schedules'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('schedules', 'backup_migrate_ui_schedule_create', TRUE), 'access' => user_access('administer backup and migrate'), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/schedule/delete', 'title' => t('Delete Schedule'), 'description' => t('View existing schedules'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('schedules', 'backup_migrate_ui_schedule_delete', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/schedule/configure', 'title' => t('Edit Schedule'), 'description' => t('View existing schedules'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('schedules', 'backup_migrate_ui_schedule_configure', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/profile', 'title' => t('Profiles'), 'description' => t('View existing profiles'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('profiles', 'backup_migrate_ui_profile_display_profiles', TRUE), 'access' => user_access('administer backup and migrate'), 'weight' => 3, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/profile/list', 'title' => t('Profile List'), 'weight' => 1, 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/profile/add', 'title' => t('Create Profile'), 'description' => t('View existing profiles'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('profiles', 'backup_migrate_ui_profile_create', TRUE), 'access' => user_access('administer backup and migrate'), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/profile/delete', 'title' => t('Delete Profile'), 'description' => t('View existing profiles'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('profiles', 'backup_migrate_ui_profile_delete', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/content/backup_migrate/profile/configure', 'title' => t('Edit Profile'), 'description' => t('View existing profiles'), 'callback' => 'backup_migrate_menu_callback', 'callback arguments' => array('profiles', 'backup_migrate_ui_profile_configure', TRUE), 'access' => user_access('administer backup and migrate'), 'type' => MENU_CALLBACK, ); } return $items; } /** * Implementation of hook_cron(). * * Takes care of scheduled backups and deletes abandoned temp files. */ function backup_migrate_cron() { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/schedules.inc'; backup_migrate_schedules_run(); // Delete temp files abandoned for 6 or more hours. foreach (file_scan_directory(file_directory_temp(), 'backup_migrate_*', array('.', '..'), 0, FALSE) as $file) { if (filectime($file->filename) < time() - 21600) { unlink($file->filename); } } } /** * Implementation of hook_exit(). */ function backup_migrate_exit() { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc'; // Delete any temporary files generated during this execution. backup_migrate_temp_file('', TRUE); } /** * Implementation of hook_perm(). */ function backup_migrate_perm() { return array('perform backup', 'access backup files', 'delete backup files', 'restore from backup', 'administer backup and migrate'); } /** * Implementation of hook_simpletest(). */ function backup_migrate_simpletest() { $dir = drupal_get_path('module', 'backup_migrate') .'/tests'; $tests = file_scan_directory($dir, '\.test$'); return array_keys($tests); } /* Menu Callbacks */ /** * A menu callback helper. Handles file includes and interactivity setting. */ function backup_migrate_menu_callback($include, $function, $interactive = TRUE) { if ($include) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/'. $include .'.inc'; } _backup_migrate_interactive($interactive); // Get the arguments with the first 3 removed. $args = array_slice(func_get_args(), 3); return call_user_func_array($function, $args); } /** * The menu call back for manual backups. */ function backup_migrate_ui_manual_backup($profile_id = NULL) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/profiles.inc'; $profile = _backup_migrate_profile_saved_default_profile($profile_id); $out = ""; $out .= drupal_get_form('backup_migrate_ui_manual_backup_load_profile_form', $profile); $out .= drupal_get_form('backup_migrate_ui_manual_backup_form', $profile); return $out; } /** * The backup/export load profile form. */ function backup_migrate_ui_manual_backup_load_profile_form($profile = NULL) { $form = array(); $profile_options = _backup_migrate_get_profile_form_item_options(); if (count($profile_options) > 0) { $profile_options = array(0 => t('-- Select a Profile --')) + $profile_options; $form['profile'] = array( "#title" => t("Settings Profile"), "#collapsible" => TRUE, "#collapsed" => FALSE, "#prefix" => 'This will delete some or all of your data and cannot be undone. If there is a sessions table in the backup file, you and all other currently logged in users will be logged out. Always test your backups on a non-production server!
'), ); $form[] = array( '#type' => 'submit', '#value' => t('Restore Database'), ); if (user_access('access backup files')) { $form[] = array( '#type' => 'markup', '#value' => t('
Or you can restore one of the files in your saved backup destinations.
', array("!url" => url("admin/content/backup_migrate/destination"))), ); } $form['#attributes'] = array('enctype' => 'multipart/form-data'); return $form; } /** * The restore submit. Do the restore. */ function backup_migrate_ui_manual_restore_form_submit($form_id, $form_values) { if ($file = file_check_upload('backup_migrate_restore_upload')) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/destinations.inc'; backup_migrate_perform_restore('upload', $file->filepath); } return 'admin/content/backup_migrate/restore'; } /** * Perform a backup with the given settings. */ function backup_migrate_perform_backup(&$settings) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/destinations.inc'; require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc'; require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/db.inc'; // If not in 'safe mode', increase the maximum execution time: if (!ini_get('safe_mode') && ini_get('max_execution_time') < 600) { set_time_limit(600); } if ($settings['append_timestamp'] && $settings['timestamp_format']) { $settings['filename'] .= "-". date($settings['timestamp_format']); } $settings['filename'] = _backup_migrate_clean_filename($settings['filename']); $source = backup_migrate_get_destination($settings['source_id']); if (!$source) { _backup_migrate_message("Could not run backup because the source '%source' is missing.", array('%source' => $settings['source_id']), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } $file = backup_migrate_temp_file('sql'); if (!$file) { _backup_migrate_message("Could not run backup because a temporary file could not be created.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } $file = backup_migrate_db_backup($source, $file, $settings); if (!$file) { _backup_migrate_message("Could not backup the database.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } $file = backup_migrate_file_compress($file, $settings); if (!$file) { _backup_migrate_message("Could not run backup because the backup file could not be compressed.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } $file = backup_migrate_destination_save_file($file, $settings); if (!$file) { _backup_migrate_message("Could not run backup because the file could not be saved to the destination.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } // Delete any temporary files we've created. backup_migrate_temp_file("", TRUE); return $file; } /** * Restore from a file in the given destination. */ function backup_migrate_perform_restore($destination_id, $file_id) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc'; // If not in 'safe mode', increase the maximum execution time: if (!ini_get('safe_mode') && ini_get('max_execution_time') < 600) { set_time_limit(600); } // Load the file from the destination. $file = backup_migrate_destination_get_file($destination_id, $file_id); if (!$file) { _backup_migrate_message("Could not restore because the file could not be loaded from the destination.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } $file = backup_migrate_perform_restore_file($file); if (!$file) { _backup_migrate_message("Could not restore the database.", array(), 'error'); backup_migrate_temp_file("", TRUE); return FALSE; } return $file; } /** * Restore from a file in the given destination. */ function backup_migrate_perform_restore_file($file) { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc'; require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/db.inc'; // If not in 'safe mode', increase the maximum execution time: if (!ini_get('safe_mode') && ini_get('max_execution_time') < 600) { set_time_limit(600); } $filename = $file['filename']; if ($file) { $file = backup_migrate_file_decompress($file); } if ($file) { $num = backup_migrate_db_restore($file); } $destination = backup_migrate_get_destination($destination_id); $message = 'Database restored from %destination file %file. %num SQL commands executed.'; if ($destination && in_array('list files', $destination['ops'])) { $message .= ' (Restore again...)'; } _backup_migrate_message($message, array("%destination" => $destination['name'], "%num" => $num, '%file' => $filename, '!restoreurl' => url('admin/content/backup_migrate/destination/restorefile/'.$destination_id."/".$file_id))); // Delete any temp files we've created. backup_migrate_temp_file("", TRUE); return $file; } /* Actions/Workflow integration */ /** * Action to backup the drupal site. Requires actions.module. */ function action_backup_migrate_backup($op, $edit = array()) { switch ($op) { case 'do': _backup_migrate_backup_with_defaults(); watchdog('action', t('Backed up database')); break; case 'metadata': return array( 'description' => t('Backup the database with the default settings'), 'type' => t('Backup and Migrate'), 'batchable' => TRUE, 'configurable' => FALSE, ); // Return an HTML config form for the action. case 'form': return ''; // Validate the HTML form. case 'validate': return TRUE; // Process the HTML form to store configuration. case 'submit': return ''; } } /* * Implementation of hook_action_info(). */ function backup_migrate_action_info() { return array( 'backup_migrate_action_backup' => array( '#label' => t('Backup the database'), '#module' => t('Backup and Migrate'), '#description' => t('Backup the database with the default settings.'), ), ); } /* * Action callback. */ function backup_migrate_action_backup() { _backup_migrate_backup_with_defaults(); } /* Utilities */ /** * Backup the database with the default settings. */ function _backup_migrate_backup_with_defaults($destination_id = "manual") { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc'; require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/db.inc'; $settings = _backup_migrate_profile_saved_default_profile(); $settings['destination_id'] = $destination_id; backup_migrate_perform_backup($settings); } /** * Helper function to set a drupal message and watchdog message depending on whether the module is being run interactively. */ function _backup_migrate_message($message, $replace = array(), $type = 'status') { // Only set a message if the module is being run interactively if (_backup_migrate_interactive()) { drupal_set_message(t($message, $replace), $type); } watchdog('backup_migrate', t($message, $replace), $type == 'error' ? WATCHDOG_ERROR : WATCHDOG_NOTICE); } /** * Status function which stores whether the module is being run interactively (via form submits) * or non-iteractively (cron, actions, etc.) */ function _backup_migrate_interactive($interactive = NULL) { static $is_interactive = NULL; if ($interactive !== NULL) { $is_interactive = $interactive; } return $is_interactive; }