| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: devel.module,v 1.258.2.87 2010/12/01 23:42:15 salvis Exp $ 3 4 // This module holds functions useful for Drupal development. 5 // Please contribute! 6 7 // Suggested profiling and stacktrace library from http://www.xdebug.org/index.php 8 9 define('DEVEL_QUERY_SORT_BY_SOURCE', 0); 10 define('DEVEL_QUERY_SORT_BY_DURATION', 1); 11 12 define('DEVEL_ERROR_HANDLER_NONE', 0); 13 define('DEVEL_ERROR_HANDLER_STANDARD', 1); 14 define('DEVEL_ERROR_HANDLER_BACKTRACE', 2); 15 16 define('DEVEL_MIN_TEXTAREA', 50); 17 18 /** 19 * Implementation of hook_help(). 20 */ 21 function devel_help($section) { 22 switch ($section) { 23 case 'devel/reference': 24 return '<p>'. t('This is a list of defined user functions that generated this current request lifecycle. Click on a function name to view its documention.') .'</p>'; 25 case 'devel/session': 26 return '<p>'. t('Here are the contents of your <code>$_SESSION</code> variable.') .'</p>'; 27 case 'devel/variable': 28 $api = variable_get('devel_api_url', 'api.drupal.org'); 29 return '<p>'. t('This is a list of the variables and their values currently stored in variables table and the <code>$conf</code> array of your settings.php file. These variables are usually accessed with <a href="@variable-get-doc">variable_get()</a> and <a href="@variable-set-doc">variable_set()</a>. Variables that are too long can slow down your pages.', array('@variable-get-doc' => "http://$api/api/HEAD/function/variable_get", '@variable-set-doc' => "http://$api/api/HEAD/function/variable_set")) .'</p>'; 30 } 31 } 32 33 /** 34 * Implementation of hook_menu(). 35 */ 36 function devel_menu() { 37 $items = array(); 38 // note: we can't dynamically append destination to querystring. do so at theme layer. fix in D7? 39 $items['devel/cache/clear'] = array( 40 'title' => 'Empty cache', 41 'page callback' => 'devel_cache_clear', 42 'description' => 'Clear the CSS cache and all database cache tables which store page, node, theme and variable caches.', 43 'access arguments' => array('access devel information'), 44 'menu_name' => 'devel', 45 ); 46 47 $items['devel/queries'] = array( 48 'title' => 'Database queries', 49 'page callback' => 'devel_queries', 50 'access callback' => 'devel_menu_access_store_queries', 51 'access arguments' => array(), 52 'menu_name' => 'devel', 53 ); 54 $items['devel/queries/empty'] = array( 55 'title' => 'Empty database queries', 56 'page callback' => 'devel_queries_empty', 57 'access callback' => 'devel_menu_access_store_queries', 58 'access arguments' => array(), 59 'menu_name' => 'devel', 60 ); 61 $items['devel/reference'] = array( 62 'title' => 'Function reference', 63 'description' => 'View a list of currently defined user functions with documentation links.', 64 'page callback' => 'devel_function_reference', 65 'access arguments' => array('access devel information'), 66 'menu_name' => 'devel', 67 ); 68 $items['devel/reinstall'] = array( 69 'title' => 'Reinstall modules', 70 'page callback' => 'drupal_get_form', 71 'page arguments' => array('devel_reinstall'), 72 'description' => 'Run hook_uninstall() and then hook_install() for a given module.', 73 'access arguments' => array('access devel information'), 74 'menu_name' => 'devel', 75 ); 76 $items['devel/source'] = array( 77 'title' => 'Display the PHP code of any file in your Drupal installation', 78 'page callback' => 'devel_display_source', 79 'access arguments' => array('display source code'), 80 'type' => MENU_CALLBACK, 81 'menu_name' => 'devel', 82 ); 83 $items['devel/menu/reset'] = array( 84 'title' => 'Rebuild menus', 85 'description' => 'Rebuild menu based on hook_menu() and revert any custom changes. All menu items return to their default settings.', 86 'page callback' => 'drupal_get_form', 87 'page arguments' => array('devel_menu_rebuild'), 88 'access arguments' => array('access devel information'), 89 'menu_name' => 'devel', 90 ); 91 $items['devel/variable'] = array( 92 'title' => 'Variable editor', 93 'description' => 'Edit and delete site variables.', 94 'page callback' => 'devel_variable_page', 95 'access arguments' => array('access devel information'), 96 'menu_name' => 'devel', 97 ); 98 // we don't want the abbreviated version provided by status report 99 $items['devel/phpinfo'] = array( 100 'title' => 'PHPinfo()', 101 'description' => 'View your server\'s PHP configuration', 102 'page callback' => 'devel_phpinfo', 103 'access arguments' => array('access devel information'), 104 'menu_name' => 'devel', 105 ); 106 $items['devel/php'] = array( 107 'title' => 'Execute PHP Code', 108 'description' => 'Execute some PHP code', 109 'page callback' => 'drupal_get_form', 110 'page arguments' => array('devel_execute_form'), 111 'access arguments' => array('execute php code'), 112 'menu_name' => 'devel', 113 ); 114 $items['devel/elements'] = array( 115 'title' => 'Hook_elements()', 116 'description' => 'View the active form/render elements for this site.', 117 'page callback' => 'devel_elements_page', 118 'access arguments' => array('access devel information'), 119 'menu_name' => 'devel', 120 ); 121 $items['devel/variable/edit/%'] = array( 122 'title' => 'Variable editor', 123 'page callback' => 'drupal_get_form', 124 'page arguments' => array('devel_variable_edit', 3), 125 'access arguments' => array('access devel information'), 126 'type' => MENU_CALLBACK, 127 'menu_name' => 'devel', 128 ); 129 $items['devel/session'] = array( 130 'title' => 'Session viewer', 131 'description' => 'List the contents of $_SESSION.', 132 'page callback' => 'devel_session', 133 'access arguments' => array('access devel information'), 134 'menu_name' => 'devel', 135 ); 136 $items['devel/switch'] = array( 137 'title' => 'Switch user', 138 'page callback' => 'devel_switch_user', 139 'access arguments' => array('switch users'), 140 'type' => MENU_CALLBACK, 141 'menu_name' => 'devel', 142 ); 143 $items['admin/settings/devel'] = array( 144 'title' => 'Devel settings', 145 'description' => 'Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the <a href="/admin/build/block">block administration</a> page.', 146 'page callback' => 'drupal_get_form', 147 'page arguments' => array('devel_admin_settings'), 148 'access arguments' => array('administer site configuration'), 149 'menu_name' => 'devel', 150 ); 151 $items['node/%node/devel'] = array( 152 'title' => 'Devel', 153 'page callback' => 'devel_load_object', 154 'page arguments' => array(1, 'node'), 155 'access callback' => 'user_access', 156 'access arguments' => array('access devel information'), 157 'type' => MENU_LOCAL_TASK, 158 'weight' => 100, 159 ); 160 $items['node/%node/devel/load'] = array( 161 'title' => 'Dev load', 162 'page callback' => 'devel_load_object', 163 'page arguments' => array(1, 'node'), 164 'access callback' => 'user_access', 165 'access arguments' => array('access devel information'), 166 'type' => MENU_DEFAULT_LOCAL_TASK, 167 'weight' => 0, 168 ); 169 $items['node/%node/devel/render'] = array( 170 'title' => 'Dev render', 171 'page callback' => 'devel_render_object', 172 'page arguments' => array('node', 1), 173 'access callback' => 'user_access', 174 'access arguments' => array('access devel information'), 175 'type' => MENU_LOCAL_TASK, 176 'weight' => 10, 177 ); 178 $items['user/%user/devel'] = array( 179 'title' => 'Devel', 180 'page callback' => 'devel_load_object', 181 'page arguments' => array(1, 'user'), 182 'access callback' => 'user_access', 183 'access arguments' => array('access devel information'), 184 'type' => MENU_LOCAL_TASK, 185 'weight' => 100, 186 ); 187 $items['user/%user/devel/load'] = array( 188 'title' => 'Dev load', 189 'page callback' => 'devel_load_object', 190 'page arguments' => array(1, 'user'), 191 'access callback' => 'user_access', 192 'access arguments' => array('access devel information'), 193 'type' => MENU_DEFAULT_LOCAL_TASK, 194 'weight' => 0, 195 ); 196 $items['user/%user/devel/render'] = array( 197 'title' => 'Dev render', 198 'page callback' => 'devel_render_object', 199 'page arguments' => array('user', 1), 200 'access callback' => 'user_access', 201 'access arguments' => array('access devel information'), 202 'type' => MENU_LOCAL_TASK, 203 'weight' => 10, 204 ); 205 $items['devel/theme/registry'] = array( 206 'title' => 'Theme registry', 207 'description' => 'View a list of available theme functions across the whole site.', 208 'page callback' => 'devel_theme_registry', 209 'access arguments' => array('access devel information'), 210 'menu_name' => 'devel', 211 ); 212 213 return $items; 214 } 215 216 function devel_menu_need_destination() { 217 return array('devel/cache/clear', 'devel/reinstall', 'devel/menu/reset', 'admin/og/og', 'devel/variable', 'admin/reports/status/run-cron'); 218 } 219 220 /** 221 * An implementation of hook_menu_link_alter(). Flag this link as needing alter at display time. 222 * This is more robust that setting alter in hook_menu(). See devel_translated_menu_link_alter(). 223 * 224 **/ 225 function devel_menu_link_alter(&$item, $menu) { 226 if (in_array($item['link_path'], devel_menu_need_destination())) { 227 $item['options']['alter'] = TRUE; 228 } 229 } 230 231 /** 232 * An implementation of hook_translated_menu_item_alter(). Append dynamic 233 * querystring 'destination' to several of our own menu items. 234 * 235 **/ 236 function devel_translated_menu_link_alter(&$item) { 237 if (in_array($item['href'], devel_menu_need_destination())) { 238 $item['localized_options']['query'] = drupal_get_destination(); 239 } 240 } 241 242 function devel_menu_access_store_queries() { 243 return user_access('access devel information') && variable_get('devel_store_queries', 0); 244 } 245 246 /** 247 * Implementation of hook_theme() 248 */ 249 function devel_theme() { // &$cache, $type, $theme, $path 250 return array( 251 'devel_variable_form' => array( 252 'arguments' => array('form' => NULL) 253 ), 254 'devel_querylog' => array( 255 'arguments' => array('header' => array(), 'rows' => array()), 256 ), 257 'devel_querylog_row' => array( 258 'arguments' => array('row' => array()), 259 ), 260 ); 261 } 262 263 /** 264 * Page callback to display syntax hilighted source code 265 * 266 * note: the path for this function is received via $_GET['path'] 267 * example http://www.example.com/devel/source?file=modules/node/node.module 268 * 269 * @param $standalone 270 * Set to FALSE to place the code inside a Drupal page. Otherwise code displays on its own. 271 */ 272 function devel_display_source($standalone = TRUE) { 273 $path = $_GET['file']; 274 // take out the nasties 275 $path = str_replace('../', '', $path); 276 $output = devel_highlight_file($path, $standalone); 277 if ($output) { 278 if ($standalone) { 279 print $output; 280 exit(); 281 } 282 return $output; 283 } 284 else { 285 drupal_set_message(t('Invalid file path'), 'error'); 286 drupal_not_found(); 287 } 288 } 289 290 /** 291 * Return PHP highlighted file 292 * 293 * @param $path 294 * path to the file 295 * *warning* there is NO VALIDATION in this function 296 * Beware of paths such as '../../../../../etc/apache/httpd.conf' 297 * 298 * @param $standalone 299 * should the returned HTML be wrapped in a full <html> page or will it be output by Drupal? 300 */ 301 function devel_highlight_file($path = NULL, $standalone = FALSE) { 302 if (file_exists($path)) { 303 $source = highlight_file($path, TRUE); 304 // add anchor links before all functions so that we can link to a function within the source 305 // ** commented out because regexes aren't working ** 306 //$source = preg_replace('!(\/\*\*.*?\*\/.*?)<br.*?function.*?#0000BB">(.*?)<\/span>!', '<a id="$2"></a> $0', $source); 307 //$source = preg_replace('!(\/\*\*.*?\*\/).*?function.*?#0000BB">(.*?)<\/span>!', '<a id="$2"></a> $0', $source); 308 if ($standalone) { 309 $source = <<<EOT 310 <head><title>$path</title></head> 311 <body>$source</body> 312 EOT; 313 } 314 return $source; 315 } 316 else { 317 return FALSE; 318 } 319 } 320 321 /** 322 * Implementation of hook_init(). 323 */ 324 function devel_init() { 325 if (!devel_silent()) { 326 if (user_access('access devel information')) { 327 devel_set_handler(variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD)); 328 // We want to include the class early so that anyone may call krumo() as needed. See http://krumo.sourceforge.net/ 329 has_krumo(); 330 331 // See http://www.firephp.org/. 332 // Support Libraries API - http://drupal.org/project/libraries 333 if (module_exists('libraries')) { 334 $firephp_path = libraries_get_path('FirePHPCore') . '/lib/FirePHPCore/'; 335 $chromephp_path = libraries_get_path('chromephp'); 336 } 337 else { 338 $firephp_path = './'. drupal_get_path('module', 'devel') .'/FirePHPCore/lib/FirePHPCore/'; 339 $chromephp_path = './' . drupal_get_path('module', 'devel') .'/chromephp'; 340 } 341 // include FirePHP if exists... 342 if (file_exists($firephp_path .'fb.php')) { 343 include_once $firephp_path .'fb.php'; 344 include_once $firephp_path .'FirePHP.class.php'; 345 } 346 347 // include ChromePHP if exists... 348 if (file_exists($chromephp_path . '/ChromePhp.php')) { 349 include_once $chromephp_path . '/ChromePhp.php'; 350 } 351 352 // Add CSS for query log if should be displayed. 353 if (variable_get('devel_query_display', 0)) { 354 drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css'); 355 } 356 } 357 } 358 if (variable_get('devel_rebuild_theme_registry', FALSE)) { 359 drupal_rebuild_theme_registry(); 360 if (flood_is_allowed('devel_rebuild_registry_warning', 1)) { 361 flood_register_event('devel_rebuild_registry_warning'); 362 if (!devel_silent() && user_access('access devel information')) { 363 drupal_set_message(t('The theme registry is being rebuilt on every request. Remember to <a href="!url">turn off</a> this feature on production websites.', array("!url" => url('admin/settings/devel')))); 364 } 365 } 366 } 367 } 368 369 // return boolean. no need for cache here. 370 function has_krumo() { 371 // see README.txt or just download from http://krumo.sourceforge.net/ 372 @include_once './'. drupal_get_path('module', 'devel') .'/krumo/class.krumo.php'; 373 if (function_exists('krumo') && php_sapi_name() != 'cli') { 374 return TRUE; 375 } 376 else { 377 return FALSE; 378 } 379 } 380 381 /** 382 * Decide whether or not to print a debug variable using krumo(). 383 * 384 * @param $input 385 * @return boolean 386 */ 387 function merits_krumo($input) { 388 return (is_object($input) || is_array($input)) && has_krumo() && variable_get('devel_krumo_skin', '') != 'disabled'; 389 } 390 391 /** 392 * Calls the http://www.firephp.org/ fb() function if it is found. 393 * 394 * @return void 395 */ 396 function dfb() { 397 if (function_exists('fb') && user_access('access devel information')) { 398 $args = func_get_args(); 399 call_user_func_array('fb', $args); 400 } 401 } 402 403 /** 404 * Calls dfb() to output a backtrace. 405 */ 406 function dfbt($label) { 407 dfb($label, FirePHP::TRACE); 408 } 409 410 function dcp() { 411 if (class_exists('ChromePhp') && user_access('access devel information')) { 412 $args = func_get_args(); 413 call_user_func_array(array('ChromePhp', 'log'), $args); 414 } 415 } 416 417 /** 418 * Implements hook_watchdog(). 419 */ 420 function devel_watchdog($log_entry) { 421 if (class_exists('FirePHP')) { 422 switch ($log_entry['severity']) { 423 case WATCHDOG_EMERG: 424 case WATCHDOG_ALERT: 425 case WATCHDOG_CRITICAL: 426 case WATCHDOG_ERROR: 427 $type = FirePHP::ERROR; 428 break; 429 case WATCHDOG_WARNING: 430 $type = FirePHP::WARN; 431 break; 432 case WATCHDOG_NOTICE: 433 case WATCHDOG_INFO: 434 $type = FirePHP::INFO; 435 break; 436 case WATCHDOG_DEBUG: 437 DEFAULT: 438 $type = FirePHP::LOG; 439 } 440 } 441 else { 442 $type = 'watchdog'; 443 } 444 $watchdog = array( 445 'type' => $log_entry['type'], 446 'message' => decode_entities(strtr($log_entry['message'], (array)$log_entry['variables'])), 447 ); 448 if (isset($log_entry['link'])) { 449 $watchdog['link'] = $log_entry['link']; 450 } 451 dfb($watchdog, $type); 452 } 453 454 function devel_set_handler($handler) { 455 switch ($handler) { 456 case DEVEL_ERROR_HANDLER_STANDARD: 457 // do nothing 458 break; 459 case DEVEL_ERROR_HANDLER_BACKTRACE: 460 if (has_krumo()) { 461 set_error_handler('backtrace_error_handler'); 462 } 463 break; 464 case DEVEL_ERROR_HANDLER_NONE: 465 restore_error_handler(); 466 break; 467 } 468 } 469 470 471 function devel_silent() { 472 // isset($_GET['q']) is needed on IIS when calling the front page. q is not set. 473 // Don't interfere with private files/images. 474 return 475 devel_verify_cli() || 476 isset($GLOBALS['devel_shutdown']) || 477 strstr($_SERVER['PHP_SELF'], 'update.php') || 478 (isset($_GET['q']) && ( 479 in_array($_GET['q'], array('upload/js', 'admin/content/node-settings/rebuild')) || 480 substr($_GET['q'], 0, strlen('system/files')) == 'system/files' || 481 substr($_GET['q'], 0, strlen('batch')) == 'batch') 482 ); 483 } 484 485 function devel_xhprof_enable() { 486 if (extension_loaded('xhprof') && variable_get('devel_xhprof_enabled', FALSE)) { 487 if ($path = variable_get('devel_xhprof_directory', '')) { 488 include_once $path . '/xhprof_lib/utils/xhprof_lib.php'; 489 include_once $path . '/xhprof_lib/utils/xhprof_runs.php'; 490 // @todo: consider a variable per-flag instead. 491 xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY); 492 493 register_shutdown_function('devel_shutdown_xhprof_drush'); 494 } 495 } 496 } 497 498 499 /** 500 * Implementation of hook_boot(). Runs even for cached pages. 501 */ 502 function devel_boot() { 503 // Initialize XHProf. 504 devel_xhprof_enable(); 505 506 if (!devel_silent()) { 507 devel_start(); 508 } 509 } 510 511 // kickoff all our tricks. put here all code which must run for ached pages too. called from both hook_boot and hook_init. 512 function devel_start() { 513 if (variable_get('dev_mem', 0) && function_exists('memory_get_usage')) { 514 global $memory_init; 515 $memory_init = memory_get_usage(); 516 } 517 518 // we need user_access() in the shutdown function. make sure it gets loaded 519 drupal_load('module', 'user'); 520 register_shutdown_function('devel_shutdown'); 521 } 522 523 function backtrace_error_handler($errno, $message, $filename, $line) { 524 // Don't respond to the error if it was suppressed with a '@' 525 if (error_reporting() == 0) { 526 return; 527 } 528 if ($errno & (E_ALL ^ E_DEPRECATED)) { 529 // We can't use the PHP E_* constants here as not all versions of PHP have all 530 // the constants defined, so for consistency, we just use the numeric equivelant. 531 $types = array( 532 1 => 'error', 533 2 => 'warning', 534 4 => 'parse error', 535 8 => 'notice', 536 16 => 'core error', 537 32 => 'core warning', 538 64 => 'compile error', 539 128 => 'compile warning', 540 256 => 'user error', 541 512 => 'user warning', 542 1024 => 'user notice', 543 2048 => 'strict warning', 544 4096 => 'recoverable error', 545 8192 => 'deprecated', 546 16384 => 'user deprecated', 547 ); 548 $type = $types[$errno]; 549 $backtrace = debug_backtrace(); 550 array_shift($backtrace); 551 $variables = array('%error' => $type, '%message' => $message, '%function' => $backtrace[0]['function'] .'()', '%file' => $filename, '%line' => $line); 552 $counter = 0; 553 554 if (variable_get('error_level', 1) == 1) { 555 foreach ($backtrace as $call) { 556 $nicetrace[$call['function'] .'<span class="'. $counter++ .'" />'] = $call; 557 } 558 print t('%error: %message in %function (line %line of %file).', $variables) ." =>\n"; 559 krumo($nicetrace); 560 } 561 562 watchdog('php', '%error: %message in %function (line %line of %file).', $variables, WATCHDOG_ERROR); 563 } 564 } 565 566 /** 567 * Implementation of hook_perm(). 568 */ 569 function devel_perm() { 570 return array('access devel information', 'execute php code', 'switch users', 'display source code'); 571 } 572 573 /** 574 * Implementation of hook_block(). 575 */ 576 function devel_block($op = 'list', $delta = 0, $edit = array()) { 577 if ($op == 'list') { 578 $blocks[0]['info'] = t('Switch user'); 579 // $blocks[1]['info'] = t('Devel'); 580 $blocks[2] = array( 581 'info' => t('Execute PHP'), 582 'visibility' => 0, 583 'pages' => 'devel/php', 584 ); 585 return $blocks; 586 } 587 elseif ($op == 'configure' && $delta == 0) { 588 $form['list_size'] = array( 589 '#type' => 'textfield', 590 '#title' => t('Number of users to display in the list'), 591 '#default_value' => variable_get('devel_switch_user_list_size', 10), 592 '#size' => '3', 593 '#maxlength' => '4', 594 ); 595 $form['show_form'] = array( 596 '#type' => 'checkbox', 597 '#title' => t('Allow entering any user name'), 598 '#default_value' => variable_get('devel_switch_user_show_form', TRUE), 599 ); 600 return $form; 601 } 602 elseif ($op == 'save' && $delta == 0) { 603 variable_set('devel_switch_user_list_size', $edit['list_size']); 604 variable_set('devel_switch_user_show_form', $edit['show_form']); 605 } 606 elseif ($op == 'view') { 607 $block = array(); 608 switch ($delta) { 609 case 0: 610 $block = devel_block_switch_user(); 611 break; 612 case 1: 613 // Deleted in favor of custom menu. do not reuse this index. 614 break; 615 case 2: 616 if (user_access('execute php code')) { 617 $block['content'] = drupal_get_form('devel_execute_block_form'); 618 } 619 break; 620 } 621 return $block; 622 } 623 } 624 625 function devel_block_switch_user() { 626 $links = devel_switch_user_list(); 627 if (!empty($links) || user_access('switch users')) { 628 $block['subject'] = t('Switch user'); 629 $block['content'] = theme('links', $links); 630 if (variable_get('devel_switch_user_show_form', TRUE)) { 631 $block['content'] .= drupal_get_form('devel_switch_user_form'); 632 } 633 return $block; 634 } 635 } 636 637 function devel_switch_user_list() { 638 $links = array(); 639 if (user_access('switch users')) { 640 $list_size = variable_get('devel_switch_user_list_size', 10); 641 $dest = drupal_get_destination(); 642 // Try to find at least $list_size users that can switch. 643 // Inactive users are omitted from all of the following db selects. 644 $roles = user_roles(TRUE, 'switch users'); 645 if (isset($roles[DRUPAL_AUTHENTICATED_RID])) { 646 // If authenticated users have this permission, just grab 647 // the last $list_size users, since there won't be records in 648 // {user_roles} and every user on the system can switch. 649 $accounts = db_query_range("SELECT DISTINCT u.uid, u.name, u.access FROM {users} u WHERE u.uid > 0 AND u.status > 0 ORDER BY u.access DESC", 0, $list_size); 650 } 651 else { 652 $where = array('u.uid = 1'); 653 if (count($roles)) { 654 $where[] = 'r.rid IN ('. implode(',', array_keys($roles)) .')'; 655 } 656 $where_sql = implode(' OR ', $where); 657 $accounts = db_query_range("SELECT DISTINCT u.uid, u.name, u.access FROM {users} u LEFT JOIN {users_roles} r ON u.uid = r.uid WHERE ($where_sql) AND u.status > 0 ORDER BY u.access DESC", 0, $list_size); 658 } 659 while ($account = db_fetch_object($accounts)) { 660 $links[$account->uid] = array( 661 'title' => theme('placeholder', $account->name), 662 'href' => 'devel/switch/'. $account->name, 663 'query' => $dest, 664 'attributes' => array('title' => t('This user can switch back.')), 665 'html' => TRUE, 666 'last_access' => $account->access, 667 ); 668 } 669 $num_links = count($links); 670 if ($num_links < $list_size) { 671 // If we don't have enough, add distinct uids until we hit $list_size. 672 $accounts = db_query_range('SELECT uid, name, access FROM {users} WHERE uid > 0 AND uid NOT IN ('. implode(',', array_keys($links)) .') AND status > 0 ORDER BY access DESC', 0, $list_size - $num_links); 673 while ($account = db_fetch_object($accounts)) { 674 $links[$account->uid] = array( 675 'title' => $account->name ? $account->name : 'anon', 676 'href' => 'devel/switch/'. $account->name, 677 'query' => $dest, 678 'attributes' => array('title' => t('Caution: this user will be unable to switch back.')), 679 'last_access' => $account->access, 680 ); 681 } 682 uasort($links, '_devel_switch_user_list_cmp'); 683 } 684 } 685 return $links; 686 } 687 688 /** 689 * Comparison helper function for uasort() in devel_switch_user_list(). 690 * 691 * Sorts the Switch User links by the user's last access timestamp. 692 */ 693 function _devel_switch_user_list_cmp($a, $b) { 694 return $b['last_access'] - $a['last_access']; 695 } 696 697 function devel_phpinfo() { 698 print phpinfo(); 699 exit; 700 } 701 702 function devel_switch_user_form() { 703 $form['username'] = array( 704 '#type' => 'textfield', 705 '#description' => t('Enter username'), 706 '#autocomplete_path' => 'user/autocomplete', 707 '#maxlength' => USERNAME_MAX_LENGTH, 708 '#size' => 16, 709 ); 710 $form['submit'] = array( 711 '#type' => 'submit', 712 '#value' => t('Switch'), 713 ); 714 return $form; 715 716 } 717 718 function devel_doc_function_form() { 719 $version = devel_get_core_version(VERSION); 720 $form['function'] = array( 721 '#type' => 'textfield', 722 '#description' => t('Enter function name for api lookup'), 723 '#size' => 16, 724 '#maxlength' => 255, 725 ); 726 $form['version'] = array('#type' => 'value', '#value' => $version); 727 $form['submit_button'] = array( 728 '#type' => 'submit', 729 '#value' => t('Submit'), 730 ); 731 return $form; 732 } 733 734 function devel_doc_function_form_submit($form, &$form_state) { 735 $version = $form_state['values']['version']; 736 $function = $form_state['values']['function']; 737 $api = variable_get('devel_api_url', 'api.drupal.org'); 738 $form_state['redirect'] = "http://$api/api/function/$function/$version"; 739 } 740 741 function devel_switch_user_form_validate($form, &$form_state) { 742 if (!$account = user_load(array('name' => $form_state['values']['username']))) { 743 form_set_error('username', t('Username not found')); 744 } 745 } 746 747 function devel_switch_user_form_submit($form, &$form_state) { 748 $form_state['redirect'] = 'devel/switch/'. $form_state['values']['username']; 749 } 750 751 function devel_exit($destination = NULL) { 752 global $user; 753 754 if (isset($destination) && !devel_silent()) { 755 // The page we are leaving is a drupal_goto(). Present a redirection page 756 // so that the developer can see the intermediate query log. 757 // We don't want to load user module here, so keep function_exists() call. 758 if (isset($user) && function_exists('user_access') && user_access('access devel information') && variable_get('devel_redirect_page', 0)) { 759 $output = t_safe('<p>The user is being redirected to <a href="@destination">@destination</a>.</p>', array('@destination' => $destination)); 760 print theme('page', $output); 761 762 // Don't allow the automatic redirect to happen. 763 drupal_page_footer(); 764 exit(); 765 } 766 else { 767 $GLOBALS['devel_redirecting'] = TRUE; 768 } 769 } 770 } 771 772 // Borrowed from Drupal 7 - drupal_is_cli(). 773 function devel_verify_cli() { 774 return ((!isset($_SERVER['SERVER_SOFTWARE']) || $_SERVER['SERVER_SOFTWARE'] == 'PHP CLI') 775 && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0))); 776 } 777 778 779 /** 780 * See devel_start() which registers this function as a shutdown function. 781 */ 782 function devel_shutdown() { 783 // Register the real shutdown function so it runs later than other shutdown functions. 784 register_shutdown_function('devel_shutdown_real'); 785 } 786 787 /** 788 * Log URL to Drush log if this is a drush request. 789 * 790 * This shutdown function is registered by devel_xhprof_enable() 791 */ 792 function devel_shutdown_xhprof_drush() { 793 global $devel_run_id; 794 $devel_run_id = variable_get('devel_xhprof_enabled', FALSE) ? devel_shutdown_xhprof(): NULL; 795 if ($devel_run_id && function_exists('drush_log')) { 796 drush_log('xhprof link: ' . devel_xhprof_link($devel_run_id, 'url'), 'notice'); 797 } 798 } 799 800 /** 801 * See devel_shutdown() which registers this function as a shutdown function. Displays developer information in the footer. 802 */ 803 function devel_shutdown_real() { 804 global $queries, $memory_init, $user; 805 $output = $txt = ''; 806 807 // Set $GLOBALS['devel_shutdown'] = FALSE in order to supress the 808 // devel footer for a page. Not necessary if your page outputs any 809 // of the Content-type http headers tested below (e.g. text/xml, 810 // text/javascript, etc). This is is advised where applicable. 811 if (!isset($GLOBALS['devel_shutdown']) && !isset($GLOBALS['devel_redirecting'])) { 812 // Try not to break non html pages. 813 if (function_exists('drupal_get_headers')) { 814 $headers = drupal_get_headers(); 815 $formats = array('xml', 'javascript', 'json', 'plain', 'image', 'application', 'csv', 'x-comma-separated-values'); 816 foreach ($formats as $format) { 817 if (strstr($headers, $format)) { 818 return; 819 } 820 } 821 } 822 823 if (isset($user) && user_access('access devel information')) { 824 list($counts, $query_summary) = devel_query_summary(); 825 // Query log off, timer on. 826 if (!variable_get('devel_query_display', 0) && variable_get('dev_timer', 0)) { 827 $output .= '<div class="dev-timer">'. devel_timer() .' '. $query_summary .'</div>'; 828 } 829 830 // Query log on. 831 $sum = 0; 832 if (variable_get('devel_query_display', FALSE)) { 833 $output .= '<div class="dev-query">'; 834 $output .= $query_summary; 835 // calling theme() during shutdown is very bad if registry gets rebuilt like when making a change on admin/build/modules 836 // so we check for presence of theme registry before calling theme() 837 if (function_exists('theme_get_registry') && theme_get_registry()) { 838 $txt = t_safe(' Queries taking longer than @threshold ms and queries executed more than once, are <span class="marker">highlighted</span>.', array('@threshold' => variable_get('devel_execution', 5))); 839 if (variable_get('dev_timer', 0)) { 840 $txt .= devel_timer(); 841 } 842 $output .= $txt; 843 $output .= '</div>'; 844 $output .= devel_query_table($queries, $counts); 845 } 846 else { 847 $output .= $txt; 848 $output .= '</div>'; 849 ob_start(); 850 dprint_r($queries); 851 $output .= ob_get_clean(); 852 } 853 } 854 855 if (variable_get('dev_mem', FALSE) && function_exists('memory_get_usage')) { 856 $memory_shutdown = memory_get_usage(); 857 $args = array('@memory_init' => round($memory_init / 1024 / 1024, 2), '@memory_shutdown' => round($memory_shutdown / 1024 / 1024, 2)); 858 $msg = '<div class="dev-memory-usage"><h3>Memory usage:</h3> Memory used at: devel_init()=<strong>@memory_init</strong> MB, devel_shutdown()=<strong>@memory_shutdown</strong> MB.</div>'; 859 // theme() may not be available. not t() either. 860 $output .= t_safe($msg, $args); 861 } 862 863 $output .= devel_xhprof_link_show(); 864 865 // TODO: gzip this text if we are sending a gzip page. see drupal_page_header(). 866 } 867 868 if ($output) { 869 print $output; 870 } 871 } 872 devel_store_queries(); 873 } 874 875 function devel_shutdown_xhprof() { 876 $namespace = variable_get('site_name', ''); // namespace for your application 877 $xhprof_data = xhprof_disable(); 878 $xhprof_runs = new XHProfRuns_Default(); 879 return $xhprof_runs->save_run($xhprof_data, $namespace); 880 } 881 882 883 function devel_store_queries() { 884 if (variable_get('devel_store_queries', 0) && rand(1, variable_get('devel_store_random', 1)) == 1) { 885 global $active_db, $queries, $db_type; 886 887 $qids = array(); 888 $values = array(); 889 $fields = array(); 890 // We need this for the devel_queries insert below. 891 setlocale(LC_NUMERIC, 'C'); 892 foreach ($queries as $value) { 893 list($function, $query) = explode("\n", $value[0]); 894 $query = preg_replace(array("/'.*'/s", "/\d.*\.\d.*/", "/\d.*/"), array("S", "F", "D"), $query); 895 $hash = md5($function . $query); 896 if (!isset($qids[$hash])) { 897 $qids[$hash] = db_result(devel_db_query("SELECT qid FROM {devel_queries} WHERE hash = '%s'", $hash)); 898 if (!$qids[$hash]) { 899 devel_db_query("INSERT INTO {devel_queries} (query, function, hash) VALUES ('%s', '%s', '%s')", $query, $function, $hash); 900 $qids[$hash] = db_last_insert_id('devel_queries', 'qid'); 901 } 902 } 903 $fields[] = "(%d, '%f')"; 904 $values[] = $qids[$hash]; 905 $values[] = $value[1]; 906 } 907 if (count($fields)) { 908 devel_db_query('INSERT INTO {devel_times} (qid, time) VALUES '. implode(',', $fields), $values); 909 } 910 } 911 } 912 913 function devel_query_summary() { 914 global $queries; 915 if (variable_get('dev_query', FALSE) && is_array($queries)) { 916 $sum = 0; 917 foreach ($queries as $query) { 918 $text[] = $query[0]; 919 $sum += $query[1]; 920 } 921 $counts = array_count_values($text); 922 return array($counts, t_safe('Executed @queries queries in @time milliseconds.', array('@queries' => count($queries), '@time' => round($sum * 1000, 2)))); 923 } 924 } 925 926 function t_safe($string, $args) { 927 // get_t caused problems here with theme registry after changing on admin/build/modules. the theme_get_registry call is needed. 928 if (function_exists('t') && function_exists('theme_get_registry')) { 929 theme_get_registry(); 930 return t($string, $args); 931 } 932 else { 933 strtr($string, $args); 934 } 935 } 936 937 /** 938 * Returns a list of all currently defined user functions in the current 939 * request lifecycle, with links their documentation. 940 */ 941 function devel_function_reference() { 942 $functions = get_defined_functions(); 943 $version = devel_get_core_version(VERSION); 944 $ufunctions = $functions['user']; 945 sort($ufunctions); 946 $api = variable_get('devel_api_url', 'api.drupal.org'); 947 foreach ($ufunctions as $function) { 948 $links[] = l($function, "http://$api/api/function/$function/$version"); 949 } 950 return theme('item_list', $links); 951 } 952 953 function devel_get_core_version($version) { 954 $version_parts = explode('.', $version); 955 // Map from 4.7.10 -> 4.7 956 if ($version_parts[0] < 5) { 957 return $version_parts[0] .'.'. $version_parts[1]; 958 } 959 // Map from 5.5 -> 5 or 6.0-beta2 -> 6 960 else { 961 return $version_parts[0]; 962 } 963 } 964 965 function devel_db_query($query) { 966 global $active_db; 967 $args = func_get_args(); 968 array_shift($args); 969 $query = db_prefix_tables($query); 970 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax 971 $args = $args[0]; 972 } 973 _db_query_callback($args, TRUE); 974 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 975 return db_query($query, $active_db); 976 } 977 978 // See http://drupal.org/node/126098 979 function devel_is_compatible_optimizer() { 980 ob_start(); 981 phpinfo(); 982 $info = ob_get_contents(); 983 ob_end_clean(); 984 985 // Match the Zend Optimezer version in the phpinfo information 986 $found = preg_match('/Zend Optimizer v([0-9])\.([0-9])\.([0-9])/', $info, $matches); 987 988 if ($matches) { 989 $major = $matches[1]; 990 $minor = $matches[2]; 991 $build = $matches[3]; 992 993 if ($major >= 3) { 994 if ($minor >= 3) { 995 return TRUE; 996 } 997 elseif ($minor == 2 && $build >= 8) { 998 return TRUE; 999 } 1000 else { 1001 return FALSE; 1002 } 1003 } 1004 else { 1005 return FALSE; 1006 } 1007 } 1008 else { 1009 return TRUE; 1010 } 1011 } 1012 1013 function devel_admin_settings() { 1014 $form['queries'] = array('#type' => 'fieldset', '#title' => t('Query log')); 1015 1016 $description = t("Collect query info. If disabled, no query log functionality will work."); 1017 if (!devel_is_compatible_optimizer()) { 1018 $description = t('You must disable or upgrade the php Zend Optimizer extension in order to enable this feature. The minimum required version is 3.2.8. Earlier versions of Zend Optimizer are <a href="!url">horribly buggy and segfault your Apache</a> ... ', array('!url' => url('http://drupal.org/node/126098'))) . $description; 1019 } 1020 $form['queries']['dev_query'] = array('#type' => 'checkbox', 1021 '#title' => t('Collect query info'), 1022 '#default_value' => variable_get('dev_query', 0), 1023 '#disabled' => !devel_is_compatible_optimizer() ? TRUE : FALSE, 1024 '#description' => $description, 1025 ); 1026 1027 $form['queries']['devel_query_display'] = array('#type' => 'checkbox', 1028 '#title' => t('Display query log'), 1029 '#default_value' => variable_get('devel_query_display', 0), 1030 '#description' => t('Display a log of the database queries needed to generate the current page, and the execution time for each. Also, queries which are repeated during a single page view are summed in the # column, and printed in red since they are candidates for caching.')); 1031 $form['queries']['devel_query_sort'] = array('#type' => 'radios', 1032 '#title' => t('Sort query log'), 1033 '#default_value' => variable_get('devel_query_sort', DEVEL_QUERY_SORT_BY_SOURCE), 1034 '#options' => array(t('by source'), t('by duration')), 1035 '#description' => t('The query table can be sorted in the order that the queries were executed or by descending duration.'), 1036 ); 1037 $form['queries']['devel_execution'] = array('#type' => 'textfield', 1038 '#title' => t('Slow query highlighting'), 1039 '#default_value' => variable_get('devel_execution', 5), 1040 '#size' => 4, 1041 '#maxlength' => 4, 1042 '#description' => t('Enter an integer in milliseconds. Any query which takes longer than this many milliseconds will be highlighted in the query log. This indicates a possibly inefficient query, or a candidate for caching.'), 1043 ); 1044 $form['queries']['devel_store_queries'] = array('#type' => 'checkbox', 1045 '#title' => t('Store executed queries'), 1046 '#default_value' => variable_get('devel_store_queries', 0), 1047 '#description' => t('Store statistics about executed queries. See the devel_x tables.')); 1048 $form['queries']['devel_store_random'] = array('#type' => 'textfield', 1049 '#title' => t('Sampling interval'), 1050 '#default_value' => variable_get('devel_store_random', 1), 1051 '#size' => 4, 1052 '#description' => t('If storing query statistics, only store every nth page view. 1 means every page view, 2 every second, and so on.')); 1053 1054 $form['xhprof'] = array( 1055 '#type' => 'fieldset', 1056 '#title' => 'XHProf', 1057 '#description' => t('XHProf is a php extension which is essential for profiling your Drupal site. It pinpoints slow functions, and also memory hogging functions.'), 1058 ); 1059 $description = extension_loaded('xhprof') ? t('Profile requests with the xhprof php extension.') : '<span class="warning">' . t('You must enable the <a href="!url">xhprof php extension</a> to use this feature.', array('!url' => url('http://techportal.ibuildings.com/2009/12/01/profiling-with-xhprof/'))) . '</span>'; 1060 $form['xhprof']['devel_xhprof_enabled'] = array( 1061 '#type' => 'checkbox', 1062 '#title' => t('Enable profiling of all page views and <a href="!drush">drush</a> requests.', array('!drush' => url('http://drush.ws'))), 1063 '#default_value' => variable_get('devel_xhprof_enabled', FALSE), 1064 '#description' => $description, 1065 '#disabled' => !extension_loaded('xhprof'), 1066 ); 1067 $form['xhprof']['devel_xhprof_directory'] = array( 1068 '#type' => 'textfield', 1069 '#title' => 'xhprof directory', 1070 '#description' => t('Location of the xhprof source code on your system, usually somewhere in /usr/local/share or /usr/share, include the leading forward slash.'), 1071 '#default_value' => variable_get('devel_xhprof_directory', ''), 1072 ); 1073 $form['xhprof']['devel_xhprof_url'] = array( 1074 '#type' => 'textfield', 1075 '#title' => 'XHProf URL', 1076 '#description' => t('Path to the publically accessible xhprof_html - required to display profiler reports. You will need to set this up outside Drupal, for example at http://xhprof.localhost/xhprof_html'), 1077 '#default_value' => variable_get('devel_xhprof_url', ''), 1078 ); 1079 1080 $form['devel_api_url'] = array('#type' => 'textfield', 1081 '#title' => t('API Site'), 1082 '#default_value' => variable_get('devel_api_url', 'api.drupal.org'), 1083 '#description' => t('The base URL for your developer documentation links. You might change this if you run <a href="!url">api.module</a> locally.', array('!url' => url('http://drupal.org/project/api')))); 1084 $form['dev_timer'] = array('#type' => 'checkbox', 1085 '#title' => t('Display page timer'), 1086 '#default_value' => variable_get('dev_timer', 0), 1087 '#description' => t('Display page execution time in the query log box.'), 1088 ); 1089 $form['dev_mem'] = array('#type' => 'checkbox', 1090 '#title' => t('Display memory usage'), 1091 '#default_value' => variable_get('dev_mem', 0), 1092 '#description' => t('Display how much memory is used to generate the current page. This will show memory usage when devel_init() is called and when devel_exit() is called. PHP must have been compiled with the <em>--enable-memory-limit</em> configuration option for this feature to work.'), 1093 ); 1094 $form['devel_redirect_page'] = array('#type' => 'checkbox', 1095 '#title' => t('Display redirection page'), 1096 '#default_value' => variable_get('devel_redirect_page', 0), 1097 '#description' => t('When a module executes drupal_goto(), the query log and other developer information is lost. Enabling this setting presents an intermediate page to developers so that the log can be examined before continuing to the destination page.'), 1098 ); 1099 $form['devel_error_handler'] = array('#type' => 'radios', 1100 '#title' => t('Error handler'), 1101 '#default_value' => variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD), 1102 '#options' => array(DEVEL_ERROR_HANDLER_NONE => t('None'), DEVEL_ERROR_HANDLER_STANDARD => t('Standard drupal')), 1103 '#description' => t('Choose an error handler for your site. <em>Backtrace</em> prints nice debug information when an error is noticed, and you <a href="@choose">choose to show errors on screen</a>. <strong>Backtrace requires the <a href="@krumo">krumo library</a></strong>. <em>None</em> is a good option when stepping through the site in your debugger.', array('@krumo' => url('http://krumo.sourceforge.net'), '@choose' => url('admin/settings/error-reporting'))), 1104 ); 1105 if (has_krumo()) { 1106 $form['devel_error_handler']['#options'][DEVEL_ERROR_HANDLER_BACKTRACE] = t('Backtrace'); 1107 } 1108 1109 $options = drupal_map_assoc(array('default', 'blue', 'green', 'orange', 'white', 'disabled')); 1110 $form['devel_krumo_skin'] = array( 1111 '#type' => 'radios', 1112 '#title' => t('Krumo display'), 1113 '#description' => t('Select a skin for your debug messages or select <em>disabled</em> to display object and array output in standard PHP format.'), 1114 '#options' => $options, 1115 '#default_value' => variable_get('devel_krumo_skin', 'default'), 1116 ); 1117 1118 // Save any old SMTP library 1119 if (variable_get('smtp_library', '') != '' && variable_get('smtp_library', '') != drupal_get_filename('module', 'devel')) { 1120 variable_set('devel_old_smtp_library', variable_get('smtp_library', '')); 1121 } 1122 $smtp_options = array( 1123 '' => t('Default'), 1124 drupal_get_filename('module', 'devel') => t('Log only'), 1125 ); 1126 if (variable_get('devel_old_smtp_library', '') != '') { 1127 $smtp_options[variable_get('devel_old_smtp_library', '')] = t('Other (!library)', array('!library' => variable_get('devel_old_smtp_library', ''))); 1128 } 1129 $form['smtp_library'] = array( 1130 '#type' => 'radios', 1131 '#title' => t('SMTP library'), 1132 '#options' => $smtp_options, 1133 '#default_value' => variable_get('smtp_library', ''), 1134 ); 1135 1136 $form['devel_rebuild_theme_registry'] = array( 1137 '#type' => 'checkbox', 1138 '#title' => t('Rebuild the theme registry on every page load'), 1139 '#description' => t('While creating new templates and theme_ overrides the theme registry needs to be rebuilt.'), 1140 '#default_value' => variable_get('devel_rebuild_theme_registry', FALSE), 1141 ); 1142 1143 return system_settings_form($form); 1144 } 1145 1146 /** 1147 * Menu callback; clears all caches, then redirects to the previous page. 1148 */ 1149 function devel_cache_clear() { 1150 // If you used to implement our own cache clear hook, implement hook_flush_caches instead. See drupal_flush_all_caches() 1151 drupal_flush_all_caches(); 1152 1153 drupal_set_message('Cache cleared.'); 1154 1155 drupal_goto(); 1156 } 1157 1158 /** 1159 * Generates the execute block form. 1160 */ 1161 function devel_execute_block_form() { 1162 $form['execute'] = array( 1163 '#type' => 'fieldset', 1164 '#title' => t('Execute PHP Code'), 1165 '#collapsible' => TRUE, 1166 '#collapsed' => (!isset($_POST['code'])), 1167 ); 1168 $form['#submit'] = array('devel_execute_form_submit'); 1169 return array_merge_recursive($form, devel_execute_form()); 1170 } 1171 1172 /** 1173 * Generates the execute form. 1174 */ 1175 function devel_execute_form() { 1176 $form['execute']['code'] = array( 1177 '#type' => 'textarea', 1178 '#title' => t('PHP code to execute'), 1179 '#description' => t('Enter some code. Do not use <code><?php ?></code> tags.'), 1180 '#rows' => 20, 1181 ); 1182 $form['execute']['op'] = array('#type' => 'submit', '#value' => t('Execute')); 1183 $form['#redirect'] = FALSE; 1184 $form['#skip_duplicate_check'] = TRUE; 1185 return $form; 1186 } 1187 1188 /** 1189 * Process PHP execute form submissions. 1190 */ 1191 function devel_execute_form_submit($form, &$form_state) { 1192 ob_start(); 1193 print eval($form_state['values']['code']); 1194 dsm(ob_get_clean()); 1195 } 1196 1197 /** 1198 * Menu callback; clear the database, resetting the menu to factory defaults. 1199 */ 1200 function devel_menu_rebuild() { 1201 menu_rebuild(); 1202 drupal_set_message(t('The menu router has been rebuilt.')); 1203 drupal_goto(); 1204 } 1205 1206 /** 1207 * Display a list of installed modules with the option to reinstall them. 1208 */ 1209 function devel_reinstall($form_state) { 1210 $output = ''; 1211 $modules = module_list(); 1212 sort($modules); 1213 $options = drupal_map_assoc($modules); 1214 $form['list'] = array( 1215 '#type' => 'checkboxes', 1216 '#options' => $options, 1217 '#description' => t('Uninstall and then install the selected modules. <code>hook_uninstall()</code> and <code>hook_install()</code> will be executed and the schema version number will be set to the most recent update number. You may have to manually clear out any existing tables first if the module doesn\'t implement <code>hook_uninstall()</code>.'), 1218 ); 1219 $form['submit'] = array( 1220 '#value' => t('Reinstall'), 1221 '#type' => 'submit', 1222 ); 1223 if (empty($form_state['post'])) { 1224 drupal_set_message(t('Warning - will delete your module tables and variables.'), 'error'); 1225 } 1226 return $form; 1227 } 1228 1229 /** 1230 * Process reinstall menu form submissions. 1231 */ 1232 function devel_reinstall_submit($form, &$form_state) { 1233 require_once './includes/install.inc'; 1234 $modules = array_filter($form_state['values']['list']); 1235 foreach ($modules as $module) { 1236 module_load_install($module); 1237 $versions = drupal_get_schema_versions($module); 1238 drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); 1239 module_invoke($module, 'uninstall'); 1240 _drupal_install_module($module); 1241 module_invoke($module, 'enable'); 1242 drupal_get_schema(NULL, TRUE); 1243 drupal_set_message(t('Uninstalled and installed the %name module.', array('%name' => $module))); 1244 } 1245 } 1246 1247 // Menu callback. 1248 function devel_theme_registry() { 1249 init_theme(); 1250 $hooks = theme_get_registry(); 1251 return kprint_r($hooks, TRUE); 1252 } 1253 1254 /** 1255 * Menu callback; display all variables. 1256 */ 1257 function devel_variable_page() { 1258 // we print our own page so as to avoid blocks 1259 $output = drupal_get_form('devel_variable_form'); 1260 print theme('page', $output, FALSE); 1261 } 1262 1263 function devel_variable_form() { 1264 $header = array( 1265 array(''), 1266 array('data' => t('Name'), 'field' => 'name', 'sort' => 'asc'), 1267 array('data' => t('Value'), 'field' => 'value'), 1268 array('data' => t('Length'), 'field' => 'length'), 1269 array('data' => t('Operations')), 1270 ); 1271 // TODO: we could get variables out of $conf but that would include hard coded ones too. ideally i would highlight overrridden/hard coded variables 1272 switch ($GLOBALS['db_type']) { 1273 case 'mssql': 1274 $sql = "SELECT *, COL_LENGTH('{variable}', 'value') AS length FROM {variable}"; 1275 break; 1276 default: 1277 $sql = "SELECT *, LENGTH(value) AS length FROM {variable}"; 1278 break; 1279 } 1280 $result = db_query($sql . tablesort_sql($header)); 1281 while ($row = db_fetch_object($result)) { 1282 $variables[$row->name] = ''; 1283 $form['name'][$row->name] = array('#value' => check_plain($row->name)); 1284 if (merits_krumo($row->value)) { 1285 $value = krumo_ob(variable_get($row->name, NULL)); 1286 } 1287 else { 1288 if (drupal_strlen($row->value) > 70) { 1289 $value = check_plain(drupal_substr($row->value, 0, 65)) .'...'; 1290 } 1291 else { 1292 $value = check_plain($row->value); 1293 } 1294 } 1295 $form[$row->name]['value'] = array('#value' => $value); 1296 $form[$row->name]['length'] = array('#value' => $row->length); 1297 $form[$row->name]['edit'] = array('#value' => l(t('edit'), "devel/variable/edit/$row->name")); 1298 } 1299 $form['variables'] = array('#type' => 'checkboxes', '#options' => $variables); 1300 $form['submit'] = array( 1301 '#type' => 'submit', 1302 '#value' => t('Delete'), 1303 ); 1304 return $form; 1305 } 1306 1307 function theme_devel_variable_form($form) { 1308 // TODO: this is not being called for some reason 1309 // die(form); 1310 $children = element_children($form['name']); 1311 foreach ($children as $key) { 1312 $rows[] = array( 1313 drupal_render($form['variables'][$key]), 1314 drupal_render($form['name'][$key]), 1315 drupal_render($form[$key]['value']), 1316 drupal_render($form[$key]['length']), 1317 drupal_render($form[$key]['edit']), 1318 ); 1319 } 1320 $header = array( 1321 theme('table_select_header_cell'), 1322 array('data' => t('Name'), 'field' => 'name', 'sort' => 'asc'), 1323 array('data' => t('Value'), 'field' => 'value'), 1324 array('data' => t('Length'), 'field' => 'length'), 1325 array('data' => t('Operations'), 'colspan' => 2), 1326 ); 1327 $output = theme('table', $header, $rows); 1328 $output .= drupal_render($form); 1329 1330 return $output; 1331 } 1332 1333 function devel_variable_form_submit($form, &$form_state) { 1334 $deletes = array_filter($form_state['values']['variables']); 1335 array_walk($deletes, 'variable_del'); 1336 if (count($deletes)) { 1337 drupal_set_message(format_plural(count($deletes), 'One variable deleted.', '@count variables deleted.')); 1338 } 1339 } 1340 1341 function devel_variable_edit($form_state, $name) { 1342 $value = variable_get($name, 'not found'); 1343 $form['name'] = array( 1344 '#type' => 'value', 1345 '#value' => $name 1346 ); 1347 $form['value'] = array( 1348 '#type' => 'item', 1349 '#title' => t('Old value'), 1350 '#value' => dpr($value, TRUE), 1351 ); 1352 if (is_string($value) || is_numeric($value)) { 1353 $form['new'] = array( 1354 '#type' => 'textarea', 1355 '#title' => t('New value'), 1356 '#default_value' => $value 1357 ); 1358 $form['submit'] = array( 1359 '#type' => 'submit', 1360 '#value' => t('Submit'), 1361 ); 1362 } 1363 else { 1364 $api = variable_get('devel_api_url', 'api.drupal.org'); 1365 $form['new'] = array( 1366 '#type' => 'item', 1367 '#title' => t('New value'), 1368 '#value' => t('Sorry, complex variable types may not be edited yet. Use the <em>Execute PHP</em> block and the <a href="@variable-set-doc">variable_set()</a> function.', array('@variable-set-doc' => "http://$api/api/HEAD/function/variable_set")) 1369 ); 1370 } 1371 drupal_set_title(check_plain($name)); 1372 return $form; 1373 } 1374 1375 function devel_variable_edit_submit($form, &$form_state) { 1376 variable_set($form_state['values']['name'], $form_state['values']['new']); 1377 drupal_set_message(t('Saved new value for %name.', array('%name' => $form_state['values']['name']))); 1378 'devel/variable'; 1379 } 1380 1381 /** 1382 * Menu callback: display the session. 1383 */ 1384 function devel_session() { 1385 global $user; 1386 $output = kprint_r($_SESSION, TRUE); 1387 $headers = array(t('Session name'), t('Session ID')); 1388 $output .= theme('table', $headers, array(array(session_name(), session_id()))); 1389 return $output; 1390 } 1391 1392 /** 1393 * Switch from original user to another user and back. 1394 * 1395 * Note: taken from mailhandler.module. 1396 * 1397 * Note: You first need to run devel_switch_user without 1398 * argument to store the current user. Call devel_switch_user 1399 * without argument to set the user back to the original user. 1400 * 1401 * @param $name The username to switch to. 1402 * 1403 */ 1404 function devel_switch_user($name = NULL) { 1405 global $user; 1406 static $orig_user = array(); 1407 1408 if (isset($name)) { 1409 $user = user_load(array('name' => $name)); 1410 } 1411 // Retrieve the initial user. Can be called multiple times. 1412 elseif (count($orig_user)) { 1413 $user = array_shift($orig_user); 1414 array_unshift($orig_user, $user); 1415 } 1416 // Store the initial user. 1417 else { 1418 $orig_user[] = $user; 1419 } 1420 drupal_goto(); 1421 } 1422 1423 /** 1424 * Menu callback; prints the loaded structure of the current node/user. 1425 */ 1426 function devel_load_object($object, $name = NULL) { 1427 $title = isset($object->title) ? $object->title : $object->name; 1428 drupal_set_title(check_plain($title)); 1429 return kdevel_print_object($object, '$'. $name .'->'); 1430 } 1431 1432 /** 1433 * Menu callback; prints the render structure of the current object (currently node or user). 1434 */ 1435 function devel_render_object($type, $object) { 1436 $output = ''; 1437 $title = isset($object->title) ? $object->title : $object->name; 1438 // not sure why menu system doesn't give us a reasonable title here. 1439 drupal_set_title(check_plain($title)); 1440 $function = $type .'_build_content'; 1441 $content = $function($object, FALSE, FALSE); 1442 return kdevel_print_object($content, '$'. $type .'->'); 1443 } 1444 1445 function devel_elements_page() { 1446 return kdevel_print_object(module_invoke_all('elements')); 1447 } 1448 1449 /** 1450 * Print an object or array using either Krumo (if installed) or devel_print_object() 1451 * 1452 * @param $object 1453 * array or object to print 1454 * @param $prefix 1455 * prefixing for output items 1456 */ 1457 function kdevel_print_object($object, $prefix = NULL) { 1458 return has_krumo() ? krumo_ob($object) : devel_print_object($object, $prefix); 1459 } 1460 1461 // Save krumo htlm using output buffering. 1462 function krumo_ob($object) { 1463 ob_start(); 1464 krumo($object); 1465 $output = ob_get_contents(); 1466 ob_end_clean(); 1467 return $output; 1468 } 1469 1470 /** 1471 * Display an object or array 1472 * 1473 * @param $object 1474 * the object or array 1475 * @param $prefix 1476 * prefix for the output items (example "$node->", "$user->", "$") 1477 * @param $header 1478 * set to FALSE to suppress the output of the h3 1479 */ 1480 function devel_print_object($object, $prefix = NULL, $header = TRUE) { 1481 drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css'); 1482 $output = '<div class="devel-obj-output">'; 1483 if ($header) { 1484 $output .= '<h3>'. t('Display of !type !obj', array('!type' => str_replace(array('$', '->'), '', $prefix), '!obj' => gettype($object))) .'</h3>'; 1485 } 1486 $output .= _devel_print_object($object, $prefix); 1487 $output .= '</div>'; 1488 return $output; 1489 } 1490 1491 /** 1492 * Recursive (and therefore magical) function goes through an array or object and 1493 * returns a nicely formatted listing of its contents. 1494 * 1495 * @param $obj 1496 * array or object to recurse through 1497 * @param $prefix 1498 * prefix for the output items (example "$node->", "$user->", "$") 1499 * @param $parents 1500 * used by recursion 1501 * @param $object 1502 * used by recursion 1503 * @return 1504 * fomatted html 1505 * 1506 * @todo 1507 * currently there are problems sending an array with a varname 1508 */ 1509 function _devel_print_object($obj, $prefix = NULL, $parents = NULL, $object = FALSE) { 1510 static $root_type, $out_format; 1511 // TODO: support objects with references. See http://drupal.org/node/234581. 1512 if (isset($obj->view)) { 1513 return; 1514 } 1515 1516 if (!isset($root_type)) { 1517 $root_type = gettype($obj); 1518 if ($root_type == 'object') { 1519 $object = TRUE; 1520 } 1521 } 1522 1523 if (is_object($obj)) { 1524 $obj = (array)$obj; 1525 } 1526 if (is_array($obj)) { 1527 $output = "<dl>\n"; 1528 foreach ($obj as $field => $value) { 1529 if ($field == 'devel_flag_reference') { 1530 continue; 1531 } 1532 if (!is_null($parents)) { 1533 if ($object) { 1534 $field = $parents .'->'. $field; 1535 } 1536 else { 1537 if (is_int($field)) { 1538 $field = $parents .'['. $field .']'; 1539 } 1540 else { 1541 $field = $parents .'[\''. $field .'\']'; 1542 } 1543 } 1544 } 1545 1546 $type = gettype($value); 1547 1548 $show_summary = TRUE; 1549 $summary = NULL; 1550 if ($show_summary) { 1551 switch ($type) { 1552 case 'string' : 1553 case 'float' : 1554 case 'integer' : 1555 if (strlen($value) == 0) { 1556 $summary = t("{empty}"); 1557 } 1558 elseif (strlen($value) < 40) { 1559 $summary = htmlspecialchars($value); 1560 } 1561 else { 1562 $summary = format_plural(drupal_strlen($value), '1 character', '@count characters'); 1563 } 1564 break; 1565 case 'array' : 1566 case 'object' : 1567 $summary = format_plural(count((array)$value), '1 element', '@count elements'); 1568 break; 1569 case 'boolean' : 1570 $summary = $value ? t('TRUE') : t('FALSE'); 1571 break; 1572 } 1573 } 1574 if (!is_null($summary)) { 1575 $typesum = '('. $type .', <em>'. $summary .'</em>)'; 1576 } 1577 else { 1578 $typesum = '('. $type .')'; 1579 } 1580 1581 $output .= '<span class="devel-attr">'; 1582 $output .= "<dt><span class=\"field\">{$prefix}{$field}</span> $typesum</dt>\n"; 1583 $output .= "<dd>\n"; 1584 // Check for references. 1585 if (is_array($value) && isset($value['devel_flag_reference'])) { 1586 $value['devel_flag_reference'] = TRUE; 1587 } 1588 // Check for references to prevent errors from recursions. 1589 if (is_array($value) && isset($value['devel_flag_reference']) && !$value['devel_flag_reference']) { 1590 $value['devel_flag_reference'] = FALSE; 1591 $output .= _devel_print_object($value, $prefix, $field); 1592 } 1593 elseif (is_object($value)) { 1594 $value->devel_flag_reference = FALSE; 1595 $output .= _devel_print_object((array)$value, $prefix, $field, TRUE); 1596 } 1597 else { 1598 $value = is_bool($value) ? ($value ? 'TRUE' : 'FALSE') : $value; 1599 $output .= htmlspecialchars(print_r($value, TRUE)) ."\n"; 1600 } 1601 $output .= "</dd></span>\n"; 1602 } 1603 $output .= "</dl>\n"; 1604 } 1605 return $output; 1606 } 1607 1608 /** 1609 * Adds a table at the bottom of the page cataloguing data on all the database queries that were made to 1610 * generate the page. 1611 */ 1612 function devel_query_table($queries, $counts) { 1613 if (empty($queries)) { 1614 return FALSE; 1615 } 1616 $version = devel_get_core_version(VERSION); 1617 $header = array('ms', '#', 'where', 'query'); 1618 $i = 0; 1619 $api = variable_get('devel_api_url', 'api.drupal.org'); 1620 foreach ($queries as $query) { 1621 // dprint_r($query); 1622 $ar = explode("\n", $query[0]); 1623 $function=array_shift($ar); 1624 $count = isset($counts[$query[0]]) ? $counts[$query[0]] : 0; 1625 $query[0]=join(' ', $ar); 1626 1627 $diff = round($query[1] * 1000, 2); 1628 if ($diff > variable_get('devel_execution', 5)) { 1629 $cell[$i][] = array('data' => $diff, 'class' => 'marker'); 1630 } 1631 else { 1632 $cell[$i][] = $diff; 1633 } 1634 if ($count > 1) { 1635 $cell[$i][] = array('data' => $count, 'class' => 'marker'); 1636 } 1637 else { 1638 $cell[$i][] = $count; 1639 } 1640 $cell[$i][] = l($function, "http://$api/api/$version/function/$function"); 1641 $pos = strpos($query[0], '*/') !== FALSE ? strpos($query[0], '*/') + 3 : 0; 1642 $cell[$i][] = check_plain(substr($query[0], $pos)); 1643 $i++; 1644 unset($diff, $count); 1645 } 1646 if (variable_get('devel_query_sort', DEVEL_QUERY_SORT_BY_SOURCE)) { 1647 usort($cell, '_devel_table_sort'); 1648 } 1649 return theme('devel_querylog', $header, $cell); 1650 } 1651 1652 function theme_devel_querylog_row($row) { 1653 $i = 0; 1654 $output = ''; 1655 foreach ($row as $cell) { 1656 $i++; 1657 1658 if (is_array($cell)) { 1659 $data = !empty($cell['data']) ? $cell['data'] : ''; 1660 unset($cell['data']); 1661 $attr = $cell; 1662 } 1663 else { 1664 $data = $cell; 1665 $attr = array(); 1666 } 1667 1668 if (!empty($attr['class'])) { 1669 $attr['class'] .= " cell cell-$i"; 1670 } 1671 else { 1672 $attr['class'] = "cell cell-$i"; 1673 } 1674 $attr = drupal_attributes($attr); 1675 1676 $output .= "<div $attr>$data</div>"; 1677 } 1678 return $output; 1679 } 1680 1681 function theme_devel_querylog($header = array(), $rows = array()) { 1682 $output = ''; 1683 if (!empty($header)) { 1684 $output .= "<div class='devel-querylog devel-querylog-header clear-block'>"; 1685 $output .= theme('devel_querylog_row', $header); 1686 $output .= "</div>"; 1687 } 1688 if (!empty($rows)) { 1689 $i = 0; 1690 foreach ($rows as $row) { 1691 $i++; 1692 $zebra = ($i % 2) == 0 ? 'even' : 'odd'; 1693 $output .= "<div class='devel-querylog devel-querylog-$zebra clear-block'>"; 1694 $output .= theme('devel_querylog_row', $row); 1695 $output .= "</div>"; 1696 } 1697 } 1698 return $output; 1699 } 1700 1701 function _devel_table_sort($a, $b) { 1702 $a = is_array($a[0]) ? $a[0]['data'] : $a[0]; 1703 $b = is_array($b[0]) ? $b[0]['data'] : $b[0]; 1704 if ($a < $b) { 1705 return 1; 1706 } 1707 if ($a > $b) { 1708 return -1; 1709 } 1710 return 0; 1711 } 1712 1713 /** 1714 * Displays page execution time at the bottom of the page. 1715 */ 1716 function devel_timer() { 1717 $time = timer_read('page'); 1718 return t_safe(' Page execution time was @time ms.', array('@time' => $time)); 1719 } 1720 1721 /** 1722 * Displays page execution time at the bottom of the page. 1723 */ 1724 function devel_xhprof_link_show() { 1725 if (variable_get('devel_xhprof_enabled', FALSE)) { 1726 return devel_xhprof_link($GLOBALS['devel_run_id']); 1727 } 1728 } 1729 1730 function devel_xhprof_link($run_id, $type = 'link') { 1731 // @todo: render results from within Drupal. 1732 $xhprof_url = variable_get('devel_xhprof_url', ''); 1733 $namespace = variable_get('site_name', ''); // namespace for your application 1734 if ($xhprof_url) { 1735 $url = $xhprof_url . "/index.php?run=$run_id&source=$namespace"; 1736 return $type == 'url' ? $url : t('<a href="@xhprof">XHProf output</a>. ', array('@xhprof' => $url)); 1737 } 1738 } 1739 1740 1741 /** 1742 * Prints the arguments passed into the current function 1743 */ 1744 function dargs($always = TRUE) { 1745 static $printed; 1746 if ($always || !$printed) { 1747 $bt = debug_backtrace(); 1748 print kdevel_print_object($bt[1]['args']); 1749 $printed = TRUE; 1750 } 1751 } 1752 1753 // An alias for drupal_debug(). 1754 function dd($data, $label = NULL) { 1755 return drupal_debug($data, $label); 1756 } 1757 1758 // Log any variable to a drupal_debug.log in the site's temp directory. 1759 // See http://drupal.org/node/314112 1760 function drupal_debug($data, $label = NULL) { 1761 ob_start(); 1762 print_r($data); 1763 $string = ob_get_clean(); 1764 if ($label) { 1765 $out = $label .': '. $string; 1766 } 1767 else { 1768 $out = $string; 1769 } 1770 $out .= "\n"; 1771 1772 // The temp directory does vary across multiple simpletest instances. 1773 $file = file_directory_temp() .'/drupal_debug.txt'; 1774 if (file_put_contents($file, $out, FILE_APPEND) === FALSE) { 1775 drupal_set_message(t('The file could not be written.'), 'error'); 1776 return FALSE; 1777 } 1778 } 1779 1780 /** 1781 * Print a variable to the 'message' area of the page. Uses drupal_set_message() 1782 */ 1783 function dpm($input, $name = NULL) { 1784 if (user_access('access devel information')) { 1785 $export = kprint_r($input, TRUE, $name); 1786 drupal_set_message($export); 1787 } 1788 } 1789 1790 /** 1791 * Var_dump() a variable to the 'message' area of the page. Uses drupal_set_message() 1792 */ 1793 function dvm($input, $name = NULL) { 1794 if (user_access('access devel information')) { 1795 $export = dprint_r($input, TRUE, $name, 'var_dump', FALSE); 1796 drupal_set_message($export); 1797 } 1798 } 1799 1800 // legacy function that was poorly named. use dpm() instead, since the 'p' maps to 'print_r' 1801 function dsm($input, $name = NULL) { 1802 dpm($input, $name); 1803 } 1804 1805 /** 1806 * An alias for dprint_r(). Saves carpal tunnel syndrome. 1807 */ 1808 function dpr($input, $return = FALSE, $name = NULL) { 1809 return dprint_r($input, $return, $name); 1810 } 1811 1812 /** 1813 * An alias for kprint_r(). Saves carpal tunnel syndrome. 1814 */ 1815 function kpr($input, $return = FALSE, $name = NULL) { 1816 return kprint_r($input, $return, $name); 1817 } 1818 1819 /** 1820 * Like dpr, but uses var_dump() instead 1821 */ 1822 function dvr($input, $return = FALSE, $name = NULL) { 1823 return dprint_r($input, $return, $name, 'var_dump', FALSE); 1824 } 1825 1826 function kprint_r($input, $return = FALSE, $name = NULL, $function = 'print_r') { 1827 // We do not want to krumo() strings and integers and such 1828 if (merits_krumo($input)) { 1829 if (user_access('access devel information')) { 1830 return $return ? (isset($name) ? $name .' => ' : '') . krumo_ob($input) : krumo($input); 1831 } 1832 } 1833 else { 1834 return dprint_r($input, $return, $name, $function); 1835 } 1836 } 1837 1838 /** 1839 * Pretty-print a variable to the browser (no krumo). 1840 * Displays only for users with proper permissions. If 1841 * you want a string returned instead of a print, use the 2nd param. 1842 */ 1843 function dprint_r($input, $return = FALSE, $name = NULL, $function = 'print_r', $check= TRUE) { 1844 if (user_access('access devel information')) { 1845 if ($name) { 1846 $name .= ' => '; 1847 } 1848 ob_start(); 1849 $function($input); 1850 $output = ob_get_clean(); 1851 if ($check) { 1852 $output = check_plain($output); 1853 } 1854 if (count($input, COUNT_RECURSIVE) > DEVEL_MIN_TEXTAREA) { 1855 // don't use fapi here because sometimes fapi will not be loaded 1856 $printed_value = "<textarea rows=30 style=\"width: 100%;\">\n". $name . $output .'</textarea>'; 1857 } 1858 else { 1859 $printed_value = '<pre>'. $name . $output .'</pre>'; 1860 } 1861 1862 if ($return) { 1863 return $printed_value; 1864 } 1865 else { 1866 print $printed_value; 1867 } 1868 } 1869 } 1870 1871 /** 1872 * Print the function call stack. 1873 */ 1874 function ddebug_backtrace() { 1875 if (user_access('access devel information')) { 1876 $trace = debug_backtrace(); 1877 array_shift($trace); 1878 foreach ($trace as $key => $value) { 1879 $rich_trace[$value['function']] = $value; 1880 } 1881 if (has_krumo()) { 1882 print krumo($rich_trace); 1883 } 1884 else { 1885 dprint_r($rich_trace); 1886 } 1887 } 1888 } 1889 1890 /** 1891 * Debugging version of db_query(). 1892 * 1893 * Echoes the query to the browser. 1894 */ 1895 function db_queryd($query) { 1896 $args = func_get_args(); 1897 array_shift($args); 1898 $query = db_prefix_tables($query); 1899 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax 1900 $args = $args[0]; 1901 } 1902 _db_query_callback($args, TRUE); 1903 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 1904 return _db_query($query, 1); 1905 } 1906 1907 // Only define our mail wrapper if the devel module is the current mail 1908 // wrapper. 1909 if (variable_get('smtp_library', '') == drupal_get_filename('module', 'devel')) { 1910 /** 1911 * Log the mails sent out instead of mailing. 1912 */ 1913 function drupal_mail_wrapper($message) { 1914 $mimeheaders = array(); 1915 foreach ($message['headers'] as $name => $value) { 1916 // the check_plain nicely encodes <> chars for web presentation 1917 $mimeheaders[] = check_plain($name .': '. mime_header_encode($value)); 1918 } 1919 watchdog( 1920 'devel', 1921 'Mail sent:<br />Id: %mail_id<br />To: %to<br />From: %from<br />Language: %lang<br />Subject: %subject<br />Body: %body<br /><br />Additional headers: <br />!header', 1922 array( 1923 '%mail_id' => $message['id'], 1924 '%to' => $message['to'], 1925 '%from' => $message['from'], 1926 '%lang' => $message['language']->language, 1927 '%subject' => $message['subject'], 1928 '%body' => $message['body'], 1929 '!header' => implode("<br />", $mimeheaders), 1930 WATCHDOG_INFO, 1931 ) 1932 ); 1933 return TRUE; 1934 } 1935 } 1936 1937 function devel_queries() { 1938 $header = array( 1939 array('data' => t('Total (ms)'), 'field' => 'total_time', 'sort' => 'desc'), 1940 array('data' => t('Average (ms)'), 'field' => 'average', 'sort' => 'desc'), 1941 array('data' => t('Std deviation (ms)')), 1942 array('data' => t('Count'), 'field' => 'count'), 1943 array('data' => t('Function'), 'field' => 'q.function'), 1944 array('data' => t('Query'), 'field' => 'q.query'), 1945 ); 1946 1947 global $db_type; 1948 if ($db_type == 'pgsql') { 1949 $result = pager_query('SELECT q.qid, q.query, q.function , t.* FROM {devel_queries} q INNER JOIN (SELECT t.qid, COUNT(t.qid) AS count,SUM(t.time) AS total_time, AVG(t.time) AS average, STDDEV(t.time) AS stddev FROM {devel_times} t GROUP BY t.qid) AS t ON t.qid=q.qid '. tablesort_sql($header), 30, 0, 'SELECT COUNT(qid) FROM {devel_queries}'); 1950 } 1951 else { 1952 $result = pager_query('SELECT q.qid, q.query, q.function, t.*, COUNT(t.qid) AS count, SUM(t.time) AS total_time, AVG(t.time) AS average, STDDEV(t.time) AS stddev FROM {devel_queries} q INNER JOIN {devel_times} t ON q.qid = t.qid GROUP BY t.qid '. tablesort_sql($header), 30, 0, 'SELECT COUNT(qid) FROM {devel_queries}'); 1953 } 1954 while ($log = db_fetch_object($result)) { 1955 $rows[] = array( 1956 round($log->total_time * 1000, 3), 1957 round($log->average * 1000, 3), 1958 round($log->stddev * 1000, 3), 1959 $log->count, 1960 $log->function, 1961 check_plain($log->query) 1962 ); 1963 } 1964 1965 $output = theme('table', $header, $rows); 1966 $output .= theme('pager', NULL, 30, 0); 1967 $output .= l(t('Delete collected query statistics'), 'devel/queries/empty'); 1968 1969 print theme('page', $output, FALSE); 1970 } 1971 1972 function devel_queries_empty() { 1973 db_query('DELETE FROM {devel_queries}'); 1974 db_query('DELETE FROM {devel_times}'); 1975 drupal_set_message(t('Stored query statistics deleted.')); 1976 drupal_goto('devel/queries'); 1977 } 1978 1979 /* 1980 * migration related functions 1981 */ 1982 1983 /** 1984 * Menu callback. Rebuild node _comment_stats table. 1985 * 1986 * @return void 1987 **/ 1988 function devel_rebuild_node_comment_statistics_page() { 1989 devel_rebuild_node_comment_statistics(); 1990 drupal_set_message('node_comment_statistics table has been rebuilt.'); 1991 drupal_goto('admin'); 1992 } 1993 1994 /** 1995 * Regenerate the data in node_comment_statistics table. 1996 * 1997 * @return void 1998 **/ 1999 function devel_rebuild_node_comment_statistics() { 2000 // Empty table 2001 $sql = "DELETE FROM {node_comment_statistics}"; 2002 db_query($sql); 2003 2004 $sql = "INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) (select nid, c.timestamp, name, uid, comment_count FROM {comments} c INNER JOIN (SELECT MAX(timestamp) AS timestamp, COUNT(*) AS comment_count FROM {comments} WHERE status=%d GROUP BY nid) AS c2 ON c.nid = c2.nid AND c.timestamp=c2.timestamp)"; 2005 db_query($sql, COMMENT_PUBLISHED); 2006 2007 // Insert 0 count records into the node_comment_statistics for nodes that are missing. See comment_enable() 2008 db_query_temporary("SELECT n.nid, n.created, n.uid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE c.comment_count IS NULL", 'missing_nids'); 2009 db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.created, NULL, n.uid, 0 FROM missing_nids n"); 2010 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |