Guía 92 – Restore de Base de Datos

Pienso, que esta debería ser la Guía 1, porque así habría dotado a todos mis ejemplos de la posibilidad de RESTAURAR de un backup de Base de Datos y tanto vosotros, como yo, podríamos disfrutar del juego de datos suficiente para ver las posibilidades del ejemplo. Ahora, en la situación actual, la mayoría de las veces no me entero que los datos han sido destruidos y me cuesta más de un «click» el restaurar la situación.

Si tenéis la necesidad de un entorno de Demo, creo que esta alternativa es muy importante para que siempre esté operativo.

Realmente, la necesidad me la ha planteado un compañero que deseaba instalar en PC’s locales un desarrollo y deseaba tener la posibilidad de Backup y Restore, de la copia de seguridad, facilitando estas acciones al usuario.

Objetivo

Disponer en un desarrollo de PHPRunner la posibilidad de Backup de la Base de datos y del Restore de uno de los Backup.

DEMO:  https://fhumanes.com/videoclub2/

Usuario «admin»/»admin»

Solución Técnica

Las dos opciones de menú están integradas en la seguridad de PHPRunner, por lo que se le pueden asignar a cualquier perfil de usuario. Esto se ha hecho utilizando Vistas de una de las tablas del proyecto. Da igual la tabla que elijas porque de esas tablas no se utiliza nada salvo el contexto de la aplicación y la seguridad de esta. Las pantallas se crean con SNIPPET y botones de 3 estados.

La funcionalidad del Backup ya la explique en la Guía 50 y en esa guía puedes obtener el detalle de cómo se hace el Backup (todo es código PHP y no requiere tener nada especial instalado en el server).

Para el Restore he utilizado un SNIPPET y un botón de 3 estados. El campo Selector, se crea dinámicamente en el Snippet, recogiendo los nombres de los ficheros que están en un directorio determinado. Se selecciona el fichero que se desea aplicar y se pulsa el botón rojo de Restore.

Como suelo hacer, busqué código para restaurar BD MySQL y seleccioné este: https://github.com/harisrozak/php-restore-mysql-database . Es bastante claro y modifiqué pequeñas cosas que necesitaba.

El código del Snippet es:

<?php

$option='';

// Recoger los ficheros de  export de base de datos, más recientes.| Leave only the 5 recent database export.

$pref_file_backup = 'Videoclub_';

chdir(__DIR__.'/backup_files/');

$arrFiles = glob($pref_file_backup.'*');


rsort($arrFiles);  // Ordenar de mayor a menor

for ($i = 0; $i < count($arrFiles); $i++) {
    $option .= "<option>".$arrFiles[$i]."</option>\n";
}   

$html = <<< EOT
<div class="form-group">
    <label class="r-edit-label control-label" for="value_file_1">
            Seleccione el fichero para la Recuperación
            <span class="icon-required"></span>
    </label>
    <select class="form-control" id="selection_file">
    $option
    </select>
</div>
EOT;
echo $html;

El código del botón de 3 estados es:

  • Client Before:
// Put your code here.
params["file_restore"] = $("#selection_file").val();   // Recoje el fichero del Selector de fichros

console.log('Fichero de carga: ',params["file_restore"]);
Swal.fire({
    // icon: 'info',
   title: 'El Restore se ha iniciado se ha inciado y se está ejecutando',
   text: '',
   imageUrl: "backup/images/calculated.gif",
   imageHeight: 200,
    imageAlt: "Estamos trabajando",
   timer: 60000,
   timerProgressBar: true,
   toast: true,
   showConfirmButton: false,
   position:  'center', // "top-start",
   footer: ''
  })

return true;
  • Server:
$file_restore = $params["file_restore"]; // Fichero del backup

include "backup/restore.php";

$result["message_user"] = $message_user;
  • Client After:
console.log('Inicia la 3 fase');
var msg_user = result['message_user'];

if (confirm("El mensaje del Restore es: " + msg_user) == true) {
  window.open("menu.php", "_self"); 
} else {
  window.open("menu.php", "_self");
}
restore.php
<?php
/**
 * PHP Restore MySQL Database
 * @author harisrozak and Modify for FHumanes
 */
 
// To debug PHP code on the server
function custom_error($number,$text){ // Function to produce the error file
    $ddf = fopen(__DIR__ .'/../error.log','a');
    fwrite($ddf,"[".date("r")."] Error $number: $text\r\n");
    fclose($ddf);
}


custom_error(1,"Se inicia el proceso del Restore de la BD"); // To debug

// require_once("../include/dbcommon.php"); // DataBase PHPRunner

// $file_restore = $params["file_restore"];

custom_error(2,"El fichero solicitado para el Restore es: ".$file_restore); // To debug
$_SESSION['db_file_restore'] = __DIR__.'/backup_files/'.$file_restore;

$ResetDB = new ResetDB();

$message_user = '';

$message_user = $ResetDB->do_reset();

custom_error(4,"Se ha acabado el proceso de Recuperacion con: ".$message_user); // To debug

unset($_SESSION['db_file_restore']); 

Class ResetDB
{	
  function __construct()
  {	
    $this->cred['host']	= $_SESSION['db_host'];
    $this->cred['user']	= $_SESSION['db_user'];
    $this->cred['passwd'] 	= $_SESSION['db_pwd'];
        $this->cred['port'] 	= $_SESSION['db_port'];
    $this->cred['dbName'] 	= $_SESSION['db_sys_dbname'];
    $this->cred['dumpdir'] 	= $_SESSION['db_file_restore'];
    $this->cred['prefix']	= "";
                
    $this->mysqli = new mysqli($this->cred['host'],$this->cred['user'],$this->cred['passwd'],$this->cred['dbName'],$this->cred['port']);
  }

  public function do_reset()
  {
    $connection = $this->connection();

    if($connection['status'])
    {
      $this->drop_tables();
      $this->restore_tables();

      return "Restore database finished! See file 'error.log' for detail";
    }
    else
    {
      return 'Error: '. $connection['message'];
    }
  }

  private function connection()
  {
    $return = array(
      'status' => true,
      'message' => 'Invalid credential'
    );

    // mysql connect check		
    if($this->mysqli->connect_errno) {
      $return['status'] = false;
      $return['message'] = "Connection failed: %s\n".$this->mysqli->connect_errno;			
    }

    return $return;
  }

  private function drop_tables()
  {
    $prefix = $this->cred['prefix']; // default wordpress
    $prefix_woo = $this->cred['prefix'].'woocommerce_'; // woocomerce

    $sql = "DROP TABLE IF EXISTS {$prefix}commentmeta,{$prefix}comments,{$prefix}links,
      {$prefix}options,{$prefix}postmeta,{$prefix}posts,{$prefix}terms,
      {$prefix}term_relationships,{$prefix}term_taxonomy,
      {$prefix}usermeta,{$prefix}users,
      {$prefix_woo}attribute_taxonomies,{$prefix_woo}downloadable_product_permissions,
      {$prefix_woo}order_itemmeta,{$prefix_woo}order_items,
      {$prefix_woo}tax_rates,{$prefix_woo}tax_rate_locations,
      {$prefix_woo}termmeta;";

    $this->mysqli->query($sql) or die($this->mysqli->error);
  }

  private function restore_tables()
  {
    $templine = '';
    $lines = file($this->cred['dumpdir']);
  
    foreach ($lines as $line)
    {
      if (substr($line, 0, 2) == '--' || $line == '')
      continue;

      $templine .= $line;
  
      if (substr(trim($line), -1, 1) == ';')
      {
        $this->mysqli->query($templine) or custom_error(3,"Error en sentencia: ".print('Error performing query \'<strong>' . $templine . '\': ' . mysql_error() . '<br /><br />'));
        $templine = '';
      }
    }
  }
}

Como siempre, os dejo los fuentes del ejemplo (PHPrunner 10.91), pero funcionaría con la versión 10.7 o superior.

Creo que no tendréis ningún problema en entender el ejemplo, pero si tenéis cualquier duda, me podéis escribir a mi email.

Adjuntos

Archivo Tamaño de archivo Descargas
zip PHPRunner 10.91 + backup BD+ Ficheros -files- 38 MB 18

Blog personal para facilitar soporte gratuito a usuarios de React y PHPRunner