system.module 120 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Configuration system that lets administrators modify the workings of the site.
 */

Steven Wittens's avatar
Steven Wittens committed
9
define('VERSION', '6.0-dev');
10
define('DRUPAL_CORE_COMPATIBILITY', '6.x');
11

12
13
14
15
16
define('DRUPAL_MINIMUM_PHP',    '4.3.3');
define('DRUPAL_MINIMUM_MYSQL',  '4.1.0'); // If using MySQL
define('DRUPAL_MINIMUM_PGSQL',  '7.4');   // If using PostgreSQL
define('DRUPAL_MINIMUM_APACHE', '1.3');   // If using Apache

17
18
19
// Maximum age of temporary files in seconds.
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);

Dries's avatar
   
Dries committed
20
21
22
/**
 * Implementation of hook_help().
 */
23
function system_help($path, $arg) {
24
25
  global $base_url;

26
  switch ($path) {
27
    case 'admin/help#system':
28
      $output = '<p>'. t('The system module provides system-wide defaults such as running jobs at a particular time, and storing web pages to improve efficiency. The ability to run scheduled jobs makes administering the website more usable, as administrators do not have to manually start jobs. The storing of web pages, or caching, allows the site to efficiently re-use web pages and improve website performance. The settings module provides control over preferences, behaviours including visual and operational settings.') .'</p>';
29
      $output .= '<p>'. t('Some modules require regularly scheduled actions, such as cleaning up logfiles. Cron, which stands for chronograph, is a periodic command scheduler executing commands at intervals specified in seconds. It can be used to control the execution of daily, weekly and monthly jobs (or anything with a period measured in seconds). The aggregator module periodically updates feeds using cron. Ping periodically notifies services of new content on your site. Search periodically indexes the content on your site. Automating tasks is one of the best ways to keep a system running smoothly, and if most of your administration does not require your direct involvement, cron is an ideal solution. Cron can, if necessary, also be run manually.') .'</p>';
30
      $output .= '<p>'. t("There is a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, the system module does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by <em>anonymous</em> users are cached. In order to reduce server load and save bandwidth, the system module stores and sends cached pages compressed.") .'</p>';
31
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@system">System page</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>';
32
      return $output;
33
    case 'admin':
34
      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
35
    case 'admin/by-module':
36
      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
37
    case 'admin/build/themes':
38
      return '<p>'. t('Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.') .'</p>';
39
40
    case 'admin/build/themes/settings/'. $arg[4]:
      $reference = explode('.', $arg[4], 2);
41
      $theme = array_pop($reference);
42
      return '<p>'. t('These options control the display settings for the <code>%template</code> theme. When your site is displayed using this theme, these settings will be used. By clicking "Reset to defaults," you can choose to use the <a href="@global">global settings</a> for this theme.', array('%template' => $theme, '@global' => url('admin/build/themes/settings'))) .'</p>';
43
44
    case 'admin/build/themes/settings':
      return '<p>'. t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') .'</p>';
45
    case 'admin/build/modules':
46
47
48
49
50
51
52
      $output = '<p>'. t('Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. Once a module is enabled, new <a href="@permissions">permissions</a> might be made available. Modules can automatically be temporarily disabled to reduce server load when your site becomes extremely busy by enabling the throttle.module and checking throttle.', array('@permissions' => url('admin/user/access')));
      if (module_exists('throttle')) {
        $output .= ' '. t('The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.', array('@throttle' => url('admin/settings/throttle')));
      }
      $output .= '</p>';
      $output .= t('<p>It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.</p><p>You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.</p>', array('@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module')));
      return $output;
53
    case 'admin/build/modules/uninstall':
54
      return '<p>'. t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it. Not all modules support this feature.') .'</p>';
55
    case 'admin/logs/status':
56
      return '<p>'. t("Here you can find a short overview of your Drupal site's parameters as well as any problems detected with your installation. It is useful to copy/paste this information when you need support.") .'</p>';
57
  }
Dries's avatar
   
Dries committed
58
59
}

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
function system_theme() {
  return array_merge(drupal_common_themes(), array(
    'system_theme_select_form' => array(
      'arguments' => array('form' => NULL),
    ),
    'system_themes_form' => array(
      'arguments' => array('form' => NULL),
    ),
    'system_modules' => array(
      'arguments' => array('form' => NULL),
    ),
    'system_modules_uninstall' => array(
      'arguments' => array('form' => NULL),
    ),
    'status_report' => array(
      'arguments' => array('requirements' => NULL),
    ),
    'admin_page' => array(
      'arguments' => array('blocks' => NULL),
    ),
    'admin_block' => array(
      'arguments' => array('block' => NULL),
    ),
    'admin_block_content' => array(
      'arguments' => array('content' => NULL),
    ),
    'system_admin_by_module' => array(
      'arguments' => array('menu_items' => NULL),
    ),
  ));
}
Dries's avatar
   
