Скрипт для резервного копирования БД MySQL

Как-то гуляя по просторам Интернета, на Ответы@Mail.Ru наткнулся на такой вопрос:
У меня проблема. Мне нужно перенести базы с одного сервака на другой. А на первом недоступна phpMyAdmin. Что делать?

Когда-то я уже встречал такой вопрос на форуме, и видел ответ. Вот его-то я и привожу здесь в неизменном виде:

<?php

$host = "localhost"// имя сервера   
$user = "root";       // имя пользователя
$password = "";       // пароль
$db_name = "sql";     // имя базы данных
$dump_dir = "./dump"; // директория, куда будем сохранять резервную копию БД

$link = mysql_connect($host, $user, $password) or die( "Сервер базы данных не доступен" );
$db = mysql_select_db($db_name) or die( "База данных не доступна" );
$tables = "SHOW TABLES";
$res = mysql_query($tables) or die( "Ошибка при выполнении запроса: ".mysql_error() );
while( $table = mysql_fetch_row($res) )
{
    $fp = fopen( $dump_dir."/".$table[0].".sql", "a" );
    if ( $fp )
    {
        $query = "TRUNCATE TABLE `".$table[0]."`;\n";
        fwrite ($fp, $query);
        $rows = 'SELECT * FROM `'.$table[0].'`';
        $r = mysql_query($rows) or die("Ошибка при выполнении запроса: ".mysql_error());
        while( $row = mysql_fetch_row($r) )
        {
            $query = "";
            foreach ( $row as $field )
            {
                if ( is_null($field) )
                    $field = "NULL";
                else
                    $field = "'".mysql_escape_string( $field )."'";
                if ( $query == "" )
                    $query = $field;
                else
                    $query = $query.', '.$field;
            }
            $query = "INSERT INTO `".$table[0]."` VALUES (".$query.");\n";
            fwrite ($fp, $query);
        }
        fclose ($fp);
    }
}
 
?>

Ссылки по теме:

Как узнать сколько раз скачали файл?

Допустим, у вас на сайте есть раздел Downloads, где посетитель может скачать скрипты, музыку, фотографии и т.п. Но как узнать, какие файлы пользуются успехом, а какие лежат мертвым грузом (и их можно безболезненно удалить, чтобы не занимали место)?

Как решить эту проблему? Выход - счетчик скачиваний. Вы наверняка уже их видели. Обычно этот счетчик устанавливается рядом со ссылкой на скачиваемый документ. Примерно, все выглядит так:

Ссылка – Скачали [57]

57 – это число, которое увеличивается на 1 при каждом скачивании файла.

Пусть информация о файлах для скачивания у нас хранится в таблице базы данных, которая имеет следующую структуру:

  • id - уникальный ID файла
  • title - название программы, например, “Текстовой редактор NotePad++
  • about - краткое описание программы, например, “Бесплатный редактор текстовых файлов (замена стандартного Блокнота) с поддержкой синтаксиса большого количества языков программирования, ориентирован для работы в операционной системе MS Windows
  • name - имя файла для скачивания, например, NotePadPP.zip
  • download - количество скачиваний

Вообще говоря, файлы можно просто хранить под именами 1.zip, 2.zip, 3.zip, где 1, 2, 3 - уникальные ID. Потому как в поле name особого смысла нет - это избыточная информация. Единственная польза от такого поля - это при скачивании отдавать файл с каким-нибудь осмысленным именем, т.е. NotePadPP.zip, а не 1.zip.

Все файлы для скачивания лежат в директории
DOCUMENT_ROOT/downloads
В этой же директории лежит файл index.php, который выводит список всех файлов, доступных для скачивания и файл download.php, который отдает файлы на скачивание.

Файл index.php

<?php
$query = "SELECT id, name, about, download FROM programs WHERE 1";
$res = mysql_query( $query );
echo '<table border="1">';
while( $row = mysql_fetch_array( $res ) ) {
  echo '<tr>';
  echo '<td>'.$row['name'].'</td>';
  echo '<td>'.$row['about'].'</td>';
  echo '<td><a href="/downloads/download.php?id='.$row['id'].'" target="_blank">Скачать</td>';
  echo '<td>Скачан '.$row['downloads'].' раз</td>';
  echo '</tr>';
}
echo '</table>';
?>

