NOXSHELL
Server: nginx/1.26.3
System: Linux vultr 6.8.0-54-generic #56-Ubuntu SMP PREEMPT_DYNAMIC Sat Feb 8 00:37:57 UTC 2025 x86_64
User: gisha-group (1019)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/gisha985666/htdocs/BackupSystem/wp_backup.py
#!/usr/bin/env python3

import os
import sys
import zipfile
import shutil
import subprocess
import logging
import json
from datetime import datetime
from pathlib import Path
import configparser

try:
    from googleapiclient.discovery import build
    from googleapiclient.http import MediaFileUpload
    from google.oauth2.service_account import Credentials
except ImportError:
    print("Error: Google API client libraries not installed.")
    print("Run: pip install google-api-python-client google-auth")
    sys.exit(1)

class WordPressBackup:
    def __init__(self, config_file='config.ini'):
        self.config = configparser.ConfigParser()
        self.config.read(config_file)
        
        # Setup logging
        log_level = self.config.get('general', 'log_level', fallback='INFO')
        logging.basicConfig(
            level=getattr(logging, log_level),
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('wp_backup.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
        
        # Configuration
        self.wp_path = self.config.get('wordpress', 'wp_path')
        self.backup_dir = self.config.get('general', 'backup_dir', fallback='/tmp/wp_backups')
        self.keep_local_files = self.config.getboolean('general', 'keep_local_files', fallback=False)
        
        # Database config
        self.db_host = self.config.get('database', 'host')
        self.db_name = self.config.get('database', 'name')
        self.db_user = self.config.get('database', 'user')
        self.db_password = self.config.get('database', 'password')
        
        # Google Drive config
        self.credentials_file = self.config.get('google_drive', 'credentials_file')
        self.drive_folder_id = self.config.get('google_drive', 'folder_id', fallback=None)
        
        # Ensure backup directory exists
        Path(self.backup_dir).mkdir(parents=True, exist_ok=True)
        
        # Initialize Google Drive service
        self.drive_service = self._init_drive_service()
    
    def _init_drive_service(self):
        """Initialize Google Drive API service"""
        try:
            credentials = Credentials.from_service_account_file(
                self.credentials_file,
                scopes=['https://www.googleapis.com/auth/drive.file']
            )
            return build('drive', 'v3', credentials=credentials)
        except Exception as e:
            self.logger.error(f"Failed to initialize Google Drive service: {e}")
            return None
    
    def create_files_backup(self):
        """Create zip backup of WordPress files"""
        self.logger.info("Starting WordPress files backup...")
        
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        zip_filename = f"wp_files_backup_{timestamp}.zip"
        zip_path = os.path.join(self.backup_dir, zip_filename)
        
        try:
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for root, dirs, files in os.walk(self.wp_path):
                    # Skip backup directory if it's inside wp_path
                    if self.backup_dir in root:
                        continue
                    
                    for file in files:
                        file_path = os.path.join(root, file)
                        arcname = os.path.relpath(file_path, self.wp_path)
                        zipf.write(file_path, arcname)
                        
            self.logger.info(f"Files backup created: {zip_path}")
            return zip_path
            
        except Exception as e:
            self.logger.error(f"Failed to create files backup: {e}")
            return None
    
    def create_database_backup(self):
        """Create database backup using mysqldump"""
        self.logger.info("Starting database backup...")
        
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        sql_filename = f"wp_db_backup_{timestamp}.sql"
        sql_path = os.path.join(self.backup_dir, sql_filename)
        zip_filename = f"wp_db_backup_{timestamp}.zip"
        zip_path = os.path.join(self.backup_dir, zip_filename)
        
        try:
            # Create SQL dump
            cmd = [
                'mysqldump',
                f'--host={self.db_host}',
                f'--user={self.db_user}',
                f'--password={self.db_password}',
                '--single-transaction',
                '--routines',
                '--triggers',
                self.db_name
            ]
            
            with open(sql_path, 'w') as f:
                subprocess.run(cmd, stdout=f, check=True)
            
            # Compress SQL file
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                zipf.write(sql_path, sql_filename)
            
            # Remove uncompressed SQL file
            os.remove(sql_path)
            
            self.logger.info(f"Database backup created: {zip_path}")
            return zip_path
            
        except subprocess.CalledProcessError as e:
            self.logger.error(f"Failed to create database backup: {e}")
            return None
        except Exception as e:
            self.logger.error(f"Unexpected error during database backup: {e}")
            return None
    
    def upload_to_drive(self, file_path):
        """Upload file to Google Drive"""
        if not self.drive_service:
            self.logger.error("Google Drive service not initialized")
            return False
        
        self.logger.info(f"Uploading {file_path} to Google Drive...")
        
        try:
            file_metadata = {
                'name': os.path.basename(file_path)
            }
            
            if self.drive_folder_id:
                file_metadata['parents'] = [self.drive_folder_id]
            
            media = MediaFileUpload(file_path, resumable=True)
            
            file = self.drive_service.files().create(
                body=file_metadata,
                media_body=media,
                fields='id',
                supportsAllDrives=True
            ).execute()
            
            self.logger.info(f"File uploaded successfully. File ID: {file.get('id')}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to upload file to Google Drive: {e}")
            return False
    
    def cleanup_local_file(self, file_path):
        """Remove local backup file"""
        if not self.keep_local_files:
            try:
                os.remove(file_path)
                self.logger.info(f"Local file removed: {file_path}")
            except Exception as e:
                self.logger.error(f"Failed to remove local file {file_path}: {e}")
    
    def run_backup(self):
        """Run complete backup process"""
        self.logger.info("Starting WordPress backup process...")
        
        success = True
        
        # Backup WordPress files
        files_backup_path = self.create_files_backup()
        if files_backup_path:
            if self.upload_to_drive(files_backup_path):
                self.cleanup_local_file(files_backup_path)
            else:
                success = False
        else:
            success = False
        
        # Backup database
        db_backup_path = self.create_database_backup()
        if db_backup_path:
            if self.upload_to_drive(db_backup_path):
                self.cleanup_local_file(db_backup_path)
            else:
                success = False
        else:
            success = False
        
        if success:
            self.logger.info("Backup process completed successfully")
        else:
            self.logger.error("Backup process completed with errors")
        
        return success

def main():
    config_file = sys.argv[1] if len(sys.argv) > 1 else 'config.ini'
    
    if not os.path.exists(config_file):
        print(f"Error: Configuration file '{config_file}' not found")
        sys.exit(1)
    
    backup = WordPressBackup(config_file)
    success = backup.run_backup()
    
    sys.exit(0 if success else 1)

if __name__ == '__main__':
    main()