Newer
Older
Gábor Hojtsy
committed
// $Id$
// This module holds functions useful for Drupal development.
// Please contribute!
Moshe Weitzman
committed
// Suggested profiling and stacktrace library from http://www.xdebug.org/index.php
Moshe Weitzman
committed
Moshe Weitzman
committed
define('DEVEL_QUERY_SORT_BY_SOURCE', 0);
define('DEVEL_QUERY_SORT_BY_DURATION', 1);
Moshe Weitzman
committed
define('DEVEL_ERROR_HANDLER_NONE', 0);
define('DEVEL_ERROR_HANDLER_STANDARD', 1);
define('DEVEL_ERROR_HANDLER_BACKTRACE', 2);
Moshe Weitzman
committed
define('DEVEL_MIN_TEXTAREA', 50);
function devel_help($section) {
switch ($section) {
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>';
return '<p>'. t('Here are the contents of your <code>$_SESSION</code> variable.') .'</p>';
$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.');
Moshe Weitzman
committed
}
Moshe Weitzman
committed
* 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',
Moshe Weitzman
committed
'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/source'] = array(
'title' => 'Display the PHP code of any file in your Drupal installation',
'page callback' => 'devel_display_source',
'access arguments' => array('display source code'),
'type' => MENU_CALLBACK,
'file' => 'devel.pages.inc',
'menu_name' => 'devel',
'description' => 'Rebuild menu based on hook_menu() and revert any custom changes. All menu items return to their default settings.',
'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',
Moshe Weitzman
committed
$items['devel/field/info'] = array(
'title' => 'Field info',
'description' => 'View fields information across the whole site.',
Yves Chedemois
committed
'page callback' => 'devel_field_info_page',
Moshe Weitzman
committed
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'menu_name' => 'devel',
);
Moshe Weitzman
committed
$items['devel/elements'] = array(
'title' => 'Hook_elements()',
'description' => 'View the active form/render elements for this site.',
Moshe Weitzman
committed
'page callback' => 'devel_elements_page',
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
'menu_name' => 'devel',
Moshe Weitzman
committed
);
$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',
Moshe Weitzman
committed
$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',
Moshe Weitzman
committed
'type' => MENU_CALLBACK
);
$items['devel/arguments'] = array(
'title' => 'Arguments query',
'page callback' => 'devel_querylog_arguments',
'description' => 'Return a giben query, with arguments instead of placeholders. Used by query log',
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'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',
);
Moshe Weitzman
committed
// 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',
Moshe Weitzman
committed
$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',
Moshe Weitzman
committed
'access arguments' => array('administer site configuration'),
);
Moshe Weitzman
committed
$items['node/%node/devel'] = array(
'title' => 'Devel',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'node'),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'weight' => 100,
Moshe Weitzman
committed
$items['node/%node/devel/load'] = array(
'title' => 'Load',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'node'),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'type' => MENU_DEFAULT_LOCAL_TASK,
);
Moshe Weitzman
committed
'title' => 'Render',
Moshe Weitzman
committed
'page callback' => 'devel_render_object',
'page arguments' => array('node', 1),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
'type' => MENU_LOCAL_TASK,
Moshe Weitzman
committed
'weight' => 100,
Moshe Weitzman
committed
$items['comment/%comment/devel'] = array(
'title' => 'Devel',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'comment'),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'devel.pages.inc',
'weight' => 100,
);
Moshe Weitzman
committed
$items['comment/%comment/devel/load'] = array(
'title' => 'Load',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'comment'),
'access arguments' => array('access devel information'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
);
$items['comment/%comment/devel/render'] = array(
Moshe Weitzman
committed
'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,
);
Moshe Weitzman
committed
$items['user/%user/devel'] = array(
'title' => 'Devel',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'user'),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'weight' => 100,
Moshe Weitzman
committed
$items['user/%user/devel/load'] = array(
'title' => 'Load',
'page callback' => 'devel_load_object',
'page arguments' => array(1, 'user'),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'type' => MENU_DEFAULT_LOCAL_TASK,
);
Moshe Weitzman
committed
'title' => 'Render',
Moshe Weitzman
committed
'page callback' => 'devel_render_object',
'page arguments' => array('user', 1),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'type' => MENU_LOCAL_TASK,
Moshe Weitzman
committed
'weight' => 100,
Moshe Weitzman
committed
);
Moshe Weitzman
committed
$items['taxonomy/term/%taxonomy_term/devel'] = array(
'title' => 'Devel',
Moshe Weitzman
committed
'page callback' => 'devel_load_object',
'page arguments' => array(2, 'term'),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'type' => MENU_LOCAL_TASK,
'weight' => 100,
);
Moshe Weitzman
committed
$items['taxonomy/term/%taxonomy_term/devel/load'] = array(
'title' => 'Load',
'page callback' => 'devel_load_object',
'page arguments' => array(2, 'term'),
'access arguments' => array('access devel information'),
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'type' => MENU_DEFAULT_LOCAL_TASK,
);
Moshe Weitzman
committed
$items['taxonomy/term/%taxonomy_term/devel/render'] = array(
Moshe Weitzman
committed
'title' => 'Render',
Moshe Weitzman
committed
'page callback' => 'devel_render_term',
'page arguments' => array(2),
'access arguments' => array('access devel information'),
'type' => MENU_LOCAL_TASK,
'file' => 'devel.pages.inc',
Moshe Weitzman
committed
'weight' => 100,
);
return $items;
}
function devel_menu_need_destination() {
Moshe Weitzman
committed
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.
Moshe Weitzman
committed
* This is more robust that 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;
}
}
Moshe Weitzman
committed
/**
* An implementation of hook_translated_menu_item_alter(). Append dynamic
Moshe Weitzman
committed
* querystring 'destination' to several of our own menu items.
Moshe Weitzman
committed
**/
function devel_translated_menu_link_alter(&$item) {
if (in_array($item['href'], devel_menu_need_destination())) {
Moshe Weitzman
committed
$item['localized_options']['query'] = drupal_get_destination();
}
elseif ($item['href'] == 'devel/menu/item') {
$item['localized_options']['query'] = array('path' => $_GET['q']);
}
Moshe Weitzman
committed
}
/**
* Implementation of hook_theme()
*/
Moshe Weitzman
committed
function devel_theme() {
return array(
Moshe Weitzman
committed
'devel_querylog' => array(
'variables' => array('header' => array(), 'rows' => array()),
Moshe Weitzman
committed
),
'devel_querylog_row' => array(
'variables' => array('row' => array()),
Moshe Weitzman
committed
),
);
if (user_access('access devel information')) {
devel_set_handler(variable_get('devel_error_handler', DEVEL_ERROR_HANDLER_STANDARD));
Moshe Weitzman
committed
// We want to include the class early so that anyone may call krumo() as needed. See http://krumo.sourceforge.net/
has_krumo();
Moshe Weitzman
committed
// See http://www.firephp.org/.
// Support Libraries API - http://drupal.org/project/libraries
if (module_exists('libraries')) {
Moshe Weitzman
committed
$path = libraries_get_path('FirePHPCore') . '/lib/FirePHPCore/';
Moshe Weitzman
committed
}
else {
Moshe Weitzman
committed
$path = './'. drupal_get_path('module', 'devel') .'/FirePHPCore/lib/FirePHPCore/';
Moshe Weitzman
committed
}
Moshe Weitzman
committed
if (file_exists($path .'fb.php')) {
include_once $path .'fb.php';
include_once $path .'FirePHP.class.php';
Moshe Weitzman
committed
// 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');
Moshe Weitzman
committed
drupal_add_js(drupal_get_path('module', 'devel'). '/devel.js');
Moshe Weitzman
committed
}
Moshe Weitzman
committed
}
Moshe Weitzman
committed
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'))));
Moshe Weitzman
committed
}
}
}
// return boolean. no need for cache here.
function has_krumo() {
// see README.txt or just download from http://krumo.sourceforge.net/
@include_once './'. drupal_get_path('module', 'devel') .'/krumo/class.krumo.php';
if (function_exists('krumo') && php_sapi_name() != 'cli') {
return TRUE;
}
else {
return FALSE;
}
}
Moshe Weitzman
committed
/**
* Decide whether or not to print a debug variable using krumo().
*
Moshe Weitzman
committed
* @return boolean
*/
function merits_krumo($input) {
return (is_object($input) || is_array($input)) && has_krumo() && variable_get('devel_krumo_skin', '') != 'disabled';
Moshe Weitzman
committed
}
Moshe Weitzman
committed
/**
* 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')) {
Moshe Weitzman
committed
$args = func_get_args();
call_user_func_array('fb', $args);
}
}
Moshe Weitzman
committed
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/**
* Calls dfb() to output a backtrace.
*/
function dfbt($label) {
dfb($label, FirePHP::TRACE);
}
/**
* Implements hook_watchdog().
*/
function devel_watchdog(array $log_entry) {
if (class_exists('FirePHP')) {
switch ($log_entry['severity']) {
case WATCHDOG_EMERG:
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';
}
$watchdog = array(
'type' => $log_entry['type'],
Moshe Weitzman
committed
'message' => decode_entities(strtr($log_entry['message'], (array)$log_entry['variables'])),
Moshe Weitzman
committed
);
if (isset($log_entry['link'])) {
$watchdog['link'] = $log_entry['link'];
}
dfb($watchdog, $type);
}
Moshe Weitzman
committed
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 on IIS when calling the front page. q is not set.
// Don't interfere with private files/images.
Moshe Weitzman
committed
function_exists('drupal_is_cli') && drupal_is_cli() ||
Moshe Weitzman
committed
strpos($_SERVER['HTTP_USER_AGENT'], 'ApacheBench') !== FALSE ||
!empty($_REQUEST['XDEBUG_PROFILE']) ||
isset($GLOBALS['devel_shutdown']) ||
strstr($_SERVER['PHP_SELF'], 'update.php') ||
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'
}
/**
* Implementation of hook_boot(). Runs even for cached pages.
*/
function devel_boot() {
if (!devel_silent()) {
devel_start();
Moshe Weitzman
committed
}
}
Moshe Weitzman
committed
// Kickoff our tricks. Put here all code which must run for cached pages too. Called from both devel_boot() and devel_init().
if (variable_get('dev_mem', 0)) {
global $memory_init;
$memory_init = memory_get_usage();
}
Moshe Weitzman
committed
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');
register_shutdown_function('devel_shutdown');
}
Moshe Weitzman
committed
function backtrace_error_handler($errno, $message, $filename, $line) {
Moshe Weitzman
committed
// Don't respond to the error if it was suppressed with a '@'
if (error_reporting() == 0) return;
Moshe Weitzman
committed
if ($errno & (E_ALL ^ E_NOTICE)) {
Moshe Weitzman
committed
// We can't use the PHP E_* constants here as not all versions of PHP have all
// the constants defined, so for consistency, we just use the numeric equivelant.
$types = array(
1 => 'error',
2 => 'warning',
4 => 'parse error',
8 => 'notice',
16 => 'core error',
32 => 'core warning',
64 => 'compile error',
128 => 'compile warning',
256 => 'user error',
512 => 'user warning',
1024 => 'user notice',
2048 => 'strict warning',
4096 => 'recoverable error',
8192 => 'deprecated',
16384 => 'user deprecated',
);
Moshe Weitzman
committed
$entry = $types[$errno] .': '. $message .' in '. $filename .' on line '. $line .'.';
if (variable_get('error_level', 1) == 1) {
$backtrace = debug_backtrace();
foreach ($backtrace as $call) {
$nicetrace[$call['function']] = $call;
Moshe Weitzman
committed
}
krumo($nicetrace);
Moshe Weitzman
committed
}
watchdog('php', '%message in %file on line %line.', array('%error' => $types[$errno], '%message' => $message, '%file' => $filename, '%line' => $line), WATCHDOG_ERROR);
return array(
'description' => t('View developer output like variable printouts, query log, etc.'),
'title' => t('Access developer information'),
),
'execute php code' => array(
'title' => t('Execute PHP code'),
'description' => t('Run arbitrary PHP from a block. Danger!'),
),
'switch users' => array(
'title' => t('Switch users'),
'description' => t('Become any user on the site with just a click. Danger!'),
),
'display source code' => array(
'title' => t('Display source code'),
'description' => t('View the site\'s php source code. Danger!'),
),
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,
);
Moshe Weitzman
committed
return $blocks;
}
/**
* Implementation of hook_block_configure().
Moshe Weitzman
committed
*/
function devel_block_configure($delta) {
if ($delta == 'switch_user') {
$form['devel_switch_user_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',
);
return $form;
}
Moshe Weitzman
committed
}
function devel_block_save($delta, $edit = array()) {
if ($delta == 'switch_user') {
variable_set('devel_switch_user_list_size', $edit['devel_switch_user_list_size']);
}
Moshe Weitzman
committed
}
function devel_block_view($delta) {
$block = array();
switch ($delta) {
case 'switch_user':
Moshe Weitzman
committed
$block = devel_block_switch_user();
break;
case 'execute_php':
Moshe Weitzman
committed
if (user_access('execute php code')) {
$block['subject'] = t('Execute PHP');
$block['content'] = drupal_get_form('devel_execute_form');
Moshe Weitzman
committed
}
break;
Moshe Weitzman
committed
return $block;
$links = devel_switch_user_list();
if (!empty($links)) {
Moshe Weitzman
committed
$block['subject'] = t('Switch user');
$build['devel_links'] = array('#theme' => 'links', '#links' => $links);
$build['devel_form'] = drupal_get_form('devel_switch_user_form');
$block['content'] = $build;
return $block;
}
}
function devel_switch_user_list() {
$links = array();
if (user_access('switch users')) {
$list_size = variable_get('devel_switch_user_list_size', 10);
// Try to find at least $list_size users that can switch.
if (isset($roles[2])) {
// If authenticated users have this permission, just grab
// the last $list_size users, since there won't be records in
// {user_roles} and every user on the system can switch.
$users = db_query_range("SELECT DISTINCT u.uid, u.name, u.access FROM {users} u WHERE u.uid > 0 ORDER BY u.access DESC", 0, $list_size);
}
else {
$where = array('u.uid = 1');
if (count($roles)) {
$where[] = 'r.rid IN ('. implode(',', array_keys($roles)) .')';
}
$where_sql = implode(' OR ', $where);
$users = 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 ORDER BY u.access DESC", 0, $list_size);
Moshe Weitzman
committed
$links[$user->uid] = array(
'title' => drupal_placeholder(array('text' => $user->name)),
'href' => 'devel/switch/'. $user->name,
Moshe Weitzman
committed
'query' => $dest,
'attributes' => array('title' => t('This user can switch back.')),
'html' => TRUE,
);
if ($num_links < $list_size) {
// If we don't have enough, add distinct uids until we hit $list_size.
$users = db_query_range('SELECT uid, name, access FROM {users} WHERE uid > 0 AND uid NOT IN ('. implode(',', array_keys($links)) .') ORDER BY access DESC', 0, $list_size - $num_links);
foreach ($users as $user) {
if (count($links) >= $list_size) {
break;
}
Moshe Weitzman
committed
$links[$user->uid] = array(
'title' => $user->name ? $user->name : 'anon',
'href' => 'devel/switch/'. $user->name,
Moshe Weitzman
committed
'query' => $dest,
'attributes' => array('title' => t('Caution: this user will be unable switch back.')),
);
return $links;
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(
'#value' => t('Switch'),
);
return $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(
'#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/$version/function/$function";
}
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'];
}
Moshe Weitzman
committed
// An implementation of hook_drupal_goto_alter().
function devel_drupal_goto_alter($path, $options, $http_response_code) {
Moshe Weitzman
committed
global $user;
Moshe Weitzman
committed
if (isset($path) && !devel_silent()) {
Jonathan Chaffer
committed
// The page we are leaving is a drupal_goto(). Present a redirection page
// so that the developer can see the intermediate query log.
Moshe Weitzman
committed
// 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)) {
Moshe Weitzman
committed
$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));
Moshe Weitzman
committed
drupal_deliver_page($output);
Jonathan Chaffer
committed
// Don't allow the automatic redirect to happen.
exit();
}
$GLOBALS['devel_redirecting'] = TRUE;
Jonathan Chaffer
committed
}
Moshe Weitzman
committed
}
Moshe Weitzman
committed
/**
* See devel_start() which registers this function as a shutdown function.
Moshe Weitzman
committed
*/
function devel_shutdown() {
// Register the real shutdown function so it runs later than other shutdown functions.
register_shutdown_function('devel_shutdown_real');
}
Moshe Weitzman
committed
function devel_page_alter($page) {
if (variable_get('devel_page_alter', FALSE) && user_access('access devel information')) {
dpm($page, 'page');
}
}
Moshe Weitzman
committed
/**
* See devel_shutdown() which registers this function as a shutdown function. Displays developer information in the footer.
*/
function devel_shutdown_real() {
global $user;
Moshe Weitzman
committed
$output = $txt = '';
Moshe Weitzman
committed
// 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 (!isset($GLOBALS['devel_shutdown']) && !isset($GLOBALS['devel_redirecting'])) {
Moshe Weitzman
committed
// 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)) {
Moshe Weitzman
committed
}
Moshe Weitzman
committed
}
Gábor Hojtsy
committed
}
Moshe Weitzman
committed
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) {
Moshe Weitzman
committed
// 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;
Moshe Weitzman
committed
}
Moshe Weitzman
committed
}
function devel_shutdown_summary($queries) {
$sum = 0;
$output = '';
Moshe Weitzman
committed
list($counts, $query_summary) = devel_query_summary($queries);
$output .= '<div class="dev-query">';
if (variable_get('devel_query_display', FALSE)) {
// Query log on.
Moshe Weitzman
committed
$output .= $query_summary;
$output .= t_safe(' Queries exceeding @threshold ms are <span class="marker">highlighted</span>.', array('@threshold' => variable_get('devel_execution', 5)));
Moshe Weitzman
committed
}
if (variable_get('dev_timer', 0)) {
$output .= devel_timer();
}
$output .= devel_shutdown_memory();
$output .= '</div>';
Moshe Weitzman
committed
return $output;
}
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);
// Save all queries to a file in temp dir. Retrieved via AJAX.
devel_query_put_contents($queries);
}
else {
}
}
Moshe Weitzman
committed
// 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);
Moshe Weitzman
committed
// Save queries as a serialized array.
file_put_contents($path, serialize($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";
}
Moshe Weitzman
committed
function devel_query_enabled() {
Moshe Weitzman
committed
return method_exists('Database', 'getLog') && variable_get('devel_query_display', FALSE);
Moshe Weitzman
committed
}
function devel_query_summary($queries) {
Moshe Weitzman
committed
if (variable_get('devel_query_display', FALSE) && is_array($queries)) {
Moshe Weitzman
committed
$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))));
Moshe Weitzman
committed
}
}
// get_t caused problems here with theme registry after changing on admin/build/modules. the theme_get_registry call is needed.
Moshe Weitzman
committed
if (function_exists('t') && function_exists('theme_get_registry')) {
theme_get_registry();
return t($string, $args);
}
else {
strtr($string, $args);
}
Moshe Weitzman
committed
}
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 Optimizer 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_form() {
$form['code'] = array(
'#type' => 'textarea',
'#title' => t('PHP code to execute'),
'#description' => t('Enter some code. Do not use <code><?php ?></code> tags.')