system.module 70.3 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.
 */

9
10
11
/**
 * The current system version.
 */
Gábor Hojtsy's avatar
Gábor Hojtsy committed
12
define('VERSION', '6.0-dev');
13
14
15
16

/**
 * Core API compatibility.
 */
17
define('DRUPAL_CORE_COMPATIBILITY', '6.x');
18

19
20
21
/**
 * Minimum supported version of PHP.
 */
22
23
define('DRUPAL_MINIMUM_PHP',    '4.3.3');

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
 * Minimum supported version of MySQL, if it is used.
 */
define('DRUPAL_MINIMUM_MYSQL',  '4.1.0');

/**
 * Minimum supported version of PostgreSQL, if it is used.
 */
define('DRUPAL_MINIMUM_PGSQL',  '7.4');

/**
 * Minimum supported version of Apache, if it is used.
 */
define('DRUPAL_MINIMUM_APACHE', '1.3');

/**
 * Maximum age of temporary files in seconds.
 */
42
43
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);

Dries's avatar
   
Dries committed
44
45
46
/**
 * Implementation of hook_help().
 */
47
function system_help($path, $arg) {
48
49
  global $base_url;

50
  switch ($path) {
51
    case 'admin/help#system':
52
53
54
55
56
      $output = '<p>'. t('The system module is at the foundation of your Drupal website, and provides basic but extensible functionality for use by other modules and themes. Some integral elements of Drupal are contained in and managed by the system module, including caching, enabling or disabling of modules and themes, preparing and displaying the administrative page, and configuring fundamental site settings. A number of key system maintenance operations are also part of the system module.') .'</p>';
      $output .= '<p>'. t('The system module provides:') .'</p>';
      $output .= '<ul><li>'. t('support for enabling and disabling <a href="@modules">modules</a>. Drupal comes packaged with a number of core modules; each module provides a discrete set of features and may be enabled depending on the needs of your site. A wide array of additional modules contributed by members of the Drupal community are available for download at the <a href="@drupal-modules">Drupal.org module page</a>.', array('@modules' => url('admin/build/modules'), '@drupal-modules' => 'http://drupal.org/project/modules')) .'</li>';
      $output .= '<li>'. t('support for enabling and disabling <a href="@themes">themes</a>, which determine the design and presentation of your site. Drupal comes packaged with several core themes and additional contributed themes are available at the <a href="@drupal-themes">Drupal.org theme page</a>.', array('@themes' => url('admin/build/themes'), '@drupal-themes' => 'http://drupal.org/project/themes')) .'</li>';
      $output .= '<li>'. t('a robust <a href="@cache-settings">caching system</a> that allows the efficient re-use of previously-constructed web pages and web page components. Drupal stores the pages requested by anonymous users in a compressed format; depending on your site configuration and the amount of your web traffic tied to anonymous visitors, Drupal\'s caching system may significantly increase the speed of your site.', array('@cache-settings' => url('admin/settings/performance'))) .'</li>';
57
58
      $output .= '<li>'. t('a set of routine administrative operations that rely on a correctly-configured <a href="@cron">cron maintenance task</a> to run automatically. A number of other modules, including the feed aggregator, ping module and search also rely on <a href="@cron">cron maintenance tasks</a>. For more information, see the online handbook entry for <a href="@handbook">configuring cron jobs</a>.', array('@cron' => url('admin/reports/status'), '@handbook' => 'http://drupal.org/cron')) .'</li>';
      $output .= '<li>'. t('basic configuration options for your site, including <a href="@date-settings">date and time settings</a>, <a href="@file-system">file system settings</a>, <a href="@clean-url">clean URL support</a>, <a href="@site-info">site name and other information</a>, and a <a href="@site-maintenance">site maintenance</a> function for taking your site temporarily off-line.', array('@date-settings' => url('admin/settings/date-time'), '@file-system' => url('admin/settings/file-system'), '@clean-url' => url('admin/settings/clean-urls'), '@site-info' => url('admin/settings/site-information'), '@site-maintenance' => url('admin/settings/site-maintenance'))) .'</li></ul>';
59
      $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@system">System module</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>';
60
      return $output;
61
    case 'admin':
62
      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
63
    case 'admin/by-module':
64
      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
65
    case 'admin/build/themes':
66
      $output = '<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. Alternatively, to override these settings in a specific theme, click the "configure" link for that theme. Note that different themes may have different regions available for displaying content; for consistency in presentation, you may wish to enable only one theme.') .'</p>';
67
68
      $output .= '<p>'. t('To change the appearance of your site, a number of <a href="@themes">contributed themes</a> are available.', array('@themes' => 'http://drupal.org/project/themes')) .'</p>';
      return $output;
69
70
    case 'admin/build/themes/settings/'. $arg[4]:
      $reference = explode('.', $arg[4], 2);
71
      $theme = array_pop($reference);
72
      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>';
73
74
    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>';
75
    case 'admin/build/modules':
76
      $output = '<p>'. t('Modules are plugins that extend Drupal\'s core functionality. Enable modules by selecting the <em>Enabled</em> checkboxes below and clicking the <em>Save configuration</em> button. Once a module is enabled, new <a href="@permissions">permissions</a> may be available. To reduce server load, modules with their <em>Throttle</em> checkbox selected are temporarily disabled when your site becomes extremely busy. (Note that the <em>Throttle</em> checkbox is only available if the Throttle module is enabled.)', array('@permissions' => url('admin/user/permissions')));
77
78
79
80
      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>';
81
82
83
      $output .= '<p>'. t('It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.', array('@update-php' => $base_url .'/update.php')) .'</p>';
      $output .= '<p>'. t('You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.', array('@by-module' => url('admin/by-module'))) .'</p>';
      $output .= '<p>'. t('To extend the functionality of your site, a number of <a href="@modules">contributed modules</a> are available.', array('@modules' => 'http://drupal.org/project/modules')) .'</p>';
84
      return $output;
85
    case 'admin/build/modules/uninstall':
86
      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>';
87
88
89
90
    case 'admin/build/block/configure':
      if ($arg[4] == 'system' && $arg[5] == 0) {
        return '<p>'. t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') .'</p>';
      }
91
      break;
92
93
94
95
96
97
98
    case 'admin/settings/actions':
    case 'admin/settings/actions/manage':
      $output = '<p>'. t('Actions are individual tasks that the system can do, such as unpublishing a piece of content or banning a user. Modules, such as the trigger module, can fire these actions when certain system events happen; for example, when a new post is added or when a user logs in. Modules may also provide additional actions.') .'</p>';
      $output .= '<p>'. t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration, and are listed here automatically. Advanced actions can do more than simple actions; for example, send an e-mail to a specified address, or check for certain words within a piece of content. These actions need to be created and configured first before they may be used. To create an advanced action, select the action from the drop-down below and click the <em>Create</em> button.') .'</p>';
      if (module_exists('trigger')) {
        $output .= '<p>'. t('You may proceed to the <a href="@url">Triggers</a> page to assign these actions to system events.', array('@url' => url('admin/build/trigger'))) .'</p>';
      }
99
      return $output;
100
101
    case 'admin/settings/actions/configure':
      return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended, in order to better identify the precise action taking place. This description will be displayed in modules such as the trigger module when assigning actions to system events, so it is best if it is as descriptive as possible (for example, "Send e-mail to Moderation Team" rather than simply "Send e-mail").');
102
    case 'admin/reports/status':
103
      return '<p>'. t("Here you can find a short overview of your site's parameters as well as any problems detected with your installation. It may be useful to copy and paste this information into support requests filed on drupal.org's support forums and project issue queues.") .'</p>';
104
  }
