[duvida] - Backups programados de um site

Infelizmente, não estou a ver como trabalha o cPanel, nem sei se será possível enviar um anexo com a função mail() do PHP. Estava a pensar fazer um backup diário da base de dados, mas nada feito, enquanto não tiver tempo/paciência para mais :(

edit ------------

Cá me desenrasquei. Modifiquei (bastante) o script do Santo38 de forma a que fizesse apenas um dump da base de dados e enviasse o GZip do dump por e-mail. Apenas a base de dados, e apenas uma (se bem que isto pode ser modificado para tratar uma array delas).

PHP:
<?php
// PHP script que permite backups automaticos e periodicos oara um servidor/conta remota.
// Este script contém passwords importantes.  MANTENHA ESTE FICHEIRO SEGURO! (coloque-o no directorio raiz e não no /www/)
// ********* OS SEGUINTES ITEMS NECESSITAM DE SER CONFIGURADOS *********
 
// Informação necessária para o acesso ao cPanel
$cpuser = "usernamecPanel"; // Username de login do CPanel
$cppass = "passwordcPanel"; // Password de login no CPanel
$domain = "dominio"; // nome do dominio onde corre o cpanel
$skin = "x3"; // Skin que é usada no cPanel
 
// nome da base de dados
$dbname = "nomedabd";
 
// Email para notificações + dados
$mailfrom = "from <email>";
$mailto = "email";
$mailsubject = "DB Backup [$dbname] @ $domain (" . date("d-m-Y H:i:s") . ")";
 
// Modo seguro ou inseguro?
$secure = 0; // Colocar a 1 para SSL (requer suporte de SSL), de outro modo usa o HTTP
 
// Colocar a 1 para colocar os resultados da página web no log do cron
$debug = 0;
 
// *********** NENHUM DOS ITEMS A SEGUIR NECESSITA DE CONFIGURAÇÃO *********
if ($secure) {
   $url = "ssl://".$domain;
   $port = 2083;
} else {
   $url = $domain;
   $port = 2082;
}
 
$socket = fsockopen($url,$port);
 
if (!$socket) { 
 echo "Falha a abrir o socket da ligação… Tchau!\n"; 
 exit; 
}
 
$response = "";
 
// codificar a string de autenticação
$authstr = $cpuser.":".$cppass;
$pass = base64_encode($authstr);
 
// Fazer post ao cpanel
fputs($socket,"POST /getsqlbackup/$dbname.sql.gz HTTP/1.0\r\n");
fputs($socket,"Host: $domain\r\n");
fputs($socket,"Authorization: Basic $pass\r\n");
fputs($socket,"Connection: Close\r\n");
fputs($socket,"\r\n");
 
// Apanhar a resposta mesmo que nao seja necessario fazer nada com ela.
while (!feof($socket)) {
  $response .= fgets($socket, 4096);
}
fclose($socket);
 
// solução muito "martelada", mas assim teve de ser
$x = explode("\r\n\r\n", $response);
$response = $x[1];
 
// para o envio do e-mail:
$filename = "$dbname.sql.gz";
$boundary1 = rand(0,9)."-" .rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999);
$boundary2 = rand(0,9)."-".rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999);
$phpver = phpversion();
 
$headers = <<< ENDOFHEADERS
From: $mailfrom
X-Mailer: PHP/$phpver
MIME-Version: 1.0
Content-Type: multipart/mixed;
 boundary="$boundary1"
ENDOFHEADERS;
 
$attach = <<< ENDOFATTACH
--$boundary1
Content-Type: application/x-gzip;
 name="$filename"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; 
 filename="$filename"
ENDOFATTACH;
 
$attach .= chunk_split(base64_encode($response), 70);
 
$body = <<< ENDOFBODY
This is a multi-part message in MIME format.
 
--$boundary1
Content-Type: multipart/alternative;
    boundary="$boundary2"
 
--$boundary2
Content-Type: text/plain;
    charset="windows-1256"
Content-Transfer-Encoding: quoted-printable
 
Backup follows
 
--$boundary2
Content-Type: text/html;
    charset="windows-1256"
Content-Transfer-Encoding: quoted-printable
 
<b>Backup follows</b>
 
--$boundary2--
 
$attach
--$boundary1--
ENDOFBODY;
 
$foiEnviado = mail($mailto, $mailsubject, $body, $headers);
 
echo ($foiEnviado?"Mail sent":"Mail not sent");
?>

Espero que dê jeito a alguém :x

p.s.: não sei usar o PEAR, por isso não me linchem por ter escrito os cabeçalhos todos :x
 
Última edição:
Isso só faz o backup à base de dados. O problema de um backup completo é que, quando o mesmo ocupa mais de 20 MBs, não pode ser enviado por e-mail.

E no meu caso esse script já está em uso, mas como a base de dados ocupa 2MBs, e, em GZip, 500KBs, não há crise :D
 
Eu encontrei este código, que supostamente, permite enviar um backup da base de dados anexado num email, ou permite enviá-lo para um servidor ftp remoto:

PHP:
<?php
  $dbhost        = 'localhost';  // Server address of your MySQL Server
 
  $dbuser        = 'usuario';      // Username to access MySQL database
  $dbpass        = 'senha';    // Password to access MySQL database
 
  $dbname        = 'nome do banco de dados';      // Database Name
 
  $use_gzip      = 'yes';        // Set to No if you don't want the files sent in .gz format
 
 
  $remove_file   = 'no';        // Set this to yes if you want to remove the file after sending. Yes is recommended.
 
 
  $use_email     = 'yes';          // Set to 'yes' if you want the backup to be sent throug email. Fill out next 3 lines.
 
  $send_to       = '[email protected]';   // E-mail to send the mail to
 
  $send_from     = '[email protected]'; // E-mail the mail comes from
 
  $subject       = "Backup do Banco de dados efetuado! - " . date("j F Y"); // Subject in the email to be sent.
 
 
  $use_ftp       = 'no'; // Do you want this database backup uploaded to an ftp server? Fill out the next 4 lines
  $ftp_server    = '';   // FTP hostname
 
  $ftp_user_name = '';   // FTP username
  $ftp_user_pass = '';   // FTP password
 
  $ftp_path      = "/";  // This is the path to upload on your ftp server!
 
  $echo_status = 'no';   // Set to 'no' if the script should work silently (no output will be sent to the screen)
 
 
 
