'drupalforfirebug_get_exec_php_callback', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implementation of hook_nodes() * TODO - are there other hooks we want to track? */ function drupalforfirebug_node_delete($node) { drupalforfirebug_node_process($node, 'delete'); } function drupalforfirebug_node_insert($node) { drupalforfirebug_node_process($node, 'insert'); } function drupalforfirebug_node_load($nodes, $types) { foreach($nodes as $node) { // TOOD - make this work drupalforfirebug_node_process($node, 'load'); } } function drupalforfirebug_node_update($node) { drupalforfirebug_node_process($node, 'update'); } function drupalforfirebug_node_validate($node) { drupalforfirebug_node_process($node, 'validate'); } function drupalforfirebug_node_view($node) { drupalforfirebug_node_process($node, 'view'); } /** * Processing function for Node API */ function drupalforfirebug_node_process(&$node, $op) { global $dfp_runtime; if (!user_access('Access Firebug Debug')) { return; } $nid = (isset($node->nid)) ? $node->nid : '*'. t('NEW') . '*'; $data = drupalforfirebug_array_compare((array) $dfp_runtime['drupalforfirebug_nodes']['original'][$node->type][$nid], (array) $node); $output = drupalforfirebug_field_object('node', $nid, $op, $data); drupalforfirebug_log($output, 'hook_nodeapi'); } /** * Implementation of hook_views_pre_view(); */ function drupalforfirebug_views_pre_view(&$view, &$display_id) { global $dfp_runtime; if (!user_access('Access Firebug Debug')) { return; } $data = drupalforfirebug_array_compare((array) $dfp_runtime['drupalforfirebug_views']['original'][$view->name], (array) $view); $output = drupalforfirebug_field_object('view', $view->name, NULL, $data); drupalforfirebug_log($output, 'hook_views'); } /** * Implementation of hook_page_alter() */ function drupalforfirebug_page_alter(&$page) { global $dfp_runtime; // TODO - make this work without recursion problems // $data = drupalforfirebug_array_compare((array) $dfp_runtime['drupalforfirebug_page']['original']['page'], (array) $page); // $output = drupalforfirebug_field_object('page', 'page', NULL, $data); $output = t('Page Alter Support is Not Yet Implemented'); drupalforfirebug_log($output, 'hook_page_alter'); } /** * Implementation of hook_form_alter() */ function drupalforfirebug_form_alter(&$form, &$form_state, $form_id) { global $dfp_runtime; if (!user_access('Access Firebug Debug')) { return; } if ($form_id != 'drupalforfirebug_execute_form') { $form_modified = (array) $form; $data = drupalforfirebug_array_compare($dfp_runtime['drupalforfirebug_forms']['original'][$form_id], $form_modified); $output = drupalforfirebug_field_object('form', $form_id, NULL, $data); drupalforfirebug_log($output, 'hook_form_alter'); } } /** * Implementation of hook_users() */ function drupalforfirebug_user_insert(&$edit, $account, $category) { drupalforfirebug_user_processing('insert', $account); } function drupalforfirebug_user_load($users) { foreach($users as $account) { drupalforfirebug_user_processing('insert', $account); } } // TODO - more user hook stuff /** * Processor for Hook Usering */ function drupalforfirebug_user_processing($op, &$account) { global $dfp_runtime; if (!user_access('Access Firebug Debug')) { return; } if (isset($account->uid)) { $uid = $account->uid; $name = $account->name; } else { $uid = '*' . t('NEW') . '*'; $name = '*' . t('NEW') . '*'; } if (is_object($account)) { $account_clone = clone($account); $account_clone->pass = '**' . t('Not shown for security reasons') . '**'; $data = drupalforfirebug_array_compare((array) $account_clone, (array) $account_clone); $output = drupalforfirebug_field_object('user', $uid, $op, $data); drupalforfirebug_log($output, 'hook_user'); } } /** * API Function to Record a Message to the Drupal Firebug Log */ function drupalforfirebug_log($message, $type = 'general') { global $dfp_runtime; $dfp_runtime['firebug_messages'][$type][] = $message; } /** * Command Function to Record a Data Element to the Drupal Firebug Log */ function firep($element, $title = NULL) { if ($title) { drupalforfirebug_log(''.$title.':'); } drupalforfirebug_log('
'. print_r($element, true) . '

', 'general'); } /** * Output Function to Return the Results of the Log */ function drupalforfirebug_get($panetype) { global $dfp_runtime; $output = ''; if (isset($dfp_runtime['firebug_messages'][$panetype])) { foreach($dfp_runtime['firebug_messages'][$panetype] as $message) { $output .= '
' . $message .'
'; } unset($dfp_runtime['firebug_messages'][$panetype]); return $output; } } /** * Output Function to Return the Results of the SQL Log */ function drupalforfirebug_get_sql_log() { $output = '
'; if (!module_exists('devel')) { $output .= '' . t('Devel Module is Not Installed') . ''; $output .= t('Please install and enable the Devel Module to display the SQL queries.'); } elseif (!variable_get('dev_query', 0)) { $output .= '' . t('Query Logging is Not Enabled') . ''; $output .= t('Please enable "Collect query info" in the Devel Module Settings (admin/settings/devel) to use this feature.'); } else { global $queries; list($counts, $query_summary) = devel_query_summary(); $output .= '' . t('SQL Query Log') . ''; $output .= $query_summary; $output .= drupalforfirebug_devel_query_table($queries, $counts); } $output .= '
'; return $output; } /** * Generates an Execute PHP Drupal For Firebug Form **/ function drupalforfirebug_execute_form() { $form['code'] = array( '#type' => 'textarea', '#rows' => 2, '#description' => t('Enter PHP code for execution. Do not use <?php ?> tags.') ); $form['token'] = array( '#type' => 'hidden', '#value' => drupal_get_token(), ); $form['op'] = array('#type' => 'submit', '#value' => t('Execute')); $form['#redirect'] = FALSE; $form['#action'] = url('admin/firebug/exec', array('absolute' => TRUE)); $form['#skip_duplicate_check'] = TRUE; return $form; } function drupalforfirebug_get_php_exec_area() { $output = ''; return $output; } function drupalforfirebug_get_php_exec($code = NULL, $token = NULL) { $output = ''; $output .= 'Execute PHP Code'; $output .= '
'; if (!user_access('Execute Firebug PHP') || (!is_null($code) && !drupal_valid_token($token))) { $output .= '' . t('Execute Firebug PHP') . ''; $output .= t('You do not have the proper permissions to use this functionality.'); $output .= '
'; print $output; exit(); } else { if (!$code) { $output .= '' . t('Execute Firebug PHP') . ''; $output .= drupal_render(drupal_get_form('drupalforfirebug_execute_form')); $output .= ''; print $output; exit(); } else { $output = '' . t('PHP Code Execution Results') . ''; // Run the PHP command, get output in variable ob_start(); eval($code); $eval_result = ob_get_contents(); ob_end_clean(); $output .= '
' . $eval_result . '
'; $output .= ''; print $output; exit(); } } } /** * Outputs a Execute PHP Form */ function drupalforfirebug_get_exec_php_callback() { $code = (isset($_POST['code'])) ? $_POST['code'] : NULL; $token = (isset($_POST['token'])) ? $_POST['token'] : NULL; return drupalforfirebug_get_php_exec($code, $token); } /** * Output Function to Return Hidden Div Containers in Footer */ function drupalforfirebug_shutdown() { if (!user_access('Access Firebug Debug')) { return; } $output = ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; $output .= ''; print $output; unset($GLOBALS['dfp_runtime']); } /** * Implementation of hook_permission() */ function drupalforfirebug_permission() { return array( 'Access Firebug Debug' => array( 'title' => t('Access Firebug Debug'), ), 'Execute Firebug PHP' => array( 'title' => t('Execute Firebug PHP'), ), ); } /** * Generalized Array Comparision Function */ function drupalforfirebug_array_compare($a, $b) { $data = drupalforfirebug_array_compare_code($a, $b); $style = drupalforfirebug_array_highlight_code($data); return $style; } /** * Specialized Function to Return an Array Row */ function drupalforfirebug_array_row_build($key, $value, $style, $depth) { $spacing = ''; for ($x = 0; $x <= $depth; $x++) { $spacing .= '    '; } switch ($style) { case 'ADDED': $color = ''; $colorend = ''; break; case 'REMOVED': $color = ''; $colorend = ''; break; case 'SAME': $color = ''; $colorend = ''; break; case 'DIFFERENT': $color = ''; $colorend = ''; break; default: // suppose to be for objects $color = ''.$style; $colorend = ''; break; } $output = ''; if (is_array($value) || is_object($value)) { if ($style == 'DIFFERENT') { // do not highlight if contained item is just changed. $color = ''; $colorend = ''; } if (is_array($value)) { $output .= "
$spacing $color [$key] => array ( $colorend
"; } else { $output .= '
$spacing [' . $key .'] => stdClass (' . $colorend .'
'; } $output .= drupalforfirebug_array_highlight_code($value, $depth + 1); $output .= "
$spacing $color ) $colorend
"; } else { if (isset($key) || isset($value)) { if (is_resource($value)) { $output .= "
$spacing $color [$key] => RESOURCE $colorend
"; } else { $output .= "
$spacing $color [$key] => [" . check_plain($value) . "] $colorend
"; } } } return $output; } /** * Specialized Array Data Style Function */ function drupalforfirebug_array_highlight_code($data, $depth = 0) { // Smartly Handling Recursion for Objects if (is_object($data)) { $data = (array) $data; static $refChain = array(); foreach ($refChain as $refVal) { if ($refVal === $data) { $data = array('**' . t('Recursion Detected') . '**'); } } array_push($refChain, $data); } $output = ''; foreach($data as $key => $value) { if ((string) $key != '#firebug_style') { if (isset($data['#firebug_style']) && isset($data['#firebug_style'][$key])) { $output .= drupalforfirebug_array_row_build($key, $value, $data['#firebug_style'][$key], $depth); } } } return $output; } /** * Specialized Array Data Comparision Code */ function drupalforfirebug_array_compare_code($a, $b, $c = array(), $history = array()) { // Create the Compared Data Object $maxcount = count($a) > count($b) ? count($a) : count($b); $akeys = is_array($a) ? array_keys($a) : array(); $bkeys = is_array($b) ? array_keys($b) : array(); for ($x = 0; $x < $maxcount; $x++) { // Set the Proper Styling if (isset($akeys[$x]) && array_key_exists($akeys[$x], array_flip($bkeys))) { // is it in B array? if ($a[$akeys[$x]] === $b[$akeys[$x]]) { $c['#firebug_style'][$akeys[$x]] = 'SAME'; } else { $c['#firebug_style'][$akeys[$x]] = 'DIFFERENT'; } } else { // not in B array, must be removed if (isset($akeys[$x])) { $c['#firebug_style'][$akeys[$x]] = 'REMOVED'; } } // Set the Proper Element if (isset($akeys[$x]) && is_array($a[$akeys[$x]])) { // is b a valid array if (isset($c[$akeys[$x]])) { $aval = &$a[$akeys[$x]]; $bval = &$b[$akeys[$x]]; $cval = &$c[$akeys[$x]]; $c[$akeys[$x]] = drupalforfirebug_array_compare_code($aval, $bval, $cval); } else { $aval = &$a[$akeys[$x]]; $bval = &$b[$akeys[$x]]; $c[$akeys[$x]] = drupalforfirebug_array_compare_code($aval, $bval, array()); } } else { if (isset($akeys[$x]) && array_key_exists($akeys[$x], array_flip($bkeys))) { // is it in B array? if ($a[$akeys[$x]] === $b[$akeys[$x]]) { $c[$akeys[$x]] = $a[$akeys[$x]]; } else { $c[$akeys[$x]] = $b[$akeys[$x]]; } } else { // not in B array, must be removed if (isset($akeys[$x])) { $c[$akeys[$x]] = $a[$akeys[$x]]; } } } if (isset($bkeys[$x]) && isset($b[$bkeys[$x]])) { // does b have a valid argument // Set the Proper Styling if (array_key_exists($bkeys[$x], array_flip($akeys))) { // is it in A array? // exists in the A array, already processed } else { $c[$bkeys[$x]] = $b[$bkeys[$x]]; $c['#firebug_style'][$bkeys[$x]] = 'ADDED'; } // Set the Proper Element if (isset($b[$bkeys[$x]]) && is_array($b[$bkeys[$x]])) { // is b a valid array $aval = &$a[$bkeys[$x]]; $bval = &$b[$bkeys[$x]]; $cval = &$c[$bkeys[$x]]; $c[$bkeys[$x]] = drupalforfirebug_array_compare_code($aval, $bval, $cval); } } } return $c; } // Array Handling Helper Function function do_offset($level) { $offset = ""; // offset for subarry for ($i=1; $i<$level;$i++) { $offset = $offset . ""; } return $offset; } // Array Handling Helper Function function drupalforfirebug_show_array($array, $level, $sub){ $output = ''; if (is_array($array) == 1){ // check if input is an array foreach($array as $key_val => $value) { $offset = ""; if (is_array($value) == 1){ // array is multidimensional $output .= ""; $offset = do_offset($level); $output .= $offset . "" . $key_val . ""; $output .= drupalforfirebug_show_array($value, $level+1, 1); } else{ // (sub)array is not multidim if ($sub != 1){ // first entry for subarray $output .= ""; $offset = do_offset($level); } $sub = 0; $output .= $offset . "" . $key_val . "" . $value . ""; $output .= "\n"; } } //foreach $array } return $output; } // Function to Show an Array function html_drupalforfirebug_show_array($array){ $output = "\n"; $output .= drupalforfirebug_show_array($array, 1, 0); $output .= "
\n"; return $output; } /** * Function for fieldsets that wrap object dumps * * For efficiency and consistent behavior in firebug window * Use to be a theme function, but that broke things */ function drupalforfirebug_field_object($marker, $id, $op = NULL, $data) { $output = '
'; $output .= '' . $op . ' $'. $marker .'->'. $id . ''; $output .= ''; $output .= '
'; return $output; } /** * Replication of Devel Query Display (but as a table instead of CSS styled div structure) * This is done to work with the Firefox extension which has a harder time loading CSS */ function drupalforfirebug_devel_query_table($queries, $counts) { $header = array ('ms', '#', 'where', 'query'); $i = 0; foreach ($queries as $query) { $ar = explode("\n", $query[0]); $function=array_shift($ar); $count = isset($counts[$query[0]]) ? $counts[$query[0]] : 0; $query[0]=join(' ',$ar); $diff = round($query[1] * 1000, 2); if ($diff > variable_get('devel_execution', 5)) { $cell[$i][] = array ('data' => $diff, 'class' => 'marker'); } else { $cell[$i][] = $diff; } if ($count > 1) { $cell[$i][] = array ('data' => $count, 'class' => 'marker'); } else { $cell[$i][] = $count; } $cell[$i][] = $function; $pos = strpos($query[0], '*/') + 3; $cell[$i][] = check_plain(substr($query[0], $pos)); $i++; unset($diff, $count); } if (variable_get('devel_query_sort', DEVEL_QUERY_SORT_BY_SOURCE)) { usort($cell, '_devel_table_sort'); } return theme('table', $header, $cell); }