| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: sitedoc.module,v 1.46.2.2.2.11 2008/09/16 13:23:47 nancyw Exp $ 3 4 /** 5 * Implementation of hook_help(). 6 */ 7 function sitedoc_help($path, $args = array()) { 8 switch ($path) { 9 case 'admin/help#sitedoc': 10 $output = '<p>'. t('The sitedoc module allows a site admin to gather extensive information about their site. It may be printed or archived for configuration/change management purposes. It may also be used to add "fancy" and up-to-date information to other site documentation, such as a succession plan.') .'</p>'; 11 break; 12 13 case 'admin/settings/sitedoc/archive': 14 $output = '<p>'. t('The Site Documentation module may be run via Cron and the output HTML file archived to disk for future review. The options chosen on the main settings page will govern the data collected and reported.') .'</p>'; 15 break; 16 17 case 'admin/settings/sitedoc': 18 $output = '<p>'. t("The Site Documentation module's data collection and output is governed by these settings. Indented options are in effect only if the parent item is selected.") .'</p>'; 19 } 20 return $output; 21 } 22 23 /** 24 * Implementation of hook_perm(). 25 */ 26 function sitedoc_perm() { 27 return array('view site documentation'); 28 } 29 30 /** 31 * Implementation of hook_menu(). 32 */ 33 function sitedoc_menu() { 34 $items = array(); 35 36 $items['admin/build/sitedoc'] = array( 37 'title' => 'Site documentation', 38 'description' => 'Show site documentation', 39 'page callback' => 'sitedoc_list', 40 'access arguments' => array('view site documentation'), 41 ); 42 $items['admin/settings/sitedoc'] = array( 43 'title' => 'Site documentation', 44 'description' => 'Set how Site Documentation works', 45 'page callback' => 'sitedoc_settings_page', 46 'access arguments' => array('view site documentation'), 47 'file' => 'sitedoc.admin.inc', 48 ); 49 $items['admin/settings/sitedoc/report'] = array( 50 'title' => 'Report', 51 'description' => 'Report settings', 52 'page callback' => 'drupal_get_form', 53 'page arguments' => array('sitedoc_settings_form'), 54 'access arguments' => array('view site documentation'), 55 'type' => MENU_DEFAULT_LOCAL_TASK, 56 'file' => 'sitedoc.admin.inc', 57 ); 58 $items['admin/settings/sitedoc/archive'] = array( 59 'title' => 'Archive', 60 'access arguments' => array('view site documentation'), 61 'page callback' => 'drupal_get_form', 62 'page arguments' => array('sitedoc_archive_form'), 63 'description' => 'Set how Site Documentation archive works', 64 'weight' => 2, 65 'type' => MENU_LOCAL_TASK, 66 'file' => 'sitedoc.admin.inc', 67 ); 68 $items['admin/build/sitedoc_node_access_view'] = array( 69 'title' => 'Site documentation node access list', 70 'page callback' => 'sitedoc_node_access_view', 71 'page arguments' => array(arg(3)), 72 'access arguments' => array('view site documentation'), 73 'type' => MENU_CALLBACK, 74 ); 75 $items['sitedoc/vocabulary'] = array( 76 'title' => 'Site Documentation Term Count by Type', 77 'page callback' => 'sitedoc_term_count_by_type', 78 'access arguments' => array('access content'), 79 'type' => MENU_CALLBACK 80 ); 81 $items['sitedoc/phpinfo'] = array( 82 'title' => 'Site Documentation PHP Information', 83 'page callback' => 'sitedoc_phpinfo', 84 'access arguments' => array('view site documentation'), 85 'type' => MENU_CALLBACK 86 ); 87 $items['sitedoc/table'] = array( 88 'title' => 'Table Contents', 89 'page callback' => 'sitedoc_show_table', 90 'access arguments' => array('view site documentation'), 91 'type' => MENU_CALLBACK 92 ); 93 94 return $items; 95 } 96 /** 97 * Implementation of hook_init(). 98 */ 99 function sitedoc_init() { 100 drupal_add_css(drupal_get_path('module', 'sitedoc') .'/sitedoc.css'); 101 } 102 103 /** 104 * Implementation of hook_enable(). 105 * 106 * Set the default parameters. This is an easy way to reset the deaults - disable and re-enable. 107 * 108 * Parameters: None. 109 * 110 * Return: None. 111 */ 112 function sitedoc_enable() { 113 $sitedoc_settings = array( 114 'drupal_section' => TRUE, 115 'kill_cron' => 0, /* kill long-running cron */ 116 'table_section' => TRUE, 117 'show_indexes' => FALSE, /* use SHOW INDEX on the tables */ 118 'optimize_tables' => FALSE, /* use OPTIMIZE to release overhead */ 119 'node_section' => FALSE, /* not on because of expense */ 120 'include_comment_count' => FALSE, /* comment count on nodes */ 121 'include_node_access' => FALSE, /* node access summary */ 122 'node_show_size' => 99999, /* show nodes exceeding x KB */ 123 'node_max_size' => 50, /* warn if nodes exceeding x KB */ 124 'module_section' => TRUE, 125 'module_suppress' => FALSE, /* exclude disabled modules */ 126 'module_sort_order' => 0, /* package, project, module */ 127 'content_section' => TRUE, 128 'vocabulary_section' => TRUE, 129 'orphan_term_node' => FALSE, /* not on to allow control */ 130 'delete_orphan_term_nodes' => FALSE, /* do not delete orphans */ 131 'theme_section' => TRUE, 132 'variables_section' => FALSE, /* not on because of expense */ 133 'block_section' => TRUE, 134 'block_warn' => TRUE, /* warn on missing theme */ 135 'block_delete' => FALSE, /* delete those orphan blocks */ 136 'roles_section' => TRUE, 137 'role_users' => TRUE, /* list users in roles */ 138 'role_perms_list' => FALSE, /* do role permissions as stream */ 139 'contacts_section' => TRUE, 140 'profile_fields_section' => FALSE, /* not on because of interest */ 141 'url_alias_section' => FALSE, /* not on because of expense */ 142 'input_format_section' => FALSE, /* not on because probably not wanted */ 143 // Archive options 144 'archive_frequency' => 0, /* don't run */ 145 'archive_directory' => 'sitedoc', /* archive directory within file setting */ 146 ); 147 variable_set('sitedoc_settings', $sitedoc_settings); 148 } 149 150 /***********************/ 151 /** main function **/ 152 /***********************/ 153 function sitedoc_list() { 154 // Retrieve the settings and check if they have been settings page. 155 $sitedoc_settings = variable_get('sitedoc_settings', array()); 156 if ($sitedoc_settings == array()) { 157 return t('It appears that you have not been to "administer >> site configuration" to set the Site Documentation settings. ') . l(t('Click here to do so.'), 'admin/settings/sitedoc'); 158 } 159 160 // Insert a wrapper division and a link back to the settings page. 161 $output = '<div class="site-documentation">'. l(t('Change settings.'), 'admin/settings/sitedoc') .'<br/><br/>'; 162 163 // Get basic Drupal info. 164 if ($sitedoc_settings['drupal_section']) { 165 $output .= '<div class="sitedoc_drupal">'; 166 $fieldset = array( 167 '#title' => t('Drupal Section'), 168 '#collapsible' => TRUE, 169 '#collapsed' => FALSE, 170 '#value' => sitedoc_drupal($sitedoc_settings['kill_cron']), 171 ); 172 $output .= theme('fieldset', $fieldset); 173 $output .= "</div>\n"; 174 } 175 176 // Get database info. 177 if ($sitedoc_settings['table_section']) { 178 $output .= '<div class="sitedoc_database_overview">'; 179 $fieldset = array( 180 '#title' => t('Table Section'), 181 '#collapsible' => TRUE, 182 '#collapsed' => FALSE, 183 '#value' => sitedoc_database_overview($sitedoc_settings['optimize_tables'], $sitedoc_settings['show_indexes']), 184 ); 185 $output .= theme('fieldset', $fieldset); 186 $output .= "</div>\n"; 187 } 188 189 // Get summary of all nodes (this is VERY expensive!). 190 if ($sitedoc_settings['node_section']) { 191 $output .= '<div class="sitedoc_node_summary">'; 192 $fieldset = array( 193 '#title' => t('Node Summary'), 194 '#collapsible' => TRUE, 195 '#collapsed' => FALSE, 196 '#value' => sitedoc_node_summary($sitedoc_settings['include_comment_count'], $sitedoc_settings['node_show_size'], $sitedoc_settings['node_max_size']), 197 ); 198 $output .= theme('fieldset', $fieldset); 199 $output .= "</div>\n"; 200 201 // Get node access summary (this is expensive!). 202 // Runs only if the node summary section is selected. 203 if ($sitedoc_settings['include_node_access']) { 204 $output .= '<div class="sitedoc_node_access">'; 205 $fieldset = array( 206 '#title' => t('Node Access'), 207 '#collapsible' => TRUE, 208 '#collapsed' => FALSE, 209 '#value' => sitedoc_node_access(), 210 ); 211 $output .= theme('fieldset', $fieldset); 212 $output .= "</div>\n"; 213 } // end access summary 214 } // end node summary 215 216 // Get content type info from node module along with workflow options from system variables. 217 if ($sitedoc_settings['content_section']) { 218 $output .= '<div class="sitedoc_content_types">'; 219 $fieldset = array( 220 '#title' => t('Content Types'), 221 '#collapsible' => TRUE, 222 '#collapsed' => FALSE, 223 '#value' => sitedoc_content_types(), 224 ); 225 $output .= theme('fieldset', $fieldset); 226 $output .= "</div>\n"; 227 } 228 229 // Get modules from the System module functions. 230 if ($sitedoc_settings['module_section']) { 231 $output .= '<div class="sitedoc_modules">'; 232 $fieldset = array( 233 '#title' => t('Modules'), 234 '#collapsible' => TRUE, 235 '#collapsed' => FALSE, 236 '#value' => sitedoc_get_modules($sitedoc_settings['module_suppress'], $sitedoc_settings['module_sort_order']), 237 ); 238 $output .= theme('fieldset', $fieldset); 239 $output .= "</div>\n"; 240 } 241 242 // Get themes from the System table. 243 if ($sitedoc_settings['theme_section']) { /* controls themes */ 244 $output .= '<div class="sitedoc_themes">'; 245 $fieldset = array( 246 '#title' => t('Themes'), 247 '#collapsible' => TRUE, 248 '#collapsed' => FALSE, 249 '#value' => sitedoc_get_system('theme'), 250 ); 251 $output .= theme('fieldset', $fieldset); 252 $output .= "</div>\n"; 253 } 254 255 // Get vocabularies and their definitions. 256 if ($sitedoc_settings['vocabulary_section']) { 257 $output .= '<div class="sitedoc_vocabularies">'; 258 $fieldset = array( 259 '#title' => t('Vocabularies'), 260 '#collapsible' => TRUE, 261 '#collapsed' => FALSE, 262 '#value' => sitedoc_get_vocabularies(), 263 ); 264 $output .= theme('fieldset', $fieldset); 265 266 // do we want to check for orphans in the Term_node table? 267 if ($sitedoc_settings['orphan_term_node']) { 268 $orphans = sitedoc_check_orphan_term_node($sitedoc_settings['delete_orphan_term_nodes']); 269 $fieldset = array( 270 '#title' => t('Orphan Term_nodes'), 271 '#collapsible' => TRUE, 272 '#collapsed' => ($orphans == '<p>'. t('No orphan term_nodes found.') .'</p>'), 273 '#value' => $orphans, 274 ); 275 $output .= theme('fieldset', $fieldset); 276 } 277 $output .= "</div>\n"; 278 } 279 280 // Get system variable info from cache. 281 if ($sitedoc_settings['variables_section']) { 282 $output .= '<div class="sitedoc_variables">'; 283 $fieldset = array( 284 '#title' => t('Variables'), 285 '#collapsible' => TRUE, 286 '#collapsed' => FALSE, 287 '#value' => sitedoc_get_variables(), 288 ); 289 $output .= theme('fieldset', $fieldset); 290 $output .= "</div>\n"; 291 } 292 293 // Get blocks info from Blocks table. 294 if ($sitedoc_settings['block_section']) { /* controls block and boxes */ 295 $output .= '<div class="sitedoc_blocks">'; 296 // use the setting to decide on a warning for missing themes 297 $fieldset = array( 298 '#title' => t('Blocks'), 299 '#collapsible' => TRUE, 300 '#collapsed' => FALSE, 301 '#value' => sitedoc_get_blocks($sitedoc_settings['block_warn'], $sitedoc_settings['block_delete']), 302 ); 303 $output .= theme('fieldset', $fieldset); 304 $output .= "</div>\n"; 305 306 // Get boxes (custom blocks) info from Boxes table. 307 // Runs only if the blocks section is selected. 308 $output .= '<div class="sitedoc_boxes">'; 309 $boxes = sitedoc_get_boxes($sitedoc_settings['block_warn'], $sitedoc_settings['block_delete']); 310 $fieldset = array( 311 '#title' => t('Custom Blocks (Boxes)'), 312 '#collapsible' => TRUE, 313 '#collapsed' => FALSE, 314 '#value' => $boxes ? $boxes : ('<p>'. t('No boxes found.') .'</p>'), 315 ); 316 $output .= theme('fieldset', $fieldset); 317 $output .= "</div>\n"; 318 } 319 320 // Get roles info from Roles table (how can we get a description of the roles?). 321 if ($sitedoc_settings['roles_section']) { 322 $output .= '<div class="sitedoc_roles">'; 323 $rpt .= sitedoc_get_roles($sitedoc_settings['role_perms_list'], $sitedoc_settings['role_users']); 324 $fieldset = array( 325 '#title' => t('Roles'), 326 '#collapsible' => TRUE, 327 '#collapsed' => FALSE, 328 '#value' => $rpt ? $rpt : (t('No roles found.') .' '. _sitedoc_img_error()), 329 ); 330 $output .= theme('fieldset', $fieldset); 331 $output .= "</div>\n"; 332 } 333 334 // Get contacts info from Contacts table. 335 if ($sitedoc_settings['contacts_section']) { 336 $output .= '<div class="sitedoc_contacts">'; 337 $rpt = sitedoc_get_contacts(); 338 $fieldset = array( 339 '#title' => t('Contacts'), 340 '#collapsible' => TRUE, 341 '#collapsed' => FALSE, 342 '#value' => $rpt ? $rpt : t('No contacts found.'), 343 ); 344 $output .= theme('fieldset', $fieldset); 345 $output .= "</div>\n"; 346 } 347 348 // Get info from Profile_fields table. 349 if ($sitedoc_settings['profile_fields_section']) { 350 $output .= '<div class="sitedoc_profile_fields">'; 351 $rpt = sitedoc_profile_fields(); 352 $fieldset = array( 353 '#title' => t('Profile Fields'), 354 '#collapsible' => TRUE, 355 '#collapsed' => FALSE, 356 '#value' => $rpt ? $rpt : ('<p>'. t('No profile fields found.') .'</p>'), 357 ); 358 $output .= theme('fieldset', $fieldset); 359 $output .= "</div>\n"; 360 } 361 362 // Get info from URL Alias table and cross-check it. 363 if ($sitedoc_settings['url_alias_section']) { 364 $output .= '<div class="sitedoc_url_alias">'; 365 $rpt = sitedoc_url_alias(); 366 $fieldset = array( 367 '#title' => t('URL Aliases'), 368 '#collapsible' => TRUE, 369 '#collapsed' => FALSE, 370 '#value' => $rpt ? $rpt : t('No aliases found.'), 371 ); 372 $output .= theme('fieldset', $fieldset); 373 $output .= "</div>\n"; 374 } 375 376 // Get info from Filter and Filter_format tables. 377 if ($sitedoc_settings['input_format_section']) { 378 $output .= '<div class="sitedoc_input_format">'; 379 $fieldset = array( 380 '#title' => t('Input Formats and Filters'), 381 '#collapsible' => TRUE, 382 '#collapsed' => FALSE, 383 '#value' => sitedoc_filters(), 384 ); 385 $output .= theme('fieldset', $fieldset); 386 $output .= "</div>\n"; 387 } 388 389 $output .= "</div>\n"; 390 return $output; 391 392 } 393 /** 394 * Implementation of hook_cron 395 * 396 * Runs the report and saves it to disk. 397 */ 398 function sitedoc_cron() { 399 // Get the module settings and verify they've been set. 400 $sitedoc_settings = variable_get('sitedoc_settings', array()); 401 if ($sitedoc_settings == array()) { 402 watchdog('Site Doc', 'It appears that you have not been to "administer >> site configuration" to set the Site Documentation settings.', null, WATCHDOG_ERROR); 403 } 404 405 // If set up for manual run, then just quit now. 406 $frequency = $sitedoc_settings['archive_frequency']; 407 if ($frequency == 0) { 408 return; 409 } 410 411 // If set up for debugging, then -1 will let us run every time. 412 if ($frequency == '999999') { 413 $frequency = -1; 414 } 415 416 // Determine if it's time to make another run. 417 $how_long = time() - $sitedoc_settings['archive_last_run']; 418 419 if ($how_long > $frequency) { /* longer than how long between saves? */ 420 // Get the file path and append a file name. 421 $filename = file_directory_path() .'/' 422 . $sitedoc_settings['archive_directory'] .'/sitedoc_'. date('Ymd_Hi') .'.html'; 423 $path = $filename; 424 // make sure we can write to it 425 $writable = fopen($path, 'w'); 426 if ($writable == FALSE) { 427 watchdog('Site Doc', 'Cannot write "!file" to archive directory.', array('!file' => $filename), WATCHDOG_ERROR); 428 return; 429 } 430 431 // Call the main list, format the output as a full page (without blocks), 432 // change all the relative paths to full paths, fix the page title. 433 $output = theme('page', sitedoc_list(), FALSE); 434 global $base_url; 435 $output = str_replace('@import "/', '@import "'. $base_url .'/', $output); 436 $output = str_replace('src="/', 'src="'. $base_url .'/', $output); 437 $output = str_replace('<title>Run cron', '<title>Site Documentation', $output); 438 439 // Save the file and write a message indicating whether it worked. 440 $saved_as = fwrite($writable, $output); 441 if ($saved_as === 0) { 442 watchdog('Site Doc', 'Documentation file save failed.', null, WATCHDOG_ERROR); 443 } 444 else { 445 watchdog('Site Doc', 'Documentation file saved as !name', array('!name' => $filename), WATCHDOG_NOTICE); 446 } 447 fclose($writable); 448 449 // update last run time 450 $sitedoc_settings['archive_last_run'] = time(); 451 variable_set('sitedoc_settings', $sitedoc_settings); 452 453 } /* end if how long */ 454 } 455 456 /** 457 * Helper functions to generate proper img tags. 458 */ 459 function _sitedoc_img_ok() { 460 return theme_image('misc/watchdog-ok.png', 'ok', 'ok'); 461 } 462 function _sitedoc_img_warning() { 463 return theme_image('misc/watchdog-warning.png', 'warning', 'warning'); 464 } 465 466 function _sitedoc_img_error() { 467 return theme_image('misc/watchdog-error.png', 'error', 'error'); 468 } 469 470 /****************************/ 471 /** Callable functions **/ 472 /****************************/ 473 474 /** 475 * Produce the basic system overview. 476 * 477 * Parameters: 478 * TRUE/FALSE - whether to fix Cron stall problem if detected. 479 * 480 * Return: HTML string. 481 */ 482 function sitedoc_drupal($kill_cron=0) { 483 global $base_url; 484 $dest = drupal_get_destination(); 485 $_abled = array(t('Disabled'), t('Enabled')); 486 $_bool = array(t('False'), t('True')); 487 $_noyes = array(t('No'), t('Yes')); 488 489 $header = array(t('Item'), t('Value'), t('Operation')); 490 $setting = t('Settings'); 491 $rows = array(); 492 493 $rows[] = array(t('Site Name'), variable_get('site_name', 'none'), l($setting, 'admin/settings/site-information', array('query' => $dest))); 494 $rows[] = array(t('Version'), VERSION, NULL); 495 $rows[] = array(t('Configuration file'), conf_path() .'/settings.php', NULL); 496 $rows[] = array(t('Install profile'), variable_get('install_profile', 'default'), NULL); 497 $rows[] = array(t('Base URL'), $base_url, NULL); 498 499 $cache = variable_get('cache', 0); 500 $cache_type = array(t('Disabled'), t('Normal'), t('Agressive')); 501 $rows[] = array(t('Cache'), $cache_type[$cache], l($setting, 'admin/settings/performance', array('query' => $dest))); 502 $rows[] = array(t('Minimum cache lifetime'), format_interval(variable_get('cache_lifetime', 0), 1), l($setting, 'admin/settings/performance', array('query' => $dest))); 503 $rows[] = array(t('CSS preprocess'), variable_get('preprocess_css', FALSE) ? t('Enabled') : t('Disabled'), l($setting, 'admin/settings/performance', array('query' => $dest))); 504 505 $clean_urls = variable_get('clean_url', FALSE); 506 $rows[] = array(t('Clean URLS'), $_abled[$clean_urls], l($setting, 'admin/settings/clean-urls', array('query' => $dest))); 507 508 $cron_last = variable_get('cron_last', NULL); 509 $cron_when = isset($cron_last) ? t('Last run !time ago', array('!time' => format_interval(time() - $cron_last))) : t('Not run yet'); 510 // If it last ran more than an hour ago, add "Run now" link. 511 if (time() - $cron_last > 3600) { 512 $cron_op .= l(t('Run now'), 'admin/reportsstatus/run-cron', array('query' => $dest)); 513 } 514 else { 515 $cron_op = NULL; 516 } 517 $cron_semaphore = variable_get('cron_semaphore', NULL); /* is it running now? */ 518 if (isset($cron_semaphore)) { 519 $how_long = time() - $cron_semaphore; /* how long it's been running (secs) */ 520 $cron_when .= ' - '. t('Running for !time', array('!time' => format_interval($how_long))) 521 ._sitedoc_img_warning(); 522 if ($kill_cron) { 523 if ($kill_cron <= $how_long) { 524 variable_del('cron_semaphore'); /* turn off "cron started" flag */ 525 variable_del('cron_last'); /** I don't think this is actually needed **/ 526 } /* end if how long */ 527 } /* end if kill_cron */ 528 } /* end if semaphore */ 529 $rows[] = array(t('Cron'), $cron_when, $cron_op); 530 531 if (module_exists('search')) { 532 $rows[] = array(t('Search Cron limit'), variable_get("search_cron_limit", null), l($setting, 'admin/settings/search', array('query' => $dest))); 533 $remaining = 0; 534 $total = 0; 535 foreach (module_list() as $module) { 536 if (module_hook($module, 'search')) { 537 $status = module_invoke($module, 'search', 'status'); 538 $remaining += $status['remaining']; 539 $total += $status['total']; 540 } 541 } 542 $count = format_plural($remaining, 'There is 1 item left to index.', 'There are @count items left to index.'); 543 $percentage = ((int)min(100, 100 * ($total - $remaining) / max(1, $total))) .'%'; 544 $status = t('%percentage of the site has been indexed.', array('%percentage' => $percentage)) .' '. $count; 545 $link = l($setting, 'admin/settings/search', array('query' => $dest)); 546 if ($remaining) { 547 $link .= ', '. l(t('Run Cron'), 'admin/reports/status/run-cron', array('query' => $dest)); 548 } 549 $rows[] = array(t('Search status'), $status, $link); 550 } 551 552 $rows[] = array(t('Anonymous'), variable_get('anonymous', 'anonymous'), l($setting, 'admin/settings/site-information', array('query' => $dest))); 553 $rows[] = array(t('File directory'), file_directory_path(), l($setting, 'admin/settings/file-system', array('query' => $dest))); 554 555 if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) { 556 $downloads = t('Public'); 557 $download_op = NULL; 558 } 559 else { 560 $downloads = t('Private') ._sitedoc_img_warning(); 561 $download_op = l($setting, 'admin/settings/file-system', array('query' => $dest)); 562 } 563 564 $rows[] = array(t('Download method'), $downloads, $download_op); 565 566 // Is the menu choice restricted? 567 $menu_restrict = variable_get('menu_parent_items', NULL); 568 // "Show all menus" is Zero. Unless the setting has been changed it won't be present (NULL) 569 if ($menu_restrict) { 570 $menu_msg = t('Restricted') .' ('. $menu_restrict .') '. _sitedoc_img_warning(); 571 } 572 else { 573 $menu_msg = t('Show all menus') ._sitedoc_img_ok(); 574 } 575 $rows[] = array(t('Content menu links'), $menu_msg, l($setting, 'admin/build/menu/settings', array('query' => $dest))); 576 577 $rows[] = array(t('Default theme'), variable_get('theme_default', 'standard'), l($setting, 'admin/build/themes', array('query' => $dest))); 578 579 $teaser_len = variable_get('teaser_length', 300); 580 $rows[] = array(t('Teaser length'), $teaser_len ? $teaser_len : t('unlimited'), l($setting, 'admin/content/node-settings', array('query' => $dest))); 581 582 // Get default filter and then look up its name. 583 // Using 0 here to identify that it hasn't been set. 584 $filter = $filter_default = variable_get('filter_default_format', 0); 585 if ($filter_default == 0) { 586 $filter = 1; 587 } 588 $filter_name = db_fetch_object(db_query_range("SELECT f.name FROM {filter_formats} f WHERE f.format='%d'", $filter, 0, 1)); 589 if ($filter_default == 1) { 590 $filter_warn = NULL; 591 $filter_op = NULL; 592 } 593 else { 594 $filter_warn = ' <em>('. t('not set') .')</em>'. _sitedoc_img_warning() .' '; 595 $filter_op = l($setting, 'admin/settings/filters', array('query' => $dest)); 596 } 597 $rows[] = array(t('Default filter format'), $filter_name->name . $filter_warn, $filter_op); 598 599 $rows[] = array(t('Operating system'), php_uname('s'), NULL); 600 601 $fieldset = array( 602 '#title' => t('Drupal'), 603 '#collapsible' => TRUE, 604 '#collapsed' => FALSE, 605 '#value' => theme('table', $header, $rows) ."\n", 606 ); 607 $output .= theme('fieldset', $fieldset); 608 609 // Webserver information. 610 $rows = array(); 611 612 $rows[] = array(t('Web server'), $_SERVER['SERVER_SOFTWARE'], NULL); 613 if (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== FALSE) { /* is it Apache? */ 614 $rows[] = array(t('Server name'), $_SERVER['SERVER_NAME'], NULL); 615 if (function_exists('apache_get_modules')) { /* can we get a list of modules ? */ 616 $rows[] = array(t('Apache modules'), implode(', ', apache_get_modules()), NULL); 617 } /* end if function */ 618 } /* end if apache */ 619 620 $fieldset = array( 621 '#title' => t('Webserver Information'), 622 '#collapsible' => TRUE, 623 '#collapsed' => TRUE, 624 '#value' => theme('table', $header, $rows) ."\n", 625 ); 626 $output .= theme('fieldset', $fieldset); 627 628 // Php info. 629 $rows = array(); 630 $error_names = array( 631 'E_ERROR' => 1, 632 'E_WARNING' => 2, 633 'E_PARSE' => 4, 634 'E_NOTICE' => 8, 635 'E_CORE_ERROR' => 16, 636 'E_CORE_WARNING' => 32, 637 'E_COMPILE_ERROR' => 64, 638 'E_COMPILE_WARNING' => 128, 639 'E_USER_ERROR' => 256, 640 'E_USER_WARNING' => 512, 641 'E_USER_NOTICE' => 1024, 642 'E_STRICT' => 2048, 643 'E_RECOVERABLE_ERROR' => 4096, 644 ); 645 646 list($php_vers, $php_rel, $php_fix) = explode('.', phpversion()); 647 648 $rows[] = array(t('Php version'), phpversion(), l(t('View phpinfo'), 'sitedoc/phpinfo')); 649 if ($php_vers < 6) { 650 $safe_mode = ini_get('safe_mode'); 651 if (is_bool($safe_mode)) { 652 $safe_mode = $_abled[$safe_mode]; 653 } 654 if (empty($safe_mode)) { 655 $safe_mode = $_abled[0]; 656 } 657 $rows[] = array(t('Safe mode'), $safe_mode, NULL); 658 } 659 660 $disperr = ini_get('display_errors'); 661 if (is_bool($disperr)) { 662 $disperr = $_noyes[$disperr]; 663 } 664 if (empty($disperr)) { 665 $disperr = $_noyes[0]; 666 } 667 $rows[] = array(t('Display errors'), $disperr, NULL); 668 669 $mem_limit = ini_get('memory_limit'); 670 $rows[] = array(t('Memory limit'), $mem_limit ? $mem_limit : t('default') .' '. _sitedoc_img_warning(), NULL); 671 672 // Changing the error level returns the previous level, so we'll turn errors off then set it back as it was. 673 $current = ini_get('error_reporting'); 674 675 $levels = array(); 676 if ($current == E_ALL) { 677 $levels[] = 'E_ALL'; 678 } 679 else { 680 foreach ($error_names as $name => $bit) { 681 if ($current && $bit) { 682 $levels[] = $name; 683 } 684 } 685 } 686 $rows[] = array(t('Error reporting'), implode(' + ', $levels), NULL); 687 688 $rows[] = array(t('Upload max filesize'), ini_get('upload_max_filesize'), NULL); 689 $rows[] = array(t('Magic quotes GPC'), $_abled[ini_get('magic_quotes_gpc')], NULL); 690 $rows[] = array(t('Magic quotes runtime'), $_abled[ini_get('magic_quotes_runtime')], NULL); 691 $rows[] = array(t('Precision'), ini_get('precision'), NULL); 692 $rows[] = array(t('Register globals'), $_abled[ini_get('register_globals')], NULL); 693 $rows[] = array(t('Session cache limiter'), ini_get('session.cache_limiter'), NULL); 694 $cookie_params = session_get_cookie_params(); 695 $rows[] = array(t('Session cookie domain'), !empty($cookie_params['domain']) ? $cookie_params['domain'] : t('- none -'), NULL); 696 $rows[] = array(t('Session name'), session_name(), NULL); 697 $rows[] = array(t('Session save handler'), ini_get('session.save_handler'), NULL); 698 699 /* php extensions */ 700 if (extension_loaded('gd')) { 701 $gd = gd_info(); 702 $rows[] = array( 703 t('GD version'), 704 $gd['GD Version'] .'<br />' 705 . t('FreeType support') .' ('. $_abled[$gd['FreeType Support']] .'), ' 706 . t('Jpg support') .' ('. $_abled[$gd['JPG Support']] .'), ' 707 . t('Png support') .' ('. $_abled[$gd['PNG Support']] .')', 708 NULL, 709 ); 710 } 711 else { 712 $rows[] = array(t('GD support'), t('Disabled')); 713 } 714 715 if (extension_loaded('curl')) { 716 $curl = curl_version(); 717 $rows[] = array(t('CURL version'), $curl['version'], NULL); 718 } 719 else { 720 $rows[] = array(t('CURL support'), t('Disabled'), NULL); 721 } 722 723 $rows[] = array(t('Multibyte support'), $_abled[extension_loaded('mbstring')], NULL); 724 $overload = ini_get('mbstring.func_overload'); 725 $oload = array(); 726 if ($overload & 1) { 727 $oload[] = t('mail'); 728 } 729 if ($overload & 2) { 730 $oload[] = t('string'); 731 } 732 if ($overload & 4) { 733 $oload[] = t('regex'); 734 } 735 $rows[] = array('Mbstring.func_overload', (empty($oload) ? t('disabled') : implode(', ', $oload)), NULL); 736 $rows[] = array(t('XML support'), $_abled[extension_loaded('xml')], NULL); 737 $rows[] = array(t('Zip support'), $_abled[extension_loaded('zip')], NULL); 738 $rows[] = array(t('Zlib support'), $_abled[extension_loaded('zlib')], NULL); 739 740 $fieldset = array( 741 '#title' => t('PHP Information'), 742 '#collapsible' => TRUE, 743 '#collapsed' => TRUE, 744 '#value' => theme('table', $header, $rows) ."\n", 745 ); 746 $output .= theme('fieldset', $fieldset); 747 748 return $output; 749 } 750 751 /** 752 * Menu callback to produce PHPINFO page. 753 */ 754 function sitedoc_phpinfo() { 755 phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_ENVIRONMENT); 756 return; 757 } 758 759 /** 760 * Produce the database tables overview and give overall size info 761 * 762 * Parameters: 763 * none 764 * 765 * Return: HTML string 766 */ 767 function sitedoc_database_overview($optimize_tables=FALSE, $show_index=FALSE) { 768 global $base_url, $db_prefix, $db_url; 769 770 // $db_url may be an array if using multiple databases. 771 if (is_array($db_url)) { 772 foreach ($db_url as $key => $value) { 773 $dbname = ucfirst($key); 774 // Switch databases 775 db_set_active($key); 776 $fieldset = array( 777 '#title' => $dbname, 778 '#collapsible' => TRUE, 779 '#collapsed' => TRUE, 780 '#value' => _sitedoc_database($dbname, $value, $optimize_tables, $show_index), 781 ); 782 $output .= theme('fieldset', $fieldset); 783 } 784 // Return to default database 785 db_set_active('default'); 786 } 787 else { 788 $fieldset = array( 789 '#title' => t('Database Information'), 790 '#collapsible' => TRUE, 791 '#collapsed' => FALSE, 792 '#value' => _sitedoc_database('database', $db_url, $optimize_tables, $show_index), 793 ); 794 $output .= theme('fieldset', $fieldset); 795 } 796 return $output; 797 } 798 799 // Format the database information. 800 // This was split out when I was informed that the $db_url variable could be an array. 801 function _sitedoc_database($actdb, $db_url, $optimize_tables=FALSE, $show_index=FALSE) { 802 global $base_url, $db_prefix; 803 $rows = array(); 804 $header = array(); 805 806 $db_types = array('mysql' => 'MySQL', 807 'mysqli' => 'MySQLi', 808 'postgres' => 'Postgres', 809 ); 810 811 $output .= '<table cellpadding="5"><tr>'."\n"; 812 813 $output .= '<td valign="top">'."\n"; 814 $output .= '<h5>'. t('Overview') ."</h5>\n"; 815 $database_type = $db_types[$GLOBALS['db_type']]; 816 $database_version = db_version(); 817 $rows[] = array(t('Database type'), isset($database_type) ? $database_type : t('Unknown')); 818 $vers = isset($database_version) ? $database_version : t('Unknown'); 819 $rows[] = array(t('Version'), l($vers, 'admin/reportsstatus/sql')); 820 821 $db = parse_url($db_url); 822 // Don't show password 823 $db['pass'] = str_repeat('•', strlen($db['pass'])); 824 $dbrows = array(); 825 foreach ($db as $key => $value) { 826 $dbrows[] = array($key, $value); 827 } 828 $rows[] = array(t('Database URL'), theme('table', NULL, $dbrows)); 829 830 $rows[] = array(t('Base URL'), $base_url); 831 $rows[] = array(t('Database prefix'), empty($db_prefix) ? '- none -' : $db_prefix); 832 $grants = db_result(db_query('SHOW GRANTS')); 833 $privileges = trim(str_replace('GRANT', ' ', substr($grants, 0, strpos($grants, ' ON')))); 834 $rows[] = array(t('Privileges'), $privileges); 835 836 $output .= theme('table', $header, $rows) ."\n"; 837 $output .= "</td>\n"; 838 839 // Check if we have a version of MySql that supports the variable and status checks 840 // TODO: Can Postgres do something similar? 841 if (('MySQL' == $database_type && version_compare($database_version, '4.1.0', '>=')) || 'MySQLi' == $database_type) { 842 843 // The next two things are done as lists to 844 // a) simplify building the query, 845 // b) create the possibility of future settings page selection. 846 847 // Get selected variables from the database. 848 $variables_list = array( 849 'character_set_database', 850 'character_set_results', 851 'collation_connection', 852 'collation_database', 853 'collation_server', 854 'have_dynamic_loading', 855 'have_innodb', 856 'have_isam', 857 'have_query_cache', 858 'have_raid', 859 'max_connections', 860 'query_cache_size', 861 'query_cache_type', 862 ); 863 $output .= _sitedoc_dbvars_list('VARIABLES', t('Selected Variables'), $variables_list, $database_version); 864 865 // Get selected status information from the database. 866 $variables_list = array( 867 'Qcache_free_memory', 868 'Qcache_hits', 869 'Qcache_not_cached', 870 'Qcache_queries_in_cache', 871 'Max_used_connections', 872 'Threads_running', 873 'Threads_cached', 874 'Threads_connected', 875 'Threads_created', 876 ); 877 $output .= _sitedoc_dbvars_list('STATUS', t('Selected Status'), $variables_list, $database_version); 878 879 $output .= "</tr></table>\n"; 880 } /* end MySql check */ 881 882 // $output .= '<h5>'. t('Table Status') ."</h5>\n"; 883 884 // Do the table status section. 885 $result = db_query("SHOW TABLE STATUS"); 886 887 // I used a class to align fields rather than 'align' because the some themes override 'align' in headers. 888 $statrpt = "\n<table><thead><tr>"; 889 $statrpt .= '<th>'. t('Table') .'</th>' 890 .'<th>'. t('Engine') .'</th>' 891 .'<th>'. t('Version') .'</th>' 892 .'<th>'. t('Row Format') .'</th>' 893 .'<th class="sitedoc_right">'. t('Rows') .'</th>' 894 .'<th class="sitedoc_right">'. t('Data Length') .'</th>' 895 .'<th class="sitedoc_right">'. t('Index Length') .'</th>' 896 .'<th class="sitedoc_right">'. t('Overhead') .'</th>' 897 .'<th class="sitedoc_right">'. t('Operation') .'</th>' 898 .'</tr></thead><tbody>'; 899 $datalen = 0; 900 $indexlen = 0; 901 $overhead = 0; 902 $row_count = 0; 903 $rows = 0; 904 $row_classes = array('even', 'odd'); 905 while ($table = db_fetch_array($result)) { 906 ++$rows; 907 $row_class = $row_classes[$rows & 1]; 908 $row_count += $table['Rows']; 909 $datalen += $table['Data_length']; 910 $indexlen += $table['Index_length']; 911 $overhead += $table['Data_free']; 912 $r = number_format($table['Rows']); 913 $d = number_format($table['Data_length']); 914 $i = number_format($table['Index_length']); 915 // Is there some overhead? 916 if ($table['Data_free']) { 917 $o = number_format($table['Data_free']); 918 // Do we want to release it? 919 if ($optimize_tables) { 920 $worked = db_query('OPTIMIZE TABLE {%s}', $table['Name']); 921 if ($worked) { 922 $o .= '<br />'. t('released'); 923 } 924 } 925 } 926 else { $o = NULL; } 927 $statrpt .= "\n".'<tr class="'. $row_class .'">' 928 .'<td>'. $table['Name'] .'</td>' 929 .'<td>'. $table['Engine'] .'</td>' 930 .'<td align="center">'. $table['Version'] .'</td>' 931 .'<td>'. $table['Row_format'] .'</td>' 932 .'<td class="sitedoc_right">'. $r .'</td>' 933 .'<td class="sitedoc_right">'. $d .'</td>' 934 .'<td class="sitedoc_right">'. $i .'</td>' 935 .'<td class="sitedoc_right">'. ($table['Data_free'] ? $o : '') .'</td>' 936 .'<td>'. l(t('Show contents'), 'sitedoc/table/'. $table['Name'], array('title' => t("Display the contents of the '@table' table.", array('@table' => $table['Name'])))) .'</td>' 937 . (empty($table['Comment']) ? NULL : '</tr><tr class="'. $row_class .'"><td></td><td colspan="10"><img src="/misc/menu-collapsed.png" width="7" height="7"> <em>'. $table['Comment'] .'</em></td>'); 938 if ($show_index) { 939 $statrpt .= '</tr><tr class="'. $row_class .'"><td></td><td valign="top" align="right"><em>'. t('Indexes') .':</em></td><td colspan="10">'. _sitedoc_show_index($table['Name']) .'</td>'; 940 } 941 $statrpt .= '</tr>'; 942 } /* end while */ 943 $statrpt .= '<tr><td colspan="4"> </td>' 944 .'<td class="sitedoc_right">----------</td>' 945 .'<td class="sitedoc_right">----------</td>' 946 .'<td class="sitedoc_right">----------</td>' 947 .'<td class="sitedoc_right">----------</td>' 948 .'</tr>'; 949 $statrpt .= '<tr><td colspan="4"><em>total</em></td>' 950 .'<td class="sitedoc_right">'. number_format($row_count) .'</td>' 951 .'<td class="sitedoc_right">'. number_format($datalen) .'</td>' 952 .'<td class="sitedoc_right">'. number_format($indexlen) .'</td>' 953 .'<td class="sitedoc_right">'. number_format($overhead) .'</td>' 954 .'</tr>'; 955 $statrpt .= "\n</table><p>"; 956 957 $fieldset = array( 958 '#title' => t('Table Status'), 959 '#collapsible' => TRUE, 960 '#collapsed' => TRUE, 961 '#value' => $statrpt, 962 ); 963 $output .= theme('fieldset', $fieldset); 964 965 $totsize = $datalen + $indexlen; 966 $kb = $totsize / 1024; 967 $mb = $kb / 1024; 968 $gb = $mb / 1024; 969 $units = 'KB'; 970 $howmany = $kb; 971 if ($mb >= 1) { 972 if ($gb >= 1) { 973 $units = 'GB'; $howmany = $gb; 974 } 975 else { 976 $units = 'MB'; $howmany = $mb; 977 } 978 } 979 980 $output .= t('Total database size is !num !unit', array('!num' => sprintf('%.1f', $howmany), '!unit' => $units)) .'</p>'; 981 drupal_set_message(t('!count tables found in !db.', array('!count' => $rows, '!db' => $actdb)), 'status'); 982 983 return $output ."\n"; 984 } 985 986 /* 987 * Helper function to show the index structure of a database table. 988 */ 989 function _sitedoc_show_index($table_name) { 990 $output = null; 991 $index_list = db_query('SHOW INDEX FROM '. $table_name); 992 $indices = array(); 993 $header = array(t('Key Name'), t('Columns'), t('Collation'), t('Cardinality')); 994 while ($index = db_fetch_array($index_list)) { 995 if ($index['Seq_in_index'] == 1) { 996 $indices[$index['Key_name']] = array( 997 'name' => $index['Column_name'] . ($index['Sub_part'] ? ' ('. $index['Sub_part'] .')' : null), 998 'collation' => $index['Collation'], 999 'count' => $index['Cardinality'], 1000 ); 1001 } 1002 else { 1003 $indices[$index['Key_name']]['name'] .= ', '. $index['Column_name'] . ($index['Sub_part'] ? ' ('. $index['Sub_part'] .')' : null); 1004 } 1005 } 1006 if (count($indices)) { 1007 $rows = array(); 1008 foreach ($indices as $key_name => $values) { 1009 $rows[] = array($key_name, 1010 $values['name'], 1011 array('data' => $values['collation'], 'align' => 'center'), 1012 array('data' => $values['count'], 'align' => 'center') 1013 ); 1014 } 1015 return theme('table', $header, $rows); 1016 } 1017 else { 1018 return '<span class="admin-missing">No index found.</span> '. _sitedoc_img_warning(); 1019 } 1020 } 1021 1022 /** 1023 * Helper function for database variable list 1024 */ 1025 function _sitedoc_dbvars_list($type, $title, $variables_list, $db_vers) { 1026 if (count($variables_list)) { 1027 $rows = array(); 1028 $output .= '<td valign="top">'."\n"; 1029 $output .= '<h5>'. $title ."</h5>\n"; 1030 $show = 'SHOW '. $type; 1031 $vers = explode('.', $db_vers); 1032 switch ($vers[0]) { 1033 case 4: 1034 foreach ($variables_list as $key => $name) { 1035 $list = $show ." LIKE '". $name ."'"; 1036 $result = db_query($list); 1037 while ($data = db_fetch_array($result)) { 1038 $rows[] = array($data['Variable_name'], $data['Value']); 1039 } 1040 } /* end foreach */ 1041 $output .= theme('table', $header, $rows) ."\n"; 1042 $output .= "</td>\n"; 1043 break; 1044 1045 case 5: 1046 $list = $show ." WHERE Variable_Name LIKE '". implode("' OR Variable_Name LIKE '", $variables_list) ."'"; 1047 $result = db_query($list); 1048 while ($data = db_fetch_array($result)) { 1049 $rows[] = array($data['Variable_name'], $data['Value']); 1050 } 1051 $output .= theme('table', $header, $rows) ."\n"; 1052 $output .= "</td>\n"; 1053 break; 1054 1055 default: 1056 drupal_set_message('Site Documentation: Unknown database version'. $vers[0], 'error'); 1057 1058 } /* end switch */ 1059 } /* end count variables */ 1060 return $output; 1061 } 1062 1063 /** 1064 * Function to display table contents. 1065 * 1066 * @param: 1067 * $table - table name to show. 1068 * $rows_per_page - how many rows to format per page. Defaults to 20. 1069 * 1070 * @return: HTML string 1071 */ 1072 function sitedoc_show_table($table = null, $rows_per_page = 20) { 1073 if (!$table || !db_table_exists($table)) { 1074 drupal_set_message(t('You must supply a valid database table name.'), 'error'); 1075 drupal_access_denied(); 1076 } 1077 1078 // We get the first (or only) part of the Primary key to be added to the sort sequence. 1079 $result = db_query("SHOW INDEX FROM {$table}"); 1080 $x = db_fetch_array($result); 1081 if ($x === false) { 1082 drupal_set_message(t("The '@table' table has no index defined. This is probably normal.", array('@table' => $table)), 'status'); 1083 $first_key = null; 1084 } 1085 else { 1086 $first_key = $x['Column_name']; 1087 } 1088 1089 drupal_set_title(t('@table Table Contents', array('@table' => ucwords($table)))); 1090 $output = '<p>'. t('Click on a column title to sort by that column.') .'</p><br/>'; 1091 $rows = array(); 1092 1093 // Now we get the column names from the table and build the header. 1094 $header = array(); 1095 $result = db_query("SHOW COLUMNS FROM {$table}"); 1096 1097 while ($col_desc = db_fetch_array($result)) { 1098 $header[] = array( 1099 'data' => ucwords(str_replace('_', ' ', $col_desc['Field'])), 1100 'field' => '`'. $col_desc['Field'] .'`', 1101 ); 1102 } 1103 1104 // Get the data rows from the table. 1105 $select = "SELECT * FROM {$table}"; 1106 // Set it up so that the user can sort on any column, but the primary key will always be the last value to sort on. 1107 $select .= tablesort_sql($header) . ($first_key ? (', '. $first_key .' ASC') : null); 1108 // Do the query so that we can page the data. 1109 $result = pager_query($select, $rows_per_page); 1110 1111 while ($row = db_fetch_array($result)) { 1112 $line = array(); 1113 foreach ($row as $key => $value) { 1114 // We use check_plain for security. 1115 $line[] = check_plain($value); 1116 } 1117 $rows[] = $line; 1118 } 1119 1120 // Build the displayable table. 1121 $output .= theme('table', $header, $rows); 1122 $output .= theme('pager', $rows_per_page); 1123 return $output; 1124 } 1125 1126 /** 1127 * Produce the modules list. 1128 * 1129 * Parameters: 1130 * none 1131 * 1132 * Return: HTML string 1133 */ 1134 function sitedoc_get_modules($exclude_disabled=FALSE, $sort_order=0) { 1135 $output = ''; 1136 $rows = array(); 1137 1138 $module = array(); 1139 $files = module_rebuild_cache(); 1140 $sortkey = array(); 1141 // Set some default package stuff for Drupal. 1142 $package_list = array('Core - required', 'Core - optional'); 1143 $package_path = array('modules/ ', 'modules/ '); 1144 1145 foreach ($files as $filename => $file) { 1146 $name = $file->info['name']; 1147 $level = NULL; 1148 1149 $package = empty($file->info['package']) ? t('Other') : ucfirst($file->info['package']); 1150 $project = empty($file->info['project']) ? ucfirst($file->name) : ucfirst($file->info['project']); 1151 $key = array(NULL, NULL, $name); 1152 1153 // The filename is something like sites/all/modules/package/contrib/project/project.module. 1154 // For the path sorting option, we want the part before "package" as key[0], 1155 // and the part after "package" ("contrib/") in key[1]. 1156 // "project.module" is in 'basename' already. 1157 // So let's start by breaking the filename up into pieces. 1158 $pieces = explode('/', $file->filename); 1159 // We don't need the last array element (project.module). 1160 unset($pieces[count($pieces) - 1]); 1161 1162 // Check for what kind of package it is. 1163 if ($package == t('Other') || $project == 'Drupal') { 1164 // 'Special' packages. Remove the last piece ("project/"). 1165 unset($pieces[count($pieces) - 1]); 1166 // We add a blank to the end because 'sort' acts funny. 1167 $key[0] = implode('/', $pieces) .'/ '; 1168 } 1169 else { 1170 // 'Normal' packages. 1171 $where = array_search($package, $pieces); 1172 if ($where === FALSE) { 1173 // If "package" is not part of the name, just pull the "project" part off. 1174 unset($pieces[count($pieces) - 1]); 1175 $key[0] = implode('/', $pieces) .'/ '; 1176 } 1177 else { 1178 // "Package" is part of the name, split the keys up. 1179 $key[0] = implode('/', array_slice($pieces, 0, $where)) .'/ '; 1180 $key[1] = implode('/', array_slice($pieces, $where + 1)) .'/'; 1181 } 1182 } 1183 1184 $where = array_search($package, $package_list); 1185 if ($where === FALSE) { 1186 $package_list[] = $package; 1187 $package_path[] = $key[0]; 1188 } 1189 else { 1190 // Package already in list. 1191 if ($package_path[$where] != $key[0] && $package != t('Other')) { 1192 // The path is different from what we found earlier. 1193 // One may be a substring of the other - that's okay, but save the shorter one. 1194 if ((strpos($package_path[$where], rtrim($key[0])) === FALSE && strpos($key[0], rtrim($package_path[$where])) === FALSE) || ($project == 'Drupal')) { 1195 if ($project == 'Drupal') { 1196 $level = 'error'; 1197 } 1198 else { 1199 $level = 'status'; 1200 } 1201 drupal_set_message(t("'!name' for the '!pkg' package was found in '!found' but a previous module was in '!prior'.", array('!name' => $name, '!pkg' => $package, '!found' => $key[0], '!prior' => $package_path[$where])), $level); 1202 } 1203 else { 1204 // Resave the shorter one. 1205 if (strlen($package_path[$where]) < strlen($key[0])) { 1206 $package_path[$where] = $key[0]; 1207 } 1208 } 1209 } 1210 } 1211 1212 $module[$name] = array( 1213 'version' => $file->info['version'], 1214 'basename' => $file->basename, 1215 'filename' => $file->filename, 1216 'path' => $key[0], 1217 'contrib_path' => $key[1], 1218 'package' => $package, 1219 'project' => $project, 1220 'dependencies' => $file->info['dependencies'], 1221 'dependents' => $file->info['dependents'], 1222 'description' => $file->info['description'], 1223 'status' => $file->status, 1224 'level' => $level, 1225 ); 1226 1227 // Build a parallel array to sort with. 1228 $separator = '|'; 1229 switch ($sort_order) { 1230 case 0: // package, project, module 1231 $key = array($module[$name]['package'], $module[$name]['project'], $name); 1232 break; 1233 1234 case 1: // path, module 1235 // Keys already set. 1236 break; 1237 1238 default: // This should never happen. 1239 drupal_set_message(t('Unrecognized sort order.'), 'error'); 1240 $key = array($module[$name]['package'], $module[$name]['project'], $name); 1241 } 1242 $sortkey[] = implode('|', $key); 1243 1244 $dependencies = array(); 1245 // Check for missing dependencies. 1246 if (is_array($file->info['dependencies'])) { 1247 foreach ($file->info['dependencies'] as $dependency) { 1248 if (!isset($files[$dependency]) || !$files[$dependency]->status) { 1249 if (isset($files[$dependency])) { 1250 $dependencies[] = $files[$dependency]->info['name'] .'<span class="admin-disabled">('. t('disabled') .')</span>'; 1251 } 1252 else { 1253 $dependencies[] = drupal_ucfirst($dependency) .'<span class="admin-missing">('. t('missing') .')</span>'; 1254 $disabled[] = $filename; 1255 } 1256 } /* end if !isset */ 1257 else { 1258 $dependencies[] = $files[$dependency]->info['name'] .'<span class="admin-enabled">('. t('enabled') .')</span>'; 1259 } 1260 } /* end foreach depend */ 1261 } /* end if isarray */ 1262 1263 // Un-array dependencies. 1264 if (!empty($dependencies)) { 1265 $module[$name]['dependencies'] = implode(', ', $dependencies); 1266 } 1267 1268 // Un-array enabled dependents. 1269 if (!empty($module[$name]['dependents'])) { 1270 $module[$name]['required'] = implode(', ', $module[$name]['dependents']); 1271 } 1272 } /* end foreach files */ 1273 1274 $header = array( 1275 t('Name'), 1276 t('Version'), 1277 t('Status'), 1278 t('Project / Package'), 1279 t('Description'), 1280 t('Required By'), 1281 t('Depends On'), 1282 ); 1283 drupal_set_message(t('!count modules found.', array('!count' => count($module))), 'status'); 1284 $disabled_count = 0; 1285 $previous = NULL; 1286 1287 // Order it by project, package, module name. 1288 sort($sortkey); 1289 1290 foreach ($sortkey as $key => $value) { 1291 $keys = explode('|', $value); 1292 $name = $keys[count($keys) - 1]; 1293 1294 if ($keys[0] != $previous) { 1295 if (count($rows) > 0) { 1296 $fieldset = array( 1297 '#title' => $previous, 1298 '#collapsible' => TRUE, 1299 '#collapsed' => TRUE, 1300 '#value' => theme('table', $header, $rows), 1301 ); 1302 $output .= theme('fieldset', $fieldset); 1303 } 1304 $previous = $keys[0]; 1305 $rows = array(); 1306 } 1307 1308 if (!$exclude_disabled || $module[$name]['status']) { 1309 $path = $module[$name]['path']; 1310 if ($module[$name]['level']) { 1311 $path = '<span class="admin-missing">'. $path .'</span>'; 1312 } 1313 $rows[] = array( 1314 $name, 1315 $module[$name]['version'], 1316 $module[$name]['status'] ? 'Enabled' : 'Disabled', 1317 '<small>'. $module[$name]['project'] .'<br />'. $module[$name]['package'] .'<br />'. $path .'</small>', 1318 '<small>'. $module[$name]['description'] .'</small>', 1319 $module[$name]['required'], 1320 $module[$name]['dependencies'], 1321 ); 1322 } // end if exclude disabled 1323 else { 1324 ++$disabled_count; 1325 } 1326 1327 } /* end foreach sortkey */ 1328 // Flush the last set. 1329 if (count($rows) > 0) { 1330 $fieldset = array( 1331 '#title' => $previous, 1332 '#collapsible' => TRUE, 1333 '#collapsed' => TRUE, 1334 '#value' => theme('table', $header, $rows), 1335 ); 1336 $output .= theme('fieldset', $fieldset); 1337 } 1338 1339 if ($exclude_disabled) { 1340 $output .= '<p>'. t('!count disabled modules excluded.', array('!count' => $disabled_count)) .'</p>'; 1341 } 1342 return $output ."\n"; 1343 } 1344 1345 /** 1346 * Produce the Themes lists 1347 * 1348 * Parameters: 1349 * Which type of row to return 1350 * theme - get themes list 1351 * 1352 * Return: HTML string 1353 */ 1354 function sitedoc_get_system($type=null) { 1355 if (!$type) { 1356 return '<p>'. t('No system table type specified.') .'</p>'; 1357 } 1358 $status = array('Disabled', 'Enabled'); 1359 1360 $string = ucfirst(strtolower($type)); 1361 1362 // This ORDER BY makes the list come out by directory the entry comes from. 1363 $result = db_query('SELECT s.name, s.filename, s.status FROM {system} s WHERE s.type=\'%s\' ORDER BY s.status DESC, s.name ASC', $type); 1364 $header = array($string, t('Path'), t('Status')); 1365 $rows = array(); 1366 while ($mod = db_fetch_array($result)) { 1367 $rows[] = array( 1368 ucfirst($mod['name']), 1369 $mod['filename'], 1370 $status[$mod['status']], 1371 ); 1372 } 1373 if (!empty($rows)) { 1374 drupal_set_message(t('!rows !type found.', array('!rows' => count($rows), '!type' => $string)), 'status'); 1375 $output .= theme('table', $header, $rows); 1376 } 1377 else { 1378 $output .= t('No entries found! Very curious.'); 1379 } 1380 return $output ."\n"; 1381 } 1382 1383 /** 1384 * Produce the blocks list 1385 * 1386 * Parameters: 1387 * $warn - TRUE / FALSE to produce orphan warning message. 1388 * $delete - TRUE / FALSE to delete orphans. 1389 * 1390 * Return: HTML string 1391 */ 1392 function sitedoc_get_blocks($warn=TRUE, $delete=FALSE) { 1393 $status = array(); 1394 $status = array(t('disabled'), t('enabled')); 1395 $viz = array(t('Show except'), t('Show only'), t('Php')); 1396 $del = NULL; 1397 1398 // Check if the table is missing an index. 1399 $indexes = db_fetch_array(db_query('SHOW INDEX FROM {blocks}')); 1400 if ($indexes == FALSE) { 1401 $index_msg = ' '. t('Performance may be improved by adding an index. See <a href="!url">this discussion</a>.', array('!url' => 'http://drupal.org/node/164532')); 1402 $msg_level = 'warning'; 1403 } 1404 else { 1405 $index_msg = NULL; 1406 $msg_level = 'status'; 1407 } 1408 1409 // Get blocks from the Blocks table. 1410 $result = db_query('SELECT b.module, b.delta, b.theme, b.status, b.weight, b.region, b.custom, b.throttle, b.visibility, b.pages, b.title FROM {blocks} b ORDER BY b.theme, b.module, b.delta'); 1411 1412 $header = array( 1413 t('Theme'), 1414 t('Module'), 1415 array('data' => t('Delta'), 'align' => 'center'), 1416 t('Name') .' /<br/>'. t('Title'), 1417 t('Status'), 1418 array('data' => t('Weight'), 'class' => 'sitedoc_right'), 1419 t('Region'), 1420 t('Roles'), 1421 array('data' => t('Visibility'), 'align' => 'center'), 1422 t('Pages'), 1423 ); 1424 $output = '<h3>'. t('Blocks') .'</h3>'; 1425 1426 $rows = array(); 1427 $missing_theme = FALSE; 1428 1429 while ($blk = db_fetch_object($result)) { 1430 $theme = $blk->theme; 1431 $thmq = db_query_range("SELECT s.status FROM {system} s WHERE s.type='theme' AND s.name='%s'", $theme, 0, 1); 1432 $thm = db_fetch_array($thmq); 1433 if (!empty($thm)) { 1434 $theme .= ' <span class="admin-'. $status[$thm['status']] .'">('. ucfirst($status[$thm['status']]) .')</span>'; 1435 } 1436 else { 1437 $theme .= ' <span class="admin-missing">('. t('missing') .')</span>'; 1438 $missing_theme = TRUE; 1439 $mod_delta = "module='$blk->module' AND delta='$blk->delta'"; 1440 $delblk = "DELETE FROM {blocks} WHERE theme='". $blk->theme ."' AND ". $mod_delta; 1441 if ($has_roles = db_query_range('SELECT rid FROM {blocks_roles} WHERE '. $mod_delta, 0, 1)) { 1442 $delrole = 'DELETE FROM {blocks_roles} WHERE '. $mod_delta; 1443 } 1444 else { 1445 $delrole = null; 1446 drupal_set_message("has_roles query returned $has_roles"); 1447 } 1448 if ($delete) { 1449 $deleted = db_query($delblk) && ($delrole ? db_query($delrole) : true); 1450 if ($deleted == false) { 1451 $theme .= ' <span class="admin-missing">('. t('NOT DELETED') .')</span>'; 1452 } 1453 else { 1454 $theme .= ' <span class="admin-disabled">('. t('DELETED') .')</span>'; 1455 drupal_set_message(t('Deleted block ') . $blk->theme .'/'. $blk->module .'/'. $blk->delta, 'status'); 1456 } 1457 } 1458 else { 1459 $del .= $delblk . $delrole; 1460 } 1461 } 1462 1463 $blocks = module_invoke($blk->module, 'block', 'list'); // Get block information from module. 1464 1465 $w = $blk->weight ? $blk->weight : ''; // Don't show 0 weight. 1466 $n = $blocks[$blk->delta]['info']; // Get block name. 1467 // If there is one, put title on next line. 1468 if (!empty($blk->title)) { 1469 $n .= ' /<br />'. $blk->title; 1470 } 1471 // The pages field format depends on the visibility setting 1472 // 2 is php, 0 or 1 is pages list 1473 if ($blk->visibility < 2) { 1474 $pt = trim(check_plain($blk->pages)); 1475 if (strcmp($pt, '') == 0) { 1476 $pgs = NULL; 1477 } 1478 else { 1479 $pgs = explode("\n", $pt); 1480 if (is_array($pgs)) { 1481 if (count($pgs) > 1) { 1482 $pgs = theme('item_list', $pgs); 1483 } 1484 else { 1485 $pgs = $pgs[0]; 1486 } 1487 } 1488 } 1489 } 1490 // Visibility = 2 1491 else { 1492 $pgs = highlight_string($blk->pages, TRUE); 1493 } 1494 1495 // Get the roles for the blocks. 1496 $rids = db_query('SELECT br.rid, r.name FROM {blocks_roles} br INNER JOIN {role} r ON r.rid=br.rid WHERE br.module=\'%s\' AND br.delta=\'%d\'', $blk->module, $blk->delta); 1497 $blk_rids = array(); 1498 while ($blk_role = db_fetch_array($rids)) { 1499 $blk_rids[] = $blk_role['name']; 1500 } 1501 1502 $rows[] = array( 1503 $theme, 1504 $blk->module == 'block' ? 'block /<br/><small><em>'. t('see boxes') .'</em></small>' : $blk->module, 1505 array('data' => $blk->delta, 'align' => 'center'), 1506 $n, 1507 '<span class="admin-'. $status[$blk->status] .'">'. ucfirst($status[$blk->status]) .'</span>', 1508 array('data' => $w, 'class' => 'sitedoc_right'), 1509 $blk->status ? $blk->region : '', /* no region if not enabled */ 1510 count($blk_rids) ? '<small>'. implode(', ', $blk_rids) .'</small>' : NULL, 1511 array('data' => $viz[$blk->visibility], 'align' => 'center'), 1512 $pgs, 1513 ); 1514 } /* end while */ 1515 1516 $count = count($rows); 1517 if ($count == 0) { 1518 drupal_set_message(t('No Blocks found.'), 'status'); 1519 } 1520 else { 1521 drupal_set_message(t('!count Blocks found.', array('!count' => $count)) . $index_msg , $msg_level); 1522 if ($index_msg) { 1523 drupal_set_message(t('For example:') .' ALTER TABLE `blocks` ADD PRIMARY KEY(`theme`(32), `module`, `delta`)', $msg_level); 1524 } 1525 $output .= theme('table', $header, $rows); 1526 } 1527 if ($missing_theme && $warn) { 1528 drupal_set_message(t('Blocks defined for non-existent theme(s)'), 'error'); 1529 } 1530 1531 if ($missing_theme && !$delete) { 1532 $output .= '<p>'. $del .'</p>'; 1533 } 1534 1535 return $output ."\n"; 1536 } 1537 1538 /** 1539 * Produce the boxes (manual blocks, additional data) list. 1540 * 1541 * Parameters: 1542 * $warn - TRUE / FALSE to produce orphan warning message. 1543 * $delete - TRUE / FALSE to delete orphans. 1544 * 1545 * Return: HTML string 1546 */ 1547 function sitedoc_get_boxes($warn=TRUE, $delete=FALSE) { 1548 $result = db_query('SELECT * FROM {boxes} b'); 1549 $output = NULL; 1550 $orphans = FALSE; 1551 $header = array( 1552 array('data' => 'Bid', 'class' => 'sitedoc_right'), 1553 t('Box Name'), 1554 array('data' => t('Format'), 'class' => 'sitedoc_right'), 1555 t('Body'), 1556 ); 1557 $rows = array(); 1558 while ($box = db_fetch_array($result)) { 1559 $info = $box['info']; 1560 $check_block = db_result(db_query_range("SELECT COUNT(theme) FROM {blocks} WHERE module='block' AND delta=%d", $box['bid'], 0, 1)); 1561 if ($check_block == 0) { 1562 $orphans = TRUE; 1563 $info .= '<br/><span class="admin-missing">('. t('block missing') .')</span>'; 1564 if ($delete) { 1565 $delbox = db_query_range('DELETE FROM {boxes} WHERE bid=%d', $box['bid'], 0, 1); 1566 drupal_set_message(t('Box number !bid deleted.', array('!bid' => $box['bid'])), 'status'); 1567 } 1568 } 1569 1570 $rows[] = array( 1571 array('data' => $box['bid'], 'class' => 'sitedoc_right'), 1572 $info, 1573 array('data' => $box['format'], 'class' => 'sitedoc_right'), 1574 highlight_string($box['body'], TRUE), 1575 ); 1576 } // End while. 1577 1578 $howmany = count($rows); 1579 if ($howmany > 0) { 1580 $output .= theme('table', $header, $rows) ."\n"; 1581 drupal_set_message(t('!count boxes found.', array('!count' => $howmany)), 'status'); 1582 } 1583 if ($orphans) { 1584 if ($warn) { 1585 drupal_set_message('Orphan boxes found.', 'error'); 1586 } 1587 } 1588 return $output; 1589 } 1590 1591 /** 1592 * Produce the content types list. 1593 * 1594 * Parameters: 1595 * none 1596 * 1597 * Return: HTML string 1598 */ 1599 function sitedoc_content_types() { 1600 $yesno = array(t('no'), t('yes')); 1601 $com_vals = array(t('disabled'), t('read-only'), t('read/write')); 1602 1603 // The TRUE here forces the node module to refresh the list. 1604 $node_types = node_get_types('types', NULL, TRUE); 1605 $header = array( 1606 t('Type'), 1607 array('data' => t('Count'), 'class' => 'sitedoc_right'), 1608 t('Name') .'/<br/>'. t('Module'), 1609 t('Description'), 1610 t('Has title') .'/<br/>'. t('Has body') .'/<br/>'. t('Has help'), 1611 array('data' => t('Min words'), 'class' => 'sitedoc_right'), 1612 t('Custom') .'/<br/>'. t('Modified') .'/<br/>'. t('Locked'), 1613 t('Workflow') .'/<br/>'. t('Comments') 1614 ); 1615 $num_contents = 0; 1616 $missing = FALSE; 1617 1618 foreach ($node_types as $type => $info) { 1619 $num_contents ++; 1620 $workflow = str_replace('status', 'published', implode(', ', variable_get('node_options_'. $info->type, array()))); 1621 if (workflow == '') { 1622 $workflow = 'not published'; 1623 } 1624 $count = db_result(db_query('SELECT COUNT(n.nid) FROM {node} n WHERE n.type=\'%s\'', $info->type)); 1625 if (module_exists($info->module)) { 1626 $mod = $info->module; 1627 } 1628 else { 1629 $mod = $info->module .' <span class="admin-missing">('. t('missing') .')</span>'; 1630 $missing = TRUE; 1631 } 1632 $has_help = $info->help ? true : false; 1633 $rows[] = array( 1634 l($info->type, 'admin/content/types/'. $info->type), 1635 array('data' => $count, 'class' => 'sitedoc_right'), 1636 $info->name .'<br/>'. $mod, 1637 $info->description, 1638 $yesno[$info->has_title] .'<br/>'. $yesno[$info->has_body] .'<br/>'. $yesno[$has_help], 1639 array('data' => $info->min_word_count, 'class' => 'sitedoc_right'), 1640 $yesno[$info->custom] .'<br/>'. $yesno[$info->modified] .'<br/>'. $yesno[$info->locked], 1641 $workflow .'<br/>'. $com_vals[variable_get('comment_'. $info->type, 0)], 1642 ); 1643 } /* end foreach */ 1644 1645 if ($missing) { 1646 drupal_set_message(t('!num content types found. Missing modules identified.', array('!num' => $num_contents)), 'error'); 1647 } 1648 else { 1649 drupal_set_message(t('!num content types found.', array('!num' => $num_contents)), 'status'); 1650 } 1651 1652 $output .= theme('table', $header, $rows); 1653 1654 return $output ."\n"; 1655 } 1656 1657 /** 1658 * Produce the vocabularies and terms list. 1659 * 1660 * Parameters: 1661 * none 1662 * 1663 * Return: HTML string 1664 */ 1665 function sitedoc_get_vocabularies() { 1666 if (!module_exists('taxonomy')) { 1667 return '<p>Taxonomy'. t(' module not enabled') .'</p>'; 1668 } 1669 $hier = array(t('Disabled'), t('Single'), t('Multiple')); 1670 $vocabularies = taxonomy_get_vocabularies(); 1671 $rows = array(); 1672 $header = array( 1673 t('Name (vid)'), 1674 t('Content Types'), 1675 t('Description'), 1676 t('Help'), 1677 t('Hierarchy'), 1678 t('Terms'), 1679 t('Module'), 1680 t('Weight'), 1681 ); 1682 foreach ($vocabularies as $vocabulary) { 1683 $types = array(); 1684 foreach ($vocabulary->nodes as $type) { 1685 $types[] = $type; 1686 } 1687 $t = array(); 1688 if ($vocabulary->relations) { 1689 $t[] = t('related'); 1690 } 1691 if ($vocabulary->multiple) { 1692 $t[] = t('multi-select'); 1693 } 1694 if ($vocabulary->required) { 1695 $t[] = t('required'); 1696 } 1697 if ($vocabulary->tags) { 1698 $t[] = t('free-tag'); 1699 } 1700 $rows[] = array( 1701 'name' => check_plain($vocabulary->name) .' ('. $vocabulary->vid .')', 1702 'type' => implode(', ', $types), 1703 $vocabulary->description . _terms_list($vocabulary->vid), /* subroutine gets terms */ 1704 $vocabulary->help ? t('yes') : t('no'), 1705 $hier[$vocabulary->hierarchy], 1706 implode(', ', $t), 1707 $vocabulary->module, 1708 $vocabulary->weight, 1709 ); 1710 } 1711 1712 $output .= theme('table', $header, $rows); 1713 return $output ."\n"; 1714 } 1715 1716 // Helper function to get vocabulary term info. 1717 function _terms_list($vid) { 1718 $items = array(); 1719 $thead = array( 1720 t('Term (tid)'), 1721 array('data' => t('Count'), 'class' => 'sitedoc_right'), 1722 t('Description'), 1723 ); 1724 $terms = taxonomy_get_tree($vid); 1725 1726 foreach ( $terms as $term ) { 1727 // This query should be very fast and includes unpublished nodes. 1728 $count = db_result(db_query('SELECT COUNT(nid) FROM {term_node} WHERE tid=%d', $term->tid)); 1729 1730 // Don't show terms with 0 count. 1731 if ($count) { 1732 $items[] = array( 1733 $term->name .' ('. $term->tid .')', 1734 array('data' => $count, 'class' => 'sitedoc_right'), 1735 $term->description); 1736 } 1737 } 1738 1739 return "\n". theme('table', $thead, $items); 1740 } 1741 1742 /** 1743 * Produce a table of taxonomy term usage by content type. 1744 * This function is available only as a callable function; 1745 * it is not called within this module. 1746 * 1747 * Parameters: 1748 * vid - the vocabulary id to show. 1749 * 1750 * Return: HTML string 1751 */ 1752 function sitedoc_term_count_by_type($vid) { 1753 $vocab = taxonomy_vocabulary_load($vid); 1754 if (!$vocab->name) { 1755 drupal_set_message(t('Vocabulary not found.'), 'error'); 1756 return t('Vocabulary not found.'); 1757 } 1758 1759 $output = '<h2>Usage of "'. $vocab->name .'" Category by Term and Content Type</h2>'; 1760 if ($vocab->description) { 1761 $output .= '<h6>'. $vocab->description .'</h6>'; 1762 } 1763 1764 $header = array(t('Term')); 1765 $rows = array(); 1766 $type = array(); 1767 1768 // Build header row with types. 1769 foreach ($vocab->nodes as $key => $value) { 1770 $type[] = $value; 1771 $name = $value; 1772 $header[] = array('data' => $name, 'align' => 'right') ; 1773 } /* end foreach */ 1774 1775 $terms = taxonomy_get_tree($vid); 1776 foreach ( $terms as $term ) { 1777 $line = array(); 1778 if (module_exists('taxonomy_image')) { 1779 $img = taxonomy_image_display($term->tid, array('align' => 'left', 'hspace' => '3')); 1780 } 1781 else { $img = NULL; } 1782 $line[] = $img . l($term->name, 'taxonomy/term/'. $term->tid) ."<br/><small>". $term->description ."</small>"; 1783 foreach ($type as $content_type) { 1784 $count = sitedoc_term_count_nodes($term->tid, $content_type); 1785 if ($count) { /* don't show terms with 0 count */ 1786 $line[] = array('data' => $count, 'align' => 'right'); 1787 } /* end if count */ 1788 else { 1789 $line[] = ' '; 1790 } 1791 } /* end each content_type */ 1792 $rows[] = $line; 1793 } /* end foreach term */ 1794 1795 $output .= theme('table', $header, $rows); 1796 return $output; 1797 } 1798 1799 /** 1800 * Check if there are any term nodes entries that don't belong to nodes. 1801 * 1802 * Parameters: 1803 * Delete - TRUE | FALSE - whether or not to delete the orphans. 1804 * 1805 * Return: HTML string 1806 */ 1807 function sitedoc_check_orphan_term_node($delete_orphans=FALSE) { 1808 if (!module_exists('taxonomy')) { 1809 return '<p>Taxonomy'. t(' module not enabled') .'</p>'; 1810 } 1811 1812 $tn = db_result(db_query('SELECT COUNT(DISTINCT(tn.nid)) FROM {term_node} tn')); 1813 $n = db_result(db_query('SELECT COUNT(DISTINCT(n.nid)) FROM {node} n')); 1814 1815 if ($tn > $n) { 1816 drupal_set_message(t('There are !tn term_nodes but only !n nodes.', array('!tn' => $tn, '!n' => $n)), 'error'); 1817 } 1818 else { 1819 return '<p>'. t('No orphan term_nodes found.') .'</p>'; 1820 } 1821 1822 $header = array('nid', 'tid', 'term', 'vocab'); 1823 $rows = array(); 1824 $del = NULL; 1825 1826 $result = db_query('SELECT tn.nid, tn.tid FROM {term_node} tn LEFT JOIN {node} n ON tn.nid=n.nid WHERE ISNULL(n.title) ORDER BY tn.nid, tn.tid'); 1827 1828 while ($tn = db_fetch_array($result)) { 1829 $term = taxonomy_get_term($tn['tid']); 1830 $vocab = taxonomy_vocabulary_load($tn['tid']); 1831 $delsql .= 'DELETE FROM {term_node} WHERE term_node.nid='. $tn['nid'] .' AND term_node.tid='. $tn['tid']; 1832 if ($delete_orphans) { 1833 db_query($delsql); 1834 drupal_set_message(t('Deleted term_node ') .'nid='. $tn['nid'] .', tid='. $tn['tid'], 'status'); 1835 } 1836 else { 1837 $del .= $delsql; 1838 } 1839 $rows[] = array($tn['nid'], $tn['tid'], $term->name, $vocab->name, $del); 1840 } 1841 1842 $output = theme('table', $header, $rows); 1843 if (!$delete_orphans) { 1844 $output .= $del; 1845 } 1846 1847 return $output ."\n"; 1848 } 1849 1850 /** 1851 * Produce the node summary. 1852 * 1853 * Parameters: 1854 * TRUE - include comments count. 1855 * FALSE - don't include comments count. 1856 * 1857 * Return: HTML string 1858 */ 1859 function sitedoc_node_summary($comment=FALSE, $show_size=99999, $max_size=99999) { 1860 $sql = "SELECT n.nid, n.title, n.type, n.status, n.promote, n.moderate, n.sticky, length(body) AS node_len"; 1861 if ($comment) { 1862 $sql .= ", c.comment_count"; 1863 } 1864 $sql .= " FROM {node} n LEFT JOIN {node_revisions} nr ON nr.vid=n.vid"; 1865 if ($comment) { 1866 $sql .= " LEFT JOIN {node_comment_statistics} c ON c.nid=n.nid"; 1867 } 1868 $result = db_query($sql); 1869 $counters = array(); 1870 $types = array(); 1871 $weight_detected = FALSE; 1872 1873 $toobig = 0; 1874 $biggies = array(); 1875 1876 while ($node = db_fetch_object($result)) { 1877 $node_kb = $node->node_len / 1024; 1878 if ($node_kb >= $show_size) { 1879 $biggies[] = array( 1880 l($node->title, 'node/'. $node->nid .'/edit'), 1881 array('data' => number_format($node_kb, 2), 'align' => 'center')); 1882 } /* end if show size */ 1883 if ($node_kb >= $max_size) { 1884 ++$toobig; 1885 } 1886 1887 if (!in_array($node->type, $types)) { 1888 $types[] = $node->type; 1889 } 1890 $counters[$node->type]['type'] ++; 1891 if ($node->status) { 1892 ++$counters[$node->type]['published']; 1893 } 1894 if ($node->promote) { 1895 ++$counters[$node->type]['promoted']; 1896 } 1897 if ($node->moderate) { 1898 ++$counters[$node->type]['moderated']; 1899 } 1900 if ($comment) { 1901 $counters[$node->type]['comments'] += $node->comment_count; 1902 } 1903 /* check if the weight module algorithm is in use */ 1904 if ($node->sticky > 1 || $node->sticky < 0) { 1905 _decode_sticky($node); 1906 if (!$weight_detected) { 1907 $weight_detected = TRUE; 1908 drupal_set_message(t('Weight-encoded in sticky field has been detected.'), 'status'); 1909 } 1910 } 1911 else { 1912 $node->weight = 0; /* set unweighted if not */ 1913 } 1914 if ($node->sticky) { 1915 ++$counters[$node->type]['sticky']; 1916 } 1917 if ($node->weight <> 0) { 1918 ++$counters[$node->type]['weight']; 1919 } 1920 } /* end while fetch */ 1921 ksort($types); 1922 $header = array( 1923 t('Type'), 1924 array('data' => t('Count'), 'class' => 'sitedoc_right'), 1925 array('data' => t('Published'), 'class' => 'sitedoc_right'), 1926 array('data' => t('Promoted'), 'class' => 'sitedoc_right'), 1927 array('data' => t('Sticky'), 'class' => 'sitedoc_right'), 1928 array('data' => t('Weighted'), 'class' => 'sitedoc_right'), 1929 array('data' => t('Moderated'), 'class' => 'sitedoc_right'), 1930 $comment ? array('data' => t('Comments'), 'class' => 'sitedoc_right') : NULL, 1931 ); 1932 $rows = array(); 1933 $tot = 0; $pub = 0; $pro = 0; $sti = 0; $mod = 0; 1934 foreach ($types as $type) { 1935 $rows[] = array( 1936 $type, 1937 array('data' => $counters[$type]['type'], 'class' => 'sitedoc_right'), 1938 array('data' => $counters[$type]['published'], 'class' => 'sitedoc_right'), 1939 array('data' => $counters[$type]['promoted'], 'class' => 'sitedoc_right'), 1940 array('data' => $counters[$type]['sticky'], 'class' => 'sitedoc_right'), 1941 array('data' => $counters[$type]['weight'], 'class' => 'sitedoc_right'), 1942 array('data' => $counters[$type]['moderated'], 'class' => 'sitedoc_right'), 1943 $comment ? array('data' => $counters[$type]['comments'], 'class' => 'sitedoc_right') : NULL, 1944 ); 1945 $tot += $counters[$type]['type']; 1946 $pub += $counters[$type]['published']; 1947 $pro += $counters[$type]['promoted']; 1948 $sti += $counters[$type]['sticky']; 1949 $wei += $counters[$type]['weight']; 1950 $mod += $counters[$type]['moderated']; 1951 $com += $counters[$type]['comments']; 1952 } /* end foreach type */ 1953 $rows[] = array( 1954 '', 1955 array('data' => '------', 'class' => 'sitedoc_right'), 1956 array('data' => '------', 'class' => 'sitedoc_right'), 1957 array('data' => '------', 'class' => 'sitedoc_right'), 1958 array('data' => '------', 'class' => 'sitedoc_right'), 1959 array('data' => '------', 'class' => 'sitedoc_right'), 1960 array('data' => '------', 'class' => 'sitedoc_right'), 1961 $comment ? array('data' => '------', 'class' => 'sitedoc_right') : NULL, 1962 ); 1963 $rows[] = array( 1964 '<em>'. t('total') .'</em>', 1965 array('data' => $tot, 'class' => 'sitedoc_right'), 1966 array('data' => $pub, 'class' => 'sitedoc_right'), 1967 array('data' => $pro, 'class' => 'sitedoc_right'), 1968 array('data' => $sti, 'class' => 'sitedoc_right'), 1969 array('data' => $wei, 'class' => 'sitedoc_right'), 1970 array('data' => $mod, 'class' => 'sitedoc_right'), 1971 $comment ? array('data' => $com, 'class' => 'sitedoc_right') : NULL, 1972 ); 1973 drupal_set_message(t('!count nodes found.', array('!count' => $tot)), 'status'); 1974 $output .= theme('table', $header, $rows); 1975 1976 if ($toobig) { 1977 $output .= '<p>'. _sitedoc_img_warning() .' '. 1978 t('!count nodes exceed !size KB.', array('!count' => $toobig, '!size' => $max_size)) .'</p>'; 1979 } 1980 else { 1981 $output .= '<p>'. _sitedoc_img_ok() .' ' 1982 . t('No nodes exceed !size KB.', array('!size' => $max_size)) .'</p>'; 1983 } 1984 if (!empty($biggies)) { 1985 $big_head = array(t('Title'), t('Length (KB)')); 1986 $fieldset = array( 1987 '#title' => t('Large Nodes'), 1988 '#collapsible' => TRUE, 1989 '#collapsed' => TRUE, 1990 '#value' => theme('table', $big_head, $biggies), 1991 ); 1992 $output .= theme('fieldset', $fieldset); 1993 } 1994 1995 return $output ."\n"; 1996 } 1997 1998 // Helper module in case weight module algorithm is used. 1999 function _decode_sticky(&$node) { 2000 $sticky = $node->sticky; /* save value */ 2001 $node->sticky = ($sticky > 0) ? 1 : 0; 2002 $node->weight = ($sticky > 0) ? 100 - $sticky : -100 - $sticky; 2003 return; 2004 } 2005 2006 /** 2007 * Produce the node access summary. 2008 * 2009 * Parameters: 2010 * None 2011 * 2012 * Return: HTML string. 2013 */ 2014 function sitedoc_node_access() { 2015 // How many nodes are not represented in the node_access table. 2016 $result = db_fetch_object(db_query('SELECT COUNT(n.nid) as num_nodes FROM {node} n LEFT JOIN {node_access} na ON n.nid = na.nid WHERE na.nid IS NULL')); 2017 if ($num = $result->num_nodes) { 2018 $output .= '<p>'. _sitedoc_img_warning() .' ' 2019 . t('You have !num nodes in your node table which are not represented in your node_access table. If you have an access control module installed, these nodes may be hidden from all users. This could be caused by publishing nodes before enabling the access control module. If this is the case, manually updating each node should add it to the node_access table and fix the problem. Click here to !rebuild.', array('!num' => l($num, 'admin/build/sitedoc_node_access_view/'), '!rebuild' => l(t('rebuild permissions'), 'admin/content/node-settings/rebuild'))) ."</p>\n"; 2020 } 2021 else { 2022 $output .= '<p>'. _sitedoc_img_ok() . t('All nodes are represented in the node_access table.') ."</p>\n"; 2023 } /* end else */ 2024 2025 // Warn user if they have any entries that could grant access to all nodes. 2026 $rows = array(); 2027 $result = db_query('SELECT DISTINCT na.realm FROM {node_access} na WHERE na.nid=0 AND na.gid=0'); 2028 while ($row = db_fetch_object($result)) { 2029 $rows[] = $row->realm; 2030 } 2031 if (!empty($rows)) { 2032 $output .= '<h5>'. t('Access Granted to All Nodes (All Users)') ."</h5>\n"; 2033 $output .= '<p>'. t('Your node_access table contains entries (!r) that may be granting all users access to all nodes. Depending on which access control module(s) you use, you may want to delete these entries. If you are not using an access control module, you should probably leave these entries as is.', array('!r' => implode(', ', $rows))) ."</p>\n"; 2034 } 2035 2036 $headers = array(t('realm')); 2037 $rows = array(); 2038 // A similar warning to the one above, but slightly more specific. 2039 $result = db_query('SELECT DISTINCT(na.realm) FROM {node_access} na WHERE na.nid=0 AND na.gid<>0'); 2040 while ($row = db_fetch_object($result)) { 2041 $rows[] = array($row->realm); 2042 } /* end while */ 2043 if (!empty($rows)) { 2044 $output .= '<h5>'. t('Access Granted to All Nodes (Some Users)') ."</h5>\n"; 2045 $output .= '<p>'. t('Your node_access table contains entries that may be granting some users access to all nodes. This may be normal, depending on which access control module(s) you use.') ."</p>\n"; 2046 $output .= theme('table', $header, $rows); 2047 } /* end all nodes */ 2048 2049 $header = array(t('Realm'), t('Nodes'), t('Notes')); 2050 $rows = array(); 2051 2052 // Count nodes by realm. 2053 $result = db_query('SELECT DISTINCT na.realm, COUNT(DISTINCT na.nid) as node_count FROM {node_access} na GROUP BY na.realm'); 2054 $all = FALSE; 2055 2056 while ($row = db_fetch_object($result)) { 2057 if ($row->realm == 'all') { 2058 $all = TRUE; 2059 $realm_type = t('Public nodes'); 2060 $caption = t('This realm grants all users access to some specific nodes. If some of your content is available to the public, this may be normal.'); 2061 } 2062 else { 2063 $realm_type = t('Private nodes'); 2064 $caption = t('This realm grants limited access to some specific nodes.'); 2065 } 2066 $rows[] = array($row->realm, l($row->node_count, 'admin/build/sitedoc_node_access_view/'. $row->realm) .' '. $realm_type, $caption); 2067 } /* end while */ 2068 if ($all && !empty($rows)) { 2069 $output .= theme('table', $header, $rows); 2070 } 2071 2072 return $output ."\n"; 2073 } 2074 2075 /** 2076 * Menu call back to produce a list of nodes within a given access realm. 2077 * 2078 * parameters: 2079 * realm name 2080 * 2081 * returns: 2082 * HTML string 2083 */ 2084 function sitedoc_node_access_view($realm=NULL) { 2085 $rows = array(); 2086 $header = array( 2087 t('Type'), 2088 t('Title') .' <small> '. t('click to edit') .'</small>', 2089 ); 2090 2091 $sql = 'SELECT DISTINCT(n.nid), n.type, n.title FROM {node} n LEFT JOIN {node_access} na ON n.nid = na.nid WHERE na.realm '; 2092 $count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n LEFT JOIN {node_access} na ON n.nid = na.nid WHERE na.realm '; 2093 if (is_null($realm)) { 2094 $output .= '<h3>'. t('Unprotected Nodes') .'</h3>'; 2095 $sql .= 'IS NULL'; 2096 $count .= 'IS NULL'; 2097 } 2098 else { 2099 $output .= '<h3>'. t('Nodes in Realm: ') . ucfirst($realm) .'</h3>'; 2100 $sql .= "= '". $realm ."'"; 2101 $count .= "= '". $realm ."'"; 2102 } 2103 2104 $result = pager_query($sql, 50, 0, $count); 2105 while ($node = db_fetch_object($result)) { 2106 $rows[] = array($node->type, l($node->title, 'node/'. $node->nid .'/edit')); 2107 } /* end while node */ 2108 $output .= theme('table', $header, $rows); 2109 $output .= theme('pager', array(), 50); 2110 2111 return $output ."\n"; 2112 } 2113 2114 /** 2115 * Produce the user roles list. 2116 * 2117 * Parameters: 2118 * 1) TRUE - permissions listed as unordered list 2119 * FALSE - permissions listed as stream (default) 2120 * 2) TRUE - include users in roles (default) 2121 * FALSE - do not include users 2122 * 2123 * Return: HTML string 2124 */ 2125 function sitedoc_get_roles($list = FALSE, $users = FALSE) { 2126 $sql = 'SELECT r.rid, r.name, p.perm, p.tid FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid'; 2127 $result = db_query($sql); 2128 $output = NULL; 2129 $header = array( 2130 array('data' => 'Rid', 'class' => 'sitedoc_right'), 2131 t('Name'), 2132 t('Permissions'), 2133 t('Blocks'), 2134 $users ? t('Users') : NULL, 2135 array('data' => 'Tid', 'class' => 'sitedoc_right'), 2136 ); 2137 2138 while ($role = db_fetch_object($result)) { 2139 // Get which blocks they can see. 2140 $bresult = db_query('SELECT b.module, b.delta FROM {blocks_roles} b WHERE b.rid = %d', $role->rid); 2141 $blk_list = array(); 2142 while ($block = db_fetch_object($bresult)) { 2143 $blk_list[] = $block->module .'/'. $block->delta; 2144 } /* end while block */ 2145 2146 // Get which users have this role. 2147 $uresult = db_query('SELECT u.name, u.uid FROM {users_roles} r INNER JOIN {users} u ON u.uid = r.uid WHERE r.rid = %d', $role->rid); 2148 $user_list = array(); 2149 while ($user = db_fetch_object($uresult)) { 2150 // Make the user a link. 2151 $user_list[] = l($user->name .'('. $user->uid .')', 'user/'. $user->uid); 2152 } 2153 2154 $rows[] = array( 2155 array('data' => $role->rid, 'class' => 'sitedoc_right'), 2156 $role->name, 2157 $list ? theme('item_list', explode(', ', $role->perm)) : $role->perm, 2158 $list ? theme('item_list', $blk_list) : implode(', ', $blk_list), 2159 $users ? ($list ? theme('item_list', $user_list) : implode(', ', $user_list)) : NULL, 2160 array('data' => $role->tid, 'class' => 'sitedoc_right'), 2161 ); 2162 } /* end while role */ 2163 2164 $howmany = count($rows); 2165 if ($howmany > 0) { 2166 drupal_set_message(t('!count Roles found.', array('!count' => $howmany)), 'status'); 2167 $output = theme('table', $header, $rows); 2168 } 2169 return $output ."\n"; 2170 } 2171 2172 /** 2173 * Produce the system variables list. 2174 * 2175 * Parameters: 2176 * None 2177 * 2178 * Return: HTML string 2179 */ 2180 function sitedoc_get_variables() { 2181 // $conf is the cached array of system variables 2182 global $conf; 2183 2184 // Save it so we can sort it 2185 $vars = $conf; 2186 ksort($vars); 2187 2188 drupal_set_message(count($vars) . t(' system variables found.'), 'status'); 2189 2190 $header = array(t('Name'), t('Value')); 2191 $rows = array(); 2192 2193 foreach ($vars as $name => $value) { 2194 $rows[] = array($name, _sitedoc_handle_data($value)); 2195 } /* end foreach */ 2196 2197 $output .= theme('table', $header, $rows); 2198 return $output ."\n"; 2199 } 2200 2201 // Helper function for traversing an array. 2202 // Since some arrays may contain arrays, this function can be called recursively. 2203 // Also handles objects. 2204 function _sitedoc_handle_data($text) { 2205 // Take care of simple data types first. 2206 if (is_string($text) || is_numeric($text) || is_float($text)) { 2207 // return filter_xss($text); 2208 return check_plain($text); 2209 } 2210 2211 if (is_null($text)) { 2212 return t('NULL'); 2213 } 2214 2215 if (is_bool($text)) { 2216 return $text ? t('True') : t('False'); 2217 } 2218 2219 // That leaves arrays and objects. 2220 if (is_array($text)) { 2221 $rows = array(); 2222 foreach ($text as $key => $value) { 2223 $rows[] = array($key, _sitedoc_handle_data($value)); 2224 } 2225 return theme('table', array(t('Key'), t('Value')), $rows); 2226 } 2227 2228 if (is_object($text)) { 2229 $rows = array(); 2230 // turn it into an array and handle like one. 2231 $data = (array) $text; 2232 foreach ($data as $key => $value) { 2233 $rows[] = array($key, _sitedoc_handle_data($value)); 2234 } 2235 return theme('table', array(t('Method'), t('Value')), $rows); 2236 } 2237 2238 // return gettype($text); 2239 2240 // Hmm, what could it be? 2241 $value = '<strong>'. gettype($array[$name]) .'</strong>'; 2242 drupal_set_message('Tell Nancy I found a '. gettype($array[$name]) .' in the variables.', 'error'); 2243 return t('Unknown data type'); 2244 } 2245 2246 /** 2247 * Produce the site-wide contacts (email) list. 2248 * 2249 * Parameters: 2250 * None 2251 * 2252 * Return: HTML string 2253 */ 2254 function sitedoc_get_contacts() { 2255 $output = NULL; 2256 if (!module_exists('contact')) { 2257 return '<p>Contact'. t(' module not enabled') .'</p>'; 2258 } 2259 $sql = 'SELECT * FROM {contact} c ORDER BY c.selected DESC, c.cid ASC'; 2260 $result = db_query($sql); 2261 $header = array( 2262 array('data' => 'Cid', 'class' => 'sitedoc_right'), 2263 t('Category'), 2264 t('Recipients'), 2265 array('data' => t('Weight'), 'class' => 'sitedoc_right'), 2266 array('data' => t('Selected'), 'align' => 'center'), 2267 ); 2268 $rows = array(); 2269 while ($contact = db_fetch_object($result)) { 2270 $recips = explode(',', $contact->recipients); 2271 if (count($recips) > 1) { 2272 $recip_list = theme('item_list', $recips); 2273 } 2274 else { $recip_list = $contact->recipients; } 2275 $rows[] = array( 2276 array('data' => $contact->cid, 'class' => 'sitedoc_right'), 2277 $contact->category, 2278 $recip_list, 2279 array('data' => $contact->weight, 'class' => 'sitedoc_right'), 2280 array('data' => $contact->selected ? 'yes' : 'no', 'align' => 'center'), 2281 ); 2282 } /* end while role */ 2283 2284 $howmany = count($rows); 2285 if ($howmany > 0) { 2286 drupal_set_message(t('!count Contacts found.', array('!count' => $howmany)), 'status'); 2287 $output = theme('table', $header, $rows); 2288 } 2289 return $output ."\n"; 2290 } 2291 2292 /** 2293 * Produce the user profile fields list. 2294 * 2295 * Parameters: 2296 * string - limits the list to only this category 2297 * 2298 * Return: HTML string 2299 */ 2300 function sitedoc_profile_fields() { 2301 if (!module_exists('profile')) { 2302 return '<p>Profile '. t('module not enabled') .'</p>'; 2303 } 2304 $output = NULL; 2305 2306 // Allow an optional param to limit the display to a specific category. 2307 if (func_num_args() > 0) { 2308 $category = func_get_arg(0); 2309 } 2310 2311 $no_yes = array(t('No'), t('Yes')); 2312 $viz = array(t('Hidden'), t('Private'), t('Profile'), t('Public')); 2313 // This is to save display space. 2314 $short_type = array( 2315 'textfield' => t('Text'), 2316 'textarea' => t('Area'), 2317 'URL' => t('URL'), 2318 'checkbox' => t('Check'), 2319 'selection' => t('select'), 2320 'list' => t('Free'), 2321 'date' => t('Date'), 2322 ); 2323 2324 $header = array( 2325 array('data' => t('Fid'), 'class' => 'sitedoc_right'), 2326 t('Title'), 2327 t('Name'), 2328 t('Explanation'), 2329 t('Page'), 2330 t('Type'), 2331 array('data' => t('Weight'), 'class' => 'sitedoc_right'), 2332 array('data' => t('Visiblity'), 'align' => 'center'), 2333 array('data' => t('Required'), 'align' => 'center'), 2334 array('data' => t('Register'), 'align' => 'center'), 2335 array('data' => t('Auto complete'), 'align' => 'center'), 2336 t('Options'), 2337 ); 2338 if ($category) { 2339 $where = " WHERE p.category='$category'"; 2340 } 2341 else { 2342 $where = ' '; 2343 } 2344 $result = db_query('SELECT * FROM {profile_fields} p'. $where .' ORDER BY p.category, p.weight, p.name'); 2345 $save_cat = ''; 2346 2347 while ($field = db_fetch_object($result)) { 2348 if ($field->category <> $save_cat) { 2349 // Flush previous rows, if any. 2350 if (!empty($save_cat)) { 2351 $output .= theme('table', $header, $rows); 2352 } 2353 $output .= '<h4>'. t('Category: ') . $field->category .'</h4>'; 2354 $save_cat = $field->category; 2355 $rows = array(); 2356 } 2357 $rows[] = array( 2358 array('data' => $field->fid, 'class' => 'sitedoc_right'), 2359 $field->title, 2360 $field->name, 2361 $field->explanation, 2362 $field->page, 2363 $short_type[$field->type], 2364 array('data' => $field->weight, 'class' => 'sitedoc_right'), 2365 array('data' => $viz[$field->visibility], 'align' => 'center'), 2366 array('data' => $no_yes[$field->required], 'align' => 'center'), 2367 array('data' => $no_yes[$field->register], 'align' => 'center'), 2368 array('data' => $no_yes[$field->autocomplete], 'align' => 'center'), 2369 $field->options, 2370 ); 2371 } /* end while field */ 2372 2373 $howmany = count($rows); 2374 drupal_set_message(t('!count Profile fields found.', array('!count' => $howmany)), 'status'); 2375 if ($howmany > 0) { 2376 $output .= theme('table', $header, $rows) ."\n"; 2377 } 2378 return $output; 2379 } 2380 2381 /** 2382 * Produce the URL Alias list and checks for orphans. 2383 * 2384 * Parameters: 2385 * string - limits the list to only this category 2386 * 2387 * Return: HTML string 2388 */ 2389 function sitedoc_url_alias() { 2390 if (!module_exists('path')) { 2391 return '<p>Path '. t('module not enabled') .'</p>'; 2392 } 2393 $output = NULL; 2394 $rows = array(); 2395 $last_src = NULL; 2396 $problems = 0; 2397 // For reverse checking. 2398 $node_alias = array(); 2399 2400 $header = array( 2401 array('data' => t('pid'), 'class' => 'sitedoc_right'), 2402 t('Source'), 2403 t('Destination'), 2404 t('Notes'), 2405 t('Operation'), 2406 ); 2407 $result = db_query('SELECT u.pid, u.src, u.dst FROM {url_alias} u ORDER BY u.src, u.dst'); 2408 2409 while ($path = db_fetch_object($result)) { 2410 $notes = array(); 2411 $ops = array(); 2412 if ($last_src == $path->src) { 2413 $notes[] = t('duplicate source'); 2414 } 2415 else { $last_src = $path->src; } 2416 2417 // Ignore "special" paths. 2418 if (substr($path->src, 0, 1) != '<') { 2419 $p = explode('/', $path->src); 2420 $edit = 'edit'; 2421 // So pseudo HTML shows (like <front>) 2422 $source = check_plain($path->src); 2423 2424 // Check first part of path. 2425 switch ($p[0]) { 2426 2427 case 'node': 2428 // Missing nid? 2429 if (empty($p[1])) { 2430 $notes[] = '<front>?'; 2431 break; 2432 } 2433 $node_exists = db_result(db_query('SELECT COUNT(n.nid) FROM {node} n WHERE n.nid = %d', $p[1])); 2434 if ($node_exists) { 2435 $source = $path->src; 2436 $ops[] = l(t('edit node'), $path->src .'/edit'); 2437 } 2438 else { 2439 $notes[] = '<span class="admin-missing">'. t('missing node') .'</span>'; 2440 $edit = 'delete'; 2441 } 2442 $node_alias[$p[1]] = TRUE; 2443 break; 2444 2445 case 'taxonomy': 2446 $taxo_exists = db_result(db_query('SELECT COUNT(td.name) FROM {term_data} td WHERE td.tid = %d', $p[2])); 2447 if (!$taxo_exists) { 2448 $notes[] = '<span class="admin-missing">'. t('missing taxonomy term') .'</span>'; 2449 } 2450 break; 2451 2452 case 'faq': /* same as taxo/term */ 2453 $taxo_exists = db_result(db_query('SELECT COUNT(td.name) FROM {term_data} td WHERE td.tid = %d', $p[1])); 2454 if (!$taxo_exists) { 2455 $notes[] = '<span class="admin-missing">'. t('missing faq taxonomy term') .'</span>'; 2456 } 2457 break; 2458 2459 case 'user': 2460 $node_exists = db_result(db_query('SELECT COUNT(u.uid) FROM {users} u WHERE u.uid = %d', $p[1])); 2461 if (!$node_exists) { 2462 $notes[] = '<span class="admin-missing">'. t('missing user') .'</span>'; 2463 } 2464 break; 2465 2466 case 'contact': /* nothing to do */ 2467 break; 2468 2469 default: 2470 if (module_exists($p[0])) { 2471 $notes[] = '<span class="admin-enabled">'. t('ask the !name module', array('!name' => $p[0])) .'</span>'; 2472 } 2473 else { 2474 $notes[] = '<span class="admin-missing">'. t('unhandled path type') .'</span>'; 2475 } 2476 2477 } /* end switch $p(0) */ 2478 } /* end if not < */ 2479 2480 $problems += count($notes); 2481 $ops[] = l($edit .' '. t('path'), 'admin/build/path/'. $edit .'/'. $path->pid); 2482 $rows[] = array(array('data' => $path->pid, 'class' => 'sitedoc_right'), 2483 $source, 2484 $path->dst, 2485 implode(', ', $notes), 2486 implode(', ', $ops), 2487 ); 2488 } /* end while path */ 2489 2490 $howmany = count($rows); 2491 if ($howmany > 0) { 2492 $output .= theme('table', $header, $rows); 2493 } 2494 2495 // Now run through the nodes to see if they have an alias. 2496 $rows = array(); 2497 2498 $result = db_query('SELECT n.nid, n.title FROM {node} n ORDER BY n.nid'); 2499 while ($node = db_fetch_object($result)) { 2500 // Does node NOT have an alias? 2501 if (!isset($node_alias[$node->nid])) { 2502 $rows[] = array($node->title, l(t('edit'), 'node/'. $node->nid .'/edit')); 2503 } 2504 } 2505 2506 if (count($rows) > 0) { 2507 $fieldset = array( 2508 '#title' => t('Nodes without URL Alias'), 2509 '#collapsible' => TRUE, 2510 '#collapsed' => count($rows) > 10, 2511 '#value' => theme('table', array(t('Title'), t('Operation')), $rows), 2512 ); 2513 $output .= '<br/>'. theme('fieldset', $fieldset); 2514 } 2515 2516 $msg = t('!count URL Aliases found', array('!count' => $howmany)); 2517 if ($problems) { 2518 $msg .= ' '. t('with !problems notes.', array('!problems' => $problems)) .' '; 2519 } 2520 else { 2521 $msg .= '.'; 2522 } 2523 if (count($rows)) { 2524 $msg .= ' '. t('!count nodes without aliases found.', array('!count' => count($rows))); 2525 } 2526 drupal_set_message($msg, 'status'); 2527 2528 return $output ."\n"; 2529 } 2530 2531 function sitedoc_term_count_nodes($tid = 0, $type = NULL) { 2532 if ($type) { 2533 $count = db_result(db_query(db_rewrite_sql("SELECT COUNT(n.nid) FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE t.tid = %d AND n.status = 1 AND n.type = '%s'"), $tid, $type)); 2534 } 2535 else { 2536 $count = db_result(db_query(db_rewrite_sql('SELECT COUNT(n.nid) FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE t.tid = %d AND n.status = 1'), $tid)); 2537 } 2538 return $count; 2539 } 2540 2541 /* 2542 * This function gets the Input Format and Filter information. 2543 */ 2544 function sitedoc_filters() { 2545 $output = "\n<h2>". t('Filters and Input Formats') .'</h2>'; 2546 $filter_list = array(); 2547 $default_format = variable_get('filter_default_format', 1); 2548 2549 // Find out which modules provide filters. 2550 $filter_modules = module_implements('filter', TRUE); 2551 foreach ($filter_modules as $module) { 2552 $list = module_invoke($module, 'filter', 'list'); 2553 foreach ($list as $delta => $name) { 2554 $filter_list[$module][$delta] = array( 2555 'name' => $name, 2556 'used' => array(), 2557 ); 2558 } 2559 } 2560 2561 $output .= "\n<h4>". t('Input Formats') ."</h4>\n"; 2562 2563 $rows = array(); 2564 $filter_names = array(); 2565 $count = 0; 2566 $output .= "\n<table>\n<tr>\n"; 2567 $output .= "\n<th>". t('Format') .'</th>' 2568 .'<th>'. t('Name') .'</th>' 2569 .'<th>'. t('Roles') .'</th>' 2570 .'<th>'. t('Cache') .'</th>' 2571 .'<th>'. t('Filters') .'</th>' 2572 ."\n</tr>\n"; 2573 2574 // Get Input Formats. 2575 $result = db_query("SELECT * FROM {filter_formats}"); 2576 while ($input = db_fetch_array($result)) { 2577 ++$count; 2578 $output .= "\n".'<tr class="'. ($count % 2 ? 'odd' : 'even') .'">'; 2579 2580 $name = $input['name']; 2581 $format = $input['format']; 2582 $filter_names[$format] = $name; 2583 2584 // Get the list of roles for this filter. 2585 // The roles list always starts and ends with a comma. 2586 $roles = substr($input['roles'], 1, strlen($input['roles']) - 2); 2587 $role_names = array(); 2588 if (empty($roles)) { 2589 $roles = '<em>'. t('None') .'</em>'; 2590 } 2591 else { 2592 // There is no need to look up the default, as all roles get it. 2593 if ($format == $default_format) { 2594 $roles = '<em>'. t('Default') .'</em>'; 2595 } 2596 else { 2597 $r_result = db_query("SELECT name FROM {role} WHERE rid IN (%s)", $roles); 2598 while ($r = db_fetch_array($r_result)) { 2599 if (!in_array($r['name'], $role_names)) { 2600 $role_names[] = $r['name']; 2601 } 2602 } 2603 $roles = theme('item_list', $role_names); 2604 } 2605 } 2606 // Get the filter info. 2607 $f_rows = array(); 2608 $filter_stuff = "\n<table><tr><th>". t('Name (Module, Delta)') .'</th><th>'. 2609 t('No Cache') .'</th><th>'. 2610 t('Weight') .'</th></tr>'; 2611 $f_result = db_query("SELECT * FROM {filters} WHERE format=%d ORDER BY format, weight", $format); 2612 while ($filter = db_fetch_array($f_result)) { 2613 $module = $filter['module']; 2614 $delta = $filter['delta']; 2615 $filter_stuff .= "\n".'<tr>' 2616 .'<td>'. ucwords($filter_list[$module][$delta]['name']) .' ('. ucwords($module) .', '. $delta .')</td>' 2617 .'<td align="center">'. (module_invoke($module, 'filter', 'no cache', $delta, $format) ? 'True' : null) .'</td>' 2618 .'<td align="center">'. $filter['weight'] .'</td>' 2619 .'<tr>'; 2620 $filter_list[$module][$delta]['used'][] = $filter_names[$format]; 2621 } 2622 $filter_stuff .= "</table>\n"; 2623 2624 $cache = $input['cache'] ? _sitedoc_img_ok() : _sitedoc_img_warning(); 2625 2626 $output .= '<td valign="top">'. $format .'</td>' 2627 .'<td valign="top">'. l($name, 'admin/settings/filters/'. $format) .'</td>' 2628 .'<td valign="top">'. $roles .'</td>' 2629 .'<td align="center" valign="top">'. $cache .'</td>' 2630 .'<td valign="top">'. $filter_stuff .'</td>' 2631 ."\n</tr>"; 2632 } 2633 $output .= "\n</table>\n"; 2634 2635 $output .= "\n<h4>". t('Available Filters') ."</h4>\n"; 2636 2637 // Show usage info. 2638 $list_rows = array(); 2639 foreach ($filter_list as $module => $deltas) { 2640 $descs = "\n<table>"; 2641 foreach ($deltas as $delta => $values) { 2642 $name = ucwords($values['name']); 2643 $descs .= "\n".'<tr><td align="center">'. $delta .'</td><td width="100">'. $name .'</td><td>'. $values['desc'] .'</td></tr>'; 2644 } 2645 $descs .= '</table>'; 2646 $used = $filter_list[$module][$delta]['used']; 2647 $list_rows[] = array(ucwords($module), $descs, 2648 count(used) ? implode(', ', $used) : t('None'), 2649 ); 2650 } 2651 $output .= theme('table', array(t('Module'), t('Provides'), t('Used In')), $list_rows); 2652 2653 return $output; 2654 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |