View source
<?php
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Database\Database;
define('DEMO_DUMP_VERSION', '1.1');
define('VERSION', '8');
function demo_get_fileconfig($filename = 'Set default value') {
$fileconfig = [];
if (!file_stream_wrapper_valid_scheme('private')) {
if (!defined('MAINTENANCE_MODE')) {
\Drupal::messenger()
->addWarning(t('The <a href="../../config/media/file-system">private filesystem</a> must be configured in order to create or load snapshots.'));
}
return FALSE;
}
$fileconfig['path'] = 'private://' . \Drupal::config('demo.settings')
->get('demo_dump_path', 'demo');
$fileconfig['dumppath'] = $fileconfig['path'];
$fileconfig['site'] = str_replace('sites', '', \Drupal::service('site.path'));
if (!\Drupal::service('file_system')
->prepareDirectory($fileconfig['dumppath'], FileSystemInterface::CREATE_DIRECTORY)) {
return FALSE;
}
file_save_htaccess($fileconfig['path'], TRUE);
$fileconfig['sql'] = $filename . '.sql';
$fileconfig['sqlfile'] = $fileconfig['dumppath'] . '/' . $fileconfig['sql'];
$fileconfig['info'] = $filename . '.info';
$fileconfig['infofile'] = $fileconfig['dumppath'] . '/' . $fileconfig['info'];
return $fileconfig;
}
function demo_get_dumps() {
$fileconfig = demo_get_fileconfig();
$files = \Drupal::service('file_system')
->scanDirectory($fileconfig['dumppath'], '/\\.info$/');
foreach ($files as $file => $object) {
$files[$file]->filemtime = filemtime($file);
$files[$file]->filesize = filesize(substr($file, 0, -4) . 'sql');
}
uasort($files, function ($a, $b) {
return $a->filemtime < $b->filemtime;
});
$element = [
'#type' => 'radios',
'#title' => t('Snapshot'),
'#required' => TRUE,
'#parents' => [
'filename',
],
'#options' => [],
'#attributes' => [
'class' => [
'demo-snapshots-widget',
],
],
'#attached' => [
'library' => [
'demo/demo-library',
],
],
];
foreach ($files as $filename => $file) {
$info = demo_get_info($filename);
$title = t('@snapshot <small>(@date, @aize)</small>', [
'@snapshot' => $info['filename'],
'@date' => \Drupal::service('date.formatter')
->format($file->filemtime, 'small'),
'@aize' => format_size($file->filesize),
]);
$description = '';
if (!empty($info['description'])) {
$description .= '<p>' . $info['description'] . '</p>';
}
$download_sql_url = Url::fromRoute('demo.download', $route_parameters = [
'filename' => $file->name,
'type' => 'sql',
]);
$download_info_url = Url::fromRoute('demo.download', $route_parameters = [
'filename' => $file->name,
'type' => 'info',
]);
$description .= '<p>' . t('Download: ' . Link::fromTextAndUrl(t('.info file'), $download_info_url) . ', ' . Link::fromTextAndUrl(t('.sql file'), $download_sql_url)) . '</p>';
if (count($info['modules']) > 1) {
$modules = array_diff($info['modules'], [
'filter',
'node',
'system',
'user',
'demo',
]);
sort($modules);
$description .= t('Modules: @modules', [
'@modules' => implode(', ', $modules),
]);
}
$element['#options'][$info['filename']] = $title;
$element[$info['filename']] = [
'#description' => $description,
'#file' => $file,
'#info' => $info,
];
}
return $element;
}
function demo_dump_db($filename, $options = []) {
$directory = dirname($filename);
if (!\Drupal::service('file_system')
->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY)) {
return FALSE;
}
if ($fp = fopen($filename, 'wb')) {
$header = [];
$header[] = '-- Demo module database dump';
$header[] = '-- Version ' . DEMO_DUMP_VERSION;
$header[] = '-- http://drupal.org/project/demo';
$header[] = '--';
$header[] = '-- Database: ' . _demo_get_database();
$header[] = '-- Date: ' . \Drupal::service('date.formatter')
->format(\Drupal::time()
->getRequestTime(), 'small');
$header[] = '-- Server version: ' . \Drupal::database()
->query('SELECT version()')
->fetchField();
$header[] = '-- PHP version: ' . PHP_VERSION;
$header[] = '-- Drupal version: ' . VERSION;
$header[] = '';
$header[] = 'SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";';
$header[] = 'SET FOREIGN_KEY_CHECKS = 0;';
$header[] = '';
$header[] = 'SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT;';
$header[] = 'SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS;';
$header[] = 'SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION;';
$header[] = 'SET NAMES utf8;';
$header[] = '';
fwrite($fp, implode("\n", $header));
foreach ($options['tables'] as $table => $dump_options) {
if (!_demo_table_is_view($table)) {
if ($dump_options['schema']) {
_demo_dump_table_schema($fp, $table);
}
if ($dump_options['data']) {
_demo_dump_table_data($fp, $table);
}
}
}
$footer = [];
$footer[] = '';
$footer[] = 'SET FOREIGN_KEY_CHECKS = 1;';
$footer[] = 'SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT;';
$footer[] = 'SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS;';
$footer[] = 'SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION;';
$footer[] = '';
$footer[] = '';
fwrite($fp, implode("\n", $footer));
fclose($fp);
return TRUE;
}
return FALSE;
}
function _demo_get_database() {
$database = array_keys(\Drupal::database()
->query('SHOW TABLES')
->fetchAssoc());
$database = preg_replace('/^Tables_in_/i', '', $database[0]);
return $database;
}
function _demo_enum_tables() {
return \Drupal::database()
->query('SHOW TABLES')
->fetchCol();
}
function _demo_dump_table_schema($fp, $table) {
$output = "\n";
$output .= "--\n";
$output .= "-- Table structure for table '{$table}'\n";
$output .= "--\n\n";
$connection = \Drupal::database();
$data = $connection
->query('SHOW CREATE TABLE ' . $table)
->fetchAssoc();
$status = $connection
->query('SHOW TABLE STATUS LIKE :table', [
':table' => $table,
])
->fetchAssoc();
foreach ($status as $key => $value) {
$key_lower = strtolower($key);
if ($key[0] != $key_lower[0]) {
$status[$key_lower] = $value;
unset($status[$key]);
}
}
$pattern_regex = [
'/^CREATE TABLE/',
'/"/',
];
$replacement_regex = [
'CREATE TABLE IF NOT EXISTS',
'`',
];
$text = $data['Create Table'];
$output .= preg_replace($pattern_regex, $replacement_regex, $text);
if (!strpos($output, ' ENGINE=')) {
$output .= ' ENGINE=' . $status['engine'];
}
if (!preg_match('@^\\) .*COMMENT.+$@', $output) && !empty($status['comment'])) {
$status['comment'] = preg_replace([
'@; InnoDB free: .+$@',
"/\\'/",
], [
'',
'`',
], $status['comment']);
$output .= " COMMENT='" . $status['comment'] . "'";
}
if (!empty($status['auto_increment'])) {
$output .= ' AUTO_INCREMENT=' . $status['auto_increment'];
}
$output .= ";\n";
fwrite($fp, $output);
}
function _demo_dump_table_data($fp, $table) {
$output = "\n";
$output .= "--\n";
$output .= "-- Dumping data for table '{$table}'\n";
$output .= "--\n\n";
$result = \Drupal::database()
->query("SELECT * FROM `{$table}`", [], [
'fetch' => PDO::FETCH_ASSOC,
]);
if ($fields = _demo_get_fields($result)) {
$output .= "/*!40000 ALTER TABLE {$table} DISABLE KEYS */;\n";
$search = [
'\\',
"'",
"\0",
"\n",
"\r",
"\32",
];
$replace = [
'\\\\',
"''",
'\\0',
'\\n',
'\\r',
'\\Z',
];
$insert_cmd = "INSERT INTO `{$table}` VALUES\n";
$insert_buffer = '';
$current_row = 0;
$query_size = 0;
foreach ($result as $row) {
$current_row++;
$values = [];
$field = 0;
foreach ($row as $value) {
if (!isset($value) || is_null($value)) {
$values[] = 'NULL';
}
elseif ($fields[$field]->numeric && !$fields[$field]->timestamp && !$fields[$field]->blob) {
$values[] = $value;
}
elseif ($fields[$field]->binary && $fields[$field]->blob) {
if (empty($value) && $value != '0') {
$values[] = "''";
}
else {
$values[] = '0x' . bin2hex($value);
}
}
else {
$values[] = "'" . str_replace($search, $replace, $value) . "'";
}
$field++;
}
if ($current_row == 1) {
$insert_buffer = $insert_cmd . '(' . implode(', ', $values) . ')';
}
else {
$insert_buffer = '(' . implode(', ', $values) . ')';
if ($query_size + strlen($insert_buffer) > 50000) {
fwrite($fp, $output . ";\n");
$output = '';
$current_row = 1;
$query_size = 0;
$insert_buffer = $insert_cmd . $insert_buffer;
}
}
$query_size += strlen($insert_buffer);
$output .= ($current_row == 1 ? '' : ",\n") . $insert_buffer;
}
if ($current_row > 0) {
$output .= ";\n";
}
$output .= "/*!40000 ALTER TABLE {$table} ENABLE KEYS */;\n";
}
fwrite($fp, $output);
}
function _demo_get_fields($result) {
$fields = [];
switch (db_driver()) {
case 'mysql':
$i = 0;
while ($meta = $result
->getColumnMeta($i)) {
settype($meta, 'object');
if (isset($meta->native_type)) {
$meta->numeric = strtolower($meta->native_type) == 'short';
$meta->blob = strtolower($meta->native_type) == 'blob';
$meta->timestamp = strtolower($meta->native_type) == 'long';
}
else {
$meta->numeric = $meta->blob = $meta->timestamp = FALSE;
}
$meta->binary = array_search('not_null', $meta->flags);
$fields[] = $meta;
$i++;
}
break;
}
return $fields;
}
function _demo_table_is_view($table) {
static $tables = [];
if (!isset($tables[$table])) {
$status = \Drupal::database()
->query('SHOW TABLE STATUS LIKE :table', [
':table' => $table,
])
->fetchAssoc();
$tables[$table] = strtoupper(substr($status['Comment'], 0, 4)) == 'VIEW';
}
return $tables[$table];
}
function demo_enum_tables() {
$tables = [];
$connection = Database::getConnection();
$db_options = $connection
->getConnectionOptions();
$prefixes = [];
if (!empty($db_options['prefix'])) {
if (is_array($db_options['prefix'])) {
$prefixes = array_filter($db_options['prefix']);
}
elseif ($db_options['prefix'] != '') {
$prefixes['default'] = $db_options['prefix'];
}
$rx = '/^' . implode('|', $prefixes) . '/';
}
$result = _demo_enum_tables();
foreach ($result as $table) {
if (!empty($prefixes)) {
if (preg_match($rx, $table, $matches)) {
$table_prefix = $matches[0];
$plain_table = substr($table, strlen($table_prefix));
if (isset($prefixes[$plain_table]) && $prefixes[$plain_table] == $table_prefix || $prefixes['default'] == $table_prefix) {
$tables[$table] = [
'schema' => TRUE,
'data' => TRUE,
];
}
}
}
else {
$tables[$table] = [
'schema' => TRUE,
'data' => TRUE,
];
}
}
$excludes = [
'{cache}',
'{cache_bootstrap}',
'{cache_block}',
'{cache_content}',
'{cache_field}',
'{cache_filter}',
'{cache_form}',
'{cache_menu}',
'{cache_page}',
'{cache_path}',
'{cache_update}',
'{watchdog}',
'{ctools_object_cache}',
'{cache_admin_menu}',
'{panels_object_cache}',
'{cache_views}',
'{cache_views_data}',
'{views_object_cache}',
'{cache_config}',
'{cache_container}',
'{cache_data}',
'{cache_default}',
'{cache_discovery}',
'{cache_render}',
'{cachetags}',
'{cache_entity}',
];
foreach (array_map([
$connection,
'prefixTables',
], $excludes) as $table) {
if (isset($tables[$table])) {
$tables[$table]['data'] = FALSE;
}
}
return $tables;
}
function _demo_dump($options) {
drupal_set_time_limit(600);
$info = demo_set_info($options);
if (!$info) {
return FALSE;
}
$fileconfig = demo_get_fileconfig($info['filename']);
\Drupal::moduleHandler()
->alter('demo_dump', $options, $info, $fileconfig);
if ($options['default']) {
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_dump_cron', $info['filename'])
->save();
}
if (!demo_dump_db($fileconfig['sqlfile'], $options)) {
return FALSE;
}
drupal_chmod($fileconfig['infofile']);
drupal_chmod($fileconfig['sqlfile']);
Drupal::moduleHandler()
->invokeAll('demo_dump', [
$options,
$info,
$fileconfig,
]);
return $fileconfig;
}
function demo_set_info($values = NULL) {
if (isset($values['filename']) && is_array($values)) {
if (!preg_match('/^[-_\\.a-zA-Z0-9]+$/', $values['filename'])) {
\Drupal::messenger()
->addError(t('Invalid filename. It must only contain alphanumeric characters, dots, dashes and underscores. Other characters, including spaces, are not allowed.'));
return FALSE;
}
if (!empty($values['description'])) {
$s = [
"\r\n",
"\r",
"\n",
'"',
];
$r = [
' ',
' ',
' ',
"'",
];
$values['description'] = str_replace($s, $r, $values['description']);
}
else {
$old_file = demo_get_fileconfig($values['filename']);
$old_description = demo_get_info($old_file['infofile'], 'description');
if (!empty($old_description)) {
$values['description'] = $old_description;
}
}
$infos = [];
$infos['filename'] = $values['filename'];
$infos['description'] = '"' . $values['description'] . '"';
$infos['modules'] = implode(' ', getModuleNames());
$infos['version'] = DEMO_DUMP_VERSION;
$fileconfig = demo_get_fileconfig($values['filename']);
$infofile = fopen($fileconfig['infofile'], 'w');
foreach ($infos as $key => $info) {
fwrite($infofile, $key . ' = ' . $info . "\n");
}
fclose($infofile);
return $infos;
}
}
function getModuleNames() {
$dirs = [];
foreach (\Drupal::moduleHandler()
->getModuleList() as $module => $filename) {
$dirs[$module] = $filename
->getExtensionFilename();
}
return $dirs;
}
function demo_get_info($filename, $field = NULL) {
$info = [];
if (file_exists($filename)) {
$info = parse_ini_file($filename);
if (isset($info['modules'])) {
$info['modules'] = explode(" ", $info['modules']);
}
else {
$info['modules'] = NULL;
}
if (!isset($info['version'])) {
$info['version'] = '1.0';
}
}
if (isset($field)) {
return isset($info[$field]) ? $info[$field] : NULL;
}
else {
return $info;
}
}
function demo_manage_delete_submit($form, &$form_state) {
$filename = $form_state
->getValue([
'filename',
]);
$url = Url::fromRoute('demo.delete_confirm', $route_parameters = [
'filename' => $filename,
]);
$form_state
->setRedirectUrl($url);
return;
}
function demo_config_delete_submit($form, &$form_state) {
$filename = $form_state
->getValue([
'filename',
]);
$filename = substr($filename, 15);
$url = Url::fromRoute('demo.delete_config_confirm_sub', $route_parameters = [
'filename' => $filename,
]);
$form_state
->setRedirectUrl($url);
return;
}
function _demo_reset($filename, $verbose = TRUE) {
drupal_set_time_limit(600);
$fileconfig = demo_get_fileconfig($filename);
if (!file_exists($fileconfig['sqlfile']) || !($fp = fopen($fileconfig['sqlfile'], 'r'))) {
if ($verbose) {
\Drupal::messenger()
->addError(t('Unable to read file %filename.', [
'%filename' => $fileconfig['sqlfile'],
]));
}
\Drupal::logger('demo')
->error('Unable to read file %filename.', [
'%filename' => $fileconfig['sqlfile'],
]);
return FALSE;
}
$info = demo_get_info($fileconfig['infofile']);
Drupal::moduleHandler()
->invokeAll('demo_reset_before', [
$filename,
$info,
$fileconfig,
]);
$variables = [
'demo_dump_path' => \Drupal::config('demo.settings')
->get('demo_dump_path', NULL),
];
\Drupal::database()
->query("SET FOREIGN_KEY_CHECKS = 0;");
$is_version_1_0_dump = version_compare($info['version'], '1.1', '<');
$watchdog = Database::getConnection()
->prefixTables('{watchdog}');
foreach (demo_enum_tables() as $table => $dump_options) {
if ($table != $watchdog || $is_version_1_0_dump) {
\Drupal::database()
->query("DROP TABLE {$table}");
}
}
$success = TRUE;
$query = '';
while (!feof($fp)) {
$line = fgets($fp, 16384);
if ($line && $line != "\n" && strncmp($line, '--', 2) && strncmp($line, '#', 1)) {
$query .= $line;
if (substr($line, -2) == ";\n") {
$options = [
'target' => 'default',
'return' => Database::RETURN_NULL,
];
$stmt = Database::getConnection($options['target'])
->prepare($query);
if (!$stmt
->execute([], $options)) {
if ($verbose) {
\Drupal::messenger()
->addError(strtr('Query failed: %query', [
'%query' => $query,
]));
}
$success = FALSE;
}
$query = '';
}
}
}
fclose($fp);
foreach ($variables as $key => $value) {
if (isset($value)) {
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set($key, $value)
->save();
}
else {
\Drupal::config('demo.settings')
->delete($key);
}
}
if ($success) {
if ($verbose) {
\Drupal::messenger()
->addMessage(t('Restored site from %filename.', [
'%filename' => $fileconfig['sqlfile'],
]));
}
\Drupal::logger('demo')
->notice('Restored site from %filename.', [
'%filename' => $fileconfig['sqlfile'],
]);
Drupal::moduleHandler()
->invokeAll('demo_reset', [
$filename,
$info,
$fileconfig,
]);
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE !== 'install') {
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_reset_last', \Drupal::time()
->getRequestTime())
->save();
$demo_dump_cron = \Drupal::config('demo.settings')
->get('demo_dump_cron', 'Set default value');
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_dump_cron', $demo_dump_cron)
->save();
}
}
else {
if ($verbose) {
\Drupal::messenger()
->addError(t('Failed to restore site from %filename.', [
'%filename' => $fileconfig['sqlfile'],
]));
}
\Drupal::logger('demo')
->error('Unable to read file %filename.', [
'%filename' => $fileconfig['sqlfile'],
]);
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE !== 'install') {
$request_time = \Drupal::request()->server
->getRequestTime();
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_reset_last', \Drupal::time()
->getRequestTime())
->save();
$demo_dump_cron = \Drupal::config('demo.settings')
->get('demo_dump_cron', 'Set default value');
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_dump_cron', $demo_dump_cron)
->save();
}
return $success;
}
}
function demo_cron() {
if ($interval = \Drupal::config('demo.settings')
->get('demo_reset_interval', 0)) {
$request_time = \Drupal::time()
->getRequestTime();
if (\Drupal::time()
->getRequestTime() - $interval >= \Drupal::config('demo.settings')
->get('demo_reset_last', 0)) {
_demo_reset(\Drupal::config('demo.settings')
->get('demo_dump_cron', 'Set default value'), FALSE);
}
}
}
function demo_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'demo_manage_form') {
$form['status']['demo_reset_default'] = [
'#type' => 'item',
'#title' => t('Default snapshot'),
'#markup' => SafeMarkup::checkPlain(\Drupal::config('demo.settings')
->get('demo_dump_cron', t('- None -'))),
];
$demo_dump_cron = \Drupal::config('demo.settings')
->get('demo_dump_cron', 'Set default value');
foreach ($form['dump'] as $name => $option) {
if ($name == $demo_dump_cron) {
$form['dump'][$name]['#value'] = $name;
break;
}
}
$form['actions']['cron'] = [
'#type' => 'submit',
'#value' => t('Use for cron runs'),
'#submit' => [
'demo_reset_demo_manage_form_submit',
],
];
}
elseif ($form_id == 'demo_dump_form') {
$form['dump']['default'] = [
'#title' => t('Use as default snapshot for cron runs'),
'#type' => 'checkbox',
];
}
}
function demo_reset_demo_manage_form_submit($form, &$form_state) {
demo_reset_set_default($form_state
->getValue([
'filename',
]));
}
function demo_reset_set_default($filename) {
\Drupal::service('config.factory')
->getEditable('demo.settings')
->set('demo_dump_cron', $filename)
->save();
\Drupal::messenger()
->addMessage(t('Snapshot %title will be used for cron runs.', [
'%title' => $filename,
]));
}
function build_options(array $intervals, $granularity = 2, $langcode = NULL) {
$callback = function ($value) use ($granularity, $langcode) {
return \Drupal::service('date.formatter')
->formatInterval($value, $granularity, $langcode);
};
return array_combine($intervals, array_map($callback, $intervals));
}
function demo_file_download($uri) {
$scheme = file_uri_scheme($uri);
$target = \Drupal::service('stream_wrapper_manager')
->getTarget($uri);
if ($scheme == 'private' && 0 === strpos($target, 'demo/')) {
if (\Drupal::currentUser()
->hasPermission('export configuration')) {
$request = \Drupal::request();
$date = DateTime::createFromFormat('U', $request->server
->get('REQUEST_TIME'));
$date_string = $date
->format('Y-m-d-H-i');
$hostname = str_replace('.', '-', $request
->getHttpHost());
$filename = 'config' . '-' . $hostname . '-' . $date_string . '.tar.gz';
$disposition = 'attachment; filename="' . $filename . '"';
return [
'Content-disposition' => $disposition,
];
}
return -1;
}
}
function demo_get_config_dumps() {
$fileconfig = demo_get_fileconfig();
$files = \Drupal::service('file_system')
->scanDirectory($fileconfig['dumppath'], '/\\.tar.gz$/');
foreach ($files as $file => $object) {
$files[$file]->filemtime = filemtime($file);
$files[$file]->filesize = filesize(substr($file, 0, -7) . '.tar.gz');
}
uasort($files, function ($a, $b) {
return $a->filemtime < $b->filemtime;
});
$element = [
'#type' => 'radios',
'#title' => t('Snapshot'),
'#required' => TRUE,
'#parents' => [
'filename',
],
'#options' => [],
'#attributes' => [
'class' => [
'demo-snapshots-widget',
],
],
'#attached' => [
'library' => [
'demo/demo-library',
],
],
];
foreach ($files as $filename => $file) {
$title = t('@snapshot <small>(@date, @aize)</small>', [
'@snapshot' => substr($filename, 15),
'@date' => \Drupal::service('date.formatter')
->format($file->filemtime, 'small'),
'@aize' => format_size($file->filesize),
]);
$element['#options'][$filename] = $title;
$element[$filename] = [
'#file' => $file,
];
}
return $element;
}
function demo_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.demo':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('demonstration site module help to create snapshots of your drupal site. This will save the current version of your site and you can restore to this version later. ') . '</p>';
$output .= '<h3>' . t('Two Options of taking snapshots :-') . '</h3>';
$output .= '<p>' . t('<b>(1) Database Snapshots</b> Takes the snapshot of the whole database.All files will get stored in the private directory. On resetting, All the configuration settings and nodes will get restore.') . '</p>';
$output .= '<p>' . t('<b>(2) Configuration Snapshots</b> Takes the snapshot only of the configuration settings of your drupal site. All files will get stored in the private directory.On resetting the drupal site, this will only configuration setting will be restored. Nodes will remain as it is.') . '</p>';
return $output;
}
}