Index: database_pgsql_dump.inc
===================================================================
RCS file: database_pgsql_dump.inc
diff -N database_pgsql_dump.inc
--- database_pgsql_dump.inc 20 Sep 2007 15:34:41 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,14 +0,0 @@
- 'fieldset',
+ '#title' => t('Status'),
+ '#collapsible' => false,
+ );
+ if (variable_get('demo_reset_last', 0)) {
+ $reset_date = format_date(variable_get('demo_reset_last', 0));
+ }
+ else {
+ $reset_date = t('Never');
+ }
+ $form['status'][] = array(
+ '#value' => t('
Last reset: !date
', array('!date' => $reset_date)),
+ );
+ $form['status'][] = array(
+ '#value' => t('Default snapshot: !snapshot
', array('!snapshot' => variable_get('demo_dump_cron', t('None')))),
+ );
+
+ $fileconfig = demo_get_fileconfig();
+
+ $form['dump'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Dump settings'),
+ '#collapsible' => true,
+ '#collapsed' => (variable_get('demo_reset_interval', 0) ? false : true),
+ );
+ $period = drupal_map_assoc(array(0, 1800, 3600, 7200, 10800, 14400, 18000, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
+ $period[0] = t('disabled');
+ $form['dump']['interval'] = array(
+ '#type' => 'select',
+ '#title' => t('Automatically reset site every'),
+ '#default_value' => variable_get('demo_reset_interval', 0),
+ '#options' => $period,
+ '#description' => t('Select how often this demonstration site is automatically reset. Ensure that you have chosen a snapshot for cron runs in Manage snapshots first. Note: This requires cron to run at least within this interval.', array('!manage' => url('admin/settings/demo/manage'))),
+ );
+
+ $form['dump']['path'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Dump path'),
+ '#default_value' => $fileconfig['path'],
+ '#size' => 30,
+ '#description' => t('Enter a writable directory where dump files of this demonstration site are stored, f.e. %files. The name of this site (e.g. %confpath) is automatically appended to this directory.
Note: For security reasons you should store site dumps outside of the document root of your webspace!', array('%files' => file_directory_path() .'/demo', '%confpath' => $fileconfig['site'])),
+ );
+ $form[] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ );
+
+ return $form;
+}
+
+function demo_admin_settings_submit($form, &$form_state) {
+ if (!file_check_directory($form_state['values']['path'], FILE_CREATE_DIRECTORY)) {
+ form_set_error('path', t('The snapshot directory %directory could not be created.', array('%directory' => $form_state['values']['path'])));
+ return FALSE;
+ }
+ else {
+ variable_set('demo_dump_path', $form_state['values']['path']);
+ }
+ variable_set('demo_reset_interval', $form_state['values']['interval']);
+ drupal_set_message(t('The configuration options have been saved.'));
+}
+
+function demo_manage() {
+ $form['dump'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Available snapshots'),
+ );
+ $form = array_merge_recursive($form, demo_get_dumps());
+ $form[] = array(
+ '#type' => 'submit',
+ '#value' => t('Set as default snapshot for cron'),
+ );
+ $form[] = array(
+ '#type' => 'submit',
+ '#value' => t('Delete selected snapshot'),
+ '#submit' => array('demo_manage_delete_submit'),
+ );
+
+ return $form;
+}
+
+function demo_manage_submit($form, &$form_state) {
+ variable_set('demo_dump_cron', $form_state['values']['filename']);
+ drupal_set_message(t('Snapshot %title will be used for upcoming cron runs.', array('%title' => $form_state['values']['filename'])));
+}
+
+function demo_manage_delete_submit($form, &$form_state) {
+ $files = demo_get_fileconfig($form_state['values']['filename']);
+ unlink($files['sqlfile']);
+ unlink($files['infofile']);
+ drupal_set_message(t('Snapshot %title has been deleted.', array('%title' => $form_state['values']['filename'])));
+}
+
+function demo_dump() {
+ $form = array();
+ $form['dump']['filename'] = array(
+ '#title' => t('File name'),
+ '#type' => 'textfield',
+ '#autocomplete_path' => 'demo/autocomplete',
+ '#required' => true,
+ '#maxlength' => 128,
+ '#description' => t('Enter the snapshot file name without file extension. Allowed characters are a-z, 0-9, dashes ("-"), underscores ("_") and dots.'),
+ );
+ $form['dump']['description'] = array(
+ '#title' => t('Description'),
+ '#type' => 'textarea',
+ '#rows' => 2,
+ '#description' => t('Optionally enter a description for this snapshot here. If no description is given and a snapshot with the same filename already exists, the previous description is used.'),
+ );
+ return confirm_form($form, t('Are you sure you want to create a new snapshot?'), 'admin/settings/demo', t('If the above filename already exists, creating a new snapshot will overwrite the existing snapshot. This action cannot be undone.'), t('Create'), t('Cancel'));
+}
+
+function demo_dump_submit($form, &$form_state) {
+ global $db_type;
+
+ // Generate info file.
+ $info = demo_set_info($form_state['values']);
+ if (!$info) {
+ return false;
+ }
+
+ // Include database specific functions.
+ $engine = ($db_type == 'mysqli' ? 'mysql' : $db_type);
+ $inc_file = drupal_get_path('module', 'demo') .'/database_'. $engine .'_dump.inc';
+ if (file_exists($inc_file)) {
+ require_once $inc_file;
+
+ // Increase PHP's max_execution_time for large dumps.
+ @set_time_limit(600);
+
+ // Perform dump.
+ $fileconfig = demo_get_fileconfig($info['filename']);
+ $exclude = array('{cache}', '{cache_content}', '{cache_filter}', '{cache_menu}', '{cache_page}', '{cache_views}', '{panels_object_cache}', '{watchdog}');
+ $exclude = array_map('db_prefix_tables', $exclude);
+ demo_dump_db($fileconfig['sqlfile'], $exclude);
+ }
+ else {
+ drupal_set_message(t('@engine support not implemented yet.', array('@engine' => ucfirst($engine))), 'error');
+ }
+
+ $form_state['redirect'] = 'admin/settings/demo/manage';
+}
+
+function demo_reset_confirm() {
+ $form['dump'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Available snapshots'),
+ );
+ $form = array_merge_recursive($form, demo_get_dumps());
+
+ return confirm_form($form, t('Are you sure you want to reset the site?'), 'admin/settings/demo', t('Resetting the site will overwrite all changes that have been made to this Drupal installation since the chosen snapshot.
THIS ACTION CANNOT BE UNDONE!
'), t('Reset'), t('Cancel'));
+}
+
+function demo_reset_confirm_submit($form, &$form_state) {
+ // Increase PHP's max_execution_time for large dumps.
+ @set_time_limit(600);
+
+ // Reset site to chosen snapshot.
+ demo_reset($form_state['values']['filename']);
+ // Save time of last reset.
+ variable_set('demo_reset_last', time());
+
+ $form_state['redirect'] = isset($form_state['values']['redirect']) ? $form_state['values']['redirect'] : 'admin/settings/demo';
+}
+
+function demo_reset($filename = 'demo_site', $verbose = TRUE) {
+ // Load any database information in front of reset.
+ $demo_dump_cron = variable_get('demo_dump_cron', $filename);
+ $fileconfig = demo_get_fileconfig($filename);
+ $version = demo_get_info($fileconfig['infofile'], 'version');
+ $is_version_1_0_dump = version_compare($version, '1.1', '<');
+
+ if (file_exists($fileconfig['sqlfile']) && $fp = fopen($fileconfig['sqlfile'], 'r')) {
+ // Drop tables
+ $dt_watchdog = db_prefix_tables('{watchdog}');
+ foreach (demo_enum_tables() as $table) {
+ // Skip watchdog, except for legacy dumps that included the watchdog table
+ if ($table != $dt_watchdog || $is_version_1_0_dump) {
+ db_query("DROP TABLE %s", $table);
+ }
+ }
+
+ // Load data from snapshot
+ $query = '';
+ $success = TRUE;
+ while (!feof($fp)) {
+ $line = fgets($fp, 16384);
+ if ($line && $line != "\n" && strncmp($line, '--', 2) && strncmp($line, '#', 1)) {
+ $query .= $line;
+ if (substr($line, -2) == ";\n") {
+ if (!_db_query($query, FALSE)) {
+ if ($verbose) {
+ // Don't use t() here, as the locale_* tables might not (yet) exist.
+ drupal_set_message(strtr('Query failed: %query', array('%query' => $query)), 'error');
+ }
+ $success = FALSE;
+ }
+ $query = '';
+ }
+ }
+ }
+ fclose($fp);
+
+ if ($success) {
+ $message = t('Successfully restored database from %filename.', array('%filename' => $fileconfig['sqlfile']));
+ }
+ else {
+ $message = t('Failed restoring database from %filename.', array('%filename' => $fileconfig['sqlfile']));
+ }
+ if ($verbose) {
+ drupal_set_message($message);
+ }
+ watchdog('demo', $message, array(), $success ? WATCHDOG_NOTICE : WATCHDOG_ERROR);
+
+ // Reset default dump to load on cron.
+ variable_set('demo_dump_cron', $demo_dump_cron);
+ return TRUE;
+ }
+ $message = t('Unable to open dump file %filename.', array('%filename' => $fileconfig['sqlfile']));
+ if ($verbose) {
+ drupal_set_message($message, 'error');
+ }
+ watchdog('demo', $message, array(), WATCHDOG_ERROR);
+ return FALSE;
+}
+
+function demo_get_fileconfig($filename = 'demo_site') {
+ $fileconfig = array();
+
+ // Build dump path.
+ $fileconfig['path'] = variable_get('demo_dump_path', file_directory_path() .'/demo');
+ $fileconfig['site'] = str_replace('sites', '', conf_path());
+ $fileconfig['dumppath'] = $fileconfig['path'] . $fileconfig['site'];
+
+ // Check if directory exists.
+ file_check_directory($fileconfig['path'], FILE_CREATE_DIRECTORY, 'path');
+ if (!file_check_directory($fileconfig['dumppath'], FILE_CREATE_DIRECTORY, 'path')) {
+ return false;
+ }
+
+ // Protect dump files.
+ $htaccess = $fileconfig['path'] ."/.htaccess";
+ if (!is_file($htaccess)) {
+ $htaccess_lines = "# demo.module snapshots\n# Do not let the webserver serve anything under here!\n#\nDeny from all\n";
+ if (($fp = fopen($htaccess, 'w')) && fputs($fp, $htaccess_lines)) {
+ fclose($fp);
+ chmod($htaccess, 0664);
+ }
+ }
+
+ // Build SQL filename.
+ $fileconfig['sql'] = $filename .'.sql';
+ $fileconfig['sqlfile'] = $fileconfig['path'] . $fileconfig['site'] .'/'. $filename .'.sql';
+
+ // Build info filename.
+ $fileconfig['info'] = $filename .'.info';
+ $fileconfig['infofile'] = $fileconfig['path'] . $fileconfig['site'] .'/'. $filename .'.info';
+
+ return $fileconfig;
+}
+
+function demo_get_dumps() {
+ $fileconfig = demo_get_fileconfig();
+
+ // Fetch list of available info files
+ $files = file_scan_directory($fileconfig['dumppath'], '.info$');
+
+ foreach ($files as $file => $object) {
+ $files[$file]->filemtime = filemtime($file);
+ $files[$file]->filesize = filesize(substr($file, 0, -4) .'sql');
+ }
+
+ // Sort snapshots by date (ascending file modification time)
+ uasort($files, create_function('$a, $b', 'return ($a->filemtime < $b->filemtime);'));
+
+ $options = array();
+ // Forms API does not pass selected value of individual radio buttons,
+ // so we manually insert an internal form value here.
+ $options['dump']['filename'] = array(
+ '#type' => 'value',
+ '#required' => true,
+ '#title' => t('Snapshot'),
+ );
+ foreach ($files as $filename => $file) {
+ // Build basic file info
+ $files[$filename] = (array)$files[$filename];
+ $info = demo_get_info($filename);
+
+ // Convert file info for Forms API
+ $option = array();
+ $option['#type'] = 'radio';
+ $option['#name'] = 'filename';
+ $option['#title'] = $info['filename'] .' ('. format_date($file->filemtime, 'small') .', '. format_size($file->filesize) .')';
+ $option['#return_value'] = $info['filename'];
+ if ($info['filename'] == variable_get('demo_dump_cron', 'demo_site')) {
+ $option['#value'] = $info['filename'];
+ }
+ $option['#description'] = '';
+ if (!empty($info['description'])) {
+ $option['#description'] .= $info['description'] .'
';
+ }
+ if (count($info['modules']) > 1) {
+ // Remove required core modules and obvious modules from module list.
+ $info['modules'] = array_diff($info['modules'], array('block', 'filter', 'node', 'system', 'user', 'watchdog', 'demo'));
+ // Sort module list alphabetically.
+ sort($info['modules']);
+ $option['#description'] .= t('Modules: ') . implode(', ', $info['modules']);
+ }
+ $option['#attributes'] = array('onclick' => "$('.description', this.parentNode.parentNode).slideToggle();");
+
+ $options['dump'][] = $option;
+ }
+
+ // Attach stylesheet to initially hide descriptions
+ drupal_add_js("$('div.form-item div.description', $('form')).hide();", 'inline', 'footer');
+
+ return $options;
+}
+
+function demo_get_info($filename, $field = NULL) {
+ $info = array();
+
+ 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_set_info($values = null) {
+ if (isset($values['filename']) && is_array($values)) {
+ // Check for valid filename
+ if (!preg_match('/^[-_\.a-zA-Z0-9]+$/', $values['filename'])) {
+ drupal_set_message(t('Dump filename %title must contain alphanumeric characters, dots, dashes and underscores only. Other characters, including blanks (spaces), are not allowed.', array('%title' => $values['filename'])), 'error');
+ return false;
+ }
+
+ if (!empty($values['description'])) {
+ // parse_ini_file() doesn't allow certain characters in description
+ $s = array("\r\n", "\r", "\n", '"');
+ $r = array(' ', ' ', ' ', "'");
+ $values['description'] = str_replace($s, $r, $values['description']);
+ }
+ else {
+ // If new description is empty, try to use previous description.
+ $old_file = demo_get_fileconfig($values['filename']);
+ $old_description = demo_get_info($old_file['infofile'], 'description');
+ if (!empty($old_description)) {
+ $values['description'] = $old_description;
+ }
+ }
+
+ // Set values
+ $infos = array();
+ $infos['filename'] = $values['filename'];
+ $infos['description'] = '"'. $values['description'] .'"';
+ $infos['modules'] = implode(' ', module_list());
+ $infos['version'] = DEMO_DUMP_VERSION;
+
+ // Write information to .info file
+ $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;
+ }
+}
+
+/**
+ * Returns a list of tables in the active database.
+ *
+ * Only returns tables whose prefix matches the configured one (or ones, if
+ * there are multiple).
+ */
+function demo_enum_tables() {
+ global $db_prefix;
+
+ $tables = array();
+
+ if (is_array($db_prefix)) {
+ // Create a regular expression for table prefix matching.
+ $rx = '/^'. implode('|', array_filter($db_prefix)) .'/';
+ }
+ else if ($db_prefix != '') {
+ $rx = '/^'. $db_prefix .'/';
+ }
+
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ $result = db_query("SHOW TABLES");
+ break;
+ case 'pgsql':
+ $result = db_query("SELECT table_name FROM information_schema.tables WHERE table_schema = '%s'", 'public');
+ break;
+ }
+
+ while ($table = db_fetch_array($result)) {
+ $table = reset($table);
+ if (is_array($db_prefix)) {
+ // Check if table name matches a configured prefix.
+ if (preg_match($rx, $table, $matches)) {
+ $table_prefix = $matches[0];
+ $plain_table = substr($table, strlen($table_prefix));
+ if ($db_prefix[$plain_table] == $table_prefix || $db_prefix['default'] == $table_prefix) {
+ $tables[] = $table;
+ }
+ }
+ }
+ else if ($db_prefix != '') {
+ if (preg_match($rx, $table)) {
+ $tables[] = $table;
+ }
+ }
+ else {
+ $tables[] = $table;
+ }
+ }
+
+ return $tables;
+}
+
+/**
+ * Retrieve a pipe delimited string of autocomplete suggestions for existing
+ * snapshot names.
+ */
+function demo_autocomplete($string = '') {
+ $matches = array();
+ if ($string && $fileconfig = demo_get_fileconfig()) {
+ $string = preg_quote($string);
+ $files = file_scan_directory($fileconfig['dumppath'], $string .'.*\.info$');
+ foreach ($files as $file) {
+ $matches[$file->name] = check_plain($file->name);
+ }
+ }
+ print drupal_to_js($matches);
+ exit();
+}
+
Index: demo.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/demo/demo.module,v
retrieving revision 1.19.2.7
diff -u -p -r1.19.2.7 demo.module
--- demo.module 12 Sep 2008 20:45:22 -0000 1.19.2.7
+++ demo.module 28 Oct 2008 18:33:07 -0000
@@ -6,18 +6,6 @@
* Demonstration Site module
*/
-define('DEMO_DUMP_VERSION', '1.1');
-
-/**
- * Implementation of hook_help().
- */
-function demo_help($path, $arg) {
- switch ($path) {
- case 'admin/settings/demo':
- return;
- }
-}
-
/**
* Implementation of hook_perm().
*/
@@ -38,6 +26,7 @@ function demo_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('demo_admin_settings'),
'access arguments' => $admin_access,
+ 'file' => 'demo.admin.inc',
);
$items['admin/settings/demo/maintenance'] = array(
'title' => 'Status',
@@ -49,6 +38,7 @@ function demo_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('demo_manage'),
'access arguments' => $admin_access,
+ 'file' => 'demo.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 1,
);
@@ -57,6 +47,7 @@ function demo_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('demo_dump'),
'access arguments' => $admin_access,
+ 'file' => 'demo.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
@@ -65,6 +56,7 @@ function demo_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('demo_reset_confirm'),
'access arguments' => $admin_access,
+ 'file' => 'demo.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 3,
);
@@ -72,20 +64,20 @@ function demo_menu() {
'title' => 'Demo Site autocomplete',
'page callback' => 'demo_autocomplete',
'access arguments' => $admin_access,
+ 'file' => 'demo.admin.inc',
'type' => MENU_CALLBACK,
);
return $items;
}
+/**
+ * Implementation of hook_block().
+ */
function demo_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
- $blocks[0] = array(
- 'info' => t('Demo site reset'),
- 'weight' => 0,
- 'enabled' => 1,
- 'region' => 'right',
- );
+ $blocks[0] = array('info' => t('Demo site reset'),
+ 'status' => 1, 'region' => 'right', 'cache' => BLOCK_NO_CACHE);
return $blocks;
case 'view':
@@ -97,184 +89,7 @@ function demo_block($op = 'list', $delta
}
}
-function demo_admin_settings() {
- global $base_url;
-
- $form['status'] = array(
- '#type' => 'fieldset',
- '#title' => t('Status'),
- '#collapsible' => false,
- );
- if (variable_get('demo_reset_last', 0)) {
- $reset_date = format_date(variable_get('demo_reset_last', 0));
- }
- else {
- $reset_date = t('Never');
- }
- $form['status'][] = array(
- '#value' => t('Last reset: !date
', array('!date' => $reset_date)),
- );
- $form['status'][] = array(
- '#value' => t('Default snapshot: !snapshot
', array('!snapshot' => variable_get('demo_dump_cron', t('None')))),
- );
-
- $fileconfig = demo_get_fileconfig();
-
- $form['dump'] = array(
- '#type' => 'fieldset',
- '#title' => t('Dump settings'),
- '#collapsible' => true,
- '#collapsed' => (variable_get('demo_reset_interval', 0) ? false : true),
- );
- $period = drupal_map_assoc(array(0, 1800, 3600, 7200, 10800, 14400, 18000, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
- $period[0] = t('disabled');
- $form['dump']['interval'] = array(
- '#type' => 'select',
- '#title' => t('Automatically reset site every'),
- '#default_value' => variable_get('demo_reset_interval', 0),
- '#options' => $period,
- '#description' => t('Select how often this demonstration site is automatically reset. Ensure that you have chosen a snapshot for cron runs in Manage snapshots first. Note: This requires cron to run at least within this interval.', array('!manage' => url('admin/settings/demo/manage'))),
- );
-
- $form['dump']['path'] = array(
- '#type' => 'textfield',
- '#title' => t('Dump path'),
- '#default_value' => $fileconfig['path'],
- '#size' => 30,
- '#description' => t('Enter a writable directory where dump files of this demonstration site are stored, f.e. %files. The name of this site (e.g. %confpath) is automatically appended to this directory.
Note: For security reasons you should store site dumps outside of the document root of your webspace!', array('%files' => file_directory_path() .'/demo', '%confpath' => $fileconfig['site'])),
- );
- $form[] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- );
-
- return $form;
-}
-
-function demo_admin_settings_submit($form, &$form_state) {
- if (!file_check_directory($form_state['values']['path'], FILE_CREATE_DIRECTORY)) {
- form_set_error('path', t('The snapshot directory %directory could not be created.', array('%directory' => $form_state['values']['path'])));
- return FALSE;
- }
- else {
- variable_set('demo_dump_path', $form_state['values']['path']);
- }
- variable_set('demo_reset_interval', $form_state['values']['interval']);
- drupal_set_message(t('The configuration options have been saved.'));
-}
-
-function demo_manage() {
- $form['dump'] = array(
- '#type' => 'fieldset',
- '#title' => t('Available snapshots'),
- );
- $form = array_merge_recursive($form, demo_get_dumps());
- $form[] = array(
- '#type' => 'submit',
- '#value' => t('Set as default snapshot for cron'),
- );
- $form[] = array(
- '#type' => 'submit',
- '#value' => t('Delete selected snapshot'),
- '#submit' => array('demo_manage_delete_submit'),
- );
-
- return $form;
-}
-
-function demo_manage_submit($form, &$form_state) {
- variable_set('demo_dump_cron', $form_state['values']['filename']);
- drupal_set_message(t('Snapshot %title will be used for upcoming cron runs.', array('%title' => $form_state['values']['filename'])));
-}
-
-function demo_manage_delete_submit($form, &$form_state) {
- $files = demo_get_fileconfig($form_state['values']['filename']);
- unlink($files['sqlfile']);
- unlink($files['infofile']);
- drupal_set_message(t('Snapshot %title has been deleted.', array('%title' => $form_state['values']['filename'])));
-}
-
-function demo_dump() {
- $form = array();
- $form['dump']['filename'] = array(
- '#title' => t('File name'),
- '#type' => 'textfield',
- '#autocomplete_path' => 'demo/autocomplete',
- '#required' => true,
- '#maxlength' => 128,
- '#description' => t('Enter the snapshot file name without file extension. Allowed characters are a-z, 0-9, dashes ("-"), underscores ("_") and dots.'),
- );
- $form['dump']['description'] = array(
- '#title' => t('Description'),
- '#type' => 'textarea',
- '#rows' => 2,
- '#description' => t('Optionally enter a description for this snapshot here. If no description is given and a snapshot with the same filename already exists, the previous description is used.'),
- );
- return confirm_form($form, t('Are you sure you want to create a new snapshot?'), 'admin/settings/demo', t('If the above filename already exists, creating a new snapshot will overwrite the existing snapshot. This action cannot be undone.'), t('Create'), t('Cancel'));
-}
-
-function demo_dump_submit($form, &$form_state) {
- global $db_type;
-
- // Write .info file
- $info = demo_set_info($form_state['values']);
- if (!$info) {
- return false;
- }
-
- // Include database specific functions
- switch ($db_type) {
- case 'mysqli':
- $engine = 'mysql';
- break;
- default:
- $engine = $db_type;
- break;
- }
- require_once drupal_get_path('module', 'demo') ."/database_{$engine}_dump.inc";
-
- // Increase PHP's max_execution_time for large dumps.
- @set_time_limit(600);
-
- // Perform dump
- $fileconfig = demo_get_fileconfig($info['filename']);
- $exclude = array('{cache}', '{cache_content}', '{cache_filter}', '{cache_menu}', '{cache_page}', '{cache_views}', '{panels_object_cache}', '{watchdog}');
- $exclude = array_map('db_prefix_tables', $exclude);
- demo_dump_db($fileconfig['sqlfile'], $exclude);
-
- $form_state['redirect'] = 'admin/settings/demo/manage';
-}
-
-function demo_reset_confirm() {
- $form['dump'] = array(
- '#type' => 'fieldset',
- '#title' => t('Available snapshots'),
- );
- $form = array_merge_recursive($form, demo_get_dumps());
-
- return confirm_form($form, t('Are you sure you want to reset the site?'), 'admin/settings/demo', t('Resetting the site will overwrite all changes that have been made to this Drupal installation since the chosen snapshot.
THIS ACTION CANNOT BE UNDONE!
'), t('Reset'), t('Cancel'));
-}
-
-function demo_reset_confirm_submit($form, &$form_state) {
- // Increase PHP's max_execution_time for large dumps.
- @set_time_limit(600);
-
- // Reset site to chosen snapshot
- demo_reset($form_state['values']['filename']);
- // Save time of last reset
- variable_set('demo_reset_last', time());
-
- if (isset($form_state['values']['redirect'])) {
- $form_state['redirect'] = $form_state['values']['redirect'];
- }
- else {
- $form_state['redirect'] = 'admin/settings/demo';
- }
-}
-
function demo_reset_now() {
- $form = array();
- $form['#submit'][] = 'demo_reset_confirm_submit';
$form['redirect'] = array(
'#type' => 'value',
'#value' => $_GET['q'],
@@ -290,284 +105,12 @@ function demo_reset_now() {
'#type' => 'submit',
'#value' => t('Reset now'),
);
-
return $form;
}
-function demo_reset($filename = 'demo_site', $verbose = TRUE) {
- // Load any database information in front of reset.
- $demo_dump_cron = variable_get('demo_dump_cron', $filename);
- $fileconfig = demo_get_fileconfig($filename);
- $version = demo_get_info($fileconfig['infofile'], 'version');
- $is_version_1_0_dump = version_compare($version, '1.1', '<');
-
- if (file_exists($fileconfig['sqlfile']) && $fp = fopen($fileconfig['sqlfile'], 'r')) {
- // Drop tables
- $dt_watchdog = db_prefix_tables('{watchdog}');
- foreach (demo_enum_tables() as $table) {
- // Skip watchdog, except for legacy dumps that included the watchdog table
- if ($table != $dt_watchdog || $is_version_1_0_dump) {
- db_query("DROP TABLE %s", $table);
- }
- }
-
- // Load data from snapshot
- $query = '';
- $success = TRUE;
- while (!feof($fp)) {
- $line = fgets($fp, 16384);
- if ($line && $line != "\n" && strncmp($line, '--', 2) && strncmp($line, '#', 1)) {
- $query .= $line;
- if (substr($line, -2) == ";\n") {
- if (!_db_query($query, FALSE)) {
- if ($verbose) {
- // Don't use t() here, as the locale_* tables might not (yet) exist.
- drupal_set_message(strtr('Query failed: %query', array('%query' => $query)), 'error');
- }
- $success = FALSE;
- }
- $query = '';
- }
- }
- }
- fclose($fp);
-
- if ($success) {
- $message = t('Successfully restored database from %filename.', array('%filename' => $fileconfig['sqlfile']));
- }
- else {
- $message = t('Failed restoring database from %filename.', array('%filename' => $fileconfig['sqlfile']));
- }
- if ($verbose) {
- drupal_set_message($message);
- }
- watchdog('demo', $message, array(), $success ? WATCHDOG_NOTICE : WATCHDOG_ERROR);
-
- // Reset default dump to load on cron.
- variable_set('demo_dump_cron', $demo_dump_cron);
- return TRUE;
- }
- $message = t('Unable to open dump file %filename.', array('%filename' => $fileconfig['sqlfile']));
- if ($verbose) {
- drupal_set_message($message, 'error');
- }
- watchdog('demo', $message, array(), WATCHDOG_ERROR);
- return FALSE;
-}
-
-function demo_get_fileconfig($filename = 'demo_site') {
- $fileconfig = array();
-
- // Build dump path.
- $fileconfig['path'] = variable_get('demo_dump_path', file_directory_path() .'/demo');
- $fileconfig['site'] = str_replace('sites', '', conf_path());
- $fileconfig['dumppath'] = $fileconfig['path'] . $fileconfig['site'];
-
- // Check if directory exists.
- file_check_directory($fileconfig['path'], FILE_CREATE_DIRECTORY, 'path');
- if (!file_check_directory($fileconfig['dumppath'], FILE_CREATE_DIRECTORY, 'path')) {
- return false;
- }
-
- // Protect dump files.
- $htaccess = $fileconfig['path'] ."/.htaccess";
- if (!is_file($htaccess)) {
- $htaccess_lines = "# demo.module snapshots\n# Do not let the webserver serve anything under here!\n#\nDeny from all\n";
- if (($fp = fopen($htaccess, 'w')) && fputs($fp, $htaccess_lines)) {
- fclose($fp);
- chmod($htaccess, 0664);
- }
- }
-
- // Build SQL filename.
- $fileconfig['sql'] = $filename .'.sql';
- $fileconfig['sqlfile'] = $fileconfig['path'] . $fileconfig['site'] .'/'. $filename .'.sql';
-
- // Build info filename.
- $fileconfig['info'] = $filename .'.info';
- $fileconfig['infofile'] = $fileconfig['path'] . $fileconfig['site'] .'/'. $filename .'.info';
-
- return $fileconfig;
-}
-
-function demo_get_dumps() {
- $fileconfig = demo_get_fileconfig();
-
- // Fetch list of available info files
- $files = file_scan_directory($fileconfig['dumppath'], '.info$');
-
- foreach ($files as $file => $object) {
- $files[$file]->filemtime = filemtime($file);
- $files[$file]->filesize = filesize(substr($file, 0, -4) .'sql');
- }
-
- // Sort snapshots by date (ascending file modification time)
- uasort($files, create_function('$a, $b', 'return ($a->filemtime < $b->filemtime);'));
-
- $options = array();
- // Forms API does not pass selected value of individual radio buttons,
- // so we manually insert an internal form value here.
- $options['dump']['filename'] = array(
- '#type' => 'value',
- '#required' => true,
- '#title' => t('Snapshot'),
- );
- foreach ($files as $filename => $file) {
- // Build basic file info
- $files[$filename] = (array)$files[$filename];
- $info = demo_get_info($filename);
-
- // Convert file info for Forms API
- $option = array();
- $option['#type'] = 'radio';
- $option['#name'] = 'filename';
- $option['#title'] = $info['filename'] .' ('. format_date($file->filemtime, 'small') .', '. format_size($file->filesize) .')';
- $option['#return_value'] = $info['filename'];
- if ($info['filename'] == variable_get('demo_dump_cron', 'demo_site')) {
- $option['#value'] = $info['filename'];
- }
- $option['#description'] = '';
- if (!empty($info['description'])) {
- $option['#description'] .= $info['description'] .'
';
- }
- if (count($info['modules']) > 1) {
- // Remove required core modules and obvious modules from module list.
- $info['modules'] = array_diff($info['modules'], array('block', 'filter', 'node', 'system', 'user', 'watchdog', 'demo'));
- // Sort module list alphabetically.
- sort($info['modules']);
- $option['#description'] .= t('Modules: ') . implode(', ', $info['modules']);
- }
- $option['#attributes'] = array('onclick' => "$('.description', this.parentNode.parentNode).slideToggle();");
-
- $options['dump'][] = $option;
- }
-
- // Attach stylesheet to initially hide descriptions
- drupal_add_js("$('div.form-item div.description', $('form')).hide();", 'inline', 'footer');
-
- return $options;
-}
-
-function demo_get_info($filename, $field = NULL) {
- $info = array();
-
- 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_set_info($values = null) {
- if (isset($values['filename']) && is_array($values)) {
- // Check for valid filename
- if (!preg_match('/^[-_\.a-zA-Z0-9]+$/', $values['filename'])) {
- drupal_set_message(t('Dump filename %title must contain alphanumeric characters, dots, dashes and underscores only. Other characters, including blanks (spaces), are not allowed.', array('%title' => $values['filename'])), 'error');
- return false;
- }
-
- if (!empty($values['description'])) {
- // parse_ini_file() doesn't allow certain characters in description
- $s = array("\r\n", "\r", "\n", '"');
- $r = array(' ', ' ', ' ', "'");
- $values['description'] = str_replace($s, $r, $values['description']);
- }
- else {
- // If new description is empty, try to use previous description.
- $old_file = demo_get_fileconfig($values['filename']);
- $old_description = demo_get_info($old_file['infofile'], 'description');
- if (!empty($old_description)) {
- $values['description'] = $old_description;
- }
- }
-
- // Set values
- $infos = array();
- $infos['filename'] = $values['filename'];
- $infos['description'] = '"'. $values['description'] .'"';
- $infos['modules'] = implode(' ', module_list());
- $infos['version'] = DEMO_DUMP_VERSION;
-
- // Write information to .info file
- $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;
- }
-}
-
-/**
- * Returns a list of tables in the active database.
- *
- * Only returns tables whose prefix matches the configured one (or ones, if
- * there are multiple).
- */
-function demo_enum_tables() {
- global $db_prefix;
-
- $tables = array();
-
- if (is_array($db_prefix)) {
- // Create a regular expression for table prefix matching.
- $rx = '/^'. implode('|', array_filter($db_prefix)) .'/';
- }
- else if ($db_prefix != '') {
- $rx = '/^'. $db_prefix .'/';
- }
-
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- $result = db_query("SHOW TABLES");
- break;
- case 'pgsql':
- $result = db_query("SELECT table_name FROM information_schema.tables WHERE table_schema = '%s'", 'public');
- break;
- }
-
- while ($table = db_fetch_array($result)) {
- $table = reset($table);
- if (is_array($db_prefix)) {
- // Check if table name matches a configured prefix.
- if (preg_match($rx, $table, $matches)) {
- $table_prefix = $matches[0];
- $plain_table = substr($table, strlen($table_prefix));
- if ($db_prefix[$plain_table] == $table_prefix || $db_prefix['default'] == $table_prefix) {
- $tables[] = $table;
- }
- }
- }
- else if ($db_prefix != '') {
- if (preg_match($rx, $table)) {
- $tables[] = $table;
- }
- }
- else {
- $tables[] = $table;
- }
- }
-
- return $tables;
+function demo_reset_now_submit($form, &$form_state) {
+ require_once drupal_get_path('module', 'demo') .'/demo.admin.inc';
+ demo_reset_confirm_submit($form, $form_state);
}
/**
@@ -575,27 +118,12 @@ function demo_enum_tables() {
*/
function demo_cron() {
if ($interval = variable_get('demo_reset_interval', 0)) {
- // See if it's time for another reset
+ // See if it's time for a reset.
if ((time() - $interval) >= variable_get('demo_reset_last', 0)) {
- demo_reset(variable_get('demo_dump_cron', 'demo_site'), false);
+ require_once drupal_get_path('module', 'demo') .'/demo.admin.inc';
+ demo_reset(variable_get('demo_dump_cron', 'demo_site'), FALSE);
variable_set('demo_reset_last', time());
}
}
}
-/**
- * Retrieve a pipe delimited string of autocomplete suggestions for existing
- * snapshot names.
- */
-function demo_autocomplete($string = '') {
- $matches = array();
- if ($string && $fileconfig = demo_get_fileconfig()) {
- $string = preg_quote($string);
- $files = file_scan_directory($fileconfig['dumppath'], $string .'.*\.info$');
- foreach ($files as $file) {
- $matches[$file->name] = check_plain($file->name);
- }
- }
- print drupal_to_js($matches);
- exit();
-}