Dries committed
91
92
93
/**
 * Implementation of hook_perm().
 */
Dries's avatar
 
Dries committed
94
function system_perm() {
95
  return array('administer site configuration', 'access administration pages', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
96
97
}

98
99
100
101
102
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
103
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
104
105

  // Inputs
106
107
  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#ahah_event' => 'submit', '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#ahah_event' => 'submit', '#process' => array('form_expand_ahah'));
108
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE);
109
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128);
110
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
111
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE);
112
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
113
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL);
114
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
115
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1);
116
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE);
117
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight'));
118
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
119
  $type['file'] = array('#input' => TRUE, '#size' => 60);
120
121

  // Form structure
122
  $type['item'] = array('#value' => '');
123
124
125
  $type['hidden'] = array('#input' => TRUE);
  $type['value'] = array('#input' => TRUE);
  $type['markup'] = array('#prefix' => '', '#suffix' => '');
126
  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL);
Dries's avatar
Dries committed
127
  $type['token'] = array('#input' => TRUE);
128
129
130
  return $type;
}

Dries's avatar
   
Dries committed
131
/**
Dries's avatar
   
Dries committed
132
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
133
 */
134
135
function system_menu() {
  $items['system/files'] = array(
136
    'title' => 'File download',
137
138
139
140
141
    'page callback' => 'file_download',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin'] = array(
142
    'title' => 'Administer',
143
144
145
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_main_admin_page',
    'weight' => 9,
146
    'file' => 'system.admin.inc',
147
148
  );
  $items['admin/compact'] = array(
149
    'title' => 'Compact mode',
150
151
152
153
    'page callback' => 'system_admin_compact_page',
    'type' => MENU_CALLBACK,
  );
  $items['admin/by-task'] = array(
154
    'title' => 'By task',
155
    'page callback' => 'system_main_admin_page',
156
    'file' => 'system.admin.inc',
157
158
159
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/by-module'] = array(
160
    'title' => 'By module',
161
162
163
164
165
166
    'page callback' => 'system_admin_by_module',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
  // menu items that are basically just menu blocks
  $items['admin/settings'] = array(
167
168
    'title' => 'Site configuration',
    'description' => 'Adjust basic site configuration options.',
169
170
171
172
173
174
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_settings_overview',
    'access arguments' => array('administer site configuration'),
  );
  $items['admin/build'] = array(
175
176
    'title' => 'Site building',
    'description' => 'Control how your site looks and feels.',
177
178
179
180
    'position' => 'right',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('administer site configuration'),
181
    'file' => 'system.admin.inc',
182
183
  );
  $items['admin/settings/admin'] = array(
184
185
    'title' => 'Administration theme',
    'description' => 'Settings for how your administrative pages should look.',
186
187
188
189
190
191
192
    'position' => 'left',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_admin_theme_settings'),
    'block callback' => 'system_admin_theme_settings',
  );
  // Themes:
  $items['admin/build/themes'] = array(
193
194
    'title' => 'Themes',
    'description' => 'Change which theme your site uses or allows users to set.',
195
    'page callback' => 'drupal_get_form',
196
    'page arguments' => array('system_themes_form', NULL),
197
198
  );
  $items['admin/build/themes/select'] = array(
199
200
    'title' => 'List',
    'description' => 'Select the default theme.',
201
202
203
204
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/build/themes/settings'] = array(
205
    'title' => 'Configure',
206
207
208
209
    'type' => MENU_LOCAL_TASK,
  );
  // Theme configuration subtabs
  $items['admin/build/themes/settings/global'] = array(
210
    'title' => 'Global settings',
211
212
213
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
Dries's avatar
   
Dries committed
214

215
216
217
  foreach (list_themes() as $theme) {
    if ($theme->status) {
      $items['admin/build/themes/settings/'. $theme->name] = array(
218
        'title' => $theme->info['name'],
219
220
221
        'page arguments' => array('system_theme_settings', $theme->name),
        'type' => MENU_LOCAL_TASK,
      );
Dries's avatar
   
Dries committed
222
    }
Dries's avatar
   
Dries committed
223
  }
drumm's avatar
drumm committed
224

225
226
  // Modules:
  $items['admin/build/modules'] = array(
227
228
    'title' => 'Modules',
    'description' => 'Enable or disable add-on modules for your site.',
229
230
231
232
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_modules'),
  );
  $items['admin/build/modules/list'] = array(
233
    'title' => 'List',
234
235
236
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/build/modules/list/confirm'] = array(
237
    'title' => 'List',
238
239
240
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/modules/uninstall'] = array(
241
    'title' => 'Uninstall',
242
243
244
245
    'page arguments' => array('system_modules_uninstall'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/modules/uninstall/confirm'] = array(
246
    'title' => 'Uninstall',
247
248
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
249

250
251
  // Settings:
  $items['admin/settings/site-information'] = array(
252
253
    'title' => 'Site information',
    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
254
255
256
257
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_information_settings'),
  );
  $items['admin/settings/error-reporting'] = array(
258
259
    'title' => 'Error reporting',
    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
260
261
262
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_error_reporting_settings'),
  );
263
  $items['admin/settings/logging'] = array(
264
265
    'title' => 'Logging and alerts',
    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.",
266
267
    'page callback' => 'system_logging_overview',
  );
268
  $items['admin/settings/performance'] = array(
269
    'title' => 'Performance',
270
    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
271
272
273
274
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_performance_settings'),
  );
  $items['admin/settings/file-system'] = array(
275
276
    'title' => 'File system',
    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
277
278
279
280
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_file_system_settings'),
  );
  $items['admin/settings/image-toolkit'] = array(
281
282
    'title' => 'Image toolkit',
    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
283
284
285
286
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_image_toolkit_settings'),
  );
  $items['admin/content/rss-publishing'] = array(
287
288
    'title' => 'RSS publishing',
    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
289
290
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_rss_feeds_settings'),
291
    'access arguments' => array('administer site configuration'),
292
293
  );
  $items['admin/settings/date-time'] = array(
294
295
    'title' => 'Date and time',
    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
296
297
298
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_date_time_settings'),
  );
299
300
301
302
303
  $items['admin/settings/date-time/lookup'] = array(
    'title' => t('Date and time lookup'),
    'type' => MENU_CALLBACK,
    'page callback' => 'system_date_time_lookup',
  );
304
  $items['admin/settings/site-maintenance'] = array(
305
306
    'title' => 'Site maintenance',
    'description' => 'Take the site off-line for maintenance or bring it back online.',
307
308
309
310
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_maintenance_settings'),
  );
  $items['admin/settings/clean-urls'] = array(
311
312
    'title' => 'Clean URLs',
    'description' => 'Enable or disable clean URLs for your site.',
313
314
315
316
317
318
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_clean_url_settings'),
  );

  // Logs:
  $items['admin/logs'] = array(
319
320
    'title' => 'Logs',
    'description' => 'View system logs and other status information.',
321
322
323
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 5,
    'position' => 'left',
324
    'file' => 'system.admin.inc',
325
326
  );
  $items['admin/logs/status'] = array(
327
328
    'title' => 'Status report',
    'description' => "Get a status report about your site's operation and any detected problems.",
329
330
331
332
333
    'page callback' => 'system_status',
    'weight' => 10,
    'access arguments' => array('administer site configuration'),
  );
  $items['admin/logs/status/run-cron'] = array(
334
    'title' => 'Run cron',
335
336
337
338
    'page callback' => 'system_run_cron',
    'type' => MENU_CALLBACK,
  );
  $items['admin/logs/status/php'] = array(
339
    'title' => 'PHP',
340
341
342
343
    'page callback' => 'system_php',
    'type' => MENU_CALLBACK,
  );
  $items['admin/logs/status/sql'] = array(
344
    'title' => 'SQL',
345
346
347
    'page callback' => 'system_sql',
    'type' => MENU_CALLBACK,
  );
348
349
350
351
352
353
  // Default page for batch operations
  $items['batch'] = array(
    'page callback' => 'system_batch_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
354
  return $items;
Dries's avatar
 
Dries committed
355
356
}

357
358
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
359
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
360
361
362
363
364
365
366
367
368
369
    global $custom_theme;
    $custom_theme = variable_get('admin_theme', '0');
    drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
  }

  // Add the CSS for this module.
  drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
  drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
}

Dries's avatar
   
Dries committed
370
371
372
373
374
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
375
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
376
  if ($type == 'form' && $category == 'account') {
377
    $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), isset($edit['theme']) ? $edit['theme'] : NULL, 2);
Dries's avatar
Dries committed
378

379
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
380
      $zones = _system_zonelist();
381
      $form['timezone'] = array(
382
        '#type' => 'fieldset',
383
384
385
386
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
387
      $form['timezone']['timezone'] = array(
388
389
390
391
392
        '#type' => 'select',
        '#title' => t('Time zone'),
        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0),
        '#options' => $zones,
        '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
393
      );
Dries's avatar
   
Dries committed
394
    }
Dries's avatar
Dries committed
395

396
    return $form;
Dries's avatar
   
Dries committed
397
  }
Dries's avatar
   
Dries committed
398
399
}

400
401
402
/**
 * Provide a single block on the administration overview page.
 */
403
function system_admin_menu_block($item) {
404
  $content = array();
405
406
  if (!isset($item['mlid'])) {
    $item['mlid'] = db_result(db_query("SELECT mlid FROM {menu_links} ml WHERE ml.router_path = '%s' AND menu_name = 'navigation'", $item['path']));
407
  }
408
409
410
411
412
413
414
  $result = db_query("
    SELECT *
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
    WHERE ml.plid = %d AND ml.menu_name = 'navigation' AND hidden = 0
    ORDER BY m.weight, m.title", $item['mlid']);
  while ($item = db_fetch_array($result)) {
415
    _menu_link_translate($item);
416
    if (!$item['access']) {
417
      continue;
418
    }
419
    $content[] = (array)$item;
420
421
422
423
424
425
426
427
428
  }
  return $content;
}

function system_admin_compact_page($mode = 'off') {
  global $user;
  user_save($user, array('admin_compact_mode' => ($mode == 'on')));
  drupal_goto('admin');
}
429

430
/**
431
 * This function allows selection of the theme to show in administration sections.
432
 */
433
function system_admin_theme_settings() {
434
435
436
437
  $themes = system_theme_data();
  ksort($themes);
  $options[0] = t('System default');
  foreach ($themes as $theme) {
438
    $options[$theme->name] = $theme->info['name'];
439
440
441
442
443
444
  }

  $form['admin_theme'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#title' => t('Administration theme'),
445
    '#description' => t('Choose which theme the administration pages should display in. If you choose "System default" the administration pages will use the same theme as the rest of the site.'),
446
    '#default_value' => variable_get('admin_theme', '0'),
447
448
  );

449
450
451
  $form['node_admin_theme'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use administration theme for content editing'),
452
    '#description' => t('Use the administration theme when editing existing posts or creating new ones.'),
453
454
455
    '#default_value' => variable_get('node_admin_theme', '0'),
  );

456
  $form['#submit'][] = 'system_admin_theme_submit';
457
  return system_settings_form($form);
458
459
460
}


461
function system_admin_theme_submit($form, &$form_state) {
462
  // If we're changing themes, make sure the theme has its blocks initialized.
463
464
  if ($form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
    $result = db_query("SELECT status FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']);
465
    if (!db_num_rows($result)) {
466
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
467
468
469
470
    }
  }
}

471
/**
472
473
474
475
476
477
478
479
480
481
482
 * Returns a fieldset containing the theme select form.
 *
 * @param $description
 *    description of the fieldset
 * @param $default_value
 *    default value of theme radios
 * @param $weight
 *    weight of the fieldset
 * @return
 *    a form array
 */
483
function system_theme_select_form(&$form_state, $description = '', $default_value = '', $weight = 0) {
484
  if (user_access('select different theme')) {
485
    $enabled = array();
486
487
488
    $themes = list_themes();

    foreach ($themes as $theme) {
489
490
491
492
493
494
495
496
497
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

    if (count($enabled) > 1) {
      ksort($enabled);

      $form['themes'] = array(
Dries's avatar
Dries committed
498
499
500
501
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
502
503
504
505
506
        '#theme' => 'system_theme_select_form'
      );

      foreach ($enabled as $info) {
        // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed.
507
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
508

509
510
511
512
513
514
515
516
517
518
519
        $screenshot = NULL;
        $theme_key = $info->name;
        while ($theme_key) {
          if (file_exists($themes[$theme_key]->info['screenshot'])) {
            $screenshot = $themes[$theme_key]->info['screenshot'];
            break;
          }
          $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL;
        }

        $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
520

521
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
522
        $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name,  '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : ''));
523
524
525
526
527
528
529
530
531
532
533
        $options[$info->key] = '';
      }

      $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : '');
      $form['#weight'] = $weight;
      return $form;
    }
  }
}

function theme_system_theme_select_form($form) {
534
535
  foreach (element_children($form) as $key) {
    $row = array();
536
    if (isset($form[$key]['description']) && is_array($form[$key]['description'])) {
537
538
539
      $row[] = drupal_render($form[$key]['screenshot']);
      $row[] = drupal_render($form[$key]['description']);
      $row[] = drupal_render($form['theme'][$key]);
540
541
542
543
    }
    $rows[] = $row;
  }

544
  $header = array(t('Screenshot'), t('Name'), t('Selected'));
545
546
547
548
  $output = theme('table', $header, $rows);
  return $output;
}

Steven Wittens's avatar
Steven Wittens committed
549
550
551
552
553
554
function _system_zonelist() {
  $timestamp = time();
  $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14);
  $zones = array();
  foreach ($zonelist as $offset) {
    $zone = $offset * 3600;
Dries's avatar
Dries committed
555
    $zones[$zone] = format_date($timestamp, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') .' O', $zone);
Steven Wittens's avatar
Steven Wittens committed
556
557
558
559
  }
  return $zones;
}

Dries's avatar
Dries committed
560
561
562
563
function system_site_information_settings() {
  $form['site_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
564
    '#default_value' => variable_get('site_name', 'Drupal'),
565
    '#description' => t('The name of this website.'),
Dries's avatar
Dries committed
566
    '#required' => TRUE
567
  );
Dries's avatar
Dries committed
568
569
570
571
  $form['site_mail'] = array(
    '#type' => 'textfield',
    '#title' => t('E-mail address'),
    '#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
572
573
    '#description' => t('A valid e-mail address to be used as the "From" address by the auto-mailer during registration, new password requests, notifications, etc.  To lessen the likelihood of e-mail being marked as spam, this e-mail address should use the same domain as the website.'),
    '#required' => TRUE,
574
  );
Dries's avatar
Dries committed
575
576
577
578
  $form['site_slogan'] = array(
    '#type' => 'textfield',
    '#title' => t('Slogan'),
    '#default_value' => variable_get('site_slogan', ''),
579
    '#description' => t('The slogan of this website. Some themes display a slogan when available.')
580
581
  );

Dries's avatar
Dries committed
582
583
584
585
  $form['site_mission'] = array(
    '#type' => 'textarea',
    '#title' => t('Mission'),
    '#default_value' => variable_get('site_mission', ''),
586
    '#description' => t('Your site\'s mission statement or focus.')
587
  );
Dries's avatar
Dries committed
588
589
590
591
  $form['site_footer'] = array(
    '#type' => 'textarea',
    '#title' => t('Footer message'),
    '#default_value' => variable_get('site_footer', ''),
592
    '#description' => t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.')
593
  );
Dries's avatar
Dries committed
594
595
596
  $form['anonymous'] = array(
    '#type' => 'textfield',
    '#title' => t('Anonymous user'),
597
    '#default_value' => variable_get('anonymous', t('Anonymous')),
598
    '#description' => t('The name used to indicate anonymous users.')
599
  );
Dries's avatar
Dries committed
600
601
602
603
  $form['site_frontpage'] = array(
    '#type' => 'textfield',
    '#title' => t('Default front page'),
    '#default_value' => variable_get('site_frontpage', 'node'),
604
605
    '#size' => 40,
    '#description' => t('The home page displays content from this relative URL. If unsure, specify "node".'),
606
    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
607
  );
608

609
  return system_settings_form($form);
Dries's avatar
Dries committed
610
611
612
613
}

function system_clean_url_settings() {
  $form['clean_url'] = array(
614
615
616
617
    '#type' => 'radios',
    '#title' => t('Clean URLs'),
    '#default_value' => variable_get('clean_url', 0),
    '#options' => array(t('Disabled'), t('Enabled')),
618
    '#description' => t('This option makes Drupal emit "clean" URLs (i.e. without <code>?q=</code> in the URL).'),
619
  );
620

621
622
  if (!variable_get('clean_url', 0)) {
    if (strpos(request_uri(), '?q=') !== FALSE) {
623
624
625
626
      drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');

      $form['clean_url']['#description'] .= ' <span>'. t('Before enabling clean URLs, you must perform a test to determine if your server is properly configured. If you are able to see this page again after clicking the "Run the clean URL test" link, the test has succeeded and the radio buttons above will be available. If instead you are directed to a "Page not found" error, you will need to change the configuration of your server. The <a href="@handbook">handbook page on Clean URLs</a> has additional troubleshooting information.', array('@handbook' => 'http://drupal.org/node/15365')) .'</span>';

627
      $form['clean_url']['#disabled'] = TRUE;
628
629
      $form['clean_url']['#prefix'] = '<div id="clean-url">';
      $form['clean_url']['#suffix'] = '<p>'. t('<a href="@clean_url">Run the clean url test</a>.', array('@clean_url' => base_path() .'admin/settings/clean-urls')) .'</p></div>';
630
631
    }
    else {
632
      $form['clean_url']['#description'] .= ' '. t('Your server has been successfully tested to support this feature.');
633
634
    }
  }
Dries's avatar
   
Dries committed
635

636
  return system_settings_form($form);
Dries's avatar
Dries committed
637
638
639
}

function system_error_reporting_settings() {
drumm's avatar
drumm committed
640
641

  $form['site_403'] = array(
Dries's avatar
Dries committed
642
    '#type' => 'textfield',
drumm's avatar
drumm committed
643
    '#title' => t('Default 403 (access denied) page'),
Dries's avatar
Dries committed
644
    '#default_value' => variable_get('site_403', ''),
645
646
    '#size' => 40,
    '#description' => t('This page is displayed when the requested document is denied to the current user. If unsure, specify nothing.'),
647
    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
648
  );
drumm's avatar
drumm committed
649
650

  $form['site_404'] = array(
Dries's avatar
Dries committed
651
    '#type' => 'textfield',
drumm's avatar
drumm committed
652
    '#title' => t('Default 404 (not found) page'),
Dries's avatar
Dries committed
653
    '#default_value' =>  variable_get('site_404', ''),
654
655
    '#size' => 40,
    '#description' => t('This page is displayed when no other content matches the requested document. If unsure, specify nothing.'),
656
    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
657
  );
drumm's avatar
drumm committed
658
659

  $form['error_level'] = array(
660
661
    '#type' => 'select', '#title' => t('Error reporting'), '#default_value' => variable_get('error_level', 1),
    '#options' => array(t('Write errors to the log'), t('Write errors to the log and to the screen')),
drumm's avatar
drumm committed
662
    '#description' =>  t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.')
663
  );
drumm's avatar
drumm committed
664

665
  return system_settings_form($form);
Dries's avatar
Dries committed
666
}
Dries's avatar
 
Dries committed
667

668
function system_performance_settings() {
669

670
671
672
673
674
675
  $description = '<p>'. t("The normal cache mode is suitable for most sites and does not cause any side effects. The aggressive cache mode causes Drupal to skip the loading (init) and unloading (exit) of enabled modules when serving a cached page. This results in an additional performance boost but can cause unwanted side effects.") .'</p>';

  $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit')));
  sort($problem_modules);

  if (count($problem_modules) > 0) {
676
    $description .= '<p>'. t('<strong class="error">The following enabled modules are incompatible with aggressive mode caching and will not function properly: %modules</strong>', array('%modules' => implode(', ', $problem_modules))) .'.</p>';
677
678
  }
  else {
679
    $description .= '<p>'. t('<strong class="ok">Currently, all enabled modules are compatible with the aggressive caching policy.</strong> Please note, if you use aggressive caching and enable new modules, you will need to check this page again to ensure compatibility.') .'</p>';
680
  }
681
682
683
684
685
  $form['page_cache'] = array(
    '#type' => 'fieldset',
    '#title' => t('Page cache'),
    '#description' => t('Enabling the cache will offer a significant performance boost. Drupal can store and send compressed cached pages requested by <em>anonymous</em> users. By caching a web page, Drupal does not have to construct the page each time someone wants to view it.'),
  );
686

687
  $form['page_cache']['cache'] = array(
Dries's avatar
Dries committed
688
    '#type' => 'radios',
689
    '#title' => t('Caching mode'),
Dries's avatar
Dries committed
690
    '#default_value' => variable_get('cache', CACHE_DISABLED),
691
692
    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended, no side effects)'), CACHE_AGGRESSIVE => t('Aggressive (experts only, possible side effects)')),
    '#description' => $description
693
694
  );

695
696
  $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval');
  $period[0] = t('none');
697
  $form['page_cache']['cache_lifetime'] = array(
Dries's avatar
Dries committed
698
699
700
701
    '#type' => 'select',
    '#title' => t('Minimum cache lifetime'),
    '#default_value' => variable_get('cache_lifetime', 0),
    '#options' => $period,
702
    '#description' => t('On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.')
703
  );
704

705
706
707
  $form['bandwidth_optimizations'] = array(
    '#type' => 'fieldset',
    '#title' => t('Bandwidth optimizations'),
708
    '#description' => t('<p>Drupal can automatically aggregate and compress external resources like CSS and JavaScript into a single cached file. This can help reduce both the size and number of requests made to your website. This in turn reduces the server load, the bandwidth used, and the average page loading time for your visitors.</p><p>These options are disabled if you have not set up your files directory, or if your download method is set to private.</p>')
709
  );
710

711
  $directory = file_directory_path();
712
  $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
713
714
  $form['bandwidth_optimizations']['preprocess_css'] = array(
    '#type' => 'radios',
715
716
    '#title' => t('Optimize CSS files'),
    '#default_value' => variable_get('preprocess_css', 0) && $is_writable,
717
718
    '#disabled' => !$is_writable,
    '#options' => array(t('Disabled'), t('Enabled')),
719
720
721
722
723
724
725
726
727
    '#description' => t("This option can interfere with theme development. It is recommended to only turn this on when your site is complete."),
  );
  $form['bandwidth_optimizations']['preprocess_js'] = array(
    '#type' => 'radios',
    '#title' => t('Optimize JavaScript files'),
    '#default_value' => variable_get('preprocess_js', 0) && $is_writable,
    '#disabled' => !$is_writable,
    '#options' => array(t('Disabled'), t('Enabled')),
    '#description' => t("This option can interfere with module development. It is recommended to only turn this on when your site is complete."),
728
729
  );

730
731
732
733
734
735
736
737
738
739
740
741
742
743
  $form['reverse_proxy'] = array(
    '#type' => 'fieldset',
    '#title' => t('Reverse proxy'),
    '#description' => t('Proper extraction of client IP addresses when Drupal is behind a reverse proxy.'),
  );

  $form['reverse_proxy']['reverse_proxy'] = array(
    '#type' => 'radios',
    '#title' => t('Reverse proxy'),
    '#default_value' => variable_get('reverse_proxy', FALSE),
    '#options' => array(t('Disabled'), t('Enabled')),
    '#description' => t('Enable this setting to determine the correct IP address of the remote client by examining information stored in the X-Forwarded-For headers. X-Forwarded-For headers are a standard mechanism for identifying client systems connecting through a reverse proxy server, such as Squid or Pound. Reverse proxy servers are often used to enhance the performance of heavily visited sites and may also provide other site caching, security or encryption benefits. If this Drupal installation operates behind a reverse proxy, this setting should be enabled so that correct IP address information is captured in Drupal\'s session management, logging, statistics and access management systems; if you are unsure about this setting, do not have a reverse proxy, or Drupal operates in a shared hosting environment, this setting should be set to disabled.'),
  );

744
  $form['#submit'][] = 'drupal_clear_css_cache';
745
  $form['#submit'][] = 'drupal_clear_js_cache';
Dries's avatar
   
Dries committed
746

747
  return system_settings_form($form);
Dries's avatar
Dries committed
748
}
Dries's avatar
   
Dries committed
749

Dries's avatar
Dries committed
750
function system_file_system_settings() {
751

Dries's avatar
Dries committed
752
  $form['file_directory_path'] = array(
753
754
755
756
    '#type' => 'textfield',
    '#title' => t('File system path'),
    '#default_value' => file_directory_path(),
    '#maxlength' => 255,
757
    '#description' => t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to the Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'),
758
    '#after_build' => array('system_check_directory'),
759
760
  );

Dries's avatar
Dries committed
761
  $form['file_directory_temp'] = array(
762
763
764
765
766
    '#type' => 'textfield',
    '#title' => t('Temporary directory'),
    '#default_value' => file_directory_temp(),
    '#maxlength' => 255,
    '#description' => t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the Drupal installation directory.'),
767
    '#after_build' => array('system_check_directory'),
768
769
  );

Dries's avatar
Dries committed
770
771
772
773
  $form['file_downloads'] = array(
    '#type' => 'radios',
    '#title' => t('Download method'),
    '#default_value' => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC),
774
    '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')),
775
    '#description' => t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.')
776
  );
Dries's avatar
   
Dries committed
777

778
  return system_settings_form($form);
Dries's avatar
Dries committed
779
780
781
}

function system_image_toolkit_settings() {
782
783
  $toolkits_available = image_get_available_toolkits();
  if (count($toolkits_available) > 1) {
Dries's avatar
Dries committed
784
785
786
787
788
    $form['image_toolkit'] = array(
      '#type' => 'radios',
      '#title' => t('Select an image processing toolkit'),
      '#default_value' => variable_get('image_toolkit', image_get_toolkit()),
      '#options' => $toolkits_available
789
    );
790
  }
Dries's avatar
Dries committed
791
  else {
792
    $form['image_toolkit'] = array('#value' => '<p>'. t("No image toolkits found. Drupal will use PHP's built-in GD library for image handling.") .'</p>');
Dries's avatar
Dries committed
793
  }
794
795
  $form['image_toolkit_settings'] = image_toolkit_invoke('settings');
  return system_settings_form($form);
Dries's avatar
Dries committed
796
797
798
}

function system_rss_feeds_settings() {
799

Dries's avatar
Dries committed
800
801
802
803
  $form['feed_default_items'] = array(
    '#type' => 'select',
    '#title' => t('Number of items per feed'),
    '#default_value' => variable_get('feed_default_items', 10),
804
805
    '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
    '#description' => t('The default number of items to include in a feed.')
806
  );
Dries's avatar
Dries committed
807
808
809
  $form['feed_item_length'] = array(
    '#type' => 'select',
    '#title' => t('Display of XML feed items'),
Dries's avatar
Dries committed
810
    '#default_value' => variable_get('feed_item_length', 'teaser'),
811
812
    '#options' => array('title' => t('Titles only'), 'teaser' => t('Titles plus teaser'), 'fulltext' => t('Full text')),
    '#description' => t('Global setting for the length of XML feed items that are output by default.')
813
  );
814

815
  return system_settings_form($form);
Dries's avatar
Dries committed
816
817
818
}

function system_date_time_settings() {
819
820
  drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
  drupal_add_js(array('dateTime' => array('lookup' => url('admin/settings/date-time/lookup'))), 'setting');
821

822
  // Date settings:
Steven Wittens's avatar
Steven Wittens committed
823
  $zones = _system_zonelist();
824

825
  // Date settings: possible date formats
826
  $date_short = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i',
827
           'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia',
Dries's avatar
   
Dries committed
828
829
           'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i',
           'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia');
830
  $date_medium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i',
Dries's avatar
   
Dries committed
831
          'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i',
Dries's avatar
   
Dries committed
832
          'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia',
833
          'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i');
834
  $date_long = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y,  F j - H:i',
835
        'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y,  F j - g:ia', 'l, j. F Y - G:i');
Dries's avatar
   
Dries committed
836

837
  // Date settings: construct choices for user
838
839
  foreach ($date_short as $f) {
    $date_short_choices[$f] = format_date(time(), 'custom', $f);
Dries's avatar
   
Dries committed
840
  }
841
842
  foreach ($date_medium as $f) {
    $date_medium_choices[$f] = format_date(time(), 'custom', $f);
Dries's avatar
   
Dries committed
843
  }
844
845
  foreach ($date_long as $f) {
    $date_long_choices[$f] = format_date(time(), 'custom', $f);
Dries's avatar
   
Dries committed
846
847
  }

848
849
  $date_long_choices['custom'] = $date_medium_choices['custom'] = $date_short_choices['custom'] = t('Custom format');

850
851
852
853
854
855
  $form['locale'] = array(
    '#type' => 'fieldset',
    '#title' => t('Locale settings'),
  );

  $form['locale']['date_default_timezone'] = array(
Dries's avatar
Dries committed
856
857
858
859
860
    '#type' => 'select',
    '#title' => t('Default time zone'),
    '#default_value' => variable_get('date_default_timezone', 0),
    '#options' => $zones,
    '#description' => t('Select the default site time zone.')
861
862
  );

863
  $form['locale']['configurable_timezones'] = array(
Dries's avatar
Dries committed
864
    '#type' => 'radios',
865
    '#title' => t('User-configurable time zones'),
Dries's avatar
Dries committed
866
867
    '#default_value' => variable_get('configurable_timezones', 1),
    '#options' => array(t('Disabled'), t('Enabled')),
868
869
870
871
872
873
874
875
876
877
878
879
880
881
    '#description' => t('When enabled, users can set their own time zone and dates will be displayed accordingly.')
  );

  $form['locale']['date_first_day'] = array(
    '#type' => 'select',
    '#title' => t('First day of week'),
    '#default_value' => variable_get('date_first_day', 0),
    '#options' => array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')),
    '#description' => t('The first day of the week for calendar views.')
  );

  $form['date_formats'] = array(
    '#type' => 'fieldset',
    '#title' => t('Formatting'),
882
883
  );

884
  $date_format_short = variable_get('date_format_short', $date_short[1]);
885
  $form['date_formats']['date_format_short'] = array(
886
887
    '#prefix' => '<div class="date-container"><div>',
    '#suffix' => '</div>',
Dries's avatar
Dries committed
888
889
    '#type' => 'select',
    '#title' => t('Short date format'),
890
891
892
893
    '#attributes' => array('class' => 'date-format'),
    '#default_value' => (isset($date_short_choices[$date_format_short]) ? $date_format_short : 'custom'),
    '#options' => $date_short_choices,
    '#description' => t('The short format of date display.'),
894
895
  );

896
  $default_short_custom = variable_get('date_format_short_custom', (isset($date_short_choices[$date_format_short]) ? $date_format_short : ''));
897
  $form['date_formats']['date_format_short_custom'] = array(
898
899
900
901
902
903
904
905
906
907
    '#prefix' => '<div class="custom-container">',
    '#suffix' => '</div></div>',
    '#type' => 'textfield',
    '#title' => t('Custom short date format'),
    '#attributes' => array('class' => 'custom-format'),