Dries's avatar
   
Dries committed
105
106
}

107
108
109
/**
 * Implementation of hook_theme().
 */
110
function system_theme() {
111
  return array_merge(drupal_common_theme(), array(
112
113
    'system_theme_select_form' => array(
      'arguments' => array('form' => NULL),
114
      'file' => 'system.admin.inc',
115
116
117
    ),
    'system_themes_form' => array(
      'arguments' => array('form' => NULL),
118
      'file' => 'system.admin.inc',
119
120
121
    ),
    'system_modules' => array(
      'arguments' => array('form' => NULL),
122
      'file' => 'system.admin.inc',
123
124
125
    ),
    'system_modules_uninstall' => array(
      'arguments' => array('form' => NULL),
126
      'file' => 'system.admin.inc',
127
128
129
    ),
    'status_report' => array(
      'arguments' => array('requirements' => NULL),
130
      'file' => 'system.admin.inc',
131
132
133
    ),
    'admin_page' => array(
      'arguments' => array('blocks' => NULL),
134
      'file' => 'system.admin.inc',
135
136
137
    ),
    'admin_block' => array(
      'arguments' => array('block' => NULL),
138
      'file' => 'system.admin.inc',
139
140
141
    ),
    'admin_block_content' => array(
      'arguments' => array('content' => NULL),
142
      'file' => 'system.admin.inc',
143
144
145
    ),
    'system_admin_by_module' => array(
      'arguments' => array('menu_items' => NULL),
146
      'file' => 'system.admin.inc',
147
    ),
148
149
150
    'system_powered_by' => array(
      'arguments' => array('image_path' => NULL),
    ),
151
152
  ));
}
153

