Skip to content
Automatizare backup WordPress Python

Cum automatizați backup-urile WordPress folosind Python

Cum automatizați backup-urile WordPress folosind Python. Python oferă instrumente puternice pentru crearea unui sistem personalizat de backup WordPress care combină flexibilitatea scripting-ului cu biblioteci pentru compresie, criptare și upload pe servicii cloud.

Spre deosebire de plugin-urile de backup WordPress, un script Python rulează independent de WordPress și funcționează chiar dacă site-ul este compromis sau inaccesibil.

Cum automatizați backup-urile WordPress folosind Python

Un sistem de backup Python complet include exportul bazei de date, arhivarea fișierelor, criptarea datelor sensibile, upload-ul pe servicii cloud, rotația automată a backup-urilor vechi și notificarea prin email la finalizare sau eroare.

Vom construi pas cu pas fiecare componentă și le vom integra într-un sistem unificat de backup automat.

Structura scriptului de backup

import os
import subprocess
import tarfile
import gzip
import shutil
import json
import smtplib
from datetime import datetime, timedelta
from pathlib import Path
from email.mime.text import MIMEText

class WordPressBackup:
    """Sistem automat de backup WordPress."""

    def __init__(self, config_file='backup_config.json'):
        with open(config_file, 'r') as f:
            self.config = json.load(f)

        self.wp_path = self.config['wp_path']
        self.backup_dir = self.config['backup_dir']
        self.db_config = self.config['database']
        self.retention_days = self.config.get('retention_days', 30)
        self.timestamp = datetime.now().strftime('%Y%m%d_%H%M')
        self.log_messages = []

        # Creare director backup
        os.makedirs(self.backup_dir, exist_ok=True)

    def log(self, message):
        """Înregistrare mesaj de log."""
        entry = f"[{datetime.now().strftime('%H:%M:%S')}] {message}"
        print(entry)
        self.log_messages.append(entry)

    def backup_database(self):
        """Export baza de date WordPress în fișier SQL comprimat."""
        db_file = os.path.join(
            self.backup_dir,
            f"db_{self.db_config['name']}_{self.timestamp}.sql"
        )
        gz_file = f"{db_file}.gz"

        self.log(f"Export bază de date: {self.db_config['name']}")

        cmd = [
            'mysqldump',
            f"--user={self.db_config['user']}",
            f"--password={self.db_config['pass']}",
            f"--host={self.db_config.get('host', 'localhost')}",
            '--single-transaction',
            '--routines',
            '--triggers',
            self.db_config['name']
        ]

        try:
            with open(db_file, 'w') as f:
                result = subprocess.run(
                    cmd, stdout=f, stderr=subprocess.PIPE,
                    timeout=300
                )

            if result.returncode != 0:
                self.log(f"EROARE mysqldump: {result.stderr.decode()}")
                return None

            # Comprimare cu gzip
            with open(db_file, 'rb') as f_in:
                with gzip.open(gz_file, 'wb') as f_out:
                    shutil.copyfileobj(f_in, f_out)

            os.remove(db_file)
            size_mb = os.path.getsize(gz_file) / (1024 * 1024)
            self.log(f"Bază de date exportată: {size_mb:.2f} MB")
            return gz_file

        except subprocess.TimeoutExpired:
            self.log("EROARE: Timeout la export bază de date")
            return None
        except Exception as e:
            self.log(f"EROARE: {e}")
            return None
  • Parametrul single-transaction asigură un export consistent fără a bloca baza de date
  • Comprimarea gzip reduce dimensiunea backup-ului cu 70-90%
  • Timeout-ul de 300 secunde previne blocarea scriptului pe baze de date mari
  • Fișierul SQL temporar este șters după comprimare

Backup-ul fișierelor WordPress

    def backup_files(self):
        """Arhivare fișiere WordPress cu excluderi."""
        archive_file = os.path.join(
            self.backup_dir,
            f"files_{self.timestamp}.tar.gz"
        )

        exclude_dirs = [
            'wp-content/cache',
            'wp-content/upgrade',
            'wp-content/backup-db',
            'wp-content/backups',
            'wp-content/wflogs',
            'wp-content/ai1wm-backups'
        ]

        self.log(f"Arhivare fișiere: {self.wp_path}")

        try:
            with tarfile.open(archive_file, 'w:gz') as tar:
                for root, dirs, files in os.walk(self.wp_path):
                    rel_root = os.path.relpath(root, self.wp_path)

                    # Excludere directoare
                    skip = False
                    for exclude in exclude_dirs:
                        if rel_root.startswith(exclude):
                            skip = True
                            break
                    if skip:
                        continue

                    for filename in files:
                        if filename.endswith(('.log', '.tmp')):
                            continue
                        filepath = os.path.join(root, filename)
                        arcname = os.path.relpath(filepath, self.wp_path)
                        try:
                            tar.add(filepath, arcname=arcname)
                        except (PermissionError, OSError):
                            self.log(f"Nu s-a putut arhiva: {arcname}")

            size_mb = os.path.getsize(archive_file) / (1024 * 1024)
            self.log(f"Fișiere arhivate: {size_mb:.2f} MB")
            return archive_file

        except Exception as e:
            self.log(f"EROARE arhivare: {e}")
            return None
  • Excluderea directoarelor de cache reduce dimensiunea și timpul de backup
  • Fișierele .log și .tmp sunt omise pentru a economisi spațiu
  • Erorile de permisiune sunt înregistrate dar nu opresc procesul
  • Formatul tar.gz oferă compresie bună și compatibilitate universală

