Backup wordpress out-of-the-box: il monolite u.g.o. per estrarre i dati senza chiedere il permesso
La complessità inutile è un’infrastruttura di controllo. Ci hanno convinti che per gestire un sito web servano decine di plugin, servizi in abbonamento e interfacce grafiche pesanti come macigni. La verità è che il web moderno è una workstation ad alte prestazioni paralizzata da bloatware amministrativi impossibili da disinstallare.
Prendiamo i backup. Affidare il salvataggio del tuo sito a un plugin che gira dentro wordpress è un bug logico clamoroso. È come chiedere a un malato di operarsi da solo. Se il database si corrompe, se la memoria satura, se il core del cms va in crash, il tuo bel plugin non partirà mai. E tu resti a guardare il vuoto, magari mentre un fuffaguru cerca di venderti la versione “pro” per darti indietro i tuoi stessi dati.
I dati sono tuoi, non del cloud. Il cloud non esiste, è solo il computer di qualcun altro che usi in affitto.
Per riprendere il controllo bisogna uscire dal recinto. Ho scritto un monolite in php puro. L’ho chiamato U.G.O. Backup Engine. Non è un plugin, è uno script di backup esterno, indipendente e brutale che agisce a livello di server. Ignora l’ecosistema infetto di wordpress, estrae ciò che serve e lo blinda.
L’invisibilità come prima linea di difesa
Se apri lo script dal browser senza essere autenticato, non vedrai alcun logo, nessuna interfaccia accattivante, nessuna informazione sul server. Solo uno schermo nero e spietato con un singolo campo di input verde. È un muro di gomma. I bot automatici che scansionano la rete in cerca di vulnerabilità non sanno come interpretarlo, perché non c’è nulla da interpretare. Se non hai la password salvata direttamente nel codice sorgente, non esisti.
La logica binaria contro l’entropia
Lo script fa esattamente tre cose, senza barre di caricamento ruffiane o pubblicità:
- Auto-scoperta e isolamento: Si legge da solo il file
wp-config.phpper trovare le credenziali. Crea una cartella di sicurezza (il vault) inaccessibile dal web tramite un.htaccesscondeny from all. Chiunque provi a entrare da fuori, trova un muro. - Estrazione spietata: Usa pdo per esportare il database riga per riga, bypassando i limiti dei server economici. Poi zippa i contenuti ignorando le cache, che sono solo entropia e rumore di fondo.
- Blindatura aes-256: Tutto l’archivio viene criptato nativamente con una chiave di sicurezza. Il file zip può essere scaricato solo passando attraverso lo script stesso, tramite un tunnel php che inietta il file direttamente nel tuo browser, bypassando il blocco di sicurezza di apache.
L’interfaccia è grezza, anti-scemo. Clicchi un bottone per avviare il backup, l’interfaccia si congela per impedirti di cliccare compulsivamente come un criceto nella ruota, e aspetti. Il silenzio del server è spazio attivo, è il tempo fisiologico della macchina che lavora. Quando ha finito, ti consegna l’archivio.
La sonda spaziale e la menzogna degli hosting
Prima di avviare un backup completo, devi sapere se il server ha abbastanza respiro per farlo. Ho inserito un pulsante “Sonda Spazio”. Cliccandolo, lo script pesa fisicamente tutti i file del tuo sito e interroga il disco per farsi dire quanto spazio è rimasto.
Attenzione però a un dettaglio strutturale: se sei su un hosting condiviso economico, il server ti mentirà. Ti dirà lo spazio libero dell’intero disco fisico (magari 800 GB), non quello che ti resta nel contratto. La sonda ti serve per sapere quanti megabyte effettivi dovrai comprimere; spetta a te fare due conti con il limite del tuo piano hosting prima di scatenare l’entropia della compressione.
Lo script (copia, incolla, domina)
PHP
<?php
/**
* U.G.O. System - WP Out-of-the-box Backup v1.1 (Con Sonda Spazio)
* Logic: Memore. Nessun fronzolo, solo esecuzione.
*/
session_start();
set_time_limit(0);
ini_set('memory_limit', '1024M');
// --- 1. CONFIGURAZIONE CRITICA ---
$access_password = "TUA_PASSWORD_ACCESSO"; // Password per aprire lo script
$zip_encryption_key = "CHIAVE_AES_ZIP"; // Password dello zip
$vault_name = 'ugo_vault_secure';
// --- 2. GESTIONE AUTENTICAZIONE ---
if (isset($_POST['login_pass']) && $_POST['login_pass'] === $access_password) {
$_SESSION['ugo_auth'] = true;
}
if (isset($_GET['logout'])) {
session_destroy();
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
// Muro di gomma. Zero informazioni all'esterno.
if (!isset($_SESSION['ugo_auth'])) {
die('<!DOCTYPE html><html><body style="background:#000;color:#0f0;font-family:monospace;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;">
<form method="POST">
[U.G.O. SYSTEM GATEWAY]<br><br>
<input type="password" name="login_pass" autofocus style="background:#000;border:1px solid #0f0;color:#0f0;padding:5px;">
</form></body></html>');
}
// --- 3. SETUP AMBIENTE E AUTO-SCOPERTA ---
$vault_path = __DIR__ . '/' . $vault_name;
if (!file_exists($vault_path)) {
mkdir($vault_path, 0755, true);
file_put_contents($vault_path . '/.htaccess', "Deny from all");
}
if (file_exists(__DIR__ . '/wp-config.php')) {
$wp_content = file_get_contents(__DIR__ . '/wp-config.php');
preg_match("/'DB_NAME',\s*'(.+?)'/", $wp_content, $db_name);
preg_match("/'DB_USER',\s*'(.+?)'/", $wp_content, $db_user);
preg_match("/'DB_PASSWORD',\s*'(.+?)'/", $wp_content, $db_pass);
preg_match("/'DB_HOST',\s*'(.+?)'/", $wp_content, $db_host);
$dsn = "mysql:host={$db_host[1]};dbname={$db_name[1]};charset=utf8mb4";
$db_user_val = $db_user[1];
$db_pass_val = $db_pass[1];
}
// --- 4. FUNZIONE DOWNLOAD ---
if (isset($_GET['dl'])) {
$file = basename($_GET['dl']);
$path = $vault_path . '/' . $file;
if (file_exists($path)) {
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $file . '"');
header('Content-Length: ' . filesize($path));
ob_clean();
flush();
readfile($path);
exit;
}
}
// --- 5. FUNZIONE ELIMINAZIONE ---
if (isset($_GET['del'])) {
$file = basename($_GET['del']);
if (file_exists($vault_path . '/' . $file)) { unlink($vault_path . '/' . $file); }
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
// --- 6. SONDA SPAZIO (CALCOLO MANUALE) ---
$spazio_sito_mb = 0;
$controllo_eseguito = false;
if (isset($_GET['check_space'])) {
$size = 0;
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__), RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $file) {
if (strpos($file->getRealPath(), $vault_name) === false) {
$size += $file->getSize();
}
}
$spazio_sito_mb = round($size / 1024 / 1024, 2);
$controllo_eseguito = true;
}
// --- 7. MOTORE DI BACKUP ---
if (isset($_GET['run'])) {
$mode = $_GET['run'];
$timestamp = date('Ymd_His');
$zip_name = "ugo_{$mode}_{$timestamp}_" . bin2hex(random_bytes(4)) . ".zip";
$target_zip = $vault_path . '/' . $zip_name;
$zip = new ZipArchive();
if ($zip->open($target_zip, ZipArchive::CREATE) === TRUE) {
if ($mode == 'full' || $mode == 'db') {
try {
$pdo = new PDO($dsn, $db_user_val, $db_pass_val);
$sql_dump = "";
foreach ($pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN) as $table) {
$create = $pdo->query("SHOW CREATE TABLE `$table`")->fetch(PDO::FETCH_ASSOC);
$sql_dump .= "\n\n" . $create['Create Table'] . ";\n\n";
$rows = $pdo->query("SELECT * FROM `$table`")->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) { $sql_dump .= "INSERT INTO `$table` VALUES (" . implode(',', array_map([$pdo, 'quote'], $row)) . ");\n"; }
}
$zip->addFromString('database_dump.sql', $sql_dump);
$zip->setEncryptionName('database_dump.sql', ZipArchive::EM_AES_256, $zip_encryption_key);
} catch (Exception $e) { die("Errore DB: " . $e->getMessage()); }
}
if ($mode == 'full' || $mode == 'files') {
$root = ($mode == 'full') ? __DIR__ : __DIR__ . '/wp-content';
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root), RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $name => $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen(__DIR__) + 1);
if (strpos($filePath, $vault_name) === false && strpos($filePath, '.git') === false && strpos($filePath, 'cache') === false) {
$zip->addFile($filePath, $relativePath);
$zip->setEncryptionName($relativePath, ZipArchive::EM_AES_256, $zip_encryption_key);
}
}
}
}
$zip->close();
header("Location: " . $_SERVER['PHP_SELF'] . "?success=1");
exit;
}
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>U.G.O. Backup System</title>
<style>
body { background: #1a1a1a; color: #eee; font-family: 'Courier New', monospace; padding: 20px; }
.btn { display: inline-block; padding: 10px 15px; background: #333; color: #0f0; text-decoration: none; border: 1px solid #0f0; margin-right: 10px; cursor: pointer; }
.btn:hover { background: #0f0; color: #000; }
.btn-del { border-color: #f00; color: #f00; }
.btn-del:hover { background: #f00; color: #000; }
.btn-sonda { border-color: #ff9900; color: #ff9900; }
.btn-sonda:hover { background: #ff9900; color: #000; }
.btn.disabled { background: #222 !important; color: #444 !important; border-color: #444 !important; pointer-events: none; cursor: not-allowed; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { text-align: left; padding: 10px; border-bottom: 1px solid #333; }
.header { border-bottom: 2px solid #0f0; padding-bottom: 10px; margin-bottom: 20px; }
#status-msg { display: none; color: #0f0; margin-top: 10px; font-weight: bold; }
.info-panel { background: #222; padding: 15px; border-left: 4px solid #ff9900; margin-bottom: 20px; font-size: 0.9em; }
</style>
</head>
<body>
<div class="header">
<h1>U.G.O. SYSTEM - BACKUP ENGINE</h1>
<a href="?run=db" class="btn js-backup">BACKUP DB</a>
<a href="?run=files" class="btn js-backup">BACKUP CONTENUTI</a>
<a href="?run=full" class="btn js-backup">BACKUP COMPLETO</a>
<a href="?check_space=1" class="btn btn-sonda">SONDA SPAZIO (TEST)</a>
<a href="?logout=1" style="float:right; color:#666;">DISCONNETTI</a>
<div id="status-msg">ELABORAZIONE IN CORSO. IL SILENZIO È SPAZIO ATTIVO. ATTENDERE.</div>
</div>
<?php if ($controllo_eseguito):
$spazio_disco_gb = round(disk_free_space(__DIR__) / 1024 / 1024 / 1024, 2);
?>
<div class="info-panel">
<strong>[DIAGNOSTICA HARDWARE]</strong><br>
Peso stimato del sito (da zippare): <strong><?php echo $spazio_sito_mb; ?> MB</strong><br>
Spazio libero riportato dal server: <strong><?php echo $spazio_disco_gb; ?> GB</strong><br>
<i>Nota logica: Se sei su hosting condiviso, i GB liberi riportati potrebbero riferirsi all'intero server fisico e non alla tua quota. Valuta il peso del sito in base al tuo contratto.</i>
</div>
<?php endif; ?>
<h3>Archivi presenti nel Vault blindato:</h3>
<table>
<tr><th>Nome File</th><th>Dimensione</th><th>Data</th><th>Azioni</th></tr>
<?php
$files = array_diff(scandir($vault_path), array('.', '..', '.htaccess'));
foreach ($files as $f) {
$size = round(filesize($vault_path . '/' . $f) / 1024 / 1024, 2) . ' MB';
$date = date("d/m/Y H:i:s", filemtime($vault_path . '/' . $f));
echo "<tr>
<td>$f</td>
<td>$size</td>
<td>$date</td>
<td>
<a href='?dl=$f' class='btn'>SCARICA</a>
<a href='?del=$f' class='btn btn-del' onclick='return confirm(\"Eliminare definitivamente?\")'>ELIMINA</a>
</td>
</tr>";
}
?>
</table>
<script>
document.querySelectorAll('.js-backup').forEach(button => {
button.addEventListener('click', function() {
document.querySelectorAll('.btn').forEach(btn => {
btn.classList.add('disabled');
if (btn.classList.contains('js-backup')) btn.innerText = "ELABORAZIONE...";
});
document.getElementById('status-msg').style.display = 'block';
});
});
</script>
</body>
</html>

Manuale di distruzione del disordine
Non servono tutorial di venti minuti su youtube per capire come usarlo. La procedura è elementare:
- Configura le chiavi: Copia il codice qui sopra e incollalo in un editor di testo serio (niente word). Alle righe 12 e 13 ci sono due variabili. Una è la password per visualizzare la plancia di comando, l’altra è la chiave crittografica per blindare lo zip. Cambiale entrambe, usa stringhe complesse e salvati la seconda, perché se la perdi i tuoi dati restano chiusi fuori.
- Carica il monolite: Salva il file come
ugo-backup.php. Apri il tuo client ftp e caricalo nella cartella principale del tuo sito (la root dove risiedewp-config.php). - Esegui e attendi: Vai sul browser e digita
tuosito.it/ugo-backup.php. Inserisci la password di accesso. Ti troverai davanti tre scelte di backup e la sonda dello spazio. Clicca quella che ti serve e stacca le mani dal mouse. L’interfaccia si bloccherà per evitare che tu impalli il server con decine di richieste inutili. Lascialo lavorare. - Estrai il bottino: Quando la pagina si ricaricherà da sola, vedrai il tuo file zip nella lista. Clicca su scarica. Lo script aggirerà le protezioni per servirti il file in locale. A quel punto, eliminalo dal server cliccando l’apposito pulsante. Non lasciare tracce in giro.
La perseveranza non è ostinarsi a far funzionare i plugin scritti dagli altri, ma demolire il problema e ricostruire la soluzione dalle fondamenta.
Il monolite estrae e comprime i dati senza pietà, ma ricordati che stai sempre operando in un recinto in affitto: fino a un paio di giga il processo è inarrestabile, ma se tenti di zippare un sito mastodontico su un hosting economico, i limiti occulti del server — come il taglio forzato della RAM, la strozzatura della velocità del disco o i timeout del proxy — decapiteranno lo script per legittima difesa, dimostrandoti ancora una volta che il cloud è solo il computer castrato di qualcun altro.