# You probably don't need to edit below this line....
#-------------------------------------------------------------------------------
 
  $db = mysql_connect("$dbhost","$dbuser","$dbpass");
 
        mysql_select_db("$dbname",$db);
 
  $path = make_dir();
 
  if ($echo_status == 'yes') {
 
    print "Dumpfile will be written to $path<br>";
  }
 
  $result = mysql_query("show tables from $dbname");
 
  while (list($table) = mysql_fetch_row($result)) {
 
    $newfile .= get_def($table);
    $newfile .= "\n\n";
    $newfile .= get_content($table);
 
    $newfile .= "\n\n";
    $i++;
    if ($echo_status == 'yes') {
 
      print "Dumped table $table<br>";
    }
  }
 
        $file_name = $dbname . "-" . date("Ymd-Hi") . ".sql";
 
        $file_path = $path . $file_name;
 
  if ($use_gzip == "yes") {
 
    $file_name .= ".gz";
    $file_path .= ".gz";
    $zp = gzopen($file_path, "wb9");
 
    gzwrite($zp,$newfile);
    gzclose($zp);
 
 
    if ($echo_status == 'yes') {
      print "<br>Gzip-file is created...<br>";
 
    }
  } else {
    $fp = fopen($file_path, "w");
 
    fwrite($fp, $newfile);
    fclose($fp);
 
    if ($echo_status == 'yes') {
 
      print "<br>SQL-file is created...<br>";
    }
  }
 
  if ($use_email == 'yes') {
 
    $fileatt_type = filetype($file_path);
 
    $headers = "From: $send_from";
 
 
    // Read the file to be attached ('rb' = read binary)
    $fp = fopen($file_path,'rb');
 
    $data = fread($fp,filesize($file_path));
    fclose($fp);
 
 
    // Generate a boundary string
    $semi_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
 
 
    // Add the headers for a file attachment
    $headers .= "\nMIME-Version: 1.0\n" ."Content-Type: multipart/mixed;\n" ." boundary=\"{$mime_boundary}\"";
 
 
    // Add a multipart boundary above the plain message
    $message = "This is a multi-part message in MIME format.\n\n" ."--{$mime_boundary}\n" ."Content-Type: text/plain; charset=\"iso-8859-1\"\n" ."Content-Transfer-Encoding: 7bit\n\n" .
 
    $message . "\n\n";
 
    // Base64 encode the file data
    $data = chunk_split(base64_encode($data));
 
 
    // Add file attachment to the message
    $message .= "--{$mime_boundary}\n" ."Content-Type: {$fileatt_type};\n" ." name=\"{$file_name}\"\n" ."Content-Disposition: attachment;\n" ." filename=\"{$file_name}\"\n" ."Content-Transfer-Encoding: base64\n\n" .
 
    $data . "\n\n" ."--{$mime_boundary}--\n";
 
    // Send the message
    $ok = @mail($send_to, $subject, $message, $headers);
 
 
    if ($echo_status == 'yes') {
      print "<br>Mail is sent...<br>";
 
    }
  }
 
  if ($use_ftp == 'yes') {
 
    if ($use_gzip == 'yes') {
      $mode = FTP_BINARY;
 
    } else {
      $mode = FTP_ASCII;
    }
    $ftp_id       = ftp_connect($ftp_server);
 
    $login_result = ftp_login($ftp_id, $ftp_user_name, $ftp_user_pass);
    $upload       = ftp_put($ftp_id, $ftp_path . $file_name, $file_path, $mode);
 
    ftp_close($ftp_id);
 
    if ($echo_status == 'yes') {
 
      print "<br>Backup is uploaded to $ftp_user_name@$ftp_server...<br>";
    }
  }
 
 
  if ($remove_file == "yes") {
    unlink($file_name);
 
    if ($echo_status == 'yes') {
      print "<br>File is deleted...<br>";
 
    }
  }
 
  if ($echo_status == 'yes') {
 
    print "<br>I am done!<br>";
  }
 
 
  function make_dir() {
 
    $page = split("/", getenv('SCRIPT_NAME'));
    $n = count($page)-1;
 
    $page = $page[$n];
    $page = split("\.", $page, 2);
 
    $extension = $page[1];
    $page = $page[0];
    $script     = "$page.$extension";
 
    $base_url   = "http://".$_SERVER['SERVER_NAME'];
    $directory  = $_SERVER['PHP_SELF'];
 
    $url_base = "$base_url$directory";
    $url_base = ereg_replace("$script", '', "$_SERVER[PATH_TRANSLATED]");
 
 
    $path = $url_base;
 
    return $path;
  }
 
  function get_def($table) {
 
    $def = "";
    $def .= "DROP TABLE IF EXISTS $table;\n";
    $def .= "CREATE TABLE $table (\n";
 
    $result = mysql_query("SHOW FIELDS FROM $table") or die("Table $table not existing in database");
 
    while($row = mysql_fetch_array($result)) {
      $def .= "    $row[Field] $row[Type]";
 
      if ($row["Default"] != "") $def .= " DEFAULT '$row[Default]'";
 
      if ($row["Null"] != "YES") $def .= " NOT NULL";
 
      if ($row[Extra] != "") $def .= " $row[Extra]";
 
      $def .= ",\n";
    }
    $def = ereg_replace(",\n$","", $def);
 
    $result = mysql_query("SHOW KEYS FROM $table");
    while($row = mysql_fetch_array($result)) {
 
      $kname=$row[Key_name];
      if(($kname != "PRIMARY") && ($row[Non_unique] == 0)) $kname="UNIQUE|$kname";
 
      if(!isset($index[$kname])) $index[$kname] = array();
 
      $index[$kname][] = $row[Column_name];
    }
    while(list($x, $columns) = @each($index)) {
 
      $def .= ",\n";
      if($x == "PRIMARY") $def .= "   PRIMARY KEY (" . implode($columns, ", ") . ")";
 
      else if (substr($x,0,6) == "UNIQUE") $def .= "   UNIQUE ".substr($x,7)." (" . implode($columns, ", ") . ")";
 
      else $def .= "   KEY $x (" . implode($columns, ", ") . ")";
 
    }
    $def .= "\n);";
    return (stripslashes($def));
 
  }
 
  function get_content($table) {
    $content="";
 
    $result = mysql_query("SELECT * FROM $table");
    while($row = mysql_fetch_row($result)) {
 
      $insert = "INSERT INTO $table VALUES (";
      for($j=0; $j<mysql_num_fields($result);$j++) {
 
        if(!isset($row[$j])) $insert .= "NULL,";
 
        else if($row[$j] != "") $insert .= "'".addslashes($row[$j])."',";
 
        else $insert .= "'',";
      }
      $insert = ereg_replace(",$","",$insert);
 
      $insert .= ");\n";
      $content .= $insert;
    }
    return $content;
 
  }
 ?>