Dries's avatar
   
Dries committed
154
155
156
/**
 * Implementation of hook_perm().
 */
Dries's avatar
   
Dries committed
157
function system_perm() {
158
  return array('administer site configuration', 'access administration pages', 'administer actions', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
159
160
}

161
162
163
164
165
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
166
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
167
168

  // Inputs
169
170
  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
171
  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
172
173
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, '#process' => array('form_expand_ahah'));
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#process' => array('form_expand_ahah'));
174
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
175
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
176
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
177
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
178
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
179
180
181
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1, '#process' => array('form_expand_ahah'));
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE, '#process' => array('form_expand_ahah'));
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight', 'form_expand_ahah'));
182
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
183
  $type['file'] = array('#input' => TRUE, '#size' => 60);
184
185

  // Form structure
186
  $type['item'] = array('#value' => '');
187
  $type['hidden'] = array('#input' => TRUE, '#process' => array('form_expand_ahah'));
188
189
  $type['value'] = array('#input' => TRUE);
  $type['markup'] = array('#prefix' => '', '#suffix' => '');
190
  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL, '#process' => array('form_expand_ahah'));
Dries's avatar
Dries committed
191
  $type['token'] = array('#input' => TRUE);
192
193
194
  return $type;
}

Dries's avatar
   
Dries committed
195
/**
Dries's avatar
   
Dries committed
196
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
197
 */
198
199
function system_menu() {
  $items['system/files'] = array(
200
    'title' => 'File download',
201
202
203
204
205
    'page callback' => 'file_download',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin'] = array(
206
    'title' => 'Administer',
207
208
209
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_main_admin_page',
    'weight' => 9,
210
    'file' => 'system.admin.inc',
211
212
  );
  $items['admin/compact'] = array(
213
    'title' => 'Compact mode',
214
215
    'page callback' => 'system_admin_compact_page',
    'type' => MENU_CALLBACK,
216
    'file' => 'system.admin.inc',
217
218
  );
  $items['admin/by-task'] = array(
219
    'title' => 'By task',
220
    'page callback' => 'system_main_admin_page',
221
    'file' => 'system.admin.inc',
222
223
224
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/by-module'] = array(
225
    'title' => 'By module',
226
    'page callback' => 'system_admin_by_module',
227
    'file' => 'system.admin.inc',
228
229
230
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
231
232
233
234
235
236
237
238
239
240
  $items['admin/content'] = array(
    'title' => 'Content management',
    'description' => "Manage your site's content.",
    'position' => 'left',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('access administration pages'),
    'file' => 'system.admin.inc',
  );

241
242
  // menu items that are basically just menu blocks
  $items['admin/settings'] = array(
243
244
    'title' => 'Site configuration',
    'description' => 'Adjust basic site configuration options.',
245
246
247
248
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_settings_overview',
    'access arguments' => array('administer site configuration'),
249
    'file' => 'system.admin.inc',
250
251
  );
  $items['admin/build'] = array(
252
253
    'title' => 'Site building',
    'description' => 'Control how your site looks and feels.',
254
255
256
257
    'position' => 'right',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('administer site configuration'),
258
    'file' => 'system.admin.inc',
259
260
  );
  $items['admin/settings/admin'] = array(
261
262
    'title' => 'Administration theme',
    'description' => 'Settings for how your administrative pages should look.',
263
264
265
266
    'position' => 'left',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_admin_theme_settings'),
    'block callback' => 'system_admin_theme_settings',
267
    'file' => 'system.admin.inc',
268
269
270
  );
  // Themes:
  $items['admin/build/themes'] = array(
271
272
    'title' => 'Themes',
    'description' => 'Change which theme your site uses or allows users to set.',
273
    'page callback' => 'drupal_get_form',
274
    'page arguments' => array('system_themes_form', NULL),
275
    'file' => 'system.admin.inc',
276
277
  );
  $items['admin/build/themes/select'] = array(
278
279
    'title' => 'List',
    'description' => 'Select the default theme.',
280
281
282
283
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/build/themes/settings'] = array(
284
    'title' => 'Configure',
285
    'page arguments' => array('system_theme_settings'),
286
287
288
289
    'type' => MENU_LOCAL_TASK,
  );
  // Theme configuration subtabs
  $items['admin/build/themes/settings/global'] = array(
290
    'title' => 'Global settings',
291
292
293
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
Dries's avatar
   
Dries committed
294

295
  foreach (list_themes() as $theme) {
296
297
298
299
300
301
302
    $items['admin/build/themes/settings/'. $theme->name] = array(
      'title' => $theme->info['name'],
      'page arguments' => array('system_theme_settings', $theme->name),
      'type' => MENU_LOCAL_TASK,
      'access callback' => '_system_themes_access',
      'access arguments' => array($theme),
    );
Dries's avatar
   
Dries committed
303
  }
drumm's avatar
drumm committed
304

305
306
  // Modules:
  $items['admin/build/modules'] = array(
307
308
    'title' => 'Modules',
    'description' => 'Enable or disable add-on modules for your site.',
309
310
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_modules'),
311
    'file' => 'system.admin.inc',
312
313
  );
  $items['admin/build/modules/list'] = array(
314
    'title' => 'List',
315
316
317
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/build/modules/list/confirm'] = array(
318
    'title' => 'List',
319
320
321
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/modules/uninstall'] = array(
322
    'title' => 'Uninstall',
323
324
325
326
    'page arguments' => array('system_modules_uninstall'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/modules/uninstall/confirm'] = array(
327
    'title' => 'Uninstall',
328
329
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
330

331
  // Actions:
332
  $items['admin/settings/actions'] = array(
333
334
335
336
337
    'title' => 'Actions',
    'description' => 'Manage the actions defined for your site.',
    'access arguments' => array('administer actions'),
    'page callback' => 'system_actions_manage'
  );
338
  $items['admin/settings/actions/manage'] = array(
339
340
341
342
343
344
    'title' => 'Manage actions',
    'description' => 'Manage the actions defined for your site.',
    'page callback' => 'system_actions_manage',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -2,
  );
345
346
  $items['admin/settings/actions/configure'] = array(
    'title' => 'Configure an advanced action',
347
348
349
350
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_configure'),
    'type' => MENU_CALLBACK,
  );
351
  $items['admin/settings/actions/delete/%actions'] = array(
352
353
354
355
356
357
    'title' => 'Delete action',
    'description' => 'Delete an action.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_delete_form', 4),
    'type' => MENU_CALLBACK,
  );
358
  $items['admin/settings/actions/orphan'] = array(
359
360
361
362
363
    'title' => 'Remove orphans',
    'page callback' => 'system_actions_remove_orphans',
    'type' => MENU_CALLBACK,
  );

364
365
  // Settings:
  $items['admin/settings/site-information'] = array(
366
367
    'title' => 'Site information',
    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
368
369
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_information_settings'),
370
    'file' => 'system.admin.inc',
371
372
  );
  $items['admin/settings/error-reporting'] = array(
373
374
    'title' => 'Error reporting',
    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
375
376
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_error_reporting_settings'),
377
    'file' => 'system.admin.inc',
378
  );
379
  $items['admin/settings/logging'] = array(
380
381
    '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.",
382
    'page callback' => 'system_logging_overview',
383
    'file' => 'system.admin.inc',
384
  );
385
  $items['admin/settings/performance'] = array(
386
    'title' => 'Performance',
387
    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
388
389
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_performance_settings'),
390
    'file' => 'system.admin.inc',
391
392
  );
  $items['admin/settings/file-system'] = array(
393
394
    'title' => 'File system',
    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
395
396
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_file_system_settings'),
397
    'file' => 'system.admin.inc',
398
399
  );
  $items['admin/settings/image-toolkit'] = array(
400
401
    'title' => 'Image toolkit',
    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
402
403
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_image_toolkit_settings'),
404
    'file' => 'system.admin.inc',
405
406
  );
  $items['admin/content/rss-publishing'] = array(
407
408
    'title' => 'RSS publishing',
    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
409
410
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_rss_feeds_settings'),
411
    'access arguments' => array('administer site configuration'),
412
    'file' => 'system.admin.inc',
413
414
  );
  $items['admin/settings/date-time'] = array(
415
416
    'title' => 'Date and time',
    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
417
418
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_date_time_settings'),
419
    'file' => 'system.admin.inc',
420
  );
421
  $items['admin/settings/date-time/lookup'] = array(
422
    'title' => 'Date and time lookup',
423
424
    'type' => MENU_CALLBACK,
    'page callback' => 'system_date_time_lookup',
425
    'file' => 'system.admin.inc',
426
  );
427
  $items['admin/settings/site-maintenance'] = array(
428
429
    'title' => 'Site maintenance',
    'description' => 'Take the site off-line for maintenance or bring it back online.',
430
431
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_maintenance_settings'),
432
    'file' => 'system.admin.inc',
433
434
  );
  $items['admin/settings/clean-urls'] = array(
435
436
    'title' => 'Clean URLs',
    'description' => 'Enable or disable clean URLs for your site.',
437
438
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_clean_url_settings'),
439
    'file' => 'system.admin.inc',
440
  );
441
442
443
444
445
446
447
  $items['admin/settings/clean-urls/check'] = array(
    'title' => 'Clean URL check',
    'page callback' => 'drupal_json',
    'page arguments' => array(array('status' => TRUE)),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
448
449
450
451
452
453
454
455
456
  // Menu handler to test that drupal_http_request() works locally.
  // @see system_check_http_request().
  $items['admin/reports/request-test'] = array(
    'title' => 'Request test',
    'page callback' => 'printf',
    'page arguments' => array('request test'),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
457

458
459
460
461
  // Reports:
  $items['admin/reports'] = array(
    'title' => 'Reports',
    'description' => 'View reports from system logs and other status information.',
462
463
464
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 5,
    'position' => 'left',
465
    'file' => 'system.admin.inc',
466
  );
467
  $items['admin/reports/status'] = array(
468
469
    'title' => 'Status report',
    'description' => "Get a status report about your site's operation and any detected problems.",
470
471
472
    'page callback' => 'system_status',
    'weight' => 10,
    'access arguments' => array('administer site configuration'),
473
    'file' => 'system.admin.inc',
474
  );
475
  $items['admin/reports/status/run-cron'] = array(
476
    'title' => 'Run cron',
477
478
    'page callback' => 'system_run_cron',
    'type' => MENU_CALLBACK,
479
    'file' => 'system.admin.inc',
480
  );
481
  $items['admin/reports/status/php'] = array(
482
    'title' => 'PHP',
483
484
    'page callback' => 'system_php',
    'type' => MENU_CALLBACK,
485
    'file' => 'system.admin.inc',
486
  );
487
  $items['admin/reports/status/sql'] = array(
488
    'title' => 'SQL',
489
490
    'page callback' => 'system_sql',
    'type' => MENU_CALLBACK,
491
    'file' => 'system.admin.inc',
492
  );
493
494
495
496
497
  // Default page for batch operations
  $items['batch'] = array(
    'page callback' => 'system_batch_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
498
    'file' => 'system.admin.inc',
499
  );
Dries's avatar
   
Dries committed
500
  return $items;
Dries's avatar
   
Dries committed
501
502
}

503
504
505
506
507
508
509
/**
 * Menu item access callback - only admin or enabled themes can be accessed.
 */
function _system_themes_access($theme) {
  return $theme->status || $theme->name == variable_get('admin_theme', '0');
}

510
511
512
/**
 * Implementation of hook_init().
 */
513
514
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
515
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
516
517
518
519
520
521
522
523
    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');
524
  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
525
526
}

Dries's avatar
   
Dries committed
527
528
529
530
531
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
532
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
533
  if ($type == 'form' && $category == 'account') {
534
    $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
535

536
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
537
      $zones = _system_zonelist();
538
      $form['timezone'] = array(
539
        '#type' => 'fieldset',
540
541
542
543
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
544
      $form['timezone']['timezone'] = array(
545
546
547
548
549
        '#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.'),
550
      );
Dries's avatar
   
Dries committed
551
    }
Dries's avatar
Dries committed
552

553
    return $form;
Dries's avatar
   
Dries committed
554
  }
Dries's avatar
   
Dries committed
555
556
}

557
/**
558
559
 * Implementation of hook_block().
 *
560
561
562
 * Generate a block with a promotional link to Drupal.org.
 */
function system_block($op = 'list', $delta = 0, $edit = NULL) {
563
  switch ($op) {
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
    case 'list':
      $blocks[0] = array(
        'info' => t('Powered by Drupal'),
        'weight' => '10',
      );
      return $blocks;
    case 'configure':
      // Compile a list of fields to show
      $form['wrapper']['color'] = array(
        '#type' => 'select',
        '#title' => t('Badge color'),
        '#default_value' => variable_get('drupal_badge_color', 'powered-blue'),
        '#options' => array('powered-black' => t('Black'), 'powered-blue' => t('Blue'), 'powered-gray' => t('Gray')),
      );
      $form['wrapper']['size'] = array(
        '#type' => 'select',
        '#title' => t('Badge size'),
        '#default_value' => variable_get('drupal_badge_size', '80x15'),
        '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'), '135x42' => t('Large')),
      );
      return $form;
    case 'save':
      variable_set('drupal_badge_color', $edit['color']);
      variable_set('drupal_badge_size', $edit['size']);
      break;
    case 'view':
      $image_path = 'misc/'. variable_get('drupal_badge_color', 'powered-blue') .'-'. variable_get('drupal_badge_size', '80x15') .'.png';
      $block['subject'] = NULL; // Don't display a title
      $block['content'] = theme('system_powered_by', $image_path);
      return $block;
  }
}

597
598
/**
 * Provide a single block on the administration overview page.
599
600
601
 *
 * @param $item
 *   The menu item to be displayed.
602
 */
603
function system_admin_menu_block($item) {
604
  $content = array();
605
  if (!isset($item['mlid'])) {
606
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
607
  }
608
  $result = db_query("
609
    SELECT m.*, ml.*
610
611
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
612
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
613
  while ($item = db_fetch_array($result)) {
614
    _menu_link_translate($item);
615
    if (!$item['access']) {
616
      continue;
617
    }
618
619
620
621
622
623
624
625
    // The link 'description' either derived from the hook_menu 'description' or
    // entered by the user via menu module is saved as the title attribute.
    if (!empty($item['options']['attributes']['title'])) {
      $item['description'] = $item['options']['attributes']['title'];
    }
    // Prepare for sorting as in function _menu_tree_check_access().
    // The weight is offset so it is always positive, with a uniform 5-digits.
    $content[(50000 + $item['weight']) .' '. $item['title'] .' '. $item['mlid']] = $item;
626
  }
627
  ksort($content);
628
629
630
  return $content;
}

631
632
633
/**
 * Process admin theme form submissions.
 */
634
function system_admin_theme_submit($form, &$form_state) {
635
  // If we're changing themes, make sure the theme has its blocks initialized.
636
  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
637
638
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
    if (!$result) {
639
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
640
641
642
643
    }
  }
}

644
/**
645
646
647
648
649
650
651
652
653
654
655
 * 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
 */
656
function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
657
  if (user_access('select different theme')) {
658
    $enabled = array();
659
660
661
    $themes = list_themes();

    foreach ($themes as $theme) {
662
663
664
665
666
667
668
669
670
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

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

      $form['themes'] = array(
Dries's avatar
Dries committed
671
672
673
674
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
675
676
677
678
679
        '#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.
680
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
681

682
683
684
685
686
687
688
689
690
691
692
        $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');
693

694
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
695
        $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>' : ''));
696
697
698
699
700
701
702
703
704
705
        $options[$info->key] = '';
      }

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

706
707
/**
 * Checks the existence of the directory specified in $form_element. This
Dries's avatar
Dries committed
708
 * function is called from the system_settings form to check both the
709
710
711
712
713
714
715
 * file_directory_path and file_directory_temp directories. If validation
 * fails, the form element is flagged with an error from within the
 * file_check_directory function.
 *
 * @param $form_element
 *   The form element containing the name of the directory to check.
 */
716
function system_check_directory($form_element) {
717
718
719
720
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
  return $form_element;
}

Dries's avatar
   
Dries committed
721
722
/**
 * Retrieves the current status of an array of files in the system table.
723
724
725
726
727
 *
 * @param $files
 *   An array of files to check.
 * @param $type
 *   The type of the files.
Dries's avatar
   
Dries committed
728
729
 */
function system_get_files_database(&$files, $type) {
Dries's avatar
   
Dries committed
730
  // Extract current files from database.
731
  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
Dries's avatar
   
Dries committed
732
  while ($file = db_fetch_object($result)) {
733
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
734
      $file->old_filename = $file->filename;
Dries's avatar
   
Dries committed
735
      foreach ($file as $key => $value) {
736
        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
Dries's avatar
Dries committed
737
738
          $files[$file->name]->$key = $value;
        }
Dries's avatar
   
Dries committed
739
      }
740
    }
Dries's avatar
   
Dries committed
741
  }
Dries's avatar
   
Dries committed
742
}
Dries's avatar
   
