Download Backup
Download and manage your WordPress backup files securely
Download Backup
Access and download your WordPress backup files securely. Choose from various download options and manage your backup archive effectively.
Download Options
Direct Browser Download
Single Backup Download
// Generate secure download link for backup
function generate_backup_download_link($backup_id, $expiration_hours = 24) {
// Verify user has permission to download
if (!current_user_can('manage_options')) {
return new WP_Error('insufficient_permissions', 'You do not have permission to download backups.');
}
// Get backup information
$backup_info = get_backup_info($backup_id);
if (!$backup_info) {
return new WP_Error('backup_not_found', 'Backup not found.');
}
// Generate secure token
$download_token = wp_generate_password(32, false);
$expires = time() + ($expiration_hours * 3600);
// Store download token temporarily
set_transient('backup_download_' . $download_token, array(
'backup_id' => $backup_id,
'backup_path' => $backup_info['path'],
'expires' => $expires,
'user_id' => get_current_user_id(),
'ip_address' => $_SERVER['REMOTE_ADDR']
), $expiration_hours * 3600);
// Generate download URL
$download_url = add_query_arg(array(
'action' => 'download_backup',
'token' => $download_token
), admin_url('admin-ajax.php'));
return array(
'url' => $download_url,
'expires' => $expires,
'filename' => basename($backup_info['path'])
);
}Handle Download Request
// Process backup download request
function handle_backup_download_request() {
$token = sanitize_text_field($_GET['token']);
if (empty($token)) {
wp_die('Invalid download request.');
}
// Get download information
$download_info = get_transient('backup_download_' . $token);
if (!$download_info) {
wp_die('Download link has expired or is invalid.');
}
// Security checks
if ($download_info['user_id'] !== get_current_user_id()) {
wp_die('You do not have permission to download this backup.');
}
if ($download_info['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
// Optional: Allow download from same IP range
$allowed_range = get_option('backup_download_ip_range', false);
if (!$allowed_range || !ip_in_range($_SERVER['REMOTE_ADDR'], $allowed_range)) {
wp_die('Download request must come from the same IP address.');
}
}
if (time() > $download_info['expires']) {
wp_die('Download link has expired.');
}
$backup_path = $download_info['backup_path'];
if (!file_exists($backup_path)) {
wp_die('Backup file not found.');
}
// Delete token after single use
delete_transient('backup_download_' . $token);
// Serve file for download
serve_backup_file($backup_path);
}
add_action('wp_ajax_download_backup', 'handle_backup_download_request');
add_action('wp_ajax_nopriv_download_backup', 'handle_backup_download_request');Batch Download
Multiple Backup Download
function create_batch_download($backup_ids) {
if (empty($backup_ids)) {
return new WP_Error('no_backups_selected', 'No backups selected for download.');
}
// Verify user permissions
if (!current_user_can('manage_options')) {
return new WP_Error('insufficient_permissions', 'You do not have permission to download backups.');
}
// Create temporary directory for batch
$batch_dir = WP_CONTENT_DIR . '/temp-batch-' . time();
wp_mkdir_p($batch_dir);
$included_backups = array();
// Copy selected backups to batch directory
foreach ($backup_ids as $backup_id) {
$backup_info = get_backup_info($backup_id);
if ($backup_info && file_exists($backup_info['path'])) {
$filename = basename($backup_info['path']);
copy($backup_info['path'], $batch_dir . '/' . $filename);
$included_backups[] = $filename;
}
}
if (empty($included_backups)) {
remove_directory_recursive($batch_dir);
return new WP_Error('no_valid_backups', 'No valid backups found for download.');
}
// Create batch archive
$batch_archive = create_batch_archive($batch_dir, $included_backups);
// Clean up temporary directory
remove_directory_recursive($batch_dir);
// Generate download link for batch archive
return generate_backup_download_link_for_file($batch_archive, 'batch_backup_' . date('Y-m-d-H-i-s') . '.zip');
}Create Batch Archive
function create_batch_archive($source_dir, $files) {
$archive_name = 'batch_backup_' . date('Y-m-d-H-i-s') . '.zip';
$archive_path = WP_CONTENT_DIR . '/temp-archives/' . $archive_name;
// Ensure archive directory exists
wp_mkdir_p(dirname($archive_path));
// Create ZIP archive
$zip = new ZipArchive();
if ($zip->open($archive_path, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
foreach ($files as $file) {
$file_path = $source_dir . '/' . $file;
if (file_exists($file_path)) {
$zip->addFile($file_path, $file);
}
}
$zip->close();
} else {
return new WP_Error('archive_creation_failed', 'Failed to create batch archive.');
}
return $archive_path;
}File Serving Functions
Serve Backup File
function serve_backup_file($file_path) {
if (!file_exists($file_path)) {
wp_die('Backup file not found.');
}
// Get file information
$file_name = basename($file_path);
$file_size = filesize($file_path);
$file_mime = mime_content_type($file_path);
// Set headers for download
header('Content-Type: ' . $file_mime);
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header('Content-Length: ' . $file_size);
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// Handle large files efficiently
if ($file_size > 10485760) { // 10MB
serve_large_file($file_path);
} else {
// Read and output file content
readfile($file_path);
}
exit;
}
function serve_large_file($file_path) {
$handle = fopen($file_path, 'rb');
if ($handle === false) {
wp_die('Unable to open backup file.');
}
// Output file in chunks to handle large files
$chunk_size = 8192; // 8KB chunks
while (!feof($handle)) {
echo fread($handle, $chunk_size);
flush(); // Flush output buffer
}
fclose($handle);
}Download Progress Tracking
function track_download_progress($file_path, $user_id) {
$file_size = filesize($file_path);
$download_id = md5($file_path . $user_id . time());
// Store download information
set_transient('download_progress_' . $download_id, array(
'file_path' => $file_path,
'file_size' => $file_size,
'user_id' => $user_id,
'start_time' => time(),
'bytes_sent' => 0
), 3600); // 1 hour expiration
return $download_id;
}
function update_download_progress($download_id, $bytes_sent) {
$progress_info = get_transient('download_progress_' . $download_id);
if ($progress_info) {
$progress_info['bytes_sent'] = $bytes_sent;
$progress_info['last_update'] = time();
set_transient('download_progress_' . $download_id, $progress_info, 3600);
}
}
function get_download_progress($download_id) {
$progress_info = get_transient('download_progress_' . $download_id);
if (!$progress_info) {
return null;
}
$percentage = ($progress_info['bytes_sent'] / $progress_info['file_size']) * 100;
$elapsed_time = time() - $progress_info['start_time'];
$speed = $elapsed_time > 0 ? $progress_info['bytes_sent'] / $elapsed_time : 0;
return array(
'percentage' => round($percentage, 2),
'bytes_sent' => $progress_info['bytes_sent'],
'total_bytes' => $progress_info['file_size'],
'speed_bps' => round($speed, 2),
'elapsed_time' => $elapsed_time
);
}Security Measures
Access Control
function verify_backup_download_permissions($backup_id, $user_id) {
// Check if user has permission to download backups
if (!current_user_can('manage_options')) {
return new WP_Error('insufficient_permissions', 'You do not have permission to download backups.');
}
// Check backup ownership
$backup_info = get_backup_info($backup_id);
if (!$backup_info) {
return new WP_Error('backup_not_found', 'Backup not found.');
}
// Check if backup is not too old (optional security measure)
$backup_age_days = (time() - filemtime($backup_info['path'])) / (60 * 60 * 24);
$max_age_days = get_option('backup_max_download_age', 30);
if ($backup_age_days > $max_age_days) {
return new WP_Error('backup_too_old', 'This backup is too old to download.');
}
return true;
}Rate Limiting
function check_download_rate_limit($user_id) {
$rate_limit_key = 'download_rate_limit_' . $user_id;
$current_usage = get_transient($rate_limit_key);
if (!$current_usage) {
$current_usage = array(
'count' => 0,
'reset_time' => time() + 3600 // 1 hour window
);
}
// Check if rate limit exceeded
$max_downloads_per_hour = get_option('max_downloads_per_hour', 10);
if ($current_usage['count'] >= $max_downloads_per_hour) {
return new WP_Error('rate_limit_exceeded', 'Download rate limit exceeded. Please try again later.');
}
// Update usage count
$current_usage['count']++;
set_transient($rate_limit_key, $current_usage, 3600);
return true;
}File Integrity Verification
function verify_backup_file_integrity($file_path) {
if (!file_exists($file_path)) {
return new WP_Error('file_not_found', 'Backup file not found.');
}
// Check file size
$file_size = filesize($file_path);
if ($file_size === 0) {
return new WP_Error('empty_file', 'Backup file is empty.');
}
// Check if file is readable
if (!is_readable($file_path)) {
return new WP_Error('file_not_readable', 'Backup file is not readable.');
}
// Verify file type based on extension
$file_extension = pathinfo($file_path, PATHINFO_EXTENSION);
$allowed_extensions = array('zip', 'tar', 'gz', 'sql', 'tar.gz');
if (!in_array($file_extension, $allowed_extensions)) {
return new WP_Error('invalid_file_type', 'Invalid backup file type.');
}
// Additional checks for compressed files
if (in_array($file_extension, array('zip', 'tar', 'gz', 'tar.gz'))) {
if (!is_backup_archive_valid($file_path)) {
return new WP_Error('corrupted_archive', 'Backup archive appears to be corrupted.');
}
}
return true;
}
function is_backup_archive_valid($file_path) {
$file_extension = pathinfo($file_path, PATHINFO_EXTENSION);
if ($file_extension === 'zip') {
$zip = new ZipArchive();
$result = $zip->open($file_path);
if ($result === true) {
$zip->close();
return true;
}
} elseif (in_array($file_extension, array('tar', 'gz', 'tar.gz'))) {
// For tar files, we can check if they're readable
$handle = fopen($file_path, 'rb');
if ($handle) {
$header = fread($handle, 512);
fclose($handle);
// Basic check for tar magic number
return strpos($header, 'ustar') !== false;
}
}
return false;
}Download Management
Download History
function log_backup_download($backup_id, $user_id, $download_method = 'direct') {
global $wpdb;
$log_data = array(
'backup_id' => $backup_id,
'user_id' => $user_id,
'download_method' => $download_method,
'download_time' => current_time('mysql'),
'ip_address' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT']
);
$wpdb->insert('backup_download_logs', $log_data);
// Update download count for backup
$backup_info = get_backup_info($backup_id);
if ($backup_info) {
update_backup_download_count($backup_id);
}
}
function update_backup_download_count($backup_id) {
$current_count = get_backup_download_count($backup_id);
update_option('backup_download_count_' . $backup_id, $current_count + 1);
}
function get_backup_download_count($backup_id) {
return get_option('backup_download_count_' . $backup_id, 0);
}Download Queue Management
class BackupDownloadQueue {
private $queue_option = 'backup_download_queue';
public function add_to_queue($backup_ids, $user_id) {
$queue = get_option($this->queue_option, array());
$queue_item = array(
'backup_ids' => $backup_ids,
'user_id' => $user_id,
'queued_time' => time(),
'status' => 'queued'
);
$queue[] = $queue_item;
update_option($this->queue_option, $queue);
return count($queue) - 1; // Return queue position
}
public function process_queue() {
$queue = get_option($this->queue_option, array());
if (empty($queue)) {
return;
}
// Process first item in queue
$queue_item = array_shift($queue);
if ($queue_item['status'] === 'queued') {
$this->process_download_request($queue_item);
}
update_option($this->queue_option, $queue);
}
private function process_download_request($queue_item) {
// Process the download request
$result = create_batch_download($queue_item['backup_ids']);
if (!is_wp_error($result)) {
// Send download link to user
send_download_link_email($queue_item['user_id'], $result);
}
}
}User Interface Enhancements
Download Dashboard Widget
function add_backup_download_widget() {
wp_add_dashboard_widget(
'backup_download_widget',
'Recent Backup Downloads',
'display_backup_download_widget'
);
}
function display_backup_download_widget() {
global $wpdb;
// Get recent downloads for current user
$recent_downloads = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM backup_download_logs
WHERE user_id = %d
ORDER BY download_time DESC
LIMIT 5",
get_current_user_id()
));
if (empty($recent_downloads)) {
echo '<p>No recent backup downloads.</p>';
return;
}
echo '<table class="widefat striped">';
echo '<thead><tr><th>Backup</th><th>Download Time</th><th>Method</th></tr></thead>';
echo '<tbody>';
foreach ($recent_downloads as $download) {
$backup_info = get_backup_info($download->backup_id);
$backup_name = $backup_info ? basename($backup_info['path']) : 'Unknown';
echo '<tr>';
echo '<td>' . esc_html($backup_name) . '</td>';
echo '<td>' . esc_html(date('M j, Y H:i', strtotime($download->download_time))) . '</td>';
echo '<td>' . esc_html(ucfirst($download->download_method)) . '</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
add_action('wp_dashboard_setup', 'add_backup_download_widget');Download Progress Indicator
function display_download_progress($download_id) {
$progress = get_download_progress($download_id);
if (!$progress) {
return '<p>Download not found or expired.</p>';
}
$progress_bar_width = $progress['percentage'] . '%';
ob_start();
?>
<div class="download-progress-container">
<div class="download-progress-bar">
<div class="download-progress-fill" style="width: <?php echo esc_attr($progress_bar_width); ?>">
<span class="download-progress-text">
<?php echo esc_html($progress['percentage']); ?>%
</span>
</div>
</div>
<div class="download-progress-info">
<span><?php echo size_format($progress['bytes_sent']); ?> of <?php echo size_format($progress['total_bytes']); ?></span>
<span><?php echo esc_html($progress['speed_bps']); ?> B/s</span>
</div>
</div>
<script>
// Auto-refresh progress every 2 seconds
setInterval(function() {
location.reload();
}, 2000);
</script>
<?php
return ob_get_clean();
}Best Practices
Security Best Practices
- Secure Tokens: Use cryptographically secure tokens for download links
- Expiration: Set reasonable expiration times for download links
- IP Validation: Validate downloads come from authorized IP addresses
- Rate Limiting: Implement download rate limiting to prevent abuse
- Audit Logging: Log all download activities for security monitoring
Performance Best Practices
- Chunked Downloads: Handle large files in chunks to prevent memory issues
- Resume Support: Allow downloads to resume if interrupted
- Progress Tracking: Provide real-time download progress feedback
- Queue Management: Process multiple downloads efficiently
- Bandwidth Control: Implement bandwidth throttling if needed
User Experience Best Practices
- Clear Instructions: Provide clear download instructions
- Progress Feedback: Show download progress and estimated time
- Error Handling: Handle download errors gracefully
- File Organization: Organize downloads by date and type
- Help Resources: Provide help for common download issues
Secure and efficient backup download management for WordPress.