Contudo, eu já tentei executar este script e dá-me estes erros:

Warning: fopen(zubux_bux-20080821-0707.sql) [function.fopen]: failed to open stream: Permission denied in /home/zubux/public_html/backup.php on line 63

Warning: fwrite(): supplied argument is not a valid stream resource in /home/zubux/public_html/backup.php on line 64

Warning: fclose(): supplied argument is not a valid stream resource in /home/zubux/public_html/backup.php on line 65

Warning: filetype() [function.filetype]: Lstat failed for zubux_bux-20080821-0707.sql in /home/zubux/public_html/backup.php on line 73

Warning: fopen(zubux_bux-20080821-0707.sql) [function.fopen]: failed to open stream: No such file or directory in /home/zubux/public_html/backup.php on line 78

Warning: filesize() [function.filesize]: stat failed for zubux_bux-20080821-0707.sql in /home/zubux/public_html/backup.php on line 79

Warning: fread(): supplied argument is not a valid stream resource in /home/zubux/public_html/backup.php on line 79

Warning: fclose(): supplied argument is not a valid stream resource in /home/zubux/public_html/backup.php on line 80

Warning: unlink(zubux_bux-20080821-0707.sql) [function.unlink]: No such file or directory in /home/zubux/public_html/backup.php on line 125

Já alterei as permissões do ficheiro para 777, e a situação permanece.

O que está errado?
 
Infelizmente, não estou a ver como trabalha o cPanel, nem sei se será possível enviar um anexo com a função mail() do PHP. Estava a pensar fazer um backup diário da base de dados, mas nada feito, enquanto não tiver tempo/paciência para mais :(

edit ------------

Cá me desenrasquei. Modifiquei (bastante) o script do Santo38 de forma a que fizesse apenas um dump da base de dados e enviasse o GZip do dump por e-mail. Apenas a base de dados, e apenas uma (se bem que isto pode ser modificado para tratar uma array delas).

PHP:
<?php
// PHP script que permite backups automaticos e periodicos oara um servidor/conta remota.
// Este script contém passwords importantes.  MANTENHA ESTE FICHEIRO SEGURO! (coloque-o no directorio raiz e não no /www/)
// ********* OS SEGUINTES ITEMS NECESSITAM DE SER CONFIGURADOS *********
 
// Informação necessária para o acesso ao cPanel
$cpuser = "usernamecPanel"; // Username de login do CPanel
$cppass = "passwordcPanel"; // Password de login no CPanel
$domain = "dominio"; // nome do dominio onde corre o cpanel
$skin = "x3"; // Skin que é usada no cPanel
 
// nome da base de dados
$dbname = "nomedabd";
 
// Email para notificações + dados
$mailfrom = "from <email>";
$mailto = "email";
$mailsubject = "DB Backup [$dbname] @ $domain (" . date("d-m-Y H:i:s") . ")";
 
// Modo seguro ou inseguro?
$secure = 0; // Colocar a 1 para SSL (requer suporte de SSL), de outro modo usa o HTTP
 
// Colocar a 1 para colocar os resultados da página web no log do cron
$debug = 0;
 
// *********** NENHUM DOS ITEMS A SEGUIR NECESSITA DE CONFIGURAÇÃO *********
if ($secure) {
   $url = "ssl://".$domain;
   $port = 2083;
} else {
   $url = $domain;
   $port = 2082;
}
 
$socket = fsockopen($url,$port);
 
if (!$socket) { 
 echo "Falha a abrir o socket da ligação… Tchau!\n"; 
 exit; 
}
 
$response = "";
 
// codificar a string de autenticação
$authstr = $cpuser.":".$cppass;
$pass = base64_encode($authstr);
 
// Fazer post ao cpanel
fputs($socket,"POST /getsqlbackup/$dbname.sql.gz HTTP/1.0\r\n");
fputs($socket,"Host: $domain\r\n");
fputs($socket,"Authorization: Basic $pass\r\n");
fputs($socket,"Connection: Close\r\n");
fputs($socket,"\r\n");
 
// Apanhar a resposta mesmo que nao seja necessario fazer nada com ela.
while (!feof($socket)) {
  $response .= fgets($socket, 4096);
}
fclose($socket);
 
// solução muito "martelada", mas assim teve de ser
$x = explode("\r\n\r\n", $response);
$response = $x[1];
 
// para o envio do e-mail:
$filename = "$dbname.sql.gz";
$boundary1 = rand(0,9)."-" .rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999);
$boundary2 = rand(0,9)."-".rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999);
$phpver = phpversion();
 
