system.module 109 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
23
/**
 * Implementation of hook_help().
 */
function system_help($section) {
24
25
  global $base_url;

26
  switch ($section) {
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
    case 'admin/build/themes/settings':
40
      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>';
41
42
    case 'admin/build/themes/settings/'. arg(4):
      $reference = explode('.', arg(4), 2);
43
      $theme = array_pop($reference);
44
      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>';
45
    case 'admin/build/modules':
46
      return t('<p>Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. Click on the name of the module in the navigation menu for their individual configuration pages. 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. The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.</p>
47
<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('@permissions' => url('admin/user/access'), '@throttle' => url('admin/settings/throttle'), '@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module')));
48
    case 'admin/build/modules/uninstall':
49
      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>';
50
    case 'admin/logs/status':
51
      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>';
52
  }
Dries's avatar
   
Dries committed
53
54
}

55
56
57
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
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
86
87
88
/**
 * Implementation of hook_perm().
 */
Dries's avatar
 
Dries committed
89
function system_perm() {
90
  return array('administer site configuration', 'access administration pages', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
91
92
}

93
94
95
96
97
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
98
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
99
100

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

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

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

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

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

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

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

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

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

391
    return $form;
Dries's avatar
   
Dries committed
392
  }
Dries's avatar
   
Dries committed
393
394
}

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

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

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

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

444
445
446
447
448
449
450
  $form['node_admin_theme'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use administration theme for content editing'),
    '#description' => t('Use the administration theme when editing existing nodes or creating new ones..'),
    '#default_value' => variable_get('node_admin_theme', '0'),
  );

451
  $form['#submit'][] = 'system_admin_theme_submit';
452
  return system_settings_form($form);
453
454
455
}


456
function system_admin_theme_submit($form, &$form_state) {
457
  // If we're changing themes, make sure the theme has its blocks initialized.
458
459
  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']);
460
    if (!db_num_rows($result)) {
461
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
462
463
464
465
    }
  }
}

466
/**
467
468
469
470
471
472
473
474
475
476
477
 * 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
 */
478
function system_theme_select_form(&$form_state, $description = '', $default_value = '', $weight = 0) {
479
  if (user_access('select different theme')) {
480
    $enabled = array();
481
482
483
    $themes = list_themes();

    foreach ($themes as $theme) {
484
485
486
487
488
489
490
491
492
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

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

      $form['themes'] = array(
Dries's avatar
Dries committed
493
494
495
496
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
497
498
499
500
501
        '#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.
502
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
503

504
505
506
507
508
509
510
511
512
513
514
        $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');
515

516
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
517
        $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>' : ''));
518
519
520
521
522
523
524
525
526
527
528
        $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) {
529
530
  foreach (element_children($form) as $key) {
    $row = array();
531
    if (isset($form[$key]['description']) && is_array($form[$key]['description'])) {
532
533
534
      $row[] = drupal_render($form[$key]['screenshot']);
      $row[] = drupal_render($form[$key]['description']);
      $row[] = drupal_render($form['theme'][$key]);
535
536
537
538
    }
    $rows[] = $row;
  }

539
  $header = array(t('Screenshot'), t('Name'), t('Selected'));
540
541
542
543
  $output = theme('table', $header, $rows);
  return $output;
}

Steven Wittens's avatar
Steven Wittens committed
544
545
546
547
548
549
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
550
    $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
551
552
553
554
  }
  return $zones;
}

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

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

604
  return system_settings_form($form);
Dries's avatar
Dries committed
605
606
607
608
}

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

616
617
  if (!variable_get('clean_url', 0)) {
    if (strpos(request_uri(), '?q=') !== FALSE) {
618
619
620
621
622
623
624
625
626
627
628
      drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
      drupal_add_js('
// Global Killswitch
if (Drupal.jsEnabled) {
  $(document).ready(function() {
    Drupal.cleanURLsSettingsCheck();
  });
}', 'inline');

      $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
  }
Dries's avatar
Dries committed
793
  else {
794
    $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
795
  }
796
797
  $form['image_toolkit_settings'] = image_toolkit_invoke('settings');
  return system_settings_form($form);
Dries's avatar
Dries committed
798
799
800
}

function system_rss_feeds_settings() {
801

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

817
  return system_settings_form($form);
Dries's avatar
Dries committed
818
819
820
}

function system_date_time_settings() {
821
822
823
824
825
826
827
  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');
  drupal_add_js('
// Global Killswitch
if (Drupal.jsEnabled) {
  $(document).ready(Drupal.dateTimeAutoAttach);
}', 'inline');
828
  // Date settings:
Steven Wittens's avatar
Steven Wittens committed
829
  $zones = _system_zonelist();
830

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

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

854
855
  $date_long_choices['custom'] = $date_medium_choices['custom'] = $date_short_choices['custom'] = t('Custom format');

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

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

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

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

902
  $default_short_custom = variable_get('date_format_short_custom', (isset($date_short_choices[$date_format_short]) ? $date_format_short : ''));
903
  $form['date_formats']['date_format_short_custom'] = array(
904
905
906
907
908
909
910
911
912
913
    '#prefix' => '<div class="custom-container">',
    '#suffix' => '</div></div>',
    '#type' => 'textfield',
    '#title' => t('Custom short date format'),
    '#attributes' => array('class' => 'custom-format'),
    '#default_value' => $default_short_custom,
    '#description' => t('A user-defined short date format. See the <a href="@url">PHP manual</a> for available options. This format is currently set to display as <span>%date</span>.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(time(), 'custom', $default_short_custom))),
  );

  $date_format_medium = variable_get('date_format_medium', $date_medium[1]);
914
  $form['date_formats']['date_format_medium'] = array(
915
916
    '#prefix' => '<div class="date-container"><div>',
    '#suffix' => '</div>',
Dries's avatar
Dries committed
917
918 </