diff --git a/components/admin.php b/components/admin.php index a90fd2ecd..108053428 100644 --- a/components/admin.php +++ b/components/admin.php @@ -20,6 +20,9 @@ function process() { global $current_screen, $pagenow; + if ( !is_admin() ) + return; + if ( !isset( $current_screen ) or empty( $current_screen ) ) { # Pre-3.0 compat: @@ -57,15 +60,20 @@ function process() { function admin_menu( $menu ) { - $menu[] = $this->menu( array( - 'title' => sprintf( __( 'Admin Screen: %s', 'query_monitor' ), $this->data['base'] ) - ) ); + if ( isset( $this->data['base'] ) ) { + $menu[] = $this->menu( array( + 'title' => sprintf( __( 'Admin Screen: %s', 'query_monitor' ), $this->data['base'] ) + ) ); + } return $menu; } function output( $args, $data ) { + if ( empty( $data ) ) + return; + $post_type_warning = ''; echo ''; @@ -152,8 +160,7 @@ function output( $args, $data ) { } function register_qm_admin( $qm ) { - if ( is_admin() ) - $qm['admin'] = new QM_Admin; + $qm['admin'] = new QM_Admin; return $qm; } diff --git a/components/conditionals.php b/components/conditionals.php index 875d6aa27..1f939f515 100644 --- a/components/conditionals.php +++ b/components/conditionals.php @@ -52,12 +52,12 @@ function output( $args, $data ) { function process() { - $conds = array( + $conds = apply_filters( 'qm_conditionals', array( 'is_404', 'is_archive', 'is_admin', 'is_attachment', 'is_author', 'is_blog_admin', 'is_category', 'is_comments_popup', 'is_date', 'is_day', 'is_feed', 'is_front_page', 'is_home', 'is_main_site', 'is_month', 'is_multitax', /*'is_multi_author',*/ 'is_network_admin', 'is_page', 'is_page_template', 'is_paged', 'is_post_type_archive', 'is_preview', 'is_robots', 'is_rtl', 'is_search', 'is_single', 'is_singular', 'is_ssl', 'is_sticky', 'is_tag', 'is_tax', 'is_time', 'is_trackback', 'is_year' - ); + ) ); $true = $false = $na = array(); diff --git a/components/db_queries.php b/components/db_queries.php index 97fec3d63..67ea32449 100644 --- a/components/db_queries.php +++ b/components/db_queries.php @@ -7,11 +7,12 @@ if ( !defined( 'QM_DB_LIMIT' ) ) define( 'QM_DB_LIMIT', 100 ); -# @TODO warnings and shit for long/slow queries +# @TODO warnings for slow queries class QM_DB_Queries extends QM { var $id = 'db_queries'; + var $db_objects = array(); function __construct() { parent::__construct(); @@ -21,7 +22,8 @@ function __construct() { } function admin_title( $title ) { - $title[] = sprintf( __( '%sQ', 'query_monitor' ), number_format_i18n( $this->data['query_num'] ) ); + foreach ( $this->data['dbs'] as $db ) + $title[] = sprintf( __( '%sQ', 'query_monitor' ), number_format_i18n( $db->total_qs ) ); return $title; } @@ -38,6 +40,7 @@ function admin_menu( $menu ) { if ( $errors = $this->get_errors() ) { $menu[] = $this->menu( array( 'id' => 'query_monitor_errors', + 'href' => '#qm-overview', 'title' => sprintf( __( 'Database Errors (%s)', 'query_monitor' ), number_format_i18n( count( $errors ) ) ) ) ); } @@ -56,13 +59,14 @@ function process() { if ( !SAVEQUERIES ) return; - $this->data['query_num'] = 0; - $this->data['errors'] = array(); - $this->data['db_objects'] = apply_filters( 'query_monitor_db_objects', array( + $this->data['query_num'] = 0; + $this->data['errors'] = array(); + + $this->db_objects = apply_filters( 'query_monitor_db_objects', array( '$wpdb' => $GLOBALS['wpdb'] ) ); - foreach ( $this->data['db_objects'] as $name => $db ) { + foreach ( $this->db_objects as $name => $db ) { if ( $this->is_db_object( $db ) ) $this->process_db_object( $name, $db ); } @@ -74,10 +78,8 @@ function output( $args, $data ) { if ( !SAVEQUERIES ) return; - foreach ( $data['db_objects'] as $name => $db ) { - if ( isset( $this->data['dbs'][$name] ) ) - $this->output_queries( $name, $this->data['dbs'][$name] ); - } + foreach ( $data['dbs'] as $name => $db ) + $this->output_queries( $name, $db ); } @@ -138,10 +140,10 @@ function process_db_object( $id, $db ) { $total_time += $ltime; $total_qs++; - if ( !empty( $funcs ) ) - $func = reset( array_reverse( explode( ', ', $funcs ) ) ); + if ( false !== strpos( $funcs, '.php' ) ) + $func = sprintf( __( 'None (%s)', 'query_monitor' ), $funcs ); else - $func = '' . __( 'none', 'query_monitor' ) . ''; + $func = reset( array_reverse( explode( ', ', $funcs ) ) ); $this->add_func_time( $func, $ltime ); @@ -154,13 +156,7 @@ function process_db_object( $id, $db ) { ) as $cmd ) $sql = trim( str_replace( " $cmd ", "
$cmd ", $sql ) ); - $rows[] = array( - 'func' => $func, - 'funcs' => $funcs, - 'sql' => $sql, - 'ltime' => $ltime, - 'result' => $result - ); + $rows[] = compact( 'func', 'funcs', 'sql', 'ltime', 'result' ); if ( is_wp_error( $result ) ) $this->data['errors'][] = $result; @@ -171,12 +167,7 @@ function process_db_object( $id, $db ) { $this->data['query_num'] += $total_qs; # @TODO put errors in here too: - $this->data['dbs'][$id] = (object) array( - 'rows' => $rows, - 'has_results' => $has_results, - 'total_time' => $total_time, - 'total_qs' => $total_qs, - ); + $this->data['dbs'][$id] = (object) compact('rows', 'types', 'has_results', 'total_time', 'total_qs' ); } @@ -245,7 +236,7 @@ function output_queries( $name, $db ) { if ( $has_results ) { if ( is_wp_error( $row['result'] ) ) { - $r = $row['result']->get_error_message( 'qmdb_error' ); + $r = $row['result']->get_error_message( 'query_monitor_db_error' ); $results = "\n"; $row_class = 'qm-warn'; } else { diff --git a/components/environment.php b/components/environment.php index f067a49e6..5dd10f974 100644 --- a/components/environment.php +++ b/components/environment.php @@ -23,17 +23,21 @@ function process() { global $wp_version, $blog_id; $vars = array( - 'key_buffer_size' => true, # Key cache limit - 'max_allowed_packet' => false, # Max individual query size - 'max_connections' => false, # Max client connections - 'query_cache_limit' => true, # Individual query cache limit - 'query_cache_size' => true, # Query cache limit + 'key_buffer_size' => true, # Key cache size limit + 'max_allowed_packet' => false, # Individual query size limit + 'max_connections' => false, # Max number of client connections + # 'profiling' => 'OFF', # Query profiling on or off + 'query_cache_limit' => true, # Individual query cache size limit + 'query_cache_size' => true, # Total cache size limit 'query_cache_type' => 'ON' # Query cache on or off ); if ( $dbq = $this->get_component( 'db_queries' ) ) { - foreach ( $dbq->data['db_objects'] as $id => $db ) { + foreach ( $dbq->db_objects as $id => $db ) { + + if ( !$dbq->is_db_object( $db ) ) + continue; $variables = $db->get_results( " SHOW VARIABLES @@ -43,6 +47,8 @@ function process() { $this->data['db'][$id] = array( 'version' => mysql_get_server_info( $db->dbh ), 'user' => $db->dbuser, + 'host' => $db->dbhost, + 'name' => $db->dbname, 'vars' => $vars, 'variables' => $variables ); @@ -112,7 +118,7 @@ function output( $args, $data ) { $name = $id . '
MySQL'; echo ''; - echo ''; + echo ''; echo ''; echo ''; echo ''; @@ -122,6 +128,16 @@ function output( $args, $data ) { echo ''; echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; $first = true; @@ -140,7 +156,7 @@ function output( $args, $data ) { else if ( is_string( $db['vars'][$key] ) and ( $val !== $db['vars'][$key] ) ) $prepend .= $warning; - if ( is_numeric( $val ) and ( $val >= 1024 ) ) + if ( is_numeric( $val ) and ( $val >= ( 1024*1024 ) ) ) $prepend .= '
~' . size_format( $val ) . ''; if ( !$first ) diff --git a/components/hooks.php b/components/hooks.php index 81150325b..090d58a47 100644 --- a/components/hooks.php +++ b/components/hooks.php @@ -24,7 +24,7 @@ function process_late() { global $wp_actions, $wp_filter, $querymonitor, $current_screen, $pagenow; - if ( $admin = $this->get_component( 'admin' ) ) + if ( is_admin() and ( $admin = $this->get_component( 'admin' ) ) ) $screen = $admin->data['base']; else $screen = ''; @@ -71,7 +71,7 @@ function process_late() { if ( $qm_class == $class ) $css_class = 'qm-qm'; - $out = $class . '->' . $function['function'][1] . '()'; + $out = $class . '->' . $function['function'][1] . '()'; } else { $out = $function['function'] . '()'; } @@ -120,7 +120,7 @@ function output( $args, $data ) { echo ''; echo ''; echo ''; echo ''; } diff --git a/components/http.php b/components/http.php index ca342d09b..6c47535fb 100644 --- a/components/http.php +++ b/components/http.php @@ -154,6 +154,8 @@ function output( $args, $data ) { unset( $row['trace'][0], $row['trace'][1], $row['trace'][2] ); $f = 6; $func = $row['trace'][$f]; + if ( 0 === strpos( $func, 'fetch_rss' ) ) + $func = $row['trace'][++$f]; if ( 0 === strpos( $func, 'SimplePie' ) ) $func = $row['trace'][++$f]; if ( 0 === strpos( $func, 'fetch_feed' ) ) diff --git a/components/php_errors.php b/components/php_errors.php index 90c2b86f6..b7ef3e39b 100644 --- a/components/php_errors.php +++ b/components/php_errors.php @@ -75,14 +75,15 @@ function output( $args, $data ) { if ( !$first ) echo ''; - $funca = $error->funcs; + $funca = $error->funcs; unset( $funca[0], $funca[1] ); + $funca = implode( ', ', array_reverse( $funca ) ); $func = $error->funcs[2]; $message = str_replace( "href='function.", "target='_blank' href='http://php.net/function.", $error->message ); echo ''; - echo ''; + echo ''; echo ''; echo ''; echo ''; @@ -129,16 +130,21 @@ function error_handler( $type, $message, $file = null, $line = null ) { $key = md5( $message . $file . $line . $funcs[0] ); + $filename = str_replace( '\\', '/', $file ); + $path = str_replace( '\\', '/', ABSPATH ); + $filename = str_replace( $path, '', $filename ); + if ( isset( $this->data['errors'][$type][$key] ) ) { $this->data['errors'][$type][$key]->calls++; } else { $this->data['errors'][$type][$key] = (object) array( - 'type' => $type, - 'message' => $message, - 'file' => $file, - 'line' => $line, - 'funcs' => $funcs, - 'calls' => 1 + 'type' => $type, + 'message' => $message, + 'file' => $file, + 'filename' => $filename, + 'line' => $line, + 'funcs' => $funcs, + 'calls' => 1 ); } diff --git a/components/query_vars.php b/components/query_vars.php index 2c9dc5701..ad6f31d53 100644 --- a/components/query_vars.php +++ b/components/query_vars.php @@ -11,8 +11,19 @@ function __construct() { function process() { - $query_vars = array_filter( $GLOBALS['wp_query']->query_vars ); $plugin_qvars = apply_filters( 'query_vars', array() ); + $qvars = $GLOBALS['wp_query']->query_vars; + $query_vars = array(); + + foreach ( $qvars as $k => $v ) { + if ( in_array( $k, $plugin_qvars ) ) { + if ( '' !== $v ) + $query_vars[$k] = $v; + } else { + if ( !empty( $v ) ) + $query_vars[$k] = $v; + } + } ksort( $query_vars ); @@ -64,6 +75,10 @@ function output( $args, $data ) { echo "
  • {$k} => {$v}
  • "; } echo ''; + } else if ( is_object( $value ) ) { + echo ''; } else { $value = esc_html( $value ); echo ""; diff --git a/components/theme.php b/components/theme.php index a029d9bf2..2a47e66e9 100644 --- a/components/theme.php +++ b/components/theme.php @@ -16,12 +16,21 @@ function body_class( $class ) { } function process() { + global $template; + + if ( is_admin() ) + return; + $this->data['template_file'] = apply_filters( 'query_monitor_template', basename( $template ) ); + } function output( $args, $data ) { + if ( empty( $data ) ) + return; + echo '
    {$r}
    ' . $name . '' . $name . 'version' . $db['version'] . '
    ' . $db['user'] . '
    host' . $db['host'] . '
    database' . $db['name'] . '
    ' . $action['priority'] . ''; - echo $action['function']; + echo esc_html( $action['function'] ); echo '
    ' . $message . '' . esc_html( $error->file ) . '' . esc_html( $error->filename ) . '' . esc_html( $error->line ) . '' . esc_html( $func ) . '
    ';
    +					print_r( $value );
    +					echo '
    {$value}
    '; echo ''; echo ''; @@ -62,9 +71,11 @@ function output( $args, $data ) { function admin_menu( $menu ) { - $menu[] = $this->menu( array( - 'title' => sprintf( __( 'Template: %s', 'query_monitor' ), $this->data['template_file'] ) - ) ); + if ( isset( $this->data['template_file'] ) ) { + $menu[] = $this->menu( array( + 'title' => sprintf( __( 'Template: %s', 'query_monitor' ), $this->data['template_file'] ) + ) ); + } return $menu; } @@ -72,8 +83,7 @@ function admin_menu( $menu ) { } function register_qm_theme( $qm ) { - if ( !is_admin() ) - $qm['theme'] = new QM_Theme; + $qm['theme'] = new QM_Theme; return $qm; } diff --git a/query-monitor.css b/query-monitor.css index 0922e0606..27c52d9ed 100644 --- a/query-monitor.css +++ b/query-monitor.css @@ -127,10 +127,11 @@ border: 1px solid #ccc !important; padding: 6px 7px 5px !important; vertical-align: top !important; + text-shadow: none !important; } .qm th { - color: #222 !important; + color: #111 !important; } .qm-inner { @@ -194,12 +195,14 @@ } .qm .qm-qm { - color: #ccc !important; + color: #999 !important; } .qm a { color: #21759B !important; text-decoration: underline !important; + text-shadow: none !important; + font-weight: normal !important; } .qm a.qm-warn { diff --git a/query-monitor.php b/query-monitor.php index 29e183031..12ce7754f 100644 --- a/query-monitor.php +++ b/query-monitor.php @@ -2,7 +2,7 @@ /* Plugin Name: Query Monitor Description: Monitoring of database queries, hooks, conditionals and much more. -Version: 2.1.4 +Version: 2.1.5 Author: John Blackbourn Author URI: http://lud.icro.us/ @@ -44,11 +44,12 @@ function __construct() { add_action( 'init', array( $this, 'enqueue_style' ) ); add_action( 'admin_footer', array( $this, 'register_output' ), 999 ); add_action( 'wp_footer', array( $this, 'register_output' ), 999 ); + add_filter( 'wp_redirect', array( $this, 'redirect' ), 999 ); register_activation_hook( __FILE__, array( $this, 'activate' ) ); register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) ); - $this->plugin_dir = plugin_dir_path( __FILE__ ); - $this->plugin_url = plugin_dir_url( __FILE__ ); + $this->plugin_dir = untrailingslashit( plugin_dir_path( __FILE__ ) ); + $this->plugin_url = untrailingslashit( plugin_dir_url( __FILE__ ) ); $this->is_multisite = ( function_exists( 'is_multisite' ) and is_multisite() ); foreach ( glob( "{$this->plugin_dir}/components/*.php" ) as $component ) @@ -73,13 +74,72 @@ function get_components() { return $this->components; } + function redirect( $location ) { + + if ( !QM_LOG_REDIRECT_DATA ) + return $location; + if ( false === strpos( $location, $_SERVER['HTTP_HOST'] ) ) + return $location; + if ( !$this->show_query_monitor() ) + return $location; + + # @TODO we're only doing this for logged-in users at the moment because I can't decide how + # best to generate and retrieve a key for non-logged-in users with a QM auth cookie. + + if ( !is_user_logged_in() ) + return $location; + + $current = ( is_ssl() ) + ? 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] + : 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + + $data = array( + 'url' => $current + ); + + foreach ( $this->get_components() as $component ) + $component->process(); + + foreach ( $this->get_components() as $component ) + $component->process_late(); + + foreach ( $this->get_components() as $component ) + $data['components'][$component->id] = $component->get_data(); + + $key = 'qm_redirect_data_' . wp_get_current_user()->ID; + + set_transient( $key, $data, 3600 ); + + return $location; + + } + + function get_redirect_data() { + + if ( !wp_get_referer() ) + return null; + if ( !is_user_logged_in() ) + return null; + + $key = 'qm_redirect_data_' . wp_get_current_user()->ID; + $data = get_transient( $key ); + + if ( empty( $data ) ) + return null; + + delete_transient( $key ); + + return $data; + + } + function activate() { if ( $admins = $this->get_admins() ) $admins->add_cap( 'view_query_monitor' ); if ( !file_exists( WP_CONTENT_DIR . '/db.php' ) and function_exists( 'symlink' ) ) - @symlink( $this->plugin_dir . 'wp-content/db.php', WP_CONTENT_DIR . '/db.php' ); + @symlink( $this->plugin_dir . '/wp-content/db.php', WP_CONTENT_DIR . '/db.php' ); } @@ -135,9 +195,10 @@ function show_query_monitor() { return true; } - $auth = $this->get_component( 'authentication' ); + if ( $auth = $this->get_component( 'authentication' ) ) + return $auth->show_query_monitor(); - return $auth ? $auth->show_query_monitor() : false; + return false; } @@ -149,7 +210,7 @@ function register_output() { foreach ( $this->get_components() as $component ) $component->process(); - add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 99 ); + add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 999 ); add_action( 'shutdown', array( $this, 'output' ), 0 ); } @@ -161,9 +222,9 @@ function enqueue_style() { wp_enqueue_style( 'query_monitor', - $this->plugin_url . 'query-monitor.css', + $this->plugin_url . '/query-monitor.css', null, - filemtime( $this->plugin_dir . 'query-monitor.css' ) + filemtime( $this->plugin_dir . '/query-monitor.css' ) ); } @@ -177,7 +238,10 @@ function output() { foreach ( $this->get_components() as $component ) $component->process_late(); - $this->output_start(); + $redirect_data = $this->get_redirect_data(); + + echo '
    '; + echo '

    Query Monitor

    '; foreach ( $this->get_components() as $component ) { $component->output( array( @@ -185,17 +249,8 @@ function output() { ), $component->data ); } - $this->output_end(); - - } - - function output_start() { - echo '
    '; - echo '

    Query Monitor

    '; - } - - function output_end() { echo '
    '; + } function wpv() { @@ -257,7 +312,7 @@ protected function _filter_trace( $trace ) { if ( in_array( $trace['function'], $ignore_func ) ) return null; - else if ( isset( $trace['args'] ) and in_array( $trace['function'], $show_arg ) ) + else if ( isset( $trace['args'][0] ) and in_array( $trace['function'], $show_arg ) ) return $trace['function'] . "('{$trace['args'][0]}')"; else return $trace['function'] . '()'; @@ -304,6 +359,12 @@ protected function get_component( $id ) { return $querymonitor->get_component( $id ); } + public function get_data() { + if ( isset( $this->data ) ) + return $this->data; + return null; + } + public function process() { return false; } @@ -321,6 +382,9 @@ public function output() { if ( !defined( 'ABSPATH' ) ) die(); -$querymonitor = new QueryMonitor; +if ( !defined( 'QM_LOG_REDIRECT_DATA' ) ) + define( 'QM_LOG_REDIRECT_DATA', false ); + +$GLOBALS['querymonitor'] = new QueryMonitor; -?> +?> \ No newline at end of file diff --git a/wp-content/db.php b/wp-content/db.php index b7e289c70..808999874 100644 --- a/wp-content/db.php +++ b/wp-content/db.php @@ -1,7 +1,7 @@ ready ) return false; + if ( $this->show_errors and class_exists( 'QM_DB_Queries' ) ) + $this->hide_errors(); + // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method if ( function_exists( 'apply_filters' ) ) $query = apply_filters( 'query', $query ); @@ -99,9 +102,15 @@ function get_caller() { } function backtrace() { - $trace = debug_backtrace( false ); - $trace = array_map( array( $this, '_filter_trace' ), $trace ); + $_trace = debug_backtrace( false ); + $trace = array_map( array( $this, '_filter_trace' ), $_trace ); $trace = array_values( array_filter( $trace ) ); + if ( empty( $trace ) ) { + $file = str_replace( '\\', '/', $_trace[3]['file'] ); + $path = str_replace( '\\', '/', ABSPATH ); + $file = str_replace( $path, '', $file ); + $trace[] = $file; + } return $trace; }