Файл download.php

<?php
if ( !isset( $_GET['id'] ) ) {
  // если не передан ID файла
  header ("HTTP/1.0 404 Not Found");
  die();
}
$id = (int)$_GET['id'];
if ( $id < 1 ) {
  header ("HTTP/1.0 404 Not Found");
  die();
}
// Узнаем имя файла для скачивания
$query = "SELECT name FROM programs WHERE id=".$id;
$res = mysql_query( $query );
if ( mysql_num_rows( $res ) == 0 ) {
  header ("HTTP/1.0 404 Not Found");
  die();
}
$filename = mysql_result( $res, 0, 0 );
// если файла нет
if (!file_exists($filename)) {
  header ("HTTP/1.0 404 Not Found");
  die();
}
// сообщаем размер файла
header( 'Content-Length: '.filesize($filename) );
// дата модификации файла для кеширования
header( 'Last-Modified: '.date("D, d M Y H:i:s T", filemtime($filename)) );
// сообщаем тип данных - zip-архив
header('Content-type: application/zip');
// файл будет получен с именем $filename
header('Content-Disposition: attachment; filename="'.$filename.'"');
// начинаем передачу содержимого файла
readfile($filename);
// Увеличиваем счетчик количества закачек
mysql_query( "UPDATE programs SET download=download+1 WHERE id=".$id );
?>

Отправка сообщения с сайта на e-mail

В очередной раз встретил на форуме сообщение: “Скажите, как сделать скрипт на php для отправки на мыло через сайт. Например, я ввожу на сайте в поля нужный текст и нажимаю “Отправить”. После чего текст отправляется кому-нибудь на e-mail. Очень нужно!“. Быстро набросал простенький скрипт отправки сообщений на e-mail. Когда в следующий раз услышу такой вопрос - буду давать ссылку на эту страницу.

Для отправки почтового сообщения создадим HTML-форму, состоящую из трех текстовых полей для имени автора name, его e-mail адреса email, темы сообщения subject и текстовой области message для ввода содержимого письма.

Письмо будем отправлять по адресу администратора сайта $admin = ‘admin@mail.ru’

<?php
session_start();
$admin = 'admin@mail.ru';

if ( isset( $_POST['sendMail'] ) ) {
  $name  = substr( $_POST['name'], 0, 64 );
  $email   = substr( $_POST['email'], 0, 64 );
  $subject = substr( $_POST['subject'], 0, 64 );
  $message = substr( $_POST['message'], 0, 250 );
 
  $error = '';
  if ( empty( $name ) ) $error = $error.'<li>Не заполнено поле "Имя"</li>';
  if ( empty( $email ) ) $error = $error.'<li>Не заполнено поле "E-mail"</li>';
  if ( empty( $subject ) ) $error = $error.'<li>Не заполнено поле "Тема"</li>';
  if ( empty( $message ) ) $error = $error.'<li>Не заполнено поле "Сообщение"</li>';
  if ( !empty( $email ) and !preg_match( "#^[0-9a-z_\-\.]+@[0-9a-z\-\.]+\.[a-z]{2,6}$#i", $email ) )
    $error = $error.'<li>поле "E-mail" должно соответствовать формату somebody@somewhere.ru</li>';
  if ( !empty( $error ) ) {
    $_SESSION['sendMailForm']['error']   = '<p>При заполнении формы были допущены ошибки:</p><ul>'.$error.'</ul>';
    $_SESSION['sendMailForm']['name']    = $name;
    $_SESSION['sendMailForm']['email']   = $email;
    $_SESSION['sendMailForm']['subject'] = $subject;
    $_SESSION['sendMailForm']['message'] = $message;
    header( 'Location: '.$_SERVER['PHP_SELF'] );
    die();
  }
 
  $body = "АВТОР:\r\n".$name."\r\n\r\n";
  $body .= "E-MAIL:\r\n".$email."\r\n\r\n";
  $body .= "ТЕМА:\r\n".$subject."\r\n\r\n";
  $body .= "СООБЩЕНИЕ:\r\n".$message;
  $body = quoted_printable_encode( $body );

  $theme   = '=?windows-1251?B?'.base64_encode('Заполнена форма на сайте').'?=';
  $headers = "From: ".$_SERVER['SERVER_NAME']." <".$email.">\r\n";
  $headers = $headers."Return-path: <".$email.">\r\n";
  $headers = $headers."Content-type: text/plain; charset=\"windows-1251\"\r\n";
  $headers = $headers."Content-Transfer-Encoding: quoted-printable\r\n\r\n";
 
  if ( mail($admin, $theme, $body, $headers) )
    $_SESSION['success'] = true;
  else
    $_SESSION['success'] = false;
  header( 'Location: '.$_SERVER['PHP_SELF'] );
  die();
}
 
