system.module 121 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 system 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['image_button'] = array('#input' => TRUE, '#button_type' => 'submit','#executes_submit_callback' => TRUE, '#ahah_event' => 'submit', '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
109
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE);
110
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128);
111
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
112
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE);
113
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
114
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL);
115
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
116
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1);
117
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE);
118
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight'));
119
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
120
  $type['file'] = array('#input' => TRUE, '#size' => 60);
121
122

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

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

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

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

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

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

359
360
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
361
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
362
363
364
365
366
367
368
369
370
371
    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
372
373
374
375
376
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
377
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
378
  if ($type == 'form' && $category == 'account') {
379
    $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
380

381
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
382
      $zones = _system_zonelist();
383
      $form['timezone'] = array(
384
        '#type' => 'fieldset',
385
386
387
388
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
389
      $form['timezone']['timezone'] = array(
390
391
392
393
394
        '#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.'),
395
      );
Dries's avatar
   
Dries committed
396
    }
Dries's avatar
Dries committed
397

398
    return $form;
Dries's avatar
   
Dries committed
399
  }
Dries's avatar
   
Dries committed
400
401
}

402
403
404
/**
 * Provide a single block on the administration overview page.
 */
405
function system_admin_menu_block($item) {
406
  $content = array();
407
408
  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']));
409
  }
410
411
412
413
414
415
416
  $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)) {
417
    _menu_link_translate($item);
418
    if (!$item['access']) {
419
      continue;
420
    }
421
    $content[] = (array)$item;
422
423
424
425
426
427
428
429
430
  }
  return $content;
}

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

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

  $form['admin_theme'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#title' => t('Administration theme'),
447
    '#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.'),
448
    '#default_value' => variable_get('admin_theme', '0'),
449
450
  );

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

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


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

473
/**
474
475
476
477
478
479
480
481
482
483
484
 * 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
 */
485
function system_theme_select_form(&$form_state, $description = '', $default_value = '', $weight = 0) {
486
  if (user_access('select different theme')) {
487
    $enabled = array();
488
489
490
    $themes = list_themes();

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

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

      $form['themes'] = array(
Dries's avatar
Dries committed
500
501
502
503
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
504
505
506
507
508
        '#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.
509
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
510

511
512
513
514
515
516
517
518
519
520
521
        $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');
522

523
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
524
        $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>' : ''));
525
526
527
528
529
530
531
532
533
534
535
        $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) {
536
537
  foreach (element_children($form) as $key) {
    $row = array();
538
    if (isset($form[$key]['description']) && is_array($form[$key]['description'])) {
539
540
541
      $row[] = drupal_render($form[$key]['screenshot']);
      $row[] = drupal_render($form[$key]['description']);
      $row[] = drupal_render($form['theme'][$key]);
542
543
544
545
    }
    $rows[] = $row;
  }

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

Steven Wittens's avatar
Steven Wittens committed
551
552
553
554
555
556
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
557
    $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
558
559
560
561
  }
  return $zones;
}

Dries's avatar
Dries committed
562
563
564
565
function system_site_information_settings() {
  $form['site_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
566
    '#default_value' => variable_get('site_name', 'Drupal'),
567
    '#description' => t('The name of this website.'),
Dries's avatar
Dries committed
568
    '#required' => TRUE
569
  );
Dries's avatar
Dries committed
570
571
572
573
  $form['site_mail'] = array(
    '#type' => 'textfield',
    '#title' => t('E-mail address'),
    '#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
574
575
    '#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,
576
  );
Dries's avatar
Dries committed
577
578
579
580
  $form['site_slogan'] = array(
    '#type' => 'textfield',
    '#title' => t('Slogan'),
    '#default_value' => variable_get('site_slogan', ''),
581
    '#description' => t('The slogan of this website. Some themes display a slogan when available.')
582
583
  );

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

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

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

623
624
  if (!variable_get('clean_url', 0)) {
    if (strpos(request_uri(), '?q=') !== FALSE) {
625
626
627
628
      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>';

629
      $form['clean_url']['#disabled'] = TRUE;
630
631
      $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>';
632
633
    }
    else {
634
      $form['clean_url']['#description'] .= ' '. t('Your server has been successfully tested to support this feature.');
635
636
    }
  }
Dries's avatar
   
Dries committed
637

638
  return system_settings_form($form);
Dries's avatar
Dries committed
639
640
641
}

function system_error_reporting_settings() {
drumm's avatar
drumm committed
642
643

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

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

  $form['error_level'] = array(
662
663
    '#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
664
    '#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.')
665
  );
drumm's avatar
drumm committed
666

667
  return system_settings_form($form);
Dries's avatar
Dries committed
668
}
Dries's avatar
   
Dries committed
669

670
function system_performance_settings() {
671

672
673
674
675
676
677
  $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) {
678
    $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>';
679
680
  }
  else {
681
    $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>';
682
  }
683
684
685
686
687
  $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.'),
  );
688

689
  $form['page_cache']['cache'] = array(
Dries's avatar
Dries committed
690
    '#type' => 'radios',
691
    '#title' => t('Caching mode'),
Dries's avatar
Dries committed
692
    '#default_value' => variable_get('cache', CACHE_DISABLED),
693
694
    '#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
695
696
  );

697
698
  $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');
699
  $form['page_cache']['cache_lifetime'] = array(
Dries's avatar
Dries committed
700
701
702
703
    '#type' => 'select',
    '#title' => t('Minimum cache lifetime'),
    '#default_value' => variable_get('cache_lifetime', 0),
    '#options' => $period,
704
    '#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.')
705
  );
706

707
708
709
  $form['bandwidth_optimizations'] = array(
    '#type' => 'fieldset',
    '#title' => t('Bandwidth optimizations'),
710
    '#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>')
711
  );
712

713
  $directory = file_directory_path();
714
  $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
715
716
  $form['bandwidth_optimizations']['preprocess_css'] = array(
    '#type' => 'radios',
717
718
    '#title' => t('Optimize CSS files'),
    '#default_value' => variable_get('preprocess_css', 0) && $is_writable,
719
720
    '#disabled' => !$is_writable,
    '#options' => array(t('Disabled'), t('Enabled')),
721
722
723
724
725
726
727
728
729
    '#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."),
730
731
  );

732
733
734
735
736
737
738
739
740
741
742
743
744
745
  $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.'),
  );

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

749
  return system_settings_form($form);
Dries's avatar
Dries committed
750
}
Dries's avatar
   
Dries committed
751

Dries's avatar
Dries committed
752
function system_file_system_settings() {
753

Dries's avatar
Dries committed
754
  $form['file_directory_path'] = array(
755
756
757
758
    '#type' => 'textfield',
    '#title' => t('File system path'),
    '#default_value' => file_directory_path(),
    '#maxlength' => 255,
759
    '#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.'),
760
    '#after_build' => array('system_check_directory'),
761
762
  );

Dries's avatar
Dries committed
763
  $form['file_directory_temp'] = array(
764
765
766
767
768
    '#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.'),
769
    '#after_build' => array('system_check_directory'),
770
771
  );

Dries's avatar
Dries committed
772
773
774
775
  $form['file_downloads'] = array(
    '#type' => 'radios',
    '#title' => t('Download method'),
    '#default_value' => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC),
776
    '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')),
777
    '#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.')
778
  );
Dries's avatar
   
Dries committed
779

780
  return system_settings_form($form);
Dries's avatar
Dries committed
781
782
783
}

function system_image_toolkit_settings() {
784
785
  $toolkits_available = image_get_available_toolkits();
  if (count($toolkits_available) > 1) {
Dries's avatar
Dries committed
786
787
788
789
790
    $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
791
    );
792
  }
793
794
  elseif (count($toolkits_available) == 1) {
    variable_set('image_toolkit', key($toolkits_available));
Dries's avatar
Dries committed
795
  }
796

797
  $form['image_toolkit_settings'] = image_toolkit_invoke('settings');
798

799
  return system_settings_form($form);
Dries's avatar
Dries committed
800
801
802
}

function system_rss_feeds_settings() {
803

Dries's avatar
Dries committed
804
805
806
807
  $form['feed_default_items'] = array(
    '#type' => 'select',
    '#title' => t('Number of items per feed'),
    '#default_value' => variable_get('feed_default_items', 10),
808
809
    '#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.')
810
  );
Dries's avatar
Dries committed
811
812
813
  $form['feed_item_length'] = array(
    '#type' => 'select',
    '#title' => t('Display of XML feed items'),
Dries's avatar
Dries committed
814
    '#default_value' => variable_get('feed_item_length', 'teaser'),
815
816
    '#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.')
817
  );
818

819
  return system_settings_form($form);
Dries's avatar
Dries committed
820
821
822
}

function system_date_time_settings() {
823
824
  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');
825

826
  // Date settings:
Steven Wittens's avatar
Steven Wittens committed
827
  $zones = _system_zonelist();
828

829
  // Date settings: possible date formats
830
  $date_short = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i',
831
           '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
832
833
           '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');
834
  $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
835
          '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
836
          'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia',
837
          'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i');
838
  $date_long = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y,  F j - H:i',
839
        '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
840

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

852
853
  $date_long_choices['custom'] = $date_medium_choices['custom'] = $date_short_choices['custom'] = t('Custom format');

854
855
856
857
858
859
  $form['locale'] = array(
    '#type' => 'fieldset',
    '#title' => t('Locale settings'),
  );

  $form['locale']['date_default_timezone'] = array(
Dries's avatar
Dries committed
860
861
862
863
864
    '#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.')
865
866
  );

867
  $form['locale']['configurable_timezones'] = array(
Dries's avatar
Dries committed
868
    '#type' => 'radios',
869
    '#title' => t('User-configurable time zones'),
Dries's avatar
Dries committed
870
871
    '#default_value' => variable_get('configurable_timezones', 1),
    '#options' => array(t('Disabled'), t('Enabled')),
872
873
874
875
876
877
878
879
880
881
882
883
884
885
    '#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'),
886
887
  );

888
  $date_format_short = variable_get('date_format_short', $date_short[1]);
889
  $form['date_formats']['date_format_short'] = array(
890
891
    '#prefix' => '<div class="date-container"><div>',
    '#suffix' => '</div>',
Dries's avatar
Dries committed
892
893
    '#type' => 'select',
    '#title' => t('Short date format'),
894
895
896
897
    '#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.'),
898
899
  );

900
  $default_short_custom = variable_get('date_format_short_custom', (isset($date_short_choices