Scanarea de malware prin WP-CLI este o metodă esențială pentru situațiile în care un plugin…

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.