function quoted_printable_encode ( $string ) {
   // rule #2, #3 (leaves space and tab characters in tact)
   $string = preg_replace_callback (
   '/[^\x21-\x3C\x3E-\x7E\x09\x20]/',
   'quoted_printable_encode_character',
   $string
   );
   $newline = "=\r\n"; // '=' + CRLF (rule #4)
   // make sure the splitting of lines does not interfere with escaped characters
   // (chunk_split fails here)
   $string = preg_replace ( '/(.{73}[^=]{0,3})/', '$1'.$newline, $string);
   return $string;
}

function quoted_printable_encode_character ( $matches ) {
   $character = $matches[0];
   return sprintf ( '=%02x', ord ( $character ) );
}
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Отправить письмо</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body>

<?php
if ( isset( $_SESSION['success'] ) ) {
  if ( $_SESSION['success'] )
    echo '<p>Письмо успешно отправлено</p>';
  else
    echo '<p>Ошибка при отправке письма</p>';
  unset( $_SESSION['success'] );
}
if ( isset( $_SESSION['sendMailForm'] ) ) {
  echo $_SESSION['sendMailForm']['error'];
  $name    = htmlspecialchars ( $_SESSION['sendMailForm']['name'] );
  $email   = htmlspecialchars ( $_SESSION['sendMailForm']['email'] );
  $subject = htmlspecialchars ( $_SESSION['sendMailForm']['subject'] );
  $message = htmlspecialchars ( $_SESSION['sendMailForm']['message'] );
  unset( $_SESSION['sendMailForm'] );
} else {
  $name    = '';
  $email   = '';
  $subject = '';
  $message = '';
}
?>

<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST">
<table>
<tr><td>Имя:</td><td><input type="text" name="name" maxlength="64" value="<?php echo $name ?>" /></td></tr>
<tr><td>E-mail:</td><td><input type="text" name="email" maxlength="64" value="<?php echo $email ?>" /></td></tr>
<tr><td>Тема:</td><td><input type="text" name="subject" maxlength="64" value="<?php echo $subject ?>" /></td></tr>
<tr><td>Сообщение:</td><td><textarea name="message" rows="5" cols="30"><?php echo $message ?></textarea></td></tr>
<tr><td>&nbsp;</td><td><input type="submit" name="sendMail" value="Отправить" /></td></tr>
</table>
</form>

</body>
</html>

Чтобы понять, зачем здесь сессия и редирект после вызова функции mail(), надо прочитать статью Обработка ошибочного заполнения формы.

Попробуйте убрать редирект и поработать со скриптом. Во-первых, если после отправки формы нажать Refresh, то браузер выдаст сообщение о том, что страницу обновить невозможно без повторной отсылки данных. Во-вторых, если после отправки сообщения уйти на другую страницу, то при нажатии на кнопку Back (т.е. при попытке вернуться на POST-страницу) опять будет выведено сообщение о необходимости повторной отсылки данных. Мало того, что это совершенно нелогично и неудобно с точки зрения пользователя (он ведь уже отправил данные!), так ещё и если он в этот момент нажмёт “OK”, то данные формы будут отправлены повторно. Соответственно, и письмо будет отправлено еще раз.

Проблем этих можно избежать, если после обработки POST-запроса сразу же делать GET-редирект.

Теперь по поводу сессии. В случае ошибочного заполнения пользователем формы, хорошим тоном считается показать ему эту же форму, заполненною введёнными данными (чтобы пользователю не пришлось заполнять всё заново) и снабжённую сообщением об ошибке. При этом ошибочно введённые данные передаются через механизм сессий.

Ссылки по теме: