| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 | <?php/** * @file * General file handling code for Backup and Migrate. */define('BACKUP_MIGRATE_FILENAME_MAXLENGTH', 255);/** * Add a file to the temporary files list for deletion when we're done. */function backup_migrate_temp_files_add($filepath = NULL) {  static $files = array();  if (!$filepath) {    return $files;  }  else {    $files[] = $filepath;  }}/** * Delete all temporary files. */function _backup_migrate_temp_files_delete() {  // Delete the temp files created during this run.  foreach (backup_migrate_temp_files_add() as $file) {    $file = drupal_realpath($file);    if (file_exists($file) && is_writable($file)) {      unlink($file);    }  }  // Delete temp files abandoned for 6 or more hours.  $dir = file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath();  $expire = time() - variable_get('backup_migrate_cleanup_time', 21600);  if (file_exists($dir) && is_dir($dir) && is_readable($dir) && $handle = opendir($dir)) {    while (FALSE !== ($file = @readdir($handle))) {      // Delete 'backup_migrate_' files in the temp directory that are older than the expire time.      // We should only attempt to delete writable files to prevent errors in shared environments.      // This could still cause issues in shared environments with poorly configured file permissions.      if (strpos($file, 'backup_migrate_') === 0 && is_writable("$dir/$file") && @filectime("$dir/$file") < $expire) {        unlink("$dir/$file");      }    }    closedir($handle);  }}/** * Return a list of backup filetypes. */function _backup_migrate_filetypes() {  backup_migrate_include('filters');  $out = backup_migrate_filters_file_types();  foreach ($out as $key => $info) {    $out[$key]['id'] = empty($info['id']) ? $key : $info['id'];  }  return $out;}/** * Adjust the length of a filename to allow for a string to be appended, * staying within the maximum filename limit. */function _backup_migrate_filename_append_prepare($filename, $append_str) {  $max_name_len = BACKUP_MIGRATE_FILENAME_MAXLENGTH - drupal_strlen($append_str);  if (drupal_strlen($filename) > $max_name_len) {    $filename = drupal_substr($filename, 0, $max_name_len);  }  return $filename;}/** * Construct a filename using token and some cleaning. */function _backup_migrate_construct_filename($filename, $timestamp='') {  if (module_exists('token')) {    $filename = token_replace($filename);  }  $filename = preg_replace("/[^a-zA-Z0-9\.\-_]/", "", $filename);  $filename = _backup_migrate_filename_append_prepare($filename, $timestamp);  $filename .= '-' . $timestamp;  $filename = trim($filename, '-');  if (drupal_strlen($filename) == 0) {    $filename = 'untitled';  }  return $filename;}/** * Construct a default filename using the site's name. */function _backup_migrate_default_filename() {  if (module_exists('token')) {    return '[site:name]';  }  else {    // Cleaning the string isn't strictly necessary but it looks better in the settings field.    return variable_get('site_name', 'backup_migrate');  }}/** * An output buffer callback which simply throws away the buffer instead of sending it to the browser. */function _backup_migrate_file_dispose_buffer($buffer) {  return "";}/** * A backup file which allows for saving to and reading from the server. */class backup_file {  var $file_info = array();  var $type = array();  var $ext = array();  var $path = "";  var $name = "";  var $handle = NULL;  /**   * Construct a file object given a file path, or create a temp file for writing.   */  function backup_file($params = array()) {    if (isset($params['filepath']) && file_exists($params['filepath'])) {      $this->set_filepath($params['filepath']);    }    else {      $this->set_file_info($params);      $this->temporary_file();    }  }  /**   * Get the file_id if the file has been saved to a destination.   */  function file_id() {    // The default file_id is the filename. Destinations can override the file_id if needed.    return isset($this->file_info['file_id']) ? $this->file_info['file_id'] : $this->filename();  }  /**   * Get the current filepath.   */  function filepath() {    return drupal_realpath($this->path);  }  /**   * Get the final filename.   */  function filename($name = NULL) {    if ($name) {      $this->name = $name;    }    return $this->name .'.'. $this->extension();  }  /**   * Set the current filepath.   */  function set_filepath($path) {    $this->path = $path;    $params = array(      'filename' => basename($path),    );    if (file_exists($path)) {      $params['filesize'] = filesize($path);      $params['filetime'] = filemtime($path);    }    $this->set_file_info($params);  }  /**   * Get one or all pieces of info for the file.   */  function info($key = NULL) {    if ($key) {      return @$this->file_info[$key];    }    return $this->file_info;  }  /**   * Get the file extension.   */  function extension() {    return implode(".", $this->ext);  }  /**   * Get the file type.   */  function type() {    return $this->type;  }  /**   * Get the file mimetype.   */  function mimetype() {    return @$this->type['filemime'] ? $this->type['filemime'] : 'application/octet-stream';  }  /**   * Get the file mimetype.   */  function type_id() {    return @$this->type['id'];  }  /**   * Can this file be used to backup to.   */  function can_backup() {    return @$this->type['backup'];  }  /**   * Can this file be used to restore to.   */  function can_restore() {    return @$this->type['restore'];  }  /**   * Can this file be used to restore to.   */  function is_recognized_type() {    return @$this->type['restore'] || @$this->type['backup'];  }  /**   * Open a file for reading or writing.   */  function open($write = FALSE, $binary = FALSE) {    if (!$this->handle) {      $path = $this->filepath();      // Check if the file can be read/written.      if ($write && ((file_exists($path) && !is_writable($path)) || !is_writable(dirname($path)))) {        _backup_migrate_message('The file %path cannot be written to.', array('%path' => $path), 'error');        return FALSE;      }      if (!$write && !is_readable($path)) {        _backup_migrate_message('The file %path cannot be read.', array('%path' => $path), 'error');        return FALSE;      }      // Open the file.      $mode = ($write ? "w" : "r") . ($binary ? "b" : "");      $this->handle = fopen($path, $mode);      return $this->handle;    }    return NULL;  }  /**   * Close a file when we're done reading/writing.   */  function close() {    fclose($this->handle);    $this->handle = NULL;  }  /**   * Write a line to the file.   */  function write($data) {    if (!$this->handle) {      $this->handle = $this->open(TRUE);    }    if ($this->handle) {      fwrite($this->handle, $data);    }  }  /**   * Read a line from the file.   */  function read($size = NULL) {    if (!$this->handle) {      $this->handle = $this->open();    }    if ($this->handle && !feof($this->handle)) {      return $size ? fread($this->handle, $size) : fgets($this->handle);    }    return NULL;  }  /**   * Write data to the file.   */  function put_contents($data) {    file_put_contents($this->filepath(), $data);  }  /**   * Read data from the file.   */  function get_contents() {    return file_get_contents($this->filepath());  }  /**   * Transfer file using http to client. Similar to the built in file_transfer,   *  but it calls module_invoke_all('exit') so that temp files can be deleted.   */  function transfer() {    $headers = array(      array('key' => 'Content-Type', 'value' => $this->mimetype()),      array('key' => 'Content-Disposition', 'value' => 'attachment; filename="'. $this->filename() .'"'),    );    // In some circumstances, web-servers will double compress gzipped files.    // This may help aleviate that issue by disabling mod-deflate.    if ($this->mimetype() == 'application/x-gzip') {      $headers[] = 'Content-Encoding: gzip';    }    if ($size = $this->info('filesize')) {      $headers[] = array('key' => 'Content-Length', 'value' => $size);    }    // Suppress the warning you get when the buffer is empty.    @ob_end_clean();    if ($this->open(FALSE, TRUE)) {      foreach ($headers as $header) {        // To prevent HTTP header injection, we delete new lines that are        // not followed by a space or a tab.        // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2        $header['value'] = preg_replace('/\r?\n(?!\t| )/', '', $header['value']);        drupal_add_http_header($header['key'], $header['value']);      }      // Transfer file in 1024 byte chunks to save memory usage.      while ($data = $this->read(1024)) {        print $data;      }      $this->close();      // Ask devel.module not to print it's footer.      $GLOBALS['devel_shutdown'] = FALSE;    }    else {      drupal_not_found();    }    // Start buffering and throw away the results so that errors don't get appended to the file.    ob_start('_backup_migrate_file_dispose_buffer');    backup_migrate_cleanup();    module_invoke_all('exit');    exit();  }  /**   * Push a file extension onto the file and return the previous file path.   */  function push_type($extension) {    $types = _backup_migrate_filetypes();    if ($type = @$types[$extension]) {      $this->push_filetype($type);    }    $out = $this->filepath();    $this->temporary_file();    return $out;  }  /**   * Push a file extension onto the file and return the previous file path.   */  function pop_type() {    $out = new backup_file(array('filepath' => $this->filepath()));    $this->pop_filetype();    $this->temporary_file();    return $out;  }  /**   * Set the current file type.   */  function set_filetype($type) {    $this->type = $type;    $this->ext = array($type['extension']);  }  /**   * Set the current file type.   */  function push_filetype($type) {    $this->ext[] = $type['extension'];    $this->type = $type;  }  /**   * Pop the current file type.   */  function pop_filetype() {    array_pop($this->ext);    $this->detect_filetype_from_extension();  }  /**   * Set the file info.   */  function set_file_info($file_info) {    $this->file_info = $file_info;    $this->ext = explode('.', @$this->file_info['filename']);    // Remove the underscores added to file extensions by Drupal's upload security.    foreach ($this->ext as $key => $val) {      $this->ext[$key] = trim($val, '_');    }    $this->filename(array_shift($this->ext));    $this->detect_filetype_from_extension();  }  /**   * Get the filetype info of the given file, or false if the file is not a valid type.   */  function detect_filetype_from_extension() {    $ext = end($this->ext);    $this->type = array();    $types = _backup_migrate_filetypes();    foreach ($types as $key => $type) {      if (trim($ext, "_0123456789") === $type['extension']) {        $this->type = $type;        $this->type['id'] = $key;      }    }  }  /**   * Get a temporary file name with path.   */  function temporary_file() {    $file = drupal_tempnam('temporary://', 'backup_migrate_');    // Add the version without the extension. The tempnam function creates this for us.    backup_migrate_temp_files_add($file);    if ($this->extension()) {      $file .= '.'. $this->extension();      // Add the version with the extension. This is the one we will actually use.      backup_migrate_temp_files_add($file);    }    $this->path = $file;  }}
 |