home | career | drupal | java | mac | mysql | perl | php | scala | uml | unix

Drupal example source code file (devel.module)

This example Drupal source code file (devel.module) is included in the DevDaily.com "Drupal Source Code Warehouse" project. The intent of this project is to help you "Learn Drupal by Example".

PHP - Drupal tags/keywords

arguments, array, devel, directory, file, function, if, information, output, page, php, return, title, type

The devel.module Drupal example source code

<?php
// $Id: devel.module,v 1.472 2011/01/04 19:47:31 weitzman Exp $

// This module holds functions useful for Drupal development.
// Please contribute!

// Suggested profiling and stacktrace library from http://www.xdebug.org/index.php

define('DEVEL_QUERY_SORT_BY_SOURCE', 0);
define('DEVEL_QUERY_SORT_BY_DURATION', 1);

define('DEVEL_ERROR_HANDLER_NONE', 0);
define('DEVEL_ERROR_HANDLER_STANDARD', 1);
define('DEVEL_ERROR_HANDLER_BACKTRACE', 2);

define('DEVEL_MIN_TEXTAREA', 50);

/**
 * Implementation of hook_help().
 */
function devel_help($section) {
  switch ($section) {
    case 'devel/reference':
      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>';
    case 'devel/session':
      return '<p>'. t('Here are the contents of your <code>$_SESSION</code> variable.') .'</p>';
    case 'devel/variable':
      $api = variable_get('devel_api_url', 'api.drupal.org');
      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>';
    case 'devel/reinstall':
      return t('Warning - will delete your module tables and variables.');
  }
}

/**
 * Implementationation of hook_menu().
 */
function devel_menu() {
  $items = array();
  // Note: we can't dynamically append destination to querystring. Do so at theme layer. Fix in D7?
  $items['devel/cache/clear'] = array(
    'title' => 'Empty cache',
    'page callback' => 'devel_cache_clear',
    'description' => 'Clear the CSS cache and all database cache tables which store page, node, theme and variable caches.',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );

  $items['devel/reference'] = array(
    'title' => 'Function reference',
    'description' => 'View a list of currently defined user functions with documentation links.',
    'page callback' => 'devel_function_reference',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/reinstall'] = array(
    'title' => 'Reinstall modules',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_reinstall'),
    'description' => 'Run hook_uninstall() and then hook_install() for a given module.',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/menu/reset'] = array(
    'title' => 'Rebuild menus',
    'description' => 'Rebuild menu based on hook_menu() and revert any custom changes. All menu items return to their default settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_menu_rebuild'),
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/menu/item'] = array(
    'title' => 'Menu item',
    'description' => 'Details about a given menu item.',
    'page callback' => 'devel_menu_item',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/variable'] = array(
    'title' => 'Variable editor',
    'description' => 'Edit and delete site variables.',
    'page callback' => 'devel_variable_page',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  // we don't want the abbreviated version provided by status report
  $items['devel/phpinfo'] = array(
    'title' => 'PHPinfo()',
    'description' => 'View your server\'s PHP configuration',
    'page callback' => 'devel_phpinfo',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/php'] = array(
    'title' => 'Execute PHP Code',
    'description' => 'Execute some PHP code',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_execute_form'),
    'access arguments' => array('execute php code'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/theme/registry'] = array(
    'title' => 'Theme registry',
    'description' => 'View a list of available theme functions across the whole site.',
    'page callback' => 'devel_theme_registry',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/entity/info'] = array(
    'title' => 'Entity info',
    'description' => 'View entity information across the whole site.',
    'page callback' => 'devel_entity_info_page',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/field/info'] = array(
    'title' => 'Field info',
    'description' => 'View fields information across the whole site.',
    'page callback' => 'devel_field_info_page',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/elements'] = array(
    'title' => 'Hook_elements()',
    'description' => 'View the active form/render elements for this site.',
    'page callback' => 'devel_elements_page',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/variable/edit/%'] = array(
    'title' => 'Variable editor',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_variable_edit', 3),
    'access arguments' => array('access devel information'),
    'type' => MENU_CALLBACK,
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/session'] = array(
    'title' => 'Session viewer',
    'description' => 'List the contents of $_SESSION.',
    'page callback' => 'devel_session',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/switch'] = array(
    'title' => 'Switch user',
    'page callback' => 'devel_switch_user',
    'access arguments' => array('switch users'),
    'type' => MENU_CALLBACK,
    'file' => 'devel.pages.inc',
    'menu_name' => 'devel',
  );
  $items['devel/explain'] = array(
    'title' => 'Explain query',
    'page callback' => 'devel_querylog_explain',
    'description' => 'Run an EXPLAIN on a given query. Used by query log',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'type' => MENU_CALLBACK
  );
  $items['devel/arguments'] = array(
    'title' => 'Arguments query',
    'page callback' => 'devel_querylog_arguments',
    'description' => 'Return a given query, with arguments instead of placeholders. Used by query log',
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'type' => MENU_CALLBACK
  );
  $items['devel/run-cron'] = array(
    'title' => 'Run cron',
    'page callback' => 'system_run_cron',
    'access arguments' => array('administer site configuration'),
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
    'menu_name' => 'devel',
  );

  // Duplicate path in 2 different menus. See http://drupal.org/node/601788.
  $items['devel/settings'] = array(
    'title' => 'Devel settings',
    'description' =>  'Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the <a href="' . url('admin/structure/block') . '">block administration</a> page.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_admin_settings'),
    'access arguments' => array('administer site configuration'),
    'file' => 'devel.admin.inc',
    'menu_name' => 'devel',
  );
  $items['admin/config/development/devel'] = array(
    'title' => 'Devel settings',
    'description' =>  'Helper functions, pages, and blocks to assist Drupal developers. The devel blocks can be managed via the <a href="' . url('admin/structure/block') . '">block administration</a> page.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('devel_admin_settings'),
    'file' => 'devel.admin.inc',
    'access arguments' => array('administer site configuration'),
  );

  $items['node/%node/devel'] = array(
    'title' => 'Devel',
    'page callback' => 'devel_load_object',
    'page arguments' => array('node', 1),
    'access arguments' => array('access devel information'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'devel.pages.inc',
    'weight' => 100,
  );
  $items['node/%node/devel/load'] = array(
    'title' => 'Load',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['node/%node/devel/render'] = array(
    'title' => 'Render',
    'page callback' => 'devel_render_object',
    'page arguments' => array('node', 1),
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 100,
  );
  $items['comment/%comment/devel'] = array(
    'title' => 'Devel',
    'page callback' => 'devel_load_object',
    'page arguments' => array('comment', 1),
    'access arguments' => array('access devel information'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'devel.pages.inc',
    'weight' => 100,
  );
  $items['comment/%comment/devel/load'] = array(
    'title' => 'Load',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['comment/%comment/devel/render'] = array(
    'title' => 'Render',
    'page callback' => 'devel_render_object',
    'page arguments' => array('comment', 1),
    'access arguments' => array('access devel information'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'devel.pages.inc',
    'weight' => 100,
  );
  $items['user/%user/devel'] = array(
    'title' => 'Devel',
    'page callback' => 'devel_load_object',
    'page arguments' => array('user', 1),
    'access arguments' => array('access devel information'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'devel.pages.inc',
    'weight' => 100,
  );
  $items['user/%user/devel/load'] = array(
    'title' => 'Load',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['user/%user/devel/render'] = array(
    'title' => 'Render',
    'page callback' => 'devel_render_object',
    'page arguments' => array('user', 1),
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 100,
  );
  $items['taxonomy/term/%taxonomy_term/devel'] = array(
    'title' => 'Devel',
    'page callback' => 'devel_load_object',
    'page arguments' => array('taxonomy_term', 2, 'term'),
    'access arguments' => array('access devel information'),
    'file' => 'devel.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 100,
  );
  $items['taxonomy/term/%taxonomy_term/devel/load'] = array(
    'title' => 'Load',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['taxonomy/term/%taxonomy_term/devel/render'] = array(
    'title' => 'Render',
    'page callback' => 'devel_render_object',
    'page arguments' => array('taxonomy_term', 2, 'term'),
    'access arguments' => array('access devel information'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'devel.pages.inc',
    'weight' => 100,
  );

  return $items;
}

/**
 * Implements hook_admin_paths().
 */
function devel_admin_paths() {
  $paths = array(
    'devel/*' => TRUE,
    'node/*/devel' => TRUE,
    'node/*/devel/*' => TRUE,
    'comment/*/devel' => TRUE,
    'comment/*/devel/*' => TRUE,
    'user/*/devel' => TRUE,
    'user/*/devel/*' => TRUE,
    'taxonomy/term/*/devel' => TRUE,
    'taxonomy/term/*/devel/*' => TRUE,
  );
  return $paths;
}

function devel_menu_need_destination() {
  return array('devel/cache/clear', 'devel/reinstall', 'devel/menu/reset', 'devel/variable', 'admin/reports/status/run-cron');
}

/**
 * An implementation of hook_menu_link_alter(). Flag this link as needing alter at display time.
 * This is more robust than setting alter in hook_menu().
 * @see devel_translated_menu_link_alter().
 *
 **/
function devel_menu_link_alter(&$item) {
  if (in_array($item['link_path'], devel_menu_need_destination()) || $item['link_path'] == 'devel/menu/item') {
    $item['options']['alter'] = TRUE;
  }
}

/**
 * An implementation of hook_translated_menu_item_alter(). Append dynamic
 * querystring 'destination' to several of our own menu items.
 *
 **/
function devel_translated_menu_link_alter(&$item) {
  if (in_array($item['href'], devel_menu_need_destination())) {
    $item['localized_options']['query'] = drupal_get_destination();
  }
  elseif ($item['href'] == 'devel/menu/item') {
    $item['localized_options']['query'] = array('path' => $_GET['q']);
  }
}

/**
 * Implementation of hook_theme()
 */
function devel_theme() {
  return array(
    'devel_querylog' => array(
      'variables' => array('header' => array(), 'rows' => array()),
    ),
    'devel_querylog_row' => array(
      'variables' => array('row' => array()),
    ),
  );
}

/**
 * Implementation of hook_init().
 */
function devel_init() {
  if (!devel_silent()) {
    if (user_access('access devel information')) {
      devel_set_handler(variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD));
      // We want to include the class early so that anyone may call krumo() as needed. See http://krumo.sourceforge.net/
      has_krumo();

      // See http://www.firephp.org/HQ/Install.htm
      $path = NULL;
      if (@include_once('fb.php')) {
        // FirePHPCore is in include_path. Probably a PEAR installation.
        $path = '';
      }
      elseif (module_exists('libraries')) {
        // Support Libraries API - http://drupal.org/project/libraries
        $firephp_path = libraries_get_path('FirePHPCore') . '/lib/FirePHPCore/';
        $chromephp_path = libraries_get_path('chromephp');
      }
      else {
        $firephp_path = './'. drupal_get_path('module', 'devel') .'/FirePHPCore/lib/FirePHPCore/';
        $chromephp_path = './' . drupal_get_path('module', 'devel') .'/chromephp';
      }

      // include FirePHP if exists...
      if (file_exists($firephp_path .'fb.php')) {
        include_once $firephp_path .'fb.php';
        include_once $firephp_path .'FirePHP.class.php';
      }

      // include ChromePHP if exists...
      if (file_exists($chromephp_path . '/ChromePhp.php')) {
        include_once $chromephp_path . '/ChromePhp.php';
      }


      // Add CSS for query log if should be displayed.
      if (variable_get('devel_query_display', 0)) {
        drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css');
        drupal_add_js(drupal_get_path('module', 'devel'). '/devel.js');
      }
    }
  }
  if (variable_get('devel_rebuild_theme_registry', FALSE)) {
    drupal_theme_rebuild();
    if (flood_is_allowed('devel_rebuild_registry_warning', 1)) {
      flood_register_event('devel_rebuild_registry_warning');
      if (!devel_silent() && user_access('access devel information')) {
        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/config/development/devel'))));
      }
    }
  }
}

function devel_set_message($msg, $type = NULL) {
  $function  = function_exists('drush_log') ? 'drush_log' : 'drupal_set_message';
  $function($msg, $type);
}

// Return boolean. No need for cache here.
function has_krumo() {
  // see README.txt or just download from http://krumo.sourceforge.net/
  @include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'devel') .'/krumo/class.krumo.php';
  return function_exists('krumo') && !drupal_is_cli();
}

/**
 * Decide whether or not to print a debug variable using krumo().
 *
 * @param $input
 * @return boolean
 */
function merits_krumo($input) {
  return (is_object($input) || is_array($input)) && has_krumo() && variable_get('devel_krumo_skin', '') != 'disabled';
}

/**
 * Calls the http://www.firephp.org/ fb() function if it is found.
 *
 * @return void
 */
function dfb() {
  if (function_exists('fb') && user_access('access devel information') && !headers_sent()) {
    $args = func_get_args();
    call_user_func_array('fb', $args);
  }
}

/**
 * Calls dfb() to output a backtrace.
 */
function dfbt($label) {
  dfb($label, FirePHP::TRACE);
}

/**
 * Wrapper for ChromePHP Class log method
 */
function dcp() {
  if (class_exists('ChromePhp') && user_access('access devel information')) {
    $args = func_get_args();
    call_user_func_array(array('ChromePhp', 'log'), $args);
  }
}

/**
 * Implements hook_watchdog().
 */
function devel_watchdog(array $log_entry) {
  if (class_exists('FirePHP') && !drupal_is_cli()) {
    switch ($log_entry['severity']) {
      case WATCHDOG_EMERGENCY:
      case WATCHDOG_ALERT:
      case WATCHDOG_CRITICAL:
      case WATCHDOG_ERROR:
        $type = FirePHP::ERROR;
        break;
      case WATCHDOG_WARNING:
        $type = FirePHP::WARN;
        break;
      case WATCHDOG_NOTICE:
      case WATCHDOG_INFO:
        $type = FirePHP::INFO;
        break;
      case WATCHDOG_DEBUG:
      DEFAULT:
        $type = FirePHP::LOG;
    }
  }
  else {
    $type = 'watchdog';
  }
  $function = function_exists('decode_entities') ? 'decode_entities' : 'html_entity_decode';
  $watchdog = array(
    'type' => $log_entry['type'],
    'message' => $function(strtr($log_entry['message'], (array)$log_entry['variables'])),
  );
  if (isset($log_entry['link'])) {
    $watchdog['link'] = $log_entry['link'];
  }
  dfb($watchdog, $type);
}

function devel_set_handler($handler) {
  switch ($handler) {
    case DEVEL_ERROR_HANDLER_STANDARD:
      // do nothing
      break;
    case DEVEL_ERROR_HANDLER_BACKTRACE:
      if (has_krumo()) {
        set_error_handler('backtrace_error_handler');
      }
      break;
    case DEVEL_ERROR_HANDLER_NONE:
      restore_error_handler();
      break;
  }
}

function devel_silent() {
  // isset($_GET['q']) is needed when calling the front page. q is not set.
  // Don't interfere with private files/images.
  return
    function_exists('drupal_is_cli') && drupal_is_cli() ||
    (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'ApacheBench') !== FALSE) ||
    !empty($_REQUEST['XDEBUG_PROFILE']) ||
    isset($GLOBALS['devel_shutdown']) ||
    strstr($_SERVER['PHP_SELF'], 'update.php') ||
    (isset($_GET['q']) && (
      in_array($_GET['q'], array( 'admin/content/node-settings/rebuild')) ||
      substr($_GET['q'], 0, strlen('system/files')) == 'system/files' ||
      substr($_GET['q'], 0, strlen('batch')) == 'batch' ||
      substr($_GET['q'], 0, strlen('file/ajax')) == 'file/ajax')
    );
}

function devel_xhprof_enable() {
  if (devel_xhprof_is_enabled()) {
    if ($path = variable_get('devel_xhprof_directory', '')) {
      include_once $path . '/xhprof_lib/utils/xhprof_lib.php';
      include_once $path . '/xhprof_lib/utils/xhprof_runs.php';
      // @todo: consider a variable per-flag instead.
      xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
    }
  }
}

function devel_xhprof_is_enabled() {
  return extension_loaded('xhprof') && variable_get('devel_xhprof_enabled', FALSE);
}

/**
 * Implementation of hook_boot(). Runs even for cached pages.
 */
function devel_boot() {
  // Initialize XHProf.
  devel_xhprof_enable();

  if (!devel_silent()) {
    if (variable_get('dev_mem', 0)) {
      global $memory_init;
      $memory_init = memory_get_usage();
    }

    if (devel_query_enabled()) {
      @include_once DRUPAL_ROOT . '/includes/database/log.inc';
      Database::startLog('devel');;
    }
  }

  // We need user_access() in the shutdown function. make sure it gets loaded.
  // Also prime the drupal_get_filename() static with user.module's location to
  // avoid a stray query.
  drupal_get_filename('module', 'user', 'modules/user/user.module');
  drupal_load('module', 'user');
  drupal_register_shutdown_function('devel_shutdown');
}

function backtrace_error_handler($error_level, $message, $filename, $line, $context) {
  // Hide stack trace and parameters from unqualified users.
  if (!user_access('access devel information')) {
    return _drupal_error_handler($error_level, $message, $filename, $line, $context);
  }
  // Don't respond to the error if it was suppressed with a '@'
  if (error_reporting() == 0) {
    return;
  }
  // Don't respond to warning caused by ourselves.
  if (preg_match('#Cannot modify header information - headers already sent by \\([^\\)]*[/\\\\]devel[/\\\\]#', $message)) {
    return;
  }
  if ($error_level & error_reporting()) {
    // Only write each distinct NOTICE message once, as repeats do not give any
    // further information and can choke the page output.
    if ($error_level == E_NOTICE) {
      static $written = array();
      if (!empty($written[$line][$filename][$message])) {
        return;
      }
      $written[$line][$filename][$message] = TRUE;
    }

    require_once DRUPAL_ROOT . '/includes/errors.inc';
    $types = drupal_error_levels();
    $type = $types[$error_level];
    $backtrace = debug_backtrace();
    array_shift($backtrace);
    $variables = array('%error' => $type[0], '%message' => $message, '%function' => $backtrace[0]['function'] .'()', '%file' => $filename, '%line' => $line);
    $counter = 0;

    if (variable_get('error_level', 1) == 1) {
      foreach ($backtrace as $call) {
        $nicetrace[$call['function'] . '<span class="' . $counter++ . '" />'] = $call;
      }
      print t('%error: %message in %function (line %line of %file).', $variables) ." =&gt;\n";
      krumo($nicetrace);
    }

    watchdog('php', '%error: %message in %function (line %line of %file).', $variables, $type[1]);
  }
}

/**
 * Implement hook_permission().
 */
function devel_permission() {
  return array(
    'access devel information' => array(
      'description' => t('View developer output like variable printouts, query log, etc.'),
      'title' => t('Access developer information'),
      'restrict access' => TRUE,
    ),
    'execute php code' => array(
      'title' => t('Execute PHP code'),
      'description' => t('Run arbitrary PHP from a block.'),
      'restrict access' => TRUE,
    ),
    'switch users' => array(
      'title' => t('Switch users'),
      'description' => t('Become any user on the site with just a click.'),
      'restrict access' => TRUE,
    ),
    'display source code' => array(
      'title' => t('Display source code'),
      'description' => t('View the site\'s php source code.'),
      'restrict access' => TRUE,
    ),
  );
}

function devel_block_info() {
  $blocks['execute_php'] = array(
    'info' => t('Execute PHP'),
    'cache' => DRUPAL_NO_CACHE,
  );
  $blocks['switch_user'] = array(
    'info' => t('Switch user'),
    'cache' => DRUPAL_NO_CACHE,
  );
  return $blocks;
}

/**
 * Implementation of hook_block_configure().
 */
function devel_block_configure($delta) {
  if ($delta == 'switch_user') {
    $form['list_size'] = array(
      '#type' => 'textfield',
      '#title' => t('Number of users to display in the list'),
      '#default_value' => variable_get('devel_switch_user_list_size', 10),
      '#size' => '3',
      '#maxlength' => '4',
    );
    $form['include_anon'] = array(
      '#type' => 'checkbox',
      '#title' => t('Include %anonymous', array('%anonymous' => format_username(drupal_anonymous_user()))),
      '#default_value' => variable_get('devel_switch_user_include_anon', FALSE),
    );
    $form['show_form'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow entering any user name'),
      '#default_value' => variable_get('devel_switch_user_show_form', TRUE),
    );
    return $form;
  }
}

function devel_block_save($delta, $edit = array()) {
  if ($delta == 'switch_user') {
    variable_set('devel_switch_user_list_size', $edit['list_size']);
    variable_set('devel_switch_user_include_anon', $edit['include_anon']);
    variable_set('devel_switch_user_show_form', $edit['show_form']);
  }
}

function devel_block_view($delta) {
  $block = array();
  switch ($delta) {
    case 'switch_user':
      $block = devel_block_switch_user();
      break;

    case 'execute_php':
      if (user_access('execute php code')) {
        $block['content'] = drupal_get_form('devel_execute_block_form');
      }
      break;
  }
  return $block;
}

function devel_block_switch_user() {
  $links = devel_switch_user_list();
  if (!empty($links) || user_access('switch users')) {
    $block['subject'] = t('Switch user');
    $build['devel_links'] = array('#theme' => 'links', '#links' => $links);
    if (variable_get('devel_switch_user_show_form', TRUE)) {
      $build['devel_form'] = drupal_get_form('devel_switch_user_form');
    }
    $block['content'] = $build;
    return $block;
  }
}

function devel_switch_user_list() {
  global $user;

  $links = array();
  if (user_access('switch users')) {
    $list_size = variable_get('devel_switch_user_list_size', 10);
    if ($include_anon = ($user->uid && variable_get('devel_switch_user_include_anon', FALSE))) {
      --$list_size;
    }
    $dest = drupal_get_destination();
    // Try to find at least $list_size users that can switch.
    // Inactive users are omitted from all of the following db selects.
    $roles = user_roles(TRUE, 'switch users');
    $query = db_select('users', 'u');
    $query->addField('u', 'uid');
    $query->distinct();
    $query->condition('u.uid', 0, '>');
    $query->condition('u.status', 0, '>');
    $query->orderBy('u.access', 'DESC');
    $query->range(0, $list_size);

    if (!isset($roles[DRUPAL_AUTHENTICATED_RID])) {
      $query->leftJoin('users_roles', 'r', 'u.uid = r.uid');
      $or_condition = db_or();
      $or_condition->condition('u.uid', 1);
      if (!empty($roles)) {
        $or_condition->condition('r.rid', array_keys($roles), 'IN');
      }
      $query->condition($or_condition);
    }

    $uids = $query->execute()->fetchCol();
    $accounts = user_load_multiple($uids);

    foreach ($accounts as $account) {
      $links[$account->uid] = array(
        'title' => drupal_placeholder(format_username($account)),
        'href' => 'devel/switch/'. $account->name,
        'query' => $dest,
        'attributes' => array('title' => t('This user can switch back.')),
        'html' => TRUE,
        'last_access' => $account->access,
      );
    }
    $num_links = count($links);
    if ($num_links < $list_size) {
      // If we don't have enough, add distinct uids until we hit $list_size.
      $uids = db_query_range('SELECT uid FROM {users} WHERE uid > 0 AND uid NOT IN (:uids) AND status > 0 ORDER BY access DESC', 0, $list_size - $num_links, array(':uids' => array_keys($links)))->fetchCol();
      $accounts = user_load_multiple($uids);
      foreach ($accounts as $account) {
        $links[$account->uid] = array(
          'title' => format_username($account),
          'href' => 'devel/switch/'. $account->name,
          'query' => $dest,
          'attributes' => array('title' => t('Caution: this user will be unable to switch back.')),
          'last_access' => $account->access,
        );
      }
      uasort($links, '_devel_switch_user_list_cmp');
    }
    if ($include_anon) {
      $link = array(
        'title' => format_username(drupal_anonymous_user()),
        'href' => 'devel/switch',
        'query' => $dest,
        'attributes' => array('title' => t('Caution: the anonymous user will be unable to switch back.')),
      );
      if (user_access('switch users', drupal_anonymous_user())) {
        $link['title'] = drupal_placeholder($link['title']);
        $link['attributes'] = array('title' => t('This user can switch back.'));
        $link['html'] = TRUE;
      }
      $links[] = $link;
    }
  }
  return $links;
}

/**
 * Comparison helper function for uasort() in devel_switch_user_list().
 *
 * Sorts the Switch User links by the user's last access timestamp.
 */
function _devel_switch_user_list_cmp($a, $b) {
  return $b['last_access'] - $a['last_access'];
}

function devel_switch_user_form() {
  $form['username'] = array(
    '#type' => 'textfield',
    '#description' => t('Enter username'),
    '#autocomplete_path' => 'user/autocomplete',
    '#maxlength' => USERNAME_MAX_LENGTH,
    '#size' => 16,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Switch'),
  );
  return $form;

}

function devel_doc_function_form() {
  $version = devel_get_core_version(VERSION);
  $form['function'] = array(
    '#type' => 'textfield',
    '#description' => t('Enter function name for api lookup'),
    '#size' => 16,
    '#maxlength' => 255,
  );
  $form['version'] = array('#type' => 'value', '#value' => $version);
  $form['submit_button'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

function devel_doc_function_form_submit($form, &$form_state) {
  $version = $form_state['values']['version'];
  $function = $form_state['values']['function'];
  $api = variable_get('devel_api_url', 'api.drupal.org');
  $form_state['redirect'] =   "http://$api/api/function/$function/$version";
}

function devel_switch_user_form_validate($form, &$form_state) {
  if (!$account = user_load_by_name($form_state['values']['username'])) {
    form_set_error('username', t('Username not found'));
  }
}

function devel_switch_user_form_submit($form, &$form_state) {
  $form_state['redirect'] = 'devel/switch/'. $form_state['values']['username'];
}

/**
 * Implements hook_drupal_goto_alter().
 */
function devel_drupal_goto_alter($path, $options, $http_response_code) {
  global $user;

  if (isset($path) && !devel_silent()) {
    // The page we are leaving is a drupal_goto(). Present a redirection page
    // so that the developer can see the intermediate query log.
    // We don't want to load user module here, so keep function_exists() call.
    if (isset($user) && function_exists('user_access') && user_access('access devel information') && variable_get('devel_redirect_page', 0)) {
      $destination = function_exists('url') ? url($path, $options) : $path;
      $output = t_safe('<p>The user is being redirected to <a href="@destination">@destination</a>.</p>', array('@destination' => $destination));
      drupal_deliver_page($output);

      // Don't allow the automatic redirect to happen.
      exit();
    }
    else {
      $GLOBALS['devel_redirecting'] = TRUE;
    }
  }
}

/**
 * Implements hook_library_alter().
 */
function devel_library_alter(&$libraries, $module) {
  // Use an uncompressed version of jQuery for debugging.
  if ($module === 'system' && variable_get('devel_use_uncompressed_jquery', FALSE) && isset($libraries['jquery'])) {
    // Make sure we're not changing the jQuery version used on the site.
    if (version_compare($libraries['jquery']['version'], '1.4.4', '=')) {
      $libraries['jquery']['js'] = array(
        drupal_get_path('module', 'devel') . '/jquery-1.4.4-uncompressed.js' => array('weight' => JS_LIBRARY - 20),
      );
    }
    else {
      if (!devel_silent() && user_access('access devel information')) {
        drupal_set_message(t('jQuery could not be replaced with an uncompressed version of 1.4.4, because jQuery @version is running on the site.', array('@version' => $libraries['jquery']['version'])));
      }

    }
  }
}

/**
 * See devel_start() which registers this function as a shutdown function.
 */
function devel_shutdown() {
  // Register the real shutdown function so it runs later than other shutdown functions.
  drupal_register_shutdown_function('devel_shutdown_real');

  global $devel_run_id;
  $devel_run_id = devel_xhprof_is_enabled() ? devel_shutdown_xhprof(): NULL;
  if ($devel_run_id && function_exists('drush_log')) {
    drush_log('xhprof link: ' . devel_xhprof_link($devel_run_id, 'url'), 'notice');
  }
}

function devel_page_alter($page) {
  if (variable_get('devel_page_alter', FALSE) && user_access('access devel information')) {
    dpm($page, 'page');
  }
}

// AJAX render reponses sometimers are sent as text/html so we have to catch them here
// and disable our footer stuff.
function devel_ajax_render_alter() {
  $GLOBALS['devel_shutdown'] = FALSE;
}

/**
 * See devel_shutdown() which registers this function as a shutdown function. Displays developer information in the footer.
 */
function devel_shutdown_real() {
  global $user;
  $output = $txt = '';

  // Set $GLOBALS['devel_shutdown'] = FALSE in order to supress the
  // devel footer for a page.  Not necessary if your page outputs any
  // of the Content-type http headers tested below (e.g. text/xml,
  // text/javascript, etc).  This is is advised where applicable.
  if (!devel_silent() && !isset($GLOBALS['devel_shutdown']) && !isset($GLOBALS['devel_redirecting'])) {
    // Try not to break non html pages.
    if (function_exists('drupal_get_http_header')) {
      $header = drupal_get_http_header('content-type');
      if ($header) {
        $formats = array('xml', 'javascript', 'json', 'plain', 'image', 'application', 'csv', 'x-comma-separated-values');
        foreach ($formats as $format) {
          if (strstr($header, $format)) {
            return;
          }
        }
      }
    }

    if (isset($user) && user_access('access devel information')) {
      $queries = Database::getLog('devel', 'default');
      $output .= devel_shutdown_summary($queries);
      $output .= devel_shutdown_query($queries);
    }

    if ($output) {
      // TODO: gzip this text if we are sending a gzip page. see drupal_page_header().
      // For some reason, this is not actually printing for cached pages even though it gets executed
      // and $output looks good.
      print $output;
    }
  }
}

function devel_shutdown_summary($queries) {
  $sum = 0;
  $output = '';
  list($counts, $query_summary) = devel_query_summary($queries);

  if (variable_get('devel_query_display', FALSE)) {
    // Query log on.
    $output .= $query_summary;
    $output .= t_safe(' Queries exceeding @threshold ms are <span class="marker">highlighted</span>.', array('@threshold' => variable_get('devel_execution', 5)));
  }

  if (variable_get('dev_timer', 0)) {
    $output .= devel_timer();
  }

  if (devel_xhprof_is_enabled()) {
    $output .= ' ' . devel_xhprof_link($GLOBALS['devel_run_id']);
  }

  $output .= devel_shutdown_memory();

  if ($output) {
    return '<div class="dev-query">' . $output . '</div>';
  }
}

function devel_shutdown_xhprof() {
  $namespace = variable_get('site_name', '');  // namespace for your application
  $xhprof_data = xhprof_disable();
  $xhprof_runs = new XHProfRuns_Default();
  return $xhprof_runs->save_run($xhprof_data, $namespace);
}

function devel_xhprof_link($run_id, $type = 'link') {
  // @todo: render results from within Drupal.
  $xhprof_url = variable_get('devel_xhprof_url', '');
  $namespace = variable_get('site_name', '');  // namespace for your application
  if ($xhprof_url) {
    $url  = $xhprof_url . "/index.php?run=$run_id&source=$namespace";
    return $type == 'url' ? $url : t('<a href="@xhprof">XHProf output</a>. ', array('@xhprof' => $url));
  }
}

function devel_shutdown_memory() {
  global $memory_init;

  if (variable_get('dev_mem', FALSE)) {
    $memory_shutdown = memory_get_usage();
    $args = array('@memory_boot' => round($memory_init / 1024 / 1024, 2), '@memory_shutdown' => round($memory_shutdown / 1024 / 1024, 2), '@memory_peak' => round(memory_get_peak_usage(TRUE) / 1024 / 1024, 2));
    $msg = '<span class="dev-memory-usages"> Memory used at: devel_boot()=<strong>@memory_boot</strong> MB, devel_shutdown()=<strong>@memory_shutdown</strong> MB, PHP peak=<strong>@memory_peak</strong> MB.</span>';
    // theme() may not be available. not t() either.
    return t_safe($msg, $args);
  }
}

function devel_shutdown_query($queries) {
  if (!empty($queries)) {
    if (function_exists('theme_get_registry') && theme_get_registry()) {
      // Safe to call theme('table).
      list($counts, $query_summary) = devel_query_summary($queries);
      $output = devel_query_table($queries, $counts);

      // Save all queries to a file in temp dir. Retrieved via AJAX.
      devel_query_put_contents($queries);
    }
    else {
      $output = '</div>' . dprint_r($queries, TRUE);
    }
    return $output;
  }
}

// Write the variables information to the a file. It will be retrieved on demand via AJAX.
function devel_query_put_contents($queries) {
  $request_id = mt_rand(1, 1000000);
  $path = "temporary://devel_querylog";

  // Create the devel_querylog within the temp folder, if needed.
  file_prepare_directory($path, FILE_CREATE_DIRECTORY);

  // Occassionally wipe the querylog dir so that files don't accumulate.
  if (mt_rand(1, 1000) == 401) {
    devel_empty_dir($path);
  }

  $path .= "/$request_id.txt";
  $path = file_stream_wrapper_uri_normalize($path);
  // Save queries as a json array. Suppress errors due to recursion ()
  file_put_contents($path, @json_encode($queries));
  $settings['devel'] = array(
    // A random string that is sent to the browser. It enables the AJAX to retrieve queries from this request.
    'request_id' => $request_id,
  );
  print '<script type="text/javascript">jQuery.extend(Drupal.settings, '.  json_encode($settings) .");</script>\n";
}

function devel_query_enabled() {
  return method_exists('Database', 'getLog') && variable_get('devel_query_display', FALSE);
}

function devel_query_summary($queries) {
  if (variable_get('devel_query_display', FALSE) && is_array($queries)) {
    $sum = 0;
    foreach ($queries as $query) {
      $text[] = $query['query'];
      $sum += $query['time'];
    }
    $counts = array_count_values($text);
    return array($counts, t_safe('Executed @queries queries in @time ms.', array('@queries' => count($queries), '@time' => round($sum * 1000, 2))));
  }
}

function t_safe($string, $args) {
  // get_t caused problems here with theme registry after changing on admin/build/modules. the theme_get_registry call is needed.
  if (function_exists('t') && function_exists('theme_get_registry')) {
    theme_get_registry();
    return t($string, $args);
  }
  else {
    strtr($string, $args);
  }
}

function devel_get_core_version($version) {
  $version_parts = explode('.', $version);
  // Map from 4.7.10 -> 4.7
  if ($version_parts[0] < 5) {
    return $version_parts[0] .'.'. $version_parts[1];
  }
  // Map from 5.5 -> 5 or 6.0-beta2 -> 6
  else {
    return $version_parts[0];
  }
}

// See http://drupal.org/node/126098
function devel_is_compatible_optimizer() {
   ob_start();
   phpinfo();
   $info = ob_get_contents();
   ob_end_clean();

   // Match the Zend Optimizer version in the phpinfo information
   $found = preg_match('/Zend&nbsp;Optimizer&nbsp;v([0-9])\.([0-9])\.([0-9])/', $info, $matches);

   if ($matches) {
     $major = $matches[1];
     $minor = $matches[2];
     $build = $matches[3];

     if ($major >= 3) {
       if ($minor >= 3) {
         return TRUE;
       }
       elseif ($minor == 2 && $build >= 8) {
         return TRUE;
       }
       else {
         return FALSE;
       }
    }
    else {
      return FALSE;
    }
  }
  else {
    return TRUE;
  }
}

/**
 * Generates the execute block form.
 */
function devel_execute_block_form() {
  $form['execute'] = array(
    '#type' => 'fieldset',
    '#title' => t('Execute PHP Code'),
    '#collapsible' => TRUE,
    '#collapsed' => (!isset($_SESSION['devel_execute_code'])),
  );
  $form['#submit'] = array('devel_execute_form_submit');
  return array_merge_recursive($form, devel_execute_form());
}

/**
 * Generates the execute form.
 */
function devel_execute_form() {
  $form['execute']['code'] = array(
    '#type' => 'textarea',
    '#title' => t('PHP code to execute'),
    '#description' => t('Enter some code. Do not use <code>&lt;?php ?&gt;</code> tags.'),
    '#default_value' => (isset($_SESSION['devel_execute_code']) ? $_SESSION['devel_execute_code'] : ''),
    '#rows' => 20,
  );
  $form['execute']['op'] = array('#type' => 'submit', '#value' => t('Execute'));
  $form['#redirect'] = FALSE;
  if (isset($_SESSION['devel_execute_code'])) {
    unset($_SESSION['devel_execute_code']);
  }
  return $form;
}

/**
 * Process PHP execute form submissions.
 */
function devel_execute_form_submit($form, &$form_state) {
  ob_start();
  print eval($form_state['values']['code']);
  $_SESSION['devel_execute_code'] = $form_state['values']['code'];
  dsm(ob_get_clean());
}

/**
 * Switch from original user to another user and back.
 * We don't call session_save_session() because we really want to change users. Usually unsafe!
 *
 * @param $name The username to switch to, or NULL to log out.
 */
function devel_switch_user($name = NULL) {
  global $user;

  if ($user->uid) {
    module_invoke_all('user_logout', $user);
  }
  if (isset($name) && $account = user_load_by_name($name)) {
    $old_uid = $user->uid;
    $user = $account;
    if (!$old_uid) {
      // Switch from anonymous to authorized.
      drupal_session_regenerate();
    }
    $edit = array();
    user_module_invoke('login', $edit, $user);
  }
  elseif ($user->uid) {
    session_destroy();
  }
  drupal_goto();
}

/**
 * Print an object or array using either Krumo (if installed) or devel_print_object()
 *
 * @param $object
 *   array or object to print
 * @param $prefix
 *   prefixing for output items
 */
function kdevel_print_object($object, $prefix = NULL) {
  return has_krumo() ? krumo_ob($object) : devel_print_object($object, $prefix);
}

// Save krumo htlm using output buffering.
function krumo_ob($object) {
  ob_start();
  krumo($object);
  $output = ob_get_contents();
  ob_end_clean();
  return $output;
}

/**
 * Display an object or array
 *
 * @param $object
 *   the object or array
 * @param $prefix
 *   prefix for the output items (example "$node->", "$user->", "$")
 * @param $header
 *   set to FALSE to suppress the output of the h3
 */
function devel_print_object($object, $prefix = NULL, $header = TRUE) {
  drupal_add_css(drupal_get_path('module', 'devel') .'/devel.css');
  $output = '<div class="devel-obj-output">';
  if ($header) {
    $output .= '<h3>'. t('Display of !type !obj', array('!type' => str_replace(array('$', '->'), '', $prefix), '!obj' => gettype($object))) .'</h3>';
  }
  $output .= _devel_print_object($object, $prefix);
  $output .= '</div>';
  return $output;
}

/**
 * Recursive (and therefore magical) function goes through an array or object and
 * returns a nicely formatted listing of its contents.
 *
 * @param $obj
 *   array or object to recurse through
 * @param $prefix
 *   prefix for the output items (example "$node->", "$user->", "$")
 * @param $parents
 *   used by recursion
 * @param $object
 *   used by recursion
 * @return
 *   fomatted html
 *
 * @todo
 *   currently there are problems sending an array with a varname
 */
function _devel_print_object($obj, $prefix = NULL, $parents = NULL, $object = FALSE) {
  static $root_type, $out_format;

  // TODO: support objects with references. See http://drupal.org/node/234581.
  if (isset($obj->view)) {
    return;
  }

  if (!isset($root_type)) {
    $root_type = gettype($obj);
    if ($root_type == 'object') {
      $object = TRUE;
    }
  }

  if (is_object($obj)) {
    $obj = (array)$obj;
  }
  if (is_array($obj)) {
    $output = "<dl>\n";
    foreach ($obj as $field => $value) {
      if ($field == 'devel_flag_reference') {
        continue;
      }
      if (!is_null($parents)) {
        if ($object) {
          $field = $parents .'->'. $field;
        }
        else {
          if (is_int($field)) {
            $field = $parents .'['. $field .']';
          }
          else {
            $field = $parents .'[\''. $field .'\']';
          }
        }
      }

      $type = gettype($value);

      $show_summary = TRUE;
      $summary = NULL;
      if ($show_summary) {
        switch ($type) {
          case 'string' :
          case 'float' :
          case 'integer' :
            if (strlen($value) == 0) {
              $summary = t("{empty}");
            }
            elseif (strlen($value) < 40) {
              $summary = htmlspecialchars($value);
            }
            else {
              $summary = format_plural(drupal_strlen($value), '1 character', '@count characters');
            }
            break;
          case 'array' :
          case 'object' :
            $summary = format_plural(count((array)$value), '1 element', '@count elements');
            break;
          case 'boolean' :
            $summary = $value ? t('TRUE') : t('FALSE');
            break;
        }
      }
      if (!is_null($summary)) {
        $typesum = '('. $type .', <em>'. $summary .'</em>)';
      }
      else {
        $typesum = '('. $type .')';
      }

      $output .= '<span class="devel-attr">';
      $output .= "<dt><span class=\"field\">{$prefix}{$field}</span> $typesum</dt>\n";
      $output .= "<dd>\n";
      // Check for references.
      if (is_array($value) && isset($value['devel_flag_reference'])) {
        $value['devel_flag_reference'] = TRUE;
      }
      // Check for references to prevent errors from recursions.
      if (is_array($value) && isset($value['devel_flag_reference']) && !$value['devel_flag_reference']) {
        $value['devel_flag_reference'] = FALSE;
        $output .= _devel_print_object($value, $prefix, $field);
      }
      elseif (is_object($value)) {
        $value->devel_flag_reference = FALSE;
        $output .= _devel_print_object((array)$value, $prefix, $field, TRUE);
      }
      else {
        $value = is_bool($value) ? ($value ? 'TRUE' : 'FALSE') : $value;
        $output .= htmlspecialchars(print_r($value, TRUE)) ."\n";
      }
      $output .= "</dd></span>\n";
    }
    $output .= "</dl>\n";
  }
  return $output;
}

/**
 * Adds a table at the bottom of the page cataloguing data on all the database queries that were made to
 * generate the page.
 */
function devel_query_table($queries, $counts) {
  $version = devel_get_core_version(VERSION);
  $header = array ('ms', '#', 'where', 'ops', 'query', 'target');
  $i = 0;
  $api = variable_get('devel_api_url', 'api.drupal.org');
  foreach ($queries as $query) {
    $function = !empty($query['caller']['class']) ? $query['caller']['class'] . '::' : '';
    $function .= $query['caller']['function'];
    $count = isset($counts[$query['query']]) ? $counts[$query['query']] : 0;

    $diff = round($query['time'] * 1000, 2);
    if ($diff > variable_get('devel_execution', 5)) {
      $cell[$i][] = array ('data' => $diff, 'class' => 'marker');
    }
    else {
      $cell[$i][] = $diff;
    }
    $cell[$i][] = $count;
    $cell[$i][] = l($function, "http://$api/api/function/$function/$version");
    $ops[] = l('P', '', array('attributes' => array('title' => 'Show placeholders', 'class' => 'dev-placeholders', 'qid' => $i)));
    $ops[] = l('A', '', array('attributes' => array('title' => 'Show arguments', 'class' => 'dev-arguments', 'qid' => $i)));
    // EXPLAIN only valid for select queries.
    if (strpos($query['query'], 'UPDATE') === FALSE && strpos($query['query'], 'INSERT') === FALSE && strpos($query['query'], 'DELETE') === FALSE) {
      $ops[] = l('E', '', array('attributes' => array('title' => 'Show EXPLAIN', 'class' => 'dev-explain', 'qid' => $i)));
    }
    $cell[$i][] = implode(' ', $ops);
    // 3 divs for each variation of the query. Last 2 are hidden by default.
    $placeholders = '<div class="dev-placeholders">' . check_plain($query['query']) . "</div>\n";
    $args = '<div class="dev-arguments" style="display: none;"></div>' . "\n";
    $explain = '<div class="dev-explain" style="display: none;"></div>' . "\n";
    $cell[$i][] = array(
      'id' => "devel-query-$i",
      'data' => $placeholders . $args . $explain,
    );
    $cell[$i][] = $query['target'];
    $i++;
    unset($diff, $count, $ops);
  }
  if (variable_get('devel_query_sort', DEVEL_QUERY_SORT_BY_SOURCE)) {
    usort($cell, '_devel_table_sort');
  }
  return theme('devel_querylog', array('header' => $header, 'rows' => $cell));
}

function theme_devel_querylog_row($variables) {
  $row = $variables['row'];
  $i = 0;
  $output = '';
  foreach ($row as $cell) {
    $i++;

    if (is_array($cell)) {
      $data = !empty($cell['data']) ? $cell['data'] : '';
      unset($cell['data']);
      $attr = $cell;
    }
    else {
      $data = $cell;
      $attr = array();
    }

    if (!empty($attr['class'])) {
      $attr['class'] .= " cell cell-$i";
    }
    else {
      $attr['class'] = "cell cell-$i";
    }
    $attr = drupal_attributes($attr);

    $output .= "<div $attr>$data</div>";
  }
  return $output;
}

function theme_devel_querylog($variables) {
  $header = $variables['header'];
  $rows = $variables['rows'];
  $output = '';
  if (!empty($header)) {
    $output .= "<div class='devel-querylog devel-querylog-header clear-block'>";
    $output .= theme('devel_querylog_row', array('row' => $header));
    $output .= "</div>";
  }
  if (!empty($rows)) {
    $i = 0;
    foreach ($rows as $row) {
      $i++;
      $zebra = ($i % 2) == 0 ? 'even' : 'odd';
      $output .= "<div class='devel-querylog devel-querylog-$zebra clear-block'>";
      $output .= theme('devel_querylog_row', array('row' => $row));
      $output .= "</div>";
    }
  }
  return $output;
}

function _devel_table_sort($a, $b) {
  $a = is_array($a[0]) ? $a[0]['data'] : $a[0];
  $b = is_array($b[0]) ? $b[0]['data'] : $b[0];
  if ($a < $b) {
    return 1;
  }
  if ($a > $b) {
    return -1;
  }
  return 0;
}

/**
 * Displays page execution time at the bottom of the page.
 */
function devel_timer() {
  $time = timer_read('page');
  return t_safe(' Page execution time was @time ms.', array('@time' => $time));
}

// An alias for drupal_debug().
function dd($data, $label = NULL) {
  return drupal_debug($data, $label);
}

// Log any variable to a drupal_debug.log in the site's temp directory.
// See http://drupal.org/node/314112
function drupal_debug($data, $label = NULL) {
  ob_start();
  print_r($data);
  $string = ob_get_clean();
  if ($label) {
    $out = $label .': '. $string;
  }
  else {
    $out = $string;
  }
  $out .= "\n";

  // The temp directory does vary across multiple simpletest instances.
  $file = 'temporary://drupal_debug.txt';
  if (file_put_contents($file, $out, FILE_APPEND) === FALSE) {
    drupal_set_message(t('The file could not be written.'), 'error');
    return FALSE;
  }
}

/**
 * Prints the arguments passed into the current function
 */
function dargs($always = TRUE) {
  static $printed;
  if ($always || !$printed) {
    $bt = debug_backtrace();
    print kdevel_print_object($bt[1]['args']);
    $printed = TRUE;
  }
}

/**
 * Print a SQL string from a DBTNG Query object. Includes quoted arguments.
 *
 * @param $query
 *   A Query object.
 * @param $return
 *   Whether to return or print the string. Default to FALSE.
 * @param $name
 *   Optional name for identifying the output.
 */
function dpq($query, $return = FALSE, $name = NULL) {
  if (user_access('access devel information')) {
    $query->preExecute();
    $sql = (string) $query;
    $quoted = array();
    $connection = Database::getConnection();
    foreach ((array)$query->arguments() as $key => $val) {
      $quoted[$key] = $connection->quote($val);
    }
    $sql = strtr($sql, $quoted);
    if ($return) {
      return $sql;
    }
    else {
      dpm($sql, $name);
    }
  }
}

/**
 * Print a variable to the 'message' area of the page. Uses drupal_set_message()
 */
function dpm($input, $name = NULL) {
  if (user_access('access devel information')) {
    $export = kprint_r($input, TRUE, $name);
    drupal_set_message($export);
  }
}

/**
 * drupal_var_export() a variable to the 'message' area of the page. Uses drupal_set_message()
 */
function dvm($input, $name = NULL) {
  if (user_access('access devel information')) {
    $export = dprint_r($input, TRUE, $name, 'drupal_var_export', FALSE);
    drupal_set_message($export);
  }
}

// legacy function that was poorly named. use dpm() instead, since the 'p' maps to 'print_r'
function dsm($input, $name = NULL) {
  dpm($input, $name);
}

/**
 * An alias for dprint_r(). Saves carpal tunnel syndrome.
 */
function dpr($input, $return = FALSE, $name = NULL) {
  return dprint_r($input, $return, $name);
}

/**
 * An alias for kprint_r(). Saves carpal tunnel syndrome.
 */
function kpr($input, $return = FALSE, $name = NULL) {
  return kprint_r($input, $return, $name);
}

/**
 * Like dpr, but uses drupal_var_export() instead
 */
function dvr($input, $return = FALSE, $name = NULL) {
  return dprint_r($input, $return, $name, 'drupal_var_export', FALSE);
}

function kprint_r($input, $return = FALSE, $name = NULL, $function = 'print_r') {
  // We do not want to krumo() strings and integers and such
  if (merits_krumo($input)) {
    if (user_access('access devel information')) {
      return $return ? (isset($name) ? $name .' => ' : '') . krumo_ob($input) : krumo($input);
    }
  }
  else {
    return dprint_r($input, $return, $name, $function);
  }
}

/**
 * Pretty-print a variable to the browser (no krumo).
 * Displays only for users with proper permissions. If
 * you want a string returned instead of a print, use the 2nd param.
 */
function dprint_r($input, $return = FALSE, $name = NULL, $function = 'print_r', $check= TRUE) {
  if (user_access('access devel information')) {
    if ($name) {
      $name .= ' => ';
    }
    if ($function == 'drupal_var_export') {
      include_once DRUPAL_ROOT . '/includes/utility.inc';
      $output = drupal_var_export($input);
    }
    else {
      ob_start();
      $function($input);
      $output = ob_get_clean();
    }

    if ($check) {
      $output = check_plain($output);
    }
    if (count($input, COUNT_RECURSIVE) > DEVEL_MIN_TEXTAREA) {
        // don't use fapi here because sometimes fapi will not be loaded
        $printed_value = "<textarea rows=30 style=\"width: 100%;\">\n". $name . $output .'</textarea>';
    }
    else {
      $printed_value = '<pre>'. $name . $output .'</pre>';
    }

    if ($return) {
      return $printed_value;
    }
    else {
      print $printed_value;
    }
  }
}

/**
 * Prints a renderable array element to the screen using kprint_r().
 *
 * #pre_render and/or #post_render pass-through callback for kprint_r().
 *
 * @todo Investigate appending to #suffix.
 * @todo Investigate label derived from #id, #title, #name, and #theme.
 */
function devel_render() {
  $args = func_get_args();
  // #pre_render and #post_render pass the rendered $element as last argument.
  kprint_r(end($args));
  // #pre_render and #post_render expect the first argument to be returned.
  return reset($args);
}

/**
 * Print the function call stack.
 */
function ddebug_backtrace() {
  if (user_access('access devel information')) {
    $trace = debug_backtrace();
    array_shift($trace);
    $count = count($trace);
    foreach ($trace as $i => $call) {
      $key = ($count - $i) . ': ' . $call['function'];
      $rich_trace[$key] = $call;
    }
    if (has_krumo()) {
      print krumo($rich_trace);
    }
    else {
      dprint_r($rich_trace);
    }
  }
}

// Delete all files in a dir. http://www.plus2net.com/php_tutorial/php-files-delete.php
function devel_empty_dir($dir) {
  foreach (new DirectoryIterator($dir) as $fileInfo) {
    unlink($fileInfo->getPathname());
  }
}

/*
 * migration related functions
 */

/**
 * Regenerate the data in node_comment_statistics table. Technique comes from
 * http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#101
 *
 * @return void
 **/
function devel_rebuild_node_comment_statistics() {
  // Empty table
  db_truncate('node_comment_statistics')->execute();

  // TODO: DBTNG. Ignore keyword is Mysql only? Is only used in the rare case when
  // two comments on the same node share same timestamp.
  $sql = "
    INSERT IGNORE INTO {node_comment_statistics} (nid, cid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) (
      SELECT c.nid, c.cid, c.created, c.name, c.uid, c2.comment_count FROM {comment} c
      JOIN (
        SELECT c.nid, MAX(c.created) AS created, COUNT(*) AS comment_count FROM {comment} c WHERE status = 1 GROUP BY c.nid
      ) AS c2 ON c.nid = c2.nid AND c.created = c2.created
    )";
  db_query($sql, array(':published' => COMMENT_PUBLISHED));

  // Insert records into the node_comment_statistics for nodes that are missing.
  $query = db_select('node', 'n');
  $query->leftJoin('node_comment_statistics', 'ncs', 'ncs.nid = n.nid');
  $query->addField('n', 'changed', 'last_comment_timestamp');
  $query->addField('n', 'uid', 'last_comment_uid');
  $query->addField('n', 'nid');
  $query->addExpression('0', 'comment_count');
  $query->addExpression('NULL', 'last_comment_name');
  $query->isNull('ncs.comment_count');

  db_insert('node_comment_statistics')
    ->from($query)
    ->execute();
}

Other Drupal examples (source code examples)

Here is a short list of links related to this Drupal devel.module source code file:

new blog posts

"Drupal" is a registered trademark of Dries Buytaert.

my drupal tutorials and examples  

Copyright 1998-2016 Alvin Alexander, alvinalexander.com
All Rights Reserved.

Beginning in 2016, a portion of the proceeds from pages under the '/drupal-code-examples/' URI will be donated to charity.