array( 'type_name' => t('Server Directory'), 'description' => t('Save the backup files to any directory on the server which the web-server can write to.'), 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.file.inc', 'save_callback' => 'backup_migrate_destination_file_save', 'load_callback' => 'backup_migrate_destination_file_load', 'list_callback' => 'backup_migrate_destination_files_list', 'delete_callback' => 'backup_migrate_destination_file_delete', 'conf_callback' => 'backup_migrate_destination_file_conf', 'ops' => array('scheduled backup', 'manual backup', 'restore', 'list files') ), 'browser' => array( 'type_name' => t('Browser Upload/Download'), 'description' => t('Save the backup files to the browser (download) or upload via a form.'), 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.browser.inc', 'save_callback' => 'backup_migrate_destination_browser_save', 'load_callback' => 'backup_migrate_destination_browser_load', 'ops' => array('manual backup', 'restore') ), 'email' => array( 'type_name' => t('Email'), 'description' => t('Send the backup as an email attachment to the specified email address.'), 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.email.inc', 'save_callback' => 'backup_migrate_destination_email_save', 'conf_callback' => 'backup_migrate_destination_email_conf', 'ops' => array('manual backup', 'scheduled backup') ), 'db' => array( 'type_name' => t('Database'), 'description' => t('Import the dump directly into another MySQL database.'), 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.db.inc', 'save_callback' => 'backup_migrate_destination_db_save', 'conf_callback' => 'backup_migrate_destination_db_conf', 'ops' => array('source', 'manual backup', 'scheduled backup') ), ); } /** * Get all the available backup destination. * * @param $op * The operation which will be performed on the destination. Hooks can use this * to return only those destinations appropriate for the given op. * Options include: * 'manual backup' - destinations available for manual backup * 'scheduled backup' - destinations available for schedules backup * 'list files' - destinations whose backup files can be listed * 'restore' - destinations whose files can be restored from * 'all' - all available destinations should be returned */ function backup_migrate_get_destinations($op = 'all') { static $destinations = NULL; // Get the list of destinations and cache them locally. if ($destinations === NULL) { $types = backup_migrate_get_destination_types(); $all_destinations = module_invoke_all('backup_migrate_destinations'); // Merge any type specific info such as callbacks and defaults. foreach ($all_destinations as $destination) { if ($destination['type'] && isset($types[$destination['type']])) { $destination = array_merge($types[$destination['type']], $destination); } // Parse the location in case that's needed $parts = _backup_migrate_destination_parse_url($destination['location']); $destinations[$destination['destination_id']] = $destination + $parts; } } if ($op == 'all') { return $destinations; } $out = array(); foreach ($destinations as $key => $destination) { if (in_array($op, (array)$destination['ops'])) { $out[$key] = $destination; } } return $out; } /** * Implementation of hook_backup_migrate_destinations(). * * Get the built in backup destinations and those in the db. */ function backup_migrate_backup_migrate_destinations() { require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/destinations.file.inc'; $out = array(); // Upload is scheduled backup only. $out[] = array( 'destination_id' => 'upload', 'name' => t("Upload"), 'type' => 'browser', 'ops' => array('restore'), ); // Download is manual backup only. $out[] = array( 'destination_id' => 'download', 'name' => t("Download"), 'type' => 'browser', 'ops' => array('manual backup'), ); // Expose the configured databases as sources. global $db_url; $urls = is_array($db_url) ? $db_url : array('default' => $db_url); foreach ((array)$urls as $key => $url) { $url_parts = _backup_migrate_destination_parse_url($url); $location = _backup_migrate_destination_glue_url($url_parts); $out[] = array( 'destination_id' => 'db_url:'.$key, 'name' => ($key == 'default' ? t("Default Database") : ($key .": ". $location)), 'type' => 'db', 'location' => $location, 'password' => $url_parts['pass'], 'conf_callback' => '', 'ops' => array('source'), ); } // Manual backup only destinations if ($location = _backup_migrate_check_destination_dir('manual')) { $out[] = array( 'destination_id' => 'manual', 'name' => $op == 'manual backup' ? t("Save to Files Directory") : t("Manual Backups Directory"), 'type_name' => t('Manual File Directory'), 'location' => $location, 'save_callback' => 'backup_migrate_destination_file_save', 'load_callback' => 'backup_migrate_destination_file_load', 'list_callback' => 'backup_migrate_destination_files_list', 'delete_callback' => 'backup_migrate_destination_file_delete', 'ops' => array('manual backup', 'restore', 'list files'), ); } // Schedule backup only destinations if ($location = _backup_migrate_check_destination_dir('scheduled')) { $out[] = array( 'destination_id' => 'scheduled', 'name' => $op == 'scheduled backup' ? t("Save to Files Directory") : t("Scheduled Backups Directory"), 'type_name' => t('Scheduled File Directory'), 'location' => $location, 'save_callback' => 'backup_migrate_destination_file_save', 'load_callback' => 'backup_migrate_destination_file_load', 'list_callback' => 'backup_migrate_destination_files_list', 'delete_callback' => 'backup_migrate_destination_file_delete', 'ops' => array('scheduled backup', 'restore', 'list files'), ); } // Get the saved destinations $result = db_query('SELECT * FROM {backup_migrate_destinations}'); while ($destination = db_fetch_array($result)) { $destination['settings'] = unserialize($destination['settings']); $destination['db'] = TRUE; $out[] = $destination; } return $out; } /** * Get the destination info for the destination with the given ID, or NULL if none exists. */ function backup_migrate_get_destination($destination_id) { $destinations = backup_migrate_get_destinations('all'); return @$destinations[$destination_id]; } /** * Get a list of the backup files in the given destination. */ function backup_migrate_destination_get_files($destination) { if ($destination) { // Include the necessary file if specified by the download type. if (!empty($destination['file'])) { require_once './'. $destination['file']; } // Call the specified download callback. if (!empty($destination['list_callback'])) { return $destination['list_callback']($destination); } } return array(); } /** * Load a file from a destination and return the file info. */ function backup_migrate_destination_get_file($destination_id, $file_id) { if ($destination = backup_migrate_get_destination($destination_id)) { // Include the necessary file if specified by the download type. if (!empty($destination['file'])) { require_once './'. $destination['file']; } // Call the specified load callback. if (!empty($destination['load_callback'])) { return $destination['load_callback']($destination, $file_id); } } return NULL; } /** * Send a file to the destination specified by the settings array. */ function backup_migrate_destination_save_file($file, &$settings) { if ($destination = backup_migrate_get_destination($settings['destination_id'])) { $settings['destination'] = $destination; // Include the necessary file if specified by the download type. if (!empty($destination['file'])) { require_once './'. $destination['file']; } // Call the specified download callback. if (!empty($destination['save_callback'])) { $settings['file_id'] = $settings['filename']; $file = $destination['save_callback']($destination, $file, $settings); return $file; } } return NULL; } /** * Delete a file in the given destination. */ function backup_migrate_destination_delete_file($destination_id, $file_id) { if ($destination = backup_migrate_get_destination($destination_id)) { // Include the necessary file if specified by the download type. if (!empty($destination['file'])) { require_once './'. $destination['file']; } // Call the specified delete callback. if (!empty($destination['delete_callback'])) { return $destination['delete_callback']($destination, $file_id); } } } /** * Save an existing destination, or create a new one with the given values. */ function backup_migrate_destination_save_destination(&$destination) { // Any extra settings get serialized into the settings variable. $settings = serialize($destination['settings']); if ($destination['destination_id']) { db_query("UPDATE {backup_migrate_destinations} SET name = '%s', type = '%s', location = '%s', username = '%s', password = '%s', settings = '%s' WHERE destination_id = %d", $destination['name'], $destination['type'], $destination['location'], $destination['username'], $destination['password'], $settings, $destination['destination_id'] ); _backup_migrate_message('Backup destination updated: %dest', array('%dest' => $destination['name'])); } else { $destination['destination_id'] = db_next_id('{backup_migrate_destinations}_destination_id'); db_query("INSERT INTO {backup_migrate_destinations} (name, type , location, username, password, settings, destination_id) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', %d)", $destination['name'], $destination['type'], $destination['location'], $destination['username'], $destination['password'], $settings, $destination['destination_id'] ); _backup_migrate_message('Backup destination created: %dest', array('%dest' => $destination['name'])); } } /** * Delete a destination from the database. */ function backup_migrate_destination_delete_destination($destination_id) { $destination = backup_migrate_get_destination($destination_id); if ($destination && $destination['db']) { db_query("DELETE FROM {backup_migrate_destinations} WHERE destination_id = %d", $destination_id); _backup_migrate_message('Backup destination deleted: %dest', array('%dest' => $destination['name'])); } } /* UI Menu Callbacks */ /** * List the available backup destinations destination in the UI. */ function backup_migrate_ui_destination_display_destinations() { $out = array(); foreach (backup_migrate_get_destinations('all') as $destination_id => $destination) { $links = _backup_migrate_destination_get_links($destination_id); // If there's nothing that can be done with this destination, don't show it. if ($links) { $out[] = array( check_plain($destination['name']), $destination['type_name'], check_plain($destination['location']), implode(" | ", $links), ); } } $headers = array( t('Name'), t('Type'), t('Location'), t('Operations'), ); return theme("table", $headers, $out) . l(t("Create new destination..."), 'admin/content/backup_migrate/destination/add'); } /** * List the backup files in the given destination. */ function backup_migrate_ui_destination_display_files($destination_id) { $out = $sort = array(); if ($destination = backup_migrate_get_destination($destination_id)) { $headers = array( array('data' => 'Filename', 'field' => 'filename'), array('data' => 'Last Modified', 'field' => 'filemtime'), array('data' => 'Size', 'field' => 'filesize'), t('Operations'), ); $sort_order = tablesort_get_order($headers); $sort_key = $sort_order['sql'] ? $sort_order['sql'] : 'filename'; $sort_dir = tablesort_get_sort($headers) == 'asc' ? SORT_ASC : SORT_DESC; $files = backup_migrate_destination_get_files($destination); // Don't display the download/delete/restore ops if they are not available for this destination. $can_read = !empty($destination['load_callback']); $can_delete = !empty($destination['delete_callback']); $i = 0; foreach ((array)$files as $info) { $sort[] = $info[$sort_key]; $out[] = array( check_plain($info['filename']), format_date($info['filemtime'], 'small'), format_size($info['filesize']), implode(" | ", _backup_migrate_destination_get_file_links($destination_id, $info['file_id'])), ); } array_multisort($sort, $sort_dir, $out); if ($out) { return theme("table", $headers, $out); } else { return t('There are no backup files to display.'); } } drupal_goto("admin/content/backup_migrate/destination"); } /** * Get a form to create a destination, or links for the available types. */ function backup_migrate_ui_destination_create($type = NULL) { $types = backup_migrate_get_destination_types(); // If a valid type has been specified, present a form if (isset($types[$type])) { $destination = array('type' => $type, 'name' => t("Untitled Destination")) + $types[$type]; $output = drupal_get_form('backup_migrate_ui_destination_configure_form', $destination); } else { $items = array(); // If no (valid) node type has been provided, display a node type overview. foreach ($types as $key => $type) { if ($type['conf_callback']) { $type_url_str = str_replace('_', '-', $key); $out = '