$headers = <<< ENDOFHEADERS
From: $mailfrom
X-Mailer: PHP/$phpver
MIME-Version: 1.0
Content-Type: multipart/mixed;
 boundary="$boundary1"
ENDOFHEADERS;
 
$attach = <<< ENDOFATTACH
--$boundary1
Content-Type: application/x-gzip;
 name="$filename"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; 
 filename="$filename"
ENDOFATTACH;
 
$attach .= chunk_split(base64_encode($response), 70);
 
$body = <<< ENDOFBODY
This is a multi-part message in MIME format.
 
--$boundary1
Content-Type: multipart/alternative;
    boundary="$boundary2"
 
--$boundary2
Content-Type: text/plain;
    charset="windows-1256"
Content-Transfer-Encoding: quoted-printable
 
Backup follows
 
--$boundary2
Content-Type: text/html;
    charset="windows-1256"
Content-Transfer-Encoding: quoted-printable
 
<b>Backup follows</b>
 
--$boundary2--
 
$attach
--$boundary1--
ENDOFBODY;
 
$foiEnviado = mail($mailto, $mailsubject, $body, $headers);
 
echo ($foiEnviado?"Mail sent":"Mail not sent");
?>
Espero que dê jeito a alguém :x

p.s.: não sei usar o PEAR, por isso não me linchem por ter escrito os cabeçalhos todos :x

Usei o teu script, e de facto, apareceu a mensagem: Mail sent.

Contudo, o anexo do email tem 1 K, ou seja não é nada aquilo.

Que problema será?
 
Afinal já deu. Era eu que tinha o nome da base de dados errado.

De qq forma, só enviou o anexo bem a primeira vez. Depois os anexos já só tinham 0K
 
Se calhar o ficheiro é read-only?
No fim, faz unlink($filename);, depois do último echo.

Agora já funciona.

Meti no cron, mas recebo um email com isto:

- Ocultar citação -
/home/zubux/ficheiro.php: line 1: ?php
: No such file or directory
/home/zubux/ficheiro.php: line 2: //: is a directory
/home/zubux/ficheiro.php: line 3: syntax error near unexpected token `('
/home/zubux/ficheiro.php: line 3: `// Este script contém passwords importantes. MANTENHA ESTE FICHEIRO SEGURO! (coloque-o no directorio raiz e não no /www/)


E não executa o ficheiro.

O comando que coloquei foi (tempo) /home/zubux/ficheiro.php
 
Lê bem este tópico! Tu não executas o ficheiro PHP, executas o programa PHP e dás como parâmetro o ficheiro PHP :P

Ou seja,
Código:
/usr/local/bin/php /home/zubux/ficheiro.php
 
Lê bem este tópico! Tu não executas o ficheiro PHP, executas o programa PHP e dás como parâmetro o ficheiro PHP :P

Ou seja,
Código:
/usr/local/bin/php /home/zubux/ficheiro.php

Ok, muito obrigado e desculpa a maçada.

Mas este script umas vezes envia a base de dados, outras vezes, n envia nada....
 
Back
Topo