You are here

function _backup_migrate_check_destination_dir in Backup and Migrate 6

Same name and namespace in other branches
  1. 5.2 includes/destinations.file.inc \_backup_migrate_check_destination_dir()
  2. 5 backup_migrate.module \_backup_migrate_check_destination_dir()

Prepare the destination directory for the backups.

5 calls to _backup_migrate_check_destination_dir()
backup_migrate_backup in ./backup_migrate.module
The backup/export form.
backup_migrate_schedule in ./backup_migrate.module
The schedule form.
_backup_migrate_list_files in ./backup_migrate.module
List the previously created backup files.
_backup_migrate_remove_expired_backups in ./backup_migrate.module
Remove older backups keeping only the number specified by the aministrator.
_backup_migrate_save_to_disk in ./backup_migrate.module
Save the backup file to the appropriete folder on the server.

File

./backup_migrate.module, line 1037
Create (manually or scheduled) and restore backups of your Drupal MySQL database with an option to exclude table data (f.e. cache_*)

Code

function _backup_migrate_check_destination_dir($mode = "") {
  $directory = _backup_migrate_get_save_path();
  $out = $subdir = rtrim($directory . "/" . $mode, "/");

  // Check for the main directory.
  if (!file_check_directory($directory, TRUE)) {

    // unable to create main directory
    $message = t("Unable to create or write to the save directory '%directory'. Please check the file permissions on your files directory.", array(
      '%directory' => $directory,
    ));
    drupal_set_message($message, "error");
    return FALSE;
  }

  // Create subdir if needed.
  if ($subdir != $directory && !file_check_directory($subdir, TRUE)) {

    // Unable to create sub directory.
    $message = t("Unable to create or write to the save directory '%directory'. Please check the file permissions on your files directory.", array(
      '%directory' => $subdir,
    ));
    drupal_set_message($message, "error");
    return FALSE;
  }

  // If the files are saved inside the webroot (ie: may be web-accesible).
  if (strtolower(substr(realpath($directory), 0, strlen($_SERVER['DOCUMENT_ROOT']))) === strtolower($_SERVER['DOCUMENT_ROOT'])) {

    // Check for a htaccess file which adequately protects the backup files.
    $htaccess_lines = "order allow,deny\ndeny from all\n";
    if (!is_file($directory . '/.htaccess') || strpos(file_get_contents($directory . '/.htaccess'), $htaccess_lines) === FALSE) {

      // Attempt to protect the backup files from public access using htaccess.
      if (($fp = @fopen($directory . '/.htaccess', 'w')) && @fputs($fp, $htaccess_lines)) {
        fclose($fp);
        chmod($directory . '/.htaccess', 0664);
      }
      else {
        $message = "Security warning: Couldn't modify .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code> or add them to the existing .htaccess file";
        $replace = array(
          '%directory' => $directory,
          '!htaccess' => '<br />' . nl2br(check_plain($htaccess_lines)),
        );
        drupal_set_message(t($message, $replace), "error");
        watchdog('security', $message, $replace, WATCHDOG_ERROR);
        return FALSE;
      }
    }

    // Check the user agent to make sure we're not responding to a request from drupal itself.
    // That should prevent infinite loops which could be caused by poormanscron in some circumstances.
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Drupal') !== FALSE) {
      return FALSE;
    }

    // Check to see if the destination is publicly accessible
    $test_contents = "this file should not be publicly accesible";

    // Create the the text.txt file if it's not already there.
    if (!is_file($subdir . '/test.txt') || file_get_contents($subdir . '/test.txt') != $test_contents) {
      if ($fp = fopen($subdir . '/test.txt', 'w')) {
        @fputs($fp, $test_contents);
        fclose($fp);
      }
      else {
        $message = t("Security notice: Backup and Migrate was unable to write a test text file to the destination directory %directory, and is therefore unable to check the security of the backup destination. Backups to the server will be disabled until the destination becomes writable and secure.", array(
          '%directory' => $directory,
        ));
        drupal_set_message($message, "error");
        return FALSE;
      }
    }

    // Attempt to read the test file via http. This may fail for other reasons, so it's not a bullet-proof check.
    $path = trim(substr($subdir . '/test.txt', strlen(file_directory_path())), '\\/');
    if (_backup_migrate_test_file_readable_remotely($path, $test_contents)) {
      $message = t("Security notice: Backup and Migrate will not save backup files to the server because the destination directory is publicly accessible. If you want to save files to the server, please secure the '%directory' directory", array(
        '%directory' => $directory,
      ));
      drupal_set_message($message, "error");
      return FALSE;
    }
  }
  return $out;
}