Snippet PHP per scaricare un intero database da un server remoto

Quando si tratta di proteggere i dati del tuo database, l’esecuzione regolare di un backup è fondamentale. Inoltre è a volte necessario creare una copia del database, per ragioni di sviluppo oltre che di sicurezza, di un’applicazione web che è accessibile solo via FTP.

Ebbene, quando l’accesso alla console MySQL o a phpMyAdmin è interdetto, ma è disponibile un’accesso in scrittura via FTP, è possibile provare i metodi che passiamo ad illustrare.

L’dea è avere una URL come example.org/dump-database.php, che invocata da browser faccia partire il download di un file sql, ottenendo così una copia dei dati del database.

Ovviamente dovrai avere le credenziali di accesso al database per poter effettuare il dump.

Script PHP che sfrutti la console mysql per il dump del database

Questo script è più performante del precedente, ma non disponibile su tutti gli hosting, in quanto utilizza il comando MySQL tramite exec (che è la funzione che esegue i comandi direttamente sulla console del sistema operativo).

<?php
// Configurazione dei parametri
$host = 'localhost'; // Host del database
$username = 'username'; // Nome utente del database
$password = 'password'; // Password del database
$dbname = 'database_name'; // Nome del database
$tables = '*'; // Tabelle da includere nel dump (puoi specificarne una lista separata da virgole o usare '*' per tutte le tabelle)

// Crea il nome del file di dump
$filename = 'database_dump_' . date('Y-m-d_H-i-s') . '.sql';

// Esegui il dump del database
exec("mysqldump -h{$host} -u{$username} -p{$password} {$dbname} {$tables} > {$filename}");

// Forza il download del file di dump
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($filename) . "\"");
readfile($filename);

// Rimuovi il file di dump dal server
unlink($filename);
?>

NOTA BENE:

  • Se tutti possono accedere alla URL su cui gira il tuo snippet tutti potranno scaricare il tuo database (vedi “Implicazioni di sicurezza”);
  • Se il database è molto grande potresti, nel navigare la URL, non ottenere l’agognato file o ritrovarti con una copia incompleta del database a causa del timeout dell’esecuzione di processi in PHP (il famoso max_execution_time).

Script in PHP puro per il dump del database

Questo script necessita solo che sul server che lo esegue, ci sia l’interprete PHP, cosa che è effettivamente possibile su praticamente tutti gli hosting sparsi per l’infosfera.

<?php
// Configurazione dei parametri
$host = 'localhost'; // Host del database
$username = 'username'; // Nome utente del database
$password = 'password'; // Password del database
$dbname = 'dbname'; // Nome del database
$tables = '*'; // Tabelle da includere nel dump (puoi specificarne una lista separata da virgole o usare '*' per tutte le tabelle)


// Connessione al database
$mysqli = new mysqli($host, $username, $password, $dbname);

// Verifica della connessione
if ($mysqli->connect_errno) {
    die('Failed to connect to MySQL: ' . $mysqli->connect_error);
}

// Recupero dei nomi delle tabelle nel database
$tables = array();
$result = $mysqli->query("SHOW TABLES");
while ($row = $result->fetch_row()) {
    $tables[] = $row[0];
}

// Creazione del dump del database
$dump = '';
foreach ($tables as $table) {
    $result = $mysqli->query("SELECT * FROM `$table`");
    $numColumns = $result->field_count;

    $dump .= "DROP TABLE IF EXISTS `$table`;\n";
    $row2 = $mysqli->query("SHOW CREATE TABLE `$table`")->fetch_row();
    $dump .= $row2[1] . ";\n\n";

    while ($row = $result->fetch_row()) {
        $dump .= "INSERT INTO `$table` VALUES (";
        for ($i = 0; $i < $numColumns; $i++) {
            $row[$i] = $mysqli->real_escape_string($row[$i]);
            $row[$i] = "'" . $row[$i] . "'";
        }
        $dump .= implode(',', $row);
        $dump .= ");\n";
    }

    $dump .= "\n";
}

// Impostazione dell'header per il download del file
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"database_dump_" . date('Y-m-d_H-i-s') . ".sql\"");

// Output del dump del database
echo $dump;

// Chiusura della connessione al database
$mysqli->close();

Implicazioni di sicurezza

Quando hai a che fare con i database stai avendo a che fare con la tua base dati, dove la parola dati dovrebbe spaventarti un poco! 😀

Pertanto assicurati di proteggere adeguatamente il file PHP che contiene lo script, ad esempio, posizionandolo in una directory non accessibile al pubblico o dandogli un nome al file, praticamente impossibile da raggiungere per caso. Se dovevi solo scaricare il dump per lavorarci altrove, allora ricordati di cancellare il file che contiene il tuo snippet!

