Problem/Motivation
Backup & Migrate does not properly support StreamWappers. I'm using Windows Azure Blob to backup my site, and I've created stream wrappers in the form of "backup://manual" and "backup://scheduled". While it does properly backup to the cloud, it does not properly load the files, download, restore or delete.
Steps to reproduce
Create a stream wrapper for an external site, such as Azure Blob. Create a new destination using the Server Directory. For the location, use the stream interface, such as "backups://manual"
Proposed resolution
I was able to get this to work with a few changes. Primarily, instead of calling drupal_realpath() to get the real URL, it should use the stream wrapper interface.
here are the changes:
In /include/file.inc, return the path variable:
public function filepath() {
if ($filepath = drupal_realpath($this->path)) {
//return $filepath;
}
return $this->path;
}
in include/destination.file.inc, use get_location() instead of get_realpath():
/**
* Get the filepath from the given file id.
*/
public function get_filepath($file_id) {
//if ($dir = $this->get_realpath()) {
if ($dir = $this->get_location()) {
$filepath = rtrim($dir, '/') . '/' . $file_id;
return $filepath;
}
return FALSE;
}
Also, in the _list_files() function, support is required for reading from stream wrappers:
/**
* File list destination callback.
*/
public function _list_files() {
$files = array();
if ($dir = $this->get_realpath()) {
if ($handle = @opendir($dir)) {
require_once dirname(__FILE__) . '/files.inc';
while (FALSE !== ($file = readdir($handle))) {
if (substr($file, 0, 1) !== '.') {
$filepath = $dir . "/" . $file;
$files[$file] = new backup_file(array('filepath' => $filepath));
}
}
}
// support for stream wrappers
else {
list($scheme, $target) = explode('://', $this->location, 2);
$scheme.='://';
$wrapper = file_stream_wrapper_get_instance_by_uri( $scheme );
if ( $wrapper->dir_opendir($this->location,'') )
{
while (FALSE !== ($file = $wrapper->dir_readdir())) {
if (substr($file, 0, 1) !== '.') {
$filepath = $this->location . "/" . $file;
$files[$file] = new backup_file(array('filepath' => $filepath));
}
}
$wrapper->dir_closedir();
}
}
}
return $files;
}
Remaining tasks
This now seems to work, but if the community can review and let me know if I missed anything. Hope this helps anyone having issues saving backups to external cloud sites like Azure.
Comments
Comment #2
dczaretsky commentedOne more thought: another way to handle both realpaths and stream wrapper paths would be to check if the file is accessible.
For example, in /includes/file.inc we check the filepath is accessible, otherwise return the stream wrapper path.
Similarly in /includes/destinations.files.inc, we can check if the dir is readable, or otherwise return the stream wrapper path:
Comment #3
ivnishDrupal 7 is EOL. This issue will be closed.