Dries committed
743

744
745
746
747
748
749
/**
 * Prepare defaults for themes.
 *
 * @return
 *   An array of default themes settings.
 */
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
function system_theme_default() {
  return array(
    'regions' => array(
      'left' => 'Left sidebar',
      'right' => 'Right sidebar',
      'content' => 'Content',
      'header' => 'Header',
      'footer' => 'Footer',
    ),
    'description' => '',
    'features' => array(
      'comment_user_picture',
      'favicon',
      'mission',
      'logo',
      'name',
      'node_user_picture',
      'search',
768
769
770
      'slogan',
      'primary_links',
      'secondary_links',
771
    ),
772
773
774
775
    'stylesheets' => array(
      'all' => array('style.css')
    ),
    'scripts' => array('script.js'),
776
    'screenshot' => 'screenshot.png',
777
    'php' => DRUPAL_MINIMUM_PHP,
778
779
780
  );
}

Dries's avatar
   
Dries committed
781
/**
782
783
784
785
 * Collect data about all currently available themes.
 *
 * @return
 *   Array of all available themes and their data.
Dries's avatar
   
Dries committed
786
 */
Dries's avatar
Dries committed
787
function system_theme_data() {
788
789
  // Scan the installation theme .info files and their engines.
  $themes = _system_theme_data();
Dries's avatar
Dries committed
790

791
792
  // Extract current files from database.
  system_get_files_database($themes, 'theme');
Dries's avatar
   
Dries committed
793

794
  db_query("DELETE FROM {system} WHERE type = 'theme'");
Dries's avatar
Dries committed
795

796
797
798
799
  foreach ($themes as $theme) {
    if (!isset($theme->owner)) {
      $theme->owner = '';
    }
800

801
802
    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
  }
803

804
805
  return $themes;
}
806

807
808
/**
 * Helper function to scan and collect theme .info data and their engines.
809
810
811
 *
 * @return
 *   An associative array of themes information.
812
813
814
 */