Come mettere lo script in un file PHP

Per utilizzare lo script PHP per il dump del database, segui questi semplici passaggi. Prima di tutto, crea un nuovo file PHP sul tuo server web. Quindi, copia il codice dello script fornito in questo articolo e incollalo nel file PHP appena creato. Assicurati di configurare correttamente i parametri, come l’host del database, il nome utente, la password e il nome del database. Salva il file PHP e caricalo sul tuo server. Prendi nota del nome del file e usalo nella URL per lanciare lo script e scaricare il tuo database tramite il browser.

Sper di esserti stato utile

Htaccess redirect a un localhost su una determinata porta via apache2 mod_rewrite.

Questo snippet di htaccess configura una regola di rewrite per il modulo mod_rewrite di Apache.

<IfModule mod_rewrite.c>
    RewriteEngine On
    #Domain REDIRECT
    RewriteCond %{HTTP_HOST} !^127\.0\.0\.1:3000$ [NC]
    RewriteRule ^(.*)$ http://127.0.0.1:3000/$1 [L,R=301]
</IfModule>

In pratica, se il modulo mod_rewrite è attivo (verificato con l’istruzione <IfModule mod_rewrite.c>), la regola specifica RewriteEngine On abilita il rewriting degli URL.

La successiva istruzione RewriteCond verifica se l’host nella richiesta HTTP non corrisponde a “127.0.0.1:3000” (cioè non sta puntando al server locale sulla porta 3000). Se la condizione è vera, viene applicata la regola di rewrite successiva.

La regola di rewrite RewriteRule prende tutto ciò che segue il dominio nella richiesta e lo redirige verso “http://127.0.0.1:3000/$1“, dove “$1” rappresenta il valore catturato tra parentesi nella parte corrispondente dell’URL richiesto. L’opzione [L,R=301] indica che si tratta di una redirezione permanente (codice HTTP 301) e che non devono essere processate ulteriori regole di rewriting.

In sintesi, questo snippet di htaccess redirige tutte le richieste in arrivo a un server locale sulla porta 3000, a meno che non siano già indirizzate a tale indirizzo.

Tieni presente che la correttezza dell’implementazione dipende dalle tue esigenze specifiche e dall’ambiente di hosting in cui viene utilizzato. È consigliabile testare attentamente il funzionamento dell’htaccess e adattarlo alle tue necessità.

Testare Drupal 10 in locale

Risolvere il problema del 404 not found che si verifica quando si tenta di effettuare il CRUD di un campo su un’entità di Drupal 10.

Quasi sicuramente se sei arrivato qui significa che all’aggiunta di un campo su un tipo di contenuto di Drupal 10, hai ricevuto un errore 404 e lo stesso ti sarà successo in modifica o delete del campo di un entità.

Se sei fortunato, come descritto da Halt nell’issue #2743633 su drupal.org il problema potrebbe essere generato dal comando php che ti consente di lanciare il webserver in ascolto su una certa porta.

Normalmente il comando che si lancia è:

php -S localhost:8000

Che ti consente, navigando con il browser su quell’host, di vedere la tua installazione Drupal 10. Tuttavia tale comando risulta insufficiente, in quanto bisogna dargli in pasto un file che è incluso nell’installazione Drupal, ovvero “.ht.router.php“.

TODO immagine boyscout che giura

Utilizzando il comando il problema non si verifica più, parola di boy scout.

php -S localhost:8888 .ht.router.php

Aprendo il file .ht.router.php scopriamo subito il suo proposito leggendo il commento in testa:

/**
 * @file
 * Router script for the built-in PHP web server.
 *
 * The built-in web server should only be used for development and testing as it
 * has a number of limitations that makes running Drupal on it highly insecure
 * and somewhat limited.
 *
 * Note that:
 * - The server is single-threaded, any requests made during the execution of
 *   the main request will hang until the main request has been completed.
 * - The web server does not enforce any of the settings in .htaccess in
 *   particular a remote user will be able to download files that normally would
 *   be protected from direct access such as .module files.
 *
 * The router script is needed to work around a bug in PHP, see
 * https://bugs.php.net/bug.php?id=61286.
 *
 * Usage:
 * php -S localhost:8888 .ht.router.php
 *
 * @see http://php.net/manual/en/features.commandline.webserver.php
 */

Cosa che significa sostanzialmente:

  • che questo file andrebbe lanciato solo per finalità di testing e sviluppo
  • che non è sicuro
  • che è limitato, ad esempio dal fatto che è single thread

Buon Drupal 10 🙂