+Currently maintained by Alex Andrascu [1], Damien McKenna [1] and Daniel Pickering [3]. All original development up through 2015 was by Ronan Dowling [4]
+with help by Drew Gorton [5].
+
+The best way to contact the authors is to submit an issue, be it a support
+request, a feature request or a bug report, in the project issue queue:
+ 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. This directory is publicly available from the web server and urgently needs to be secured! Please see the Drupal manual on <a href="@manual">configuring the private directory path</a> on how to fix this problem.',
+ // If the HTTP request comes back as a status 200 that
+ // means the file is accessible.
+ if (!empty($result->code) && $result->code == 200) {
+ // Get the human readable information for this
+ // destination.
+ $dest_spec = $destination->get_list_row();
+
+ // Display a warning message.
+ $requirements['bmdest_' . $dest_name] = array(
+ 'severity' => REQUIREMENT_ERROR,
+ 'title' => 'Backup Migrate',
+ 'value' => $t('Files in "%dest" are publicly accessible!', array('%dest' => $dest_spec['name'])),
+ 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. These file(s) are publicly available from the web server and urgently need to be secured! Please see the Drupal manual on <a href="@manual">configuring the private directory path</a> on how to fix this problem.',
+ // 'value' => $t('Backup destinations are safe'),
+ // 'description' => $t('The backup destinations were all checked and none of them were exposing files to the public. This is a good thing.'),
+ // );
+ // }
+ // @endcode
+
+ if (variable_get('backup_migrate_disable_cron', FALSE)) {
+ $requirements['bm_disable_cron'] = array(
+ 'severity' => REQUIREMENT_INFO,
+ 'title' => 'Backup Migrate',
+ 'value' => $t('Cron tasks are disabled'),
+ 'description' => $t('The cron tasks have been disabled, so scheduled backups will not run. See the Backup & Migrate module\'s README.txt file for further details.'),
+ );
+ }
+ }
+
return $requirements;
return $requirements;
}
}
/**
/**
- * Implementation of hook_schema().
+ * Implements hook_schema().
*/
*/
function backup_migrate_schema() {
function backup_migrate_schema() {
$schema['backup_migrate_profiles'] = array(
$schema['backup_migrate_profiles'] = array(
@@ -25,11 +141,14 @@ function backup_migrate_schema() {
'key name' => 'Profile ID',
'key name' => 'Profile ID',
'admin_title' => 'name',
'admin_title' => 'name',
'primary key' => 'profile_id',
'primary key' => 'profile_id',
- 'identifier' => 'item', // Exports will be defined as $preset
- 'default hook' => 'exportables_backup_migrate_profiles', // Function hook name.
+ * Leave a message to explain the mixup over the backup option.
+ */
+function backup_migrate_update_7306() {
+ drupal_set_message(t('Please note that release 7.x-3.4 had a bug which caused all backups to be overwritten instead of having a timestamp added. Please review all backup settings to ensure they work as intended.'), 'warning');
}
}
+/**
+ * 'backup_migrate_backup_memory_limit' vs 'backup_migrate_memory_limit'.
@@ -15,9 +14,9 @@ function backup_migrate_drush_command() {
'description' => dt('Backup the site\'s database with Backup and Migrate.'),
'description' => dt('Backup the site\'s database with Backup and Migrate.'),
'aliases' => array('bb'),
'aliases' => array('bb'),
'examples' => array(
'examples' => array(
- 'drush bam-backup' => 'Backup the default databse to the manual backup directory using the default settings.',
- 'drush bam-backup db scheduled mysettings' => 'Backup the database to the scheduled directory using a settings profile called "mysettings"',
- 'drush bam-backup files' => 'Backup the files directory to the manual directory using the default settings. The Backup and Migrate Files module is required for files backups.',
+ 'drush bam-backup' => 'Backup the default database to the manual backup directory using the default settings.',
+ 'drush bam-backup db scheduled mysettings' => 'Backup the database to the scheduled directory using a settings profile called "mysettings"',
+ 'drush bam-backup files' => 'Backup the files directory to the manual directory using the default settings.',
),
),
'arguments' => array(
'arguments' => array(
'source' => "Optional. The id of the source (usually a database) to backup. Use 'drush bam-sources' to get a list of sources. Defaults to 'db'",
'source' => "Optional. The id of the source (usually a database) to backup. Use 'drush bam-sources' to get a list of sources. Defaults to 'db'",
@@ -41,7 +40,6 @@ function backup_migrate_drush_command() {
_backup_migrate_message("Could not find the profile '@profile'. Try using 'drush bam-profiles' to get a list of available profiles.", array('@profile' => $profile_id), 'error');
_backup_migrate_message("Could not find the profile '@profile'. Try using 'drush bam-profiles' to get a list of available profiles.", array('@profile' => $profile_id), 'error');
+ if (!($schedule = backup_migrate_get_schedule($schedule_id))) {
+ _backup_migrate_message("Could not find the schedule '@schedule'. Try using 'drush bam-schedules' to get a list of available schedules.", array('@schedule' => $schedule_id), 'error');
+ return;
+ }
+
+ if (!$schedule->enabled) {
+ _backup_migrate_message("Nothing to do, the schedule '@schedule' is disabled.", array('@schedule' => $schedule_id), 'warning');
_backup_migrate_message("Could not find the destination '@destination'. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
_backup_migrate_message("Could not find the destination '@destination'. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
_backup_migrate_message("Could not find the file '@file'. Try using 'drush bam-backups @destination' to get a list of available backup files in this destination destinations.", array('@destination' => $destination_id, '@file' => $file_id), 'error');
_backup_migrate_message("Could not find the file '@file'. Try using 'drush bam-backups @destination' to get a list of available backup files in this destination destinations.", array('@destination' => $destination_id, '@file' => $file_id), 'error');
* Get the rendered action links for a destination.
* Get the rendered action links for a destination.
*/
*/
- function get_actions() {
+ public function get_actions() {
$links = $this->get_action_links();
$links = $this->get_action_links();
return implode(" ", $links);
return implode(" ", $links);
}
}
@@ -774,7 +776,7 @@ class backup_migrate_item {
/**
/**
* Get the edit form for the item.
* Get the edit form for the item.
*/
*/
- function edit_form() {
+ public function edit_form() {
$form = array();
$form = array();
$form['item'] = array(
$form['item'] = array(
'#type' => 'value',
'#type' => 'value',
@@ -811,37 +813,36 @@ class backup_migrate_item {
/**
/**
* Validate the edit form for the item.
* Validate the edit form for the item.
*/
*/
- function edit_form_validate($form, &$form_state) {
+ public function edit_form_validate($form, &$form_state) {
}
}
/**
/**
* Submit the edit form for the item.
* Submit the edit form for the item.
*/
*/
- function edit_form_submit($form, &$form_state) {
+ public function edit_form_submit($form, &$form_state) {
$this->from_array($form_state['values']);
$this->from_array($form_state['values']);
$this->save();
$this->save();
_backup_migrate_message('Your !type was saved', array('!type' => t($this->singular)));
_backup_migrate_message('Your !type was saved', array('!type' => t($this->singular)));
}
}
/**
/**
- * Get the message to send to the user when confirming the deletion of the item.
+ * The message to send to the user when confirming the deletion of the item.
*/
*/
- function delete_confirm_message() {
+ public function delete_confirm_message() {
return t('Are you sure you want to delete the !type %name?', array('!type' => t($this->singular), '%name' => $this->get('name')));
return t('Are you sure you want to delete the !type %name?', array('!type' => t($this->singular), '%name' => $this->get('name')));
}
}
/**
/**
- * Get the message to send to the user when confirming the deletion of the item.
+ * The message to send to the user when confirming the deletion of the item.
*/
*/
- function revert_confirm_message() {
+ public function revert_confirm_message() {
return t('Are you sure you want to revert the !type %name back to the default settings?', array('!type' => t($this->singular), '%name' => $this->get('name')));
return t('Are you sure you want to revert the !type %name back to the default settings?', array('!type' => t($this->singular), '%name' => $this->get('name')));
$form['scheme']['#description'] = t('The type of the database. Drupal only supports one database type at a time, so this must be the same as the current database type.');
$form['scheme']['#description'] = t('The type of the database. Drupal only supports one database type at a time, so this must be the same as the current database type.');
$form['path']['#title'] = t('Database name');
$form['path']['#title'] = t('Database name');
$form['path']['#description'] = t('The name of the database. The database must exist, it will not be created for you.');
$form['path']['#description'] = t('The name of the database. The database must exist, it will not be created for you.');
@@ -54,7 +53,7 @@ class backup_migrate_destination_db extends backup_migrate_destination_remote {
/**
/**
* Validate the configuration form. Make sure the db info is valid.
* Validate the configuration form. Make sure the db info is valid.
*/
*/
- function edit_form_validate($form, &$form_state) {
+ public function edit_form_validate($form, &$form_state) {
if (!preg_match('/[a-zA-Z0-9_\$]+/', $form_state['values']['path'])) {
if (!preg_match('/[a-zA-Z0-9_\$]+/', $form_state['values']['path'])) {
form_set_error('path', t('The database name is not valid.'));
form_set_error('path', t('The database name is not valid.'));
}
}
@@ -62,56 +61,63 @@ class backup_migrate_destination_db extends backup_migrate_destination_remote {
}
}
/**
/**
- * Get the form for the settings for this destination.
+ * Get the default settings for this object.
*
*
- * Return the default tables whose data can be ignored. These tables mostly contain
- * info which can be easily reproducted (such as cache or search index)
- * but also tables which can become quite bloated but are not necessarily extremely
- * important to back up or migrate during development (such ass access log and watchdog)
+ * @return array
+ * The default tables whose data can be ignored. These tables mostly
+ * contain info which can be easily reproducted (such as cache or search
+ * index) but also tables which can become quite bloated but are not
+ * necessarily extremely important to back up or migrate during development
* Get the form for the backup settings for this destination.
* Get the form for the backup settings for this destination.
*/
*/
- function backup_settings_form($settings) {
+ public function backup_settings_form($settings) {
$objects = $this->get_object_names();
$objects = $this->get_object_names();
$form['#description'] = t("You may omit specific tables, or specific table data from the backup file. Only omit data that you know you will not need such as cache data, or tables from other applications. Excluding tables can break your Drupal install, so <strong>do not change these settings unless you know what you're doing</strong>.");
$form['#description'] = t("You may omit specific tables, or specific table data from the backup file. Only omit data that you know you will not need such as cache data, or tables from other applications. Excluding tables can break your Drupal install, so <strong>do not change these settings unless you know what you're doing</strong>.");
$form['exclude_tables'] = array(
$form['exclude_tables'] = array(
@@ -143,16 +149,15 @@ class backup_migrate_destination_db extends backup_migrate_destination_remote {
/**
/**
* Backup from this source.
* Backup from this source.
*/
*/
- function backup_to_file($file, $settings) {
+ public function backup_to_file($file, $settings) {
@@ -188,7 +193,7 @@ class backup_migrate_destination_files extends backup_migrate_destination {
/**
/**
* Check that a destination is valid.
* Check that a destination is valid.
*/
*/
- function confirm_destination() {
+ public function confirm_destination() {
if ($dir = $this->get_location()) {
if ($dir = $this->get_location()) {
return $this->check_dir($dir);
return $this->check_dir($dir);
}
}
@@ -198,10 +203,10 @@ class backup_migrate_destination_files extends backup_migrate_destination {
/**
/**
* Prepare the destination directory for the backups.
* Prepare the destination directory for the backups.
*/
*/
- function check_dir($directory) {
+ public function check_dir($directory) {
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
// Unable to create destination directory.
// Unable to create destination directory.
- _backup_migrate_message("Unable to create or write to the save directory '%directory'. Please check the file permissions that directory and try again.", array('%directory' => $directory), "error");
+ _backup_migrate_message("Unable to create or write to the save directory '%directory'. Please check the file permissions of that directory and try again.", array('%directory' => $directory), "error");
return FALSE;
return FALSE;
}
}
@@ -216,25 +221,25 @@ class backup_migrate_destination_files extends backup_migrate_destination {
/**
/**
* Check that a web accessible directory has been properly secured, othewise attempt to secure it.
* Check that a web accessible directory has been properly secured, othewise attempt to secure it.
*/
*/
- function check_web_dir($directory) {
+ public function check_web_dir($directory) {
// Check if the file has already been tested.
// Check if the file has already been tested.
- if (is_file($directory .'/tested.txt')) {
+ if (is_file($directory .'/tested.txt')) {
return $directory;
return $directory;
}
}
else {
else {
file_create_htaccess($directory, TRUE);
file_create_htaccess($directory, TRUE);
-
+
// Check the user agent to make sure we're not responding to a request from drupal itself.
// 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.
// That should prevent infinite loops which could be caused by poormanscron in some circumstances.
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Drupal') !== FALSE) {
if (strpos($_SERVER['HTTP_USER_AGENT'], 'Drupal') !== FALSE) {
return FALSE;
return FALSE;
}
}
-
- // Check to see if the destination is publicly accessible
+
+ // Check to see if the destination is publicly accessible.
$test_contents = "this file should not be publicly accessible";
$test_contents = "this file should not be publicly accessible";
// Create the the text.txt file if it's not already there.
// Create the the text.txt file if it's not already there.
- if (!is_file($directory .'/test.txt') || file_get_contents($directory .'/test.txt') != $test_contents) {
- if ($fp = fopen($directory .'/test.txt', 'w')) {
+ if (!is_file($directory .'/test.txt') || file_get_contents($directory .'/test.txt') != $test_contents) {
+ if ($fp = fopen($directory .'/test.txt', 'w')) {
@fputs($fp, $test_contents);
@fputs($fp, $test_contents);
fclose($fp);
fclose($fp);
}
}
@@ -244,16 +249,16 @@ class backup_migrate_destination_files extends backup_migrate_destination {
return FALSE;
return FALSE;
}
}
}
}
-
+
// Attempt to read the test file via http. This may fail for other reasons,
// Attempt to read the test file via http. This may fail for other reasons,
// so it's not a bullet-proof check.
// so it's not a bullet-proof check.
- if ($this->test_file_readable_remotely($directory .'/test.txt', $test_contents)) {
+ if ($this->test_file_readable_remotely($directory .'/test.txt', $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));
$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");
drupal_set_message($message, "error");
return FALSE;
return FALSE;
}
}
// Directory tested OK, so we mark it as tested.
// Directory tested OK, so we mark it as tested.
- if ($fp = fopen($directory .'/tested.txt', 'w')) {
+ if ($fp = fopen($directory .'/tested.txt', 'w')) {
$contents = t('The presence of this file indicates that this directory has been tested as safe to use as a destination for Backup and Migrate. If you change the permissions of this directory or change your web server settings, please delete this file so that the directory can be checked again.');
$contents = t('The presence of this file indicates that this directory has been tested as safe to use as a destination for Backup and Migrate. If you change the permissions of this directory or change your web server settings, please delete this file so that the directory can be checked again.');
@fputs($fp, $contents);
@fputs($fp, $contents);
fclose($fp);
fclose($fp);
@@ -265,7 +270,7 @@ class backup_migrate_destination_files extends backup_migrate_destination {
/**
/**
* Check if the given directory is within the webroot and is therefore web accessible.
* Check if the given directory is within the webroot and is therefore web accessible.
_backup_migrate_message('FTP Error: Couldn\'t write to @complete_filename when trying to save file on the ftp server.', array('@complete_filename' => $complete_filename), 'error');
_backup_migrate_message('FTP Error: Couldn\'t write to @complete_filename when trying to save file on the ftp server.', array('@complete_filename' => $complete_filename), 'error');
return FALSE;
return FALSE;
}
}
- // Everything worked OK
+ // Everything worked OK.
return TRUE;
return TRUE;
}
}
else {
else {
@@ -259,19 +256,18 @@ function drupal_ftp_file_to_ftp($file, $ftp_filename, $ftp_directory, &$ftp) {
}
}
/**
/**
- * The drupal_ftp_change_directory Function
+ * The drupal_ftp_change_directory Function
* This function simply changes into the $directory folder on the FTP server.
* This function simply changes into the $directory folder on the FTP server.
* If a connection or permission error occurs then _backup_migrate_message() will contain the error message.
* If a connection or permission error occurs then _backup_migrate_message() will contain the error message.
*/
*/
function drupal_ftp_change_directory($directory, &$ftp) {
function drupal_ftp_change_directory($directory, &$ftp) {
// Switch to another directory on the web server. If we don't
// Switch to another directory on the web server. If we don't
- // have permissions then an error will occur
-
+ // have permissions then an error will occur.
if (!@drupal_ftp_connect($ftp)) {
if (!@drupal_ftp_connect($ftp)) {
return FALSE;
return FALSE;
}
}
- // Try and change into another directory
+ // Try and change into another directory.
$chdir = ftp_chdir($ftp->__conn, $directory);
$chdir = ftp_chdir($ftp->__conn, $directory);
if (!$chdir) {
if (!$chdir) {
@@ -279,21 +275,20 @@ function drupal_ftp_change_directory($directory, &$ftp) {
return FALSE;
return FALSE;
}
}
else {
else {
- // Changing directories worked OK
+ // Changing directories worked OK.
return TRUE;
return TRUE;
}
}
}
}
/**
/**
- * The drupal_ftp_file_list Function
+ * The drupal_ftp_file_list Function
* This function will change into the $directory folder and get a list of files and directories contained in that folder.
* This function will change into the $directory folder and get a list of files and directories contained in that folder.
* This function still needs a lot of work, but should work in most cases.
* This function still needs a lot of work, but should work in most cases.
*/
*/
function drupal_ftp_file_list($directory, &$ftp) {
function drupal_ftp_file_list($directory, &$ftp) {
// This function will attempt to change into the specified
// This function will attempt to change into the specified
// directory and retrieve a list of files as an associative
// directory and retrieve a list of files as an associative
- // array. This list will include file name, size and date last modified
-
+ // array. This list will include file name, size and date last modified.
$file_array = array();
$file_array = array();
// Can we switch to the desired directory?
// Can we switch to the desired directory?
@@ -305,14 +300,14 @@ function drupal_ftp_file_list($directory, &$ftp) {
// This is slower than parsing the raw return values, but it is faster.
// This is slower than parsing the raw return values, but it is faster.
+ 'description' => t('Save the backup files to a bucket on your <a href="@link" target="_blank">Amazon S3 account</a>.', array('@link' => url('http://aws.amazon.com/s3/'))),
- $form = confirm_form($form, t('Are you sure you want to restore the database?'), BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id, t('Are you sure you want to restore the database from the backup file %file_id? This will delete some or all of your data and cannot be undone. <strong>Always test your backups on a non-production server!</strong>', array('%file_id' => $file_id)), t('Restore'), t('Cancel'));
+ $form = confirm_form($form, t('Are you sure you want to restore the database?'), BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id, t('Are you sure you want to restore the database from the backup file %file_id? This will delete some or all of your data and cannot be undone. <strong>Always test your backups on a non-production server!</strong>', array('%file_id' => $file_id)), t('Restore'), t('Cancel'));
drupal_set_message(t('Restoring will delete some or all of your data and cannot be undone. <strong>Always test your backups on a non-production server!</strong>'), 'warning', FALSE);
drupal_set_message(t('Restoring will delete some or all of your data and cannot be undone. <strong>Always test your backups on a non-production server!</strong>'), 'warning', FALSE);
- return confirm_form($form, t('Are you sure you want to delete the backup file?'), BACKUP_MIGRATE_MENU_PATH . '/destination/list/files/'. $destination_id, t('Are you sure you want to delete the backup file %file_id? <strong>This action cannot be undone.</strong>', array('%file_id' => $file_id)), t('Delete'), t('Cancel'));
+ return confirm_form($form, t('Are you sure you want to delete the backup file?'), BACKUP_MIGRATE_MENU_PATH . '/destination/list/files/'. $destination_id, t('Are you sure you want to delete the backup file %file_id? <strong>This action cannot be undone.</strong>', array('%file_id' => $file_id)), t('Delete'), t('Cancel'));
}
}
/**
/**
@@ -635,7 +633,7 @@ function backup_migrate_ui_destination_delete_file_confirm_submit($form, &$form_
@@ -968,14 +963,14 @@ class backup_migrate_destination extends backup_migrate_location {
/**
/**
* Delete the file with the given destination specific id.
* Delete the file with the given destination specific id.
*/
*/
- function _delete_file($file_id) {
+ public function _delete_file($file_id) {
// This must be overriden.
// This must be overriden.
}
}
/**
/**
* Get the edit form for the item.
* Get the edit form for the item.
*/
*/
- function edit_form() {
+ public function edit_form() {
if (get_class($this) !== 'backup_migrate_destination') {
if (get_class($this) !== 'backup_migrate_destination') {
$form = parent::edit_form();
$form = parent::edit_form();
$form['subtype'] = array(
$form['subtype'] = array(
@@ -990,17 +985,17 @@ class backup_migrate_destination extends backup_migrate_location {
'title' => t('Offsite Destinations'),
'title' => t('Offsite Destinations'),
'description' => t('For the highest level of protection, set up an offsite backup destination in a location separate from your website.'),
'description' => t('For the highest level of protection, set up an offsite backup destination in a location separate from your website.'),
'items' => array(),
'items' => array(),
- ),
+ ),
'local' => array(
'local' => array(
'title' => t('Local Destinations'),
'title' => t('Local Destinations'),
'description' => t('Local backups are quick and convenient but do not provide the additional safety of offsite backups.'),
'description' => t('Local backups are quick and convenient but do not provide the additional safety of offsite backups.'),
'items' => array(),
'items' => array(),
- ),
+ ),
'other' => array(
'other' => array(
'title' => t('Other Destinations'),
'title' => t('Other Destinations'),
'description' => t('These destinations have not been classified because they were created for Backup and Migrate version 2. They may not work correctly with this version.'),
'description' => t('These destinations have not been classified because they were created for Backup and Migrate version 2. They may not work correctly with this version.'),
'items' => array(),
'items' => array(),
- ),
+ ),
);
);
@@ -1009,8 +1004,8 @@ class backup_migrate_destination extends backup_migrate_location {
@@ -1046,27 +1041,27 @@ class backup_migrate_destination extends backup_migrate_location {
/**
/**
* Get the message to send to the user when confirming the deletion of the item.
* Get the message to send to the user when confirming the deletion of the item.
*/
*/
- function delete_confirm_message() {
+ public function delete_confirm_message() {
return t('Are you sure you want to delete the destination %name? Backup files already saved to this destination will not be deleted.', array('%name' => $this->get_name()));
return t('Are you sure you want to delete the destination %name? Backup files already saved to this destination will not be deleted.', array('%name' => $this->get_name()));
}
}
/**
/**
* Get a boolean representing if the destination is remote or local.
* Get a boolean representing if the destination is remote or local.
*/
*/
- function get_remote() {
+ public function get_remote() {
return $this->op('remote backup');
return $this->op('remote backup');
}
}
/**
/**
* Get the action links for a destination.
* Get the action links for a destination.
*/
*/
- function get_action_links() {
+ public function get_action_links() {
$out = parent::get_action_links();
$out = parent::get_action_links();
$item_id = $this->get_id();
$item_id = $this->get_id();
// Don't display the download/delete/restore ops if they are not available for this destination.
// Don't display the download/delete/restore ops if they are not available for this destination.
if ($this->op('list files') && user_access("access backup files")) {
if ($this->op('list files') && user_access("access backup files")) {
if (!$this->s3 && !empty($this->dest_url['user'])) {
if (!$this->s3 && !empty($this->dest_url['user'])) {
- $this->s3 = new S3($this->dest_url['user'], $this->dest_url['pass']);
+ // The hostname can be overridden.
+ $host = 's3.amazonaws.com';
+ if (isset($this->dest_url['host'])) {
+ $host = $this->dest_url['host'];
+ }
+ $this->s3 = new S3($this->dest_url['user'], $this->dest_url['pass'], FALSE, $host);
}
}
return $this->s3;
return $this->s3;
}
}
@@ -181,4 +182,5 @@ class backup_migrate_destination_s3 extends backup_migrate_destination_remote {
drupal_set_message(t('Due to drupal.org code hosting policies, the S3 library needed to use an S3 destination is no longer distributed with this module. You must download the library from !link and place it in one of these locations: %locations.', array('%locations' => implode(', ', $library_paths), '!link' => l('http://undesigned.org.za/2007/10/22/amazon-s3-php-class', 'http://undesigned.org.za/2007/10/22/amazon-s3-php-class'))), 'error', FALSE);
drupal_set_message(t('Due to drupal.org code hosting policies, the S3 library needed to use an S3 destination is no longer distributed with this module. You must download the library from !link and place it in one of these locations: %locations.', array('%locations' => implode(', ', $library_paths), '!link' => l('http://undesigned.org.za/2007/10/22/amazon-s3-php-class', 'http://undesigned.org.za/2007/10/22/amazon-s3-php-class'))), 'error', FALSE);
@@ -62,9 +61,9 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * Return a list of backup filetypes.
+ * Returns a list of backup filetypes.
*/
*/
- function file_types() {
+ public function file_types() {
return array(
return array(
"aes" => array(
"aes" => array(
"extension" => "aes",
"extension" => "aes",
@@ -76,9 +75,9 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * Get the compression options as an options array for a form item.
+ * Gets the compression options as an options array for a form item.
*/
*/
- function _backup_migrate_get_encryption_form_item_options() {
+ public function _backup_migrate_get_encryption_form_item_options() {
$options = array();
$options = array();
$options = array('' => t('No Encryption'));
$options = array('' => t('No Encryption'));
if (@function_exists("aes_encrypt")) {
if (@function_exists("aes_encrypt")) {
@@ -88,13 +87,14 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * AES encrypt a file.
+ * AES encrypts a file.
*/
*/
- function aes_encrypt($source, $dest) {
+ public function aes_encrypt($source, $dest) {
$success = FALSE;
$success = FALSE;
if (function_exists('aes_encrypt')) {
if (function_exists('aes_encrypt')) {
if ($data = $source->get_contents()) {
if ($data = $source->get_contents()) {
- // Add a marker to the end of the data so we can trim the padding on decrpypt.
+ // Add a marker to the end of the data so we can trim the padding on
+ // decrpypt.
$data = pack("a*H2", $data, "80");
$data = pack("a*H2", $data, "80");
if ($data = aes_encrypt($data, FALSE)) {
if ($data = aes_encrypt($data, FALSE)) {
$dest->put_contents($data);
$dest->put_contents($data);
@@ -106,9 +106,9 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * Gzip decode a file.
+ * AES decodes a file.
*/
*/
- function aes_decrypt($source, $dest) {
+ public function aes_decrypt($source, $dest) {
$success = FALSE;
$success = FALSE;
if (function_exists('aes_decrypt')) {
if (function_exists('aes_decrypt')) {
if ($data = $source->get_contents()) {
if ($data = $source->get_contents()) {
@@ -124,10 +124,11 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * Compress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
+ * Compresses a file with the given settings.
+ *
+ * Also updates settings to reflect new file mime and file extension.
*/
*/
- function file_encrypt($file, $settings) {
+ public function file_encrypt($file, $settings) {
if (!empty($settings->filters['encryption'])) {
if (!empty($settings->filters['encryption'])) {
switch ($settings->filters['encryption']) {
switch ($settings->filters['encryption']) {
case "aes":
case "aes":
@@ -146,10 +147,11 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
}
}
/**
/**
- * Decompress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
+ * Decompresses a file with the given settings.
+ *
+ * Also updates settings to reflect new file mime and file extension.
*/
*/
- function file_decrypt($file) {
+ public function file_decrypt($file) {
$success = FALSE;
$success = FALSE;
if ($file) {
if ($file) {
switch ($file->type_id()) {
switch ($file->type_id()) {
@@ -157,11 +159,11 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
$from = $file->pop_type();
$from = $file->pop_type();
$success = $this->aes_decrypt($from, $file);
$success = $this->aes_decrypt($from, $file);
break;
break;
+
default:
default:
return $file;
return $file;
- break;
- }
-
+ }
+
if (!$success) {
if (!$success) {
if (function_exists('aes_decrypt')) {
if (function_exists('aes_decrypt')) {
_backup_migrate_message("Could not decrpyt backup file. Please check that the file is valid and that the encryption key of the server matches the server that created the backup.", array(), 'error');
_backup_migrate_message("Could not decrpyt backup file. Please check that the file is valid and that the encryption key of the server matches the server that created the backup.", array(), 'error');
@@ -173,5 +175,5 @@ class backup_migrate_filter_encryption extends backup_migrate_filter {
@@ -65,7 +64,7 @@ class backup_migrate_filter_utils extends backup_migrate_filter {
'#type' => 'textarea',
'#type' => 'textarea',
'#title' => t('Site off-line message'),
'#title' => t('Site off-line message'),
'#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
'#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
- '#description' => t('Message to show visitors when the site is in off-line mode.')
+ '#description' => t('Message to show visitors when the site is in off-line mode.'),
);
);
$form['advanced']['utils_description'] = array(
$form['advanced']['utils_description'] = array(
'#type' => 'textarea',
'#type' => 'textarea',
@@ -92,7 +91,7 @@ class backup_migrate_filter_utils extends backup_migrate_filter {
/**
/**
* Get the form for the restore settings for this filter.
* Get the form for the restore settings for this filter.
*/
*/
- function restore_settings_form($settings) {
+ public function restore_settings_form($settings) {
$form = array();
$form = array();
if (module_exists('devel') && variable_get('dev_query', 0)) {
if (module_exists('devel') && variable_get('dev_query', 0)) {
@@ -118,7 +117,13 @@ class backup_migrate_filter_utils extends backup_migrate_filter {
'#type' => 'textarea',
'#type' => 'textarea',
'#title' => t('Site off-line message'),
'#title' => t('Site off-line message'),
'#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
'#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
- '#description' => t('Message to show visitors when the site is in off-line mode.')
+ '#description' => t('Message to show visitors when the site is in off-line mode.'),
- foreach ((array)$this->destination_id as $destination_id) {
- if (!in_array($destination_id, $ids) && $destination = backup_migrate_get_destination($destination_id)) {
+ foreach ((array)$this->destination_id as $destination_id) {
+ if (!in_array($destination_id, $ids) && $destination = backup_migrate_get_destination($destination_id)) {
$this->destinations[] = $destination;
$this->destinations[] = $destination;
$weights[] = $destination->get('weight');
$weights[] = $destination->get('weight');
$ids[] = $destination_id;
$ids[] = $destination_id;
@@ -323,7 +341,7 @@ class backup_migrate_profile extends backup_migrate_item {
/**
/**
* Get the name of the destination.
* Get the name of the destination.
*/
*/
- function get_destination_name() {
+ public function get_destination_name() {
$out = array();
$out = array();
foreach ($this->get_destinations() as $destination) {
foreach ($this->get_destinations() as $destination) {
$out[] = $destination->get_name();
$out[] = $destination->get_name();
@@ -335,9 +353,9 @@ class backup_migrate_profile extends backup_migrate_item {
}
}
/**
/**
- * Get the source and destinations specified in the given settings profile
+ * Get the source and destinations specified in the given settings profile.
*/
*/
- function get_all_locations() {
+ public function get_all_locations() {
$out = array();
$out = array();
$out += $this->get('destinations');
$out += $this->get('destinations');
$out[] = $this->get('source');
$out[] = $this->get('source');
@@ -347,7 +365,7 @@ class backup_migrate_profile extends backup_migrate_item {
/**
/**
* Get the edit form.
* Get the edit form.
*/
*/
- function edit_form() {
+ public function edit_form() {
$form = parent::edit_form();
$form = parent::edit_form();
$form['name'] = array(
$form['name'] = array(
"#type" => "textfield",
"#type" => "textfield",
@@ -362,8 +380,8 @@ class backup_migrate_profile extends backup_migrate_item {
/**
/**
* Get the message to send to the user when confirming the deletion of the item.
* Get the message to send to the user when confirming the deletion of the item.
*/
*/
- function delete_confirm_message() {
+ public function delete_confirm_message() {
return t('Are you sure you want to delete the profile %name? Any schedules using this profile will be disabled.', array('%name' => $this->get('name')));
return t('Are you sure you want to delete the profile %name? Any schedules using this profile will be disabled.', array('%name' => $this->get('name')));
$form['cron_settings']['cron_elysia']['#description'] .= ' ' . t('Install !elysia to enable this option.', array('!elysia' => l(t('Elysia Cron'), 'http://drupal.org/project/elysia_cron')));
$form['cron_settings']['cron_elysia']['#description'] .= ' ' . t('Install !elysia to enable this option.', array('!elysia' => l(t('Elysia Cron'), 'http://drupal.org/project/elysia_cron')));
}
}
@@ -488,7 +487,7 @@ class backup_migrate_schedule extends backup_migrate_item {
"#type" => "textfield",
"#type" => "textfield",
"#title" => t('Cron Schedule'),
"#title" => t('Cron Schedule'),
'#length' => 10,
'#length' => 10,
- "#description" => t('Specify the frequecy of the schedule using standard cron notation. For more information see the !elysiareadme.', array('!elysiareadme' => l(t('the Elysia Cron README'), 'http://drupalcode.org/project/elysia_cron.git/blob/refs/heads/7.x-1.x:/README.txt'))),
+ "#description" => t('Specify the frequency of the schedule using standard cron notation. For more information see the !elysiareadme.', array('!elysiareadme' => l(t('the Elysia Cron README'), 'http://drupalcode.org/project/elysia_cron.git/blob/refs/heads/7.x-1.x:/README.txt'))),
"#default_value" => $this->get('cron_schedule'),
"#default_value" => $this->get('cron_schedule'),
'#parents' => array('cron_schedule'),
'#parents' => array('cron_schedule'),
);
);
@@ -502,8 +501,6 @@ class backup_migrate_schedule extends backup_migrate_item {
'#parents' => array('cron'),
'#parents' => array('cron'),
);
);
-
-
$keep = $this->get('keep');
$keep = $this->get('keep');
$form['delete'] = array(
$form['delete'] = array(
'#type' => 'checkbox',
'#type' => 'checkbox',
@@ -558,7 +555,7 @@ class backup_migrate_schedule extends backup_migrate_item {
/**
/**
* Submit the edit form.
* Submit the edit form.
*/
*/
- function edit_form_validate($form, &$form_state) {
+ public function edit_form_validate($form, &$form_state) {
if (!is_numeric($form_state['values']['period']['number']) || $form_state['values']['period']['number'] <= 0) {
if (!is_numeric($form_state['values']['period']['number']) || $form_state['values']['period']['number'] <= 0) {
form_set_error('period][number', t('Backup period must be a number greater than 0.'));
form_set_error('period][number', t('Backup period must be a number greater than 0.'));
}
}
@@ -566,10 +563,10 @@ class backup_migrate_schedule extends backup_migrate_item {
@@ -613,14 +610,14 @@ class backup_migrate_schedule extends backup_migrate_item {
/**
/**
* Get the message to send to the user when confirming the deletion of the item.
* Get the message to send to the user when confirming the deletion of the item.
*/
*/
- function delete_confirm_message() {
+ public function delete_confirm_message() {
return t('Are you sure you want to delete the schedule %name? Backups made with this schedule will not be deleted.', array('%name' => $this->get('name')));
return t('Are you sure you want to delete the schedule %name? Backups made with this schedule will not be deleted.', array('%name' => $this->get('name')));
}
}
/**
/**
* Perform the cron action. Run the backup if enough time has elapsed.
* Perform the cron action. Run the backup if enough time has elapsed.
*/
*/
- function cron() {
+ public function cron() {
$now = time();
$now = time();
// Add a small negative buffer (1% of the entire period) to the time to account for slight difference in cron run length.
// Add a small negative buffer (1% of the entire period) to the time to account for slight difference in cron run length.
@@ -635,13 +632,17 @@ class backup_migrate_schedule extends backup_migrate_item {
/**
/**
* Run the actual schedule.
* Run the actual schedule.
*/
*/
- function run() {
+ public function run() {
+ // Clear cached profile data which could have been altered by previous
_backup_migrate_message('Files were not restored because the archive did not seem to contain a files directory or was in a format that Backup and Migrate couldn\'t read', array(), 'warning');
_backup_migrate_message('Files were not restored because the archive did not seem to contain a files directory or was in a format that Backup and Migrate couldn\'t read', array(), 'warning');
@@ -210,7 +233,7 @@ class backup_migrate_files_destination_archivesource extends backup_migrate_dest
// Restore the sql db.
// Restore the sql db.
if ($sqlfile && file_exists($sqlfile)) {
if ($sqlfile && file_exists($sqlfile)) {
- $db_settings = drupal_clone($settings);
+ $db_settings = clone $settings;
$db_settings->source_id = 'db';
$db_settings->source_id = 'db';
$file = new backup_file(array('filepath' => $sqlfile));
$file = new backup_file(array('filepath' => $sqlfile));
* Get the form for the backup settings for this destination.
* Get the form for the backup settings for this destination.
*/
*/
- function backup_settings_form($settings) {
+ public function backup_settings_form($settings) {
$objects = $this->get_object_names();
$objects = $this->get_object_names();
$form['#description'] = t("You may omit specific tables, or specific table data from the backup file. Only omit data that you know you will not need such as cache data, or tables from other applications. Excluding tables can break your Drupal install, so <strong>do not change these settings unless you know what you're doing</strong>.");
$form['#description'] = t("You may omit specific tables, or specific table data from the backup file. Only omit data that you know you will not need such as cache data, or tables from other applications. Excluding tables can break your Drupal install, so <strong>do not change these settings unless you know what you're doing</strong>.");
$form['exclude_tables'] = array(
$form['exclude_tables'] = array(
@@ -141,23 +147,27 @@ class backup_migrate_source_db extends backup_migrate_source_remote {
/**
/**
* Backup from this source.
* Backup from this source.
*/
*/
- function backup_to_file($file, $settings) {
+ public function backup_to_file($file, $settings) {
- * Get the form for the settings for the files destination.
+ * Gets the form for the settings for the files destination.
*/
*/
- function edit_form() {
+ public function edit_form() {
$form = parent::edit_form();
$form = parent::edit_form();
$form['location'] = array(
$form['location'] = array(
"#type" => "textfield",
"#type" => "textfield",
"#title" => t("Directory path"),
"#title" => t("Directory path"),
"#default_value" => $this->get_location(),
"#default_value" => $this->get_location(),
"#required" => TRUE,
"#required" => TRUE,
- "#description" => t('Enter the path to the directory to save the backups to. Use a relative path to pick a path relative to your Drupal root directory. The web server must be able to write to this path.'),
+ "#description" => t('Enter the path to the directory to backup. Use a relative path to pick a path relative to your Drupal root directory. The web server must be able to read from this path.'),
);
);
return $form;
return $form;
}
}
/**
/**
- * Return a list of backup filetypes.
+ * Returns a list of backup filetypes.
*/
*/
- function file_types() {
+ public function file_types() {
return array(
return array(
"tar" => array(
"tar" => array(
"extension" => "tar",
"extension" => "tar",
@@ -61,27 +69,27 @@ class backup_migrate_destination_filesource extends backup_migrate_source {
}
}
/**
/**
- * Get the form for the settings for this destination.
+ * Gets the form for the settings for this destination.
*
*
- * Return the default directories whose data can be ignored. These directories contain
- * info which can be easily reproducted. Also exclude the backup and migrate folder
- * to prevent exponential bloat.
+ * Return the default directories whose data can be ignored. These directories
+ * contain info which can be easily reproducted. Also exclude the backup and
@@ -37,7 +37,7 @@ function _context_context_registry() {
'plugin' => 'context_condition_path',
'plugin' => 'context_condition_path',
),
),
'query_string' => array(
'query_string' => array(
- 'title' => t('Query String'),
+ 'title' => t('Query string'),
'description' => t('Set this context when any of the query strings above match the page query string. Put each query string on a separate line. You can use the "*" character as a wildcard and <code>~</code> to exclude one or more query strings.'),
'description' => t('Set this context when any of the query strings above match the page query string. Put each query string on a separate line. You can use the "*" character as a wildcard and <code>~</code> to exclude one or more query strings.'),
'plugin' => 'context_condition_query_string',
'plugin' => 'context_condition_query_string',
),
),
@@ -119,7 +119,7 @@ function _context_context_registry() {
'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
);
);
return $permissions;
return $permissions;
@@ -143,7 +143,7 @@ function context_ui_editor($form, &$form_state, $contexts) {
$form['title'] = array(
$form['title'] = array(
'#prefix' => '<h2 class="context-editor-title">',
'#prefix' => '<h2 class="context-editor-title">',
- '#markup' => t('Select the Context/Layer to Edit'),
+ '#markup' => t('Select the context/layer to edit'),
'#suffix' => '</h2>',
'#suffix' => '</h2>',
'#weight' => -2,
'#weight' => -2,
);
);
@@ -151,10 +151,7 @@ function context_ui_editor($form, &$form_state, $contexts) {
//add some help text to the top of the form
//add some help text to the top of the form
$form['help'] = array (
$form['help'] = array (
'#prefix' => '<p class="context-help help">',
'#prefix' => '<p class="context-help help">',
- '#markup' => t('Select which context, or layer of blocks, to edit.
- Each context is configured to appear on different sets of pages so read the description carefully.
- When you are done editing click Done and save your changes.
- You may use the Stop Editing Layout link to close the editor.'),
+ '#markup' => t('Select which context, or layer of blocks, to edit. Each context is configured to appear on different sets of pages so read the description carefully. When you are done editing click Done and save your changes. You may use the Stop Editing Layout link to close the editor.'),
'#suffix' => '</p>',
'#suffix' => '</p>',
'#weight' => -1,
'#weight' => -1,
);
);
@@ -166,10 +163,9 @@ function context_ui_editor($form, &$form_state, $contexts) {
- '#description' => t('When enabled all contextual links will have a Edit Layout link that will refresh the page with the context editor in a dialog box.'),
+ '#description' => t('When enabled all contextual links will have a <em>Edit layout</em> link that will refresh the page with the context editor in a dialog box.'),
@@ -14,7 +14,7 @@ class context_reaction_template_suggestions extends context_reaction {
return array(
return array(
'#title' => t('Template suggestions'),
'#title' => t('Template suggestions'),
'#type' => 'textarea',
'#type' => 'textarea',
- '#description' => t('Enter template suggestions such as "page__front", one per line, in order of preference (using underscores instead of hyphens). For more information, please visit ') . l(t('Drupal 7 Template (Theme Hook) Suggestions'), 'http://drupal.org/node/1089656', array(array('target' => '_blank'), 'html' => TRUE,)) . '.',
+ '#description' => t('Enter template suggestions such as "page__front", one per line, in order of preference (using underscores instead of hyphens). For more information, please visit <a href="@template-suggestions">Drupal 7 Template (Theme Hook) Suggestions</a>.', array('@template-suggestions' => 'http://drupal.org/node/1089656')),
- '#markup' => t('To add a block to the current region, simply click on the block. You may use the category filter to filter by
- block type or the search filter to find the block that you wish to add.'),
+ '#markup' => t('To add a block to the current region, simply click on the block. You may use the category filter to filter by block type or the search filter to find the block that you wish to add.'),
'#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'),
'#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'),
+ '#description' => t('If you have a large site with many features, you may experience lag on accessing the modules administration page. If disabled, features will not rebuild when viewing the modules list.'),
+ $this->assertTrue(!empty($export['features']['features_api']) && key($export['features']['features_api']) == 'api:' . FEATURES_API, 'Features API key added to new export.');
+ $this->assertTrue((bool)features_get_features('features_test'), 'Features test recognized as a feature.');
+ $this->assertFalse((bool)features_get_features('features'), 'Features module not recognized as a feature.');
@@ -29,16 +29,8 @@ function features_test_image_default_styles() {
// Exported image style: features_test.
// Exported image style: features_test.
$styles['features_test'] = array(
$styles['features_test'] = array(
- 'name' => 'features_test',
'effects' => array(
'effects' => array(
2 => array(
2 => array(
- 'label' => 'Scale',
- 'help' => 'Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.',
else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) {
else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) {
// Download link clicked.
// Download link clicked.
console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.googleanalytics.getPageUrl(this.href), Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase());
console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.googleanalytics.getPageUrl(this.href), Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase());
$this->assertRaw(t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'), '[testGoogleAnalyticsConfiguration]: Invalid Web Property ID number validated.');
$this->assertRaw(t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'), '[testGoogleAnalyticsConfiguration]: Invalid Web Property ID number validated.');
+ $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
+ $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is enabled.');
+ $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is enabled.');
+ $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
+ $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is disabled.');
+ $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is disabled.');
}
}
function testGoogleAnalyticsPageVisibility() {
function testGoogleAnalyticsPageVisibility() {
// Verify that no tracking code is embedded into the webpage; if there is
// Verify that no tracking code is embedded into the webpage; if there is
// only the module installed, but UA code not configured. See #2246991.
// only the module installed, but UA code not configured. See #2246991.
$this->drupalGet('');
$this->drupalGet('');
- $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
+ $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
// Checking for tracking code URI here, as $ua_code is displayed in the form.
// Checking for tracking code URI here, as $ua_code is displayed in the form.
- $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
+ $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
// Test whether tracking code display is properly flipped.
// Test whether tracking code display is properly flipped.
// Checking for tracking code URI here, as $ua_code is displayed in the form.
// Checking for tracking code URI here, as $ua_code is displayed in the form.
- $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
+ $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
$this->drupalGet('');
$this->drupalGet('');
$this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.');
$this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.');
@@ -97,13 +126,15 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
// Enable tracking code for all user roles.
// Enable tracking code for all user roles.
variable_set('googleanalytics_roles', array());
variable_set('googleanalytics_roles', array());
+ $base_path = base_path();
+
// Test whether 403 forbidden tracking code is shown if user has no access.
// Test whether 403 forbidden tracking code is shown if user has no access.
$this->drupalGet('admin');
$this->drupalGet('admin');
- $this->assertRaw('/403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.');
+ $this->assertRaw($base_path . '403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.');
// Test whether 404 not found tracking code is shown on non-existent pages.
// Test whether 404 not found tracking code is shown on non-existent pages.
$this->drupalGet($this->randomName(64));
$this->drupalGet($this->randomName(64));
- $this->assertRaw('/404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.');
+ $this->assertRaw($base_path . '404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.');
// DNT Tests:
// DNT Tests:
// Enable system internal page cache for anonymous users.
// Enable system internal page cache for anonymous users.
@@ -139,7 +170,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
@@ -227,13 +258,14 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
$this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.');
$this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.');
$this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.');
$this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.');
$this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.');
$this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.');
+ $this->assertRaw('"trackDomainMode":2,', '[testGoogleAnalyticsTrackingCode]: Domain mode value is of type integer.');
$this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.');
$this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.');
variable_set('googleanalytics_domain_mode', 0);
variable_set('googleanalytics_domain_mode', 0);
// Test whether debugging script has been enabled.
// Test whether debugging script has been enabled.
variable_set('googleanalytics_debug', 1);
variable_set('googleanalytics_debug', 1);
$this->drupalGet('');
$this->drupalGet('');
- $this->assertRaw('//www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
+ $this->assertRaw('https://www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
// Check if text and link is shown on 'Status Reports' page.
// Check if text and link is shown on 'Status Reports' page.
// Requires 'administer site configuration' permission.
// Requires 'administer site configuration' permission.
@@ -243,7 +275,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
// Test whether debugging script has been disabled.
// Test whether debugging script has been disabled.
variable_set('googleanalytics_debug', 0);
variable_set('googleanalytics_debug', 0);
$this->drupalGet('');
$this->drupalGet('');
- $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
+ $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
// Test whether the CREATE and BEFORE and AFTER code is added to the tracker.
// Test whether the CREATE and BEFORE and AFTER code is added to the tracker.
$codesnippet_create = array(
$codesnippet_create = array(
@@ -284,6 +316,7 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase {
+ $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 1)), '@invalid-tokens' => implode(', ', array('[current-user:name]')))));
+ $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 2)), '@invalid-tokens' => implode(', ', array('[current-user:edit-url]')))));
+ $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 3)), '@invalid-tokens' => implode(', ', array('[user:name]')))));
+ // BUG #2037595
+ //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 4)), '@invalid-tokens' => implode(', ', array('[term:name]')))));
+ //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 5)), '@invalid-tokens' => implode(', ', array('[term:tid]')))));
+ }
+}
+
+/**
+ * Test custom url functionality of Google Analytics module.
- //drupal_set_message('Example error <em>message</em> with html tags and <a href="http://example.com/">link</a>.', 'error');
+ //drupal_set_message('Example error <em>message</em> with html tags and <a href="https://example.com/">link</a>.', 'error');
//$this->drupalGet('');
//$this->drupalGet('');
//$this->assertNoRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
//$this->assertNoRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
//$this->assertNoRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
//$this->assertNoRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
@@ -684,13 +782,13 @@ class GoogleAnalyticsPhpFilterTest extends DrupalWebTestCase {
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar' has been detected as internal link.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar' has been detected as internal link.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar#foo'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar#foo' has been detected as internal link.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'node/1?foo=bar#foo'), "Link '" + base_url + Drupal.settings.basePath + "node/1?foo=bar#foo' has been detected as internal link.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'go/foo'), "Link '" + base_url + Drupal.settings.basePath + "go/foo' has been detected as internal link.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isInternal(base_url + Drupal.settings.basePath + 'go/foo'), "Link '" + base_url + Drupal.settings.basePath + "go/foo' has been detected as internal link.");
- Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isInternal('http://example.com/node/3'), "Link 'http://example.com/node/3' has been detected as external link.");
+ Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isInternal('https://example.com/node/3'), "Link 'https://example.com/node/3' has been detected as external link.");
console.groupEnd();
console.groupEnd();
console.group("Test 'isInternalSpecial':");
console.group("Test 'isInternalSpecial':");
@@ -86,9 +86,11 @@ $(document).ready(function() {
console.groupEnd();
console.groupEnd();
console.group("Test 'getPageUrl':");
console.group("Test 'getPageUrl':");
- Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
- Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from absolute url '" + base_path + "'.");
- Drupal.googleanalytics.test.assertSame('http://example.com/node/2', Drupal.googleanalytics.getPageUrl('http://example.com/node/2'), "Full qualified external url 'http://example.com/node/2' has been extracted.");
+ Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(window.location.href), "Absolute internal URL '" + base_path + "' has been extracted from full qualified url '" + window.location.href + "'.");
+ Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_path), "Absolute internal URL '" + base_path + "' has been extracted from absolute url '" + base_path + "'.");
+ //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
+ //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from absolute url '" + base_path + "'.");
+ Drupal.googleanalytics.test.assertSame('https://example.com/node/2', Drupal.googleanalytics.getPageUrl('https://example.com/node/2'), "Full qualified external url 'https://example.com/node/2' has been extracted.");
Drupal.googleanalytics.test.assertSame('//example.com/node/2', Drupal.googleanalytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted.");
Drupal.googleanalytics.test.assertSame('//example.com/node/2', Drupal.googleanalytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
- Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
+ Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.net' has been found in cross domain list.");
Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
- Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
+ Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.net' not found in cross domain list.");
}
}
else {
else {
console.warn('Cross domain tracking is not enabled. Tests skipped.');
console.warn('Cross domain tracking is not enabled. Tests skipped.');