Criptarea backup-urilor

    def encrypt_file(self, filepath):
        """Criptare fișier cu OpenSSL AES-256."""
        encrypted_file = f"{filepath}.enc"
        password = self.config.get('encryption_password', '')

        if not password:
            self.log("Criptare omisă (fără parolă configurată)")
            return filepath

        self.log(f"Criptare: {os.path.basename(filepath)}")

        try:
            cmd = [
                'openssl', 'enc', '-aes-256-cbc',
                '-salt', '-pbkdf2',
                '-in', filepath,
                '-out', encrypted_file,
                '-pass', f'pass:{password}'
            ]
            result = subprocess.run(cmd, capture_output=True, timeout=300)

            if result.returncode == 0:
                os.remove(filepath)
                self.log("Criptare completă")
                return encrypted_file
            else:
                self.log(f"EROARE criptare: {result.stderr.decode()}")
                return filepath

        except Exception as e:
            self.log(f"EROARE criptare: {e}")
            return filepath
  • AES-256-CBC oferă criptare puternică standard industrial
  • PBKDF2 protejează parola împotriva atacurilor de dicționar
  • Fișierul necriptat este șters automat după criptare
  • Păstrați parola de criptare într-un loc sigur, fără ea backup-ul este inutilizabil

Rotația și curățarea backup-urilor vechi

    def rotate_backups(self):
        """Ștergere backup-uri mai vechi de retention_days."""
        self.log(f"Rotație backup-uri (păstrare: {self.retention_days} zile)")
        cutoff = datetime.now() - timedelta(days=self.retention_days)
        deleted = 0

        for filename in os.listdir(self.backup_dir):
            filepath = os.path.join(self.backup_dir, filename)
            if os.path.isfile(filepath):
                file_time = datetime.fromtimestamp(os.path.getmtime(filepath))
                if file_time < cutoff:
                    os.remove(filepath)
                    deleted += 1
                    self.log(f"Șters: {filename}")

        self.log(f"Backup-uri vechi șterse: {deleted}")

    def notify(self, success=True):
        """Trimite notificare email."""
        email_config = self.config.get('email', {})
        if not email_config:
            return

        status = "SUCCES" if success else "EȘEC"
        body = f"Backup WordPress {status}n"
        body += f"Data: {self.timestamp}nn"
        body += "n".join(self.log_messages)

        msg = MIMEText(body)
        msg['Subject'] = f'[Backup {status}] WordPress {self.timestamp}'
        msg['From'] = email_config.get('from', 'backup@wpsecurity.ro')
        msg['To'] = email_config['to']

        try:
            server = smtplib.SMTP(email_config['smtp_host'], email_config.get('smtp_port', 587))
            server.starttls()
            server.login(email_config['smtp_user'], email_config['smtp_pass'])
            server.send_message(msg)
            server.quit()
        except Exception as e:
            self.log(f"Eroare email: {e}")

Executarea backup-ului complet

    def run(self):
        """Execută backup complet."""
        self.log("=" * 50)
        self.log(f"BACKUP WORDPRESS START: {self.timestamp}")
        self.log("=" * 50)

        success = True
        files = []

        # Backup bază de date
        db_backup = self.backup_database()
        if db_backup:
            db_backup = self.encrypt_file(db_backup)
            files.append(db_backup)
        else:
            success = False

        # Backup fișiere
        files_backup = self.backup_files()
        if files_backup:
            files_backup = self.encrypt_file(files_backup)
            files.append(files_backup)
        else:
            success = False

        # Rotație
        self.rotate_backups()

        # Sumar
        total_size = sum(os.path.getsize(f) for f in files if os.path.exists(f))
        self.log(f"nDimensiune totală: {total_size / (1024*1024):.2f} MB")
        self.log(f"Status: {'SUCCES' if success else 'PARȚIAL/EȘEC'}")

        # Notificare
        self.notify(success)

        return success

# Configurare exemplu (backup_config.json)
config = {
    "wp_path": "/home/user/public_html",
    "backup_dir": "/home/user/backups",
    "database": {
        "name": "wpsecurity_db",
        "user": "wpsecurity_user",
        "pass": "PAROLA_DB",
        "host": "localhost"
    },
    "retention_days": 30,
    "encryption_password": "PAROLA_CRIPTARE_PUTERNICA",
    "email": {
        "to": "admin@wpsecurity.ro",
        "from": "backup@wpsecurity.ro",
        "smtp_host": "mail.wpsecurity.ro",
        "smtp_port": 587,
        "smtp_user": "backup@wpsecurity.ro",
        "smtp_pass": "PAROLA_SMTP"
    }
}

with open('backup_config.json', 'w') as f:
    json.dump(config, f, indent=2)

# Rulare backup
if __name__ == '__main__':
    backup = WordPressBackup()
    backup.run()
  • Scriptul poate fi rulat manual sau programat prin cron
  • Configurarea externă JSON permite modificări fără a edita codul
  • Notificarea prin email confirmă finalizarea sau raportează erorile
  • Protejați fișierul de configurare cu permisiuni restrictive (chmod 600)

Automatizarea backup-urilor WordPress cu Python oferă control complet și funcționare independentă de WordPress. Pentru strategii avansate de protecție, vizitați securitate cibernetică și blogul nostru. Echipa WPSecurity oferă servicii speciale de implementare backup, contactați-ne pentru detalii.

Despre autor

Dorel Tănase este specialist în optimizarea site-urilor pentru motoarele de căutare. Lucrează în online din 1997 și în SEO din 2007, iar activitatea se desfășoară prin GO SEO MARKETING S.R.L. din Alba Iulia. Se ocupă de audit tehnic, arhitectura site-urilor, conținut și construirea legăturilor.

Sus