function _system_theme_data() {
  static $themes_info = array();
815

816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  if (empty($theme_info)) {
    // Find themes
    $themes = drupal_system_listing('\.info$', 'themes');
    // Find theme engines
    $engines = drupal_system_listing('\.engine$', 'themes/engines');

    $defaults = system_theme_default();

    $sub_themes = array();
    // Read info files for each theme
    foreach ($themes as $key => $theme) {
      $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;

      // Invoke hook_system_info_alter() to give installed modules a chance to
      // modify the data in the .info files if necessary.
      drupal_alter('system_info', $themes[$key]->info, $themes[$key]);

      if (!empty($themes[$key]->info['base theme'])) {
        $sub_themes[] = $key;
Dries's avatar
   
Dries committed
835
      }
836
837
838
839
840
841
      if (empty($themes[$key]->info['engine'])) {
        $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme';
        if (file_exists($filename)) {
          $themes[$key]->owner = $filename;
          $themes[$key]->prefix = $key;
        }
842
      }
843
844
845
846
847
848
849
      else {
        $engine = $themes[$key]->info['engine'];
        if (isset($engines[$engine])) {
          $themes[$key]->owner = $engines[$engine]->filename;
          $themes[$key]->prefix = $engines[$engine]->name;
          $themes[$key]->template = TRUE;
        }
850
      }
Dries's avatar
Dries committed
851

852
853
854
855
856
857
858
859
      // Give the stylesheets proper path information.
      $pathed_stylesheets = array();
      foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
        foreach ($stylesheets as $stylesheet) {
          $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) .'/'. $stylesheet;
        }
      }
      $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
Dries's avatar
   
Dries committed
860

861
862
863
864
      // Give the scripts proper path information.
      $scripts = array();
      foreach ($themes[$key]->info['scripts'] as $script) {
        $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
865
      }
866
867
868
869
      $themes[$key]->info['scripts'] = $scripts;
      // Give the screenshot proper path information.
      if (!empty($themes[$key]->info['screenshot'])) {
        $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
Dries's avatar
   
Dries committed
870
871
      }
    }
Dries's avatar
Dries committed
872

873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
    // Now that we've established all our master themes, go back and fill in
    // data for subthemes.
    foreach ($sub_themes as $key) {
      $base_key = system_find_base_theme($themes, $key);
      if (!$base_key) {
        continue;
      }
      // Copy the 'owner' and 'engine' over if the top level theme uses a
      // theme engine.
      if (isset($themes[$base_key]->owner)) {
        if (isset($themes[$base_key]->info['engine'])) {
          $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
          $themes[$key]->owner = $themes[$base_key]->owner;
          $themes[$key]->prefix = $themes[$base_key]->prefix;
        }
        else {
          $themes[$key]->prefix = $key;
        }
      }
892
    }
893

894
    $themes_info = $themes;
Dries's avatar
Dries committed
895
896
  }

897
  return $themes_info;
Dries's avatar
Dries committed
898
899
}

900
901
/**
 * Recursive function to find the top level base theme. Themes can inherit
902
903
904
905
906
907
908
909
910
911
 * templates and function implementations from earlier themes.
 *
 * @param $themes
 *   An array of available themes.
 * @param $key
 *   The name of the theme whose base we are looking for.
 * @param $used_keys
 *   A recursion parameter preventing endless loops.
 * @return
 *   Returns the top level parent that has no ancestor or returns NULL if there isn't a valid parent.
912
913
914
915
916
917
918
919
920
921
922
 */
function system_find_base_theme($themes, $key, $used_keys = array()) {
  $base_key = $themes[$key]->info['base theme'];
  // Does the base theme exist?
  if (!isset($themes[$base_key])) {
    return NULL;
  }

  // Is the base theme itself a child of another theme?
  if (isset($themes[$base_key]->info['base theme'])) {
    // Prevent loops.
923
    if (!empty($used_keys[$base_key])) {
924
925
926
927
928
929
930
931
932
      return NULL;
    }
    $used_keys[$base_key] = TRUE;
    return system_find_base_theme($themes, $base_key, $used_keys);
  }
  // If we get here, then this is our parent theme.
  return $base_key;
}

933
934
935
/**
 * Get a list of available regions from a specified theme.
 *
936
 * @param $theme_key
937
938
939
940
 *   The name of a theme.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
941
function system_region_list($theme_key) {
942
943
  static $list = array();

944
  if (!array_key_exists($theme_key, $list)) {
945
946
    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
    $list[$theme_key] = array_map('t', $info['regions']);
947
948
  }

949
  return $list[$theme_key];
950
951
952
953
954
955
956
957
958
959
960
961
}

/**
 * Get the name of the default region for a given theme.
 *
 * @param $theme
 *   The name of a theme.
 * @return
 *   A string that is the region name.
 */
function system_default_region($theme) {
  $regions = array_keys(system_region_list($theme));