public function process() { $this->data['time_taken'] = self::timer_stop_float(); $this->data['time_limit'] = ini_get('max_execution_time'); $this->data['time_start'] = $GLOBALS['timestart']; if (!empty($this->data['time_limit'])) { $this->data['time_usage'] = 100 / $this->data['time_limit'] * $this->data['time_taken']; } else { $this->data['time_usage'] = 0; } if (function_exists('memory_get_peak_usage')) { $this->data['memory'] = memory_get_peak_usage(); } else { if (function_exists('memory_get_usage')) { $this->data['memory'] = memory_get_usage(); } else { $this->data['memory'] = 0; } } if (is_user_logged_in()) { $this->data['current_user'] = self::format_user(wp_get_current_user()); } else { $this->data['current_user'] = false; } if (function_exists('current_user_switched') && current_user_switched()) { $this->data['switched_user'] = self::format_user(current_user_switched()); } else { $this->data['switched_user'] = false; } $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes(ini_get('memory_limit')); $this->data['memory_usage'] = 100 / $this->data['memory_limit'] * $this->data['memory']; $this->data['is_admin'] = is_admin(); }
public function after_output() { # flush once, because we're nice if (QM_Util::is_ajax() and ob_get_length()) { ob_flush(); } }
public function deactivate() { if ($admins = QM_Util::get_admins()) { $admins->remove_cap('view_query_monitor'); } # Only delete db.php if it belongs to Query Monitor if (class_exists('QM_DB')) { unlink(WP_CONTENT_DIR . '/db.php'); } }
public function process() { $this->data['time'] = self::timer_stop_float(); $this->data['time_limit'] = ini_get('max_execution_time'); if (!empty($this->data['time_limit'])) { $this->data['time_usage'] = 100 / $this->data['time_limit'] * $this->data['time']; } else { $this->data['time_usage'] = 0; } $this->data['memory'] = memory_get_peak_usage(); $this->data['memory_limit'] = QM_Util::convert_hr_to_bytes(ini_get('memory_limit')); $this->data['memory_usage'] = 100 / $this->data['memory_limit'] * $this->data['memory']; }
public function process() { global $template; $template_path = QM_Util::standard_dir($template); $stylesheet_directory = QM_Util::standard_dir(get_stylesheet_directory()); $template_directory = QM_Util::standard_dir(get_template_directory()); $template_file = str_replace(array($stylesheet_directory, $template_directory), '', $template_path); $template_file = ltrim($template_file, '/'); $this->data['template_path'] = $template_path; $this->data['template_file'] = $template_file; $this->data['stylesheet'] = get_stylesheet(); $this->data['template'] = get_template(); if (isset($this->data['body_class'])) { asort($this->data['body_class']); } }
public function output() { $data = $this->collector->get_data(); if (empty($data['languages'])) { return; } echo '<div class="qm" id="' . esc_attr($this->collector->id()) . '">'; echo '<table cellspacing="0">'; echo '<thead>'; echo '<tr>'; echo '<th>' . esc_html__('Languages', 'query-monitor') . '</th>'; echo '<th colspan="3">' . esc_html__('Language Setting:', 'query-monitor') . ' ' . esc_html(get_locale()) . '</th>'; echo '</tr>'; echo '<tr>'; echo '<td>' . esc_html__('Text Domain', 'query-monitor') . '</td>'; echo '<td>' . esc_html__('Caller', 'query-monitor') . '</td>'; echo '<td>' . esc_html__('MO File', 'query-monitor') . '</td>'; echo '<td>' . esc_html__('Loaded', 'query-monitor') . '</td>'; echo '</tr>'; echo '</thead>'; echo '<tbody>'; foreach ($data['languages'] as $mofile) { echo '<tr>'; echo '<td>' . esc_html($mofile['domain']) . '</td>'; echo '<td class="qm-nowrap">'; echo self::output_filename($mofile['caller']['display'], $mofile['caller']['file'], $mofile['caller']['line']); // WPCS: XSS ok. echo '</td>'; echo '<td>'; echo esc_html(QM_Util::standard_dir($mofile['mofile'], '')); echo '</td>'; if ($mofile['found']) { echo '<td class="qm-nowrap">'; echo esc_html__('Found', 'query-monitor') . '<br />'; echo esc_html(size_format($mofile['found'])); echo '</td>'; } else { echo '<td class="qm-warn">'; echo esc_html__('Not Found', 'query-monitor'); echo '</td>'; } echo '</tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; }
public function process() { global $wp_rewrite; if (is_admin() or QM_Util::is_async()) { return; } if (!($request = QM_Collectors::get('request'))) { return; } if (empty($wp_rewrite->rules)) { return; } $req = $request->data['request']['request']; $matching = array(); foreach ($wp_rewrite->rules as $match => $query) { if (preg_match("#^{$match}#", $req)) { $matching[$match] = $query; } } $this->data['matching'] = $matching; }
public function process() { if (!empty($this->data['template_path'])) { $template_path = QM_Util::standard_dir($this->data['template_path']); $stylesheet_directory = QM_Util::standard_dir(get_stylesheet_directory()); $template_directory = QM_Util::standard_dir(get_template_directory()); $theme_directory = QM_Util::standard_dir(get_theme_root()); $template_file = str_replace(array($stylesheet_directory, $template_directory, ABSPATH), '', $template_path); $template_file = ltrim($template_file, '/'); $theme_template_file = str_replace(array($theme_directory, ABSPATH), '', $template_path); $theme_template_file = ltrim($theme_template_file, '/'); $this->data['template_path'] = $template_path; $this->data['template_file'] = $template_file; $this->data['theme_template_file'] = $theme_template_file; foreach (get_included_files() as $file) { $filename = str_replace(array($stylesheet_directory, $template_directory), '', $file); if ($filename !== $file) { $slug = trim(str_replace('.php', '', $filename), '/'); $display = trim($filename, '/'); $theme_display = trim(str_replace($theme_directory, '', $file), '/'); if (did_action("get_template_part_{$slug}")) { $this->data['template_parts'][$file] = $display; $this->data['theme_template_parts'][$file] = $theme_display; } else { $slug = trim(preg_replace('|\\-[^\\-]+$|', '', $slug), '/'); if (did_action("get_template_part_{$slug}")) { $this->data['template_parts'][$file] = $display; $this->data['theme_template_parts'][$file] = $theme_display; } } } } } $this->data['stylesheet'] = get_stylesheet(); $this->data['template'] = get_template(); $this->data['is_child_theme'] = $this->data['stylesheet'] != $this->data['template']; if (isset($this->data['body_class'])) { asort($this->data['body_class']); } }
public function error_handler($errno, $message, $file = null, $line = null) { #if ( !( error_reporting() & $errno ) ) # return false; switch ($errno) { case E_WARNING: case E_USER_WARNING: $type = 'warning'; break; case E_NOTICE: case E_USER_NOTICE: $type = 'notice'; break; case E_STRICT: $type = 'strict'; break; case QM_E_DEPRECATED: case QM_E_USER_DEPRECATED: $type = 'deprecated'; break; default: return false; break; } if (error_reporting() > 0) { if (!class_exists('QM_Backtrace')) { return false; } $trace = new QM_Backtrace(array('ignore_current_filter' => false)); $caller = $trace->get_caller(); $key = md5($message . $file . $line . $caller['id']); $filename = QM_Util::standard_dir($file, ''); if (isset($this->data['errors'][$type][$key])) { $this->data['errors'][$type][$key]->calls++; } else { $this->data['errors'][$type][$key] = (object) array('errno' => $errno, 'type' => $type, 'message' => $message, 'file' => $file, 'filename' => $filename, 'line' => $line, 'trace' => $trace, 'calls' => 1); } } return apply_filters('qm/collect/php_errors_return_value', false); }
public function output() { if (!QM_Util::is_ajax()) { return; } $data = $this->collector->get_data(); if (empty($data['errors'])) { return; } $count = 0; foreach ($data['errors'] as $type => $errors) { foreach ($errors as $key => $error) { $count++; # @TODO we should calculate the component during process() so we don't need to do it # separately in each output. $component = $error->trace->get_component(); $output_error = array('type' => $error->type, 'message' => wp_strip_all_tags($error->message), 'file' => $error->file, 'line' => $error->line, 'stack' => $error->trace->get_stack(), 'component' => $component->name); header(sprintf('X-QM-Error-%d: %s', $count, json_encode($output_error))); } } header(sprintf('X-QM-Errors: %d', $count)); }
protected function process_action($name, array $wp_filter) { $actions = $components = array(); if (isset($wp_filter[$name])) { # http://core.trac.wordpress.org/ticket/17817 $action = $wp_filter[$name]; foreach ($action as $priority => $callbacks) { foreach ($callbacks as $callback) { $callback = QM_Util::populate_callback($callback); if (isset($callback['component'])) { if ($this->hide_qm and 'query-monitor' === $callback['component']->context) { continue; } $components[$callback['component']->name] = $callback['component']->name; } $actions[] = array('priority' => $priority, 'callback' => $callback); } } } $parts = array_filter(preg_split('#[_/-]#', $name)); return array('name' => $name, 'actions' => $actions, 'parts' => $parts, 'components' => $components); }
public function is_active() { if (!QM_Util::is_ajax()) { return false; } if (!$this->user_can_view()) { return false; } # If the headers have already been sent then we can't do anything about it if (headers_sent()) { return false; } # Don't process if the minimum required actions haven't fired: if (is_admin()) { if (!did_action('admin_init')) { return false; } } else { if (!did_action('wp')) { return false; } } return true; }
public function process() { global $wp_actions, $wp_filter; if (is_admin() and $admin = QueryMonitor::get_collector('admin')) { $this->data['screen'] = $admin->data['base']; } else { $this->data['screen'] = ''; } $hooks = $parts = $components = array(); foreach ($wp_actions as $name => $count) { $actions = array(); # @TODO better variable name: $c = array(); if (isset($wp_filter[$name])) { # http://core.trac.wordpress.org/ticket/17817 $action = $wp_filter[$name]; foreach ($action as $priority => $callbacks) { foreach ($callbacks as $callback) { $callback = QM_Util::populate_callback($callback); if (isset($callback['component'])) { $c[$callback['component']->name] = $callback['component']->name; } $actions[] = array('priority' => $priority, 'callback' => $callback); } } } # @TODO better variable name: $p = array_filter(preg_split('/[_\\/-]/', $name)); $parts = array_merge($parts, $p); $components = array_merge($components, $c); $hooks[$name] = array('name' => $name, 'actions' => $actions, 'parts' => $p, 'components' => $c); } $this->data['hooks'] = $hooks; $this->data['parts'] = array_unique(array_filter($parts)); $this->data['components'] = array_unique(array_filter($components)); }
public static function populate_callback(array $callback) { if (is_string($callback['function']) and false !== strpos($callback['function'], '::')) { $callback['function'] = explode('::', $callback['function']); } try { if (is_array($callback['function'])) { if (is_object($callback['function'][0])) { $class = get_class($callback['function'][0]); $access = '->'; } else { $class = $callback['function'][0]; $access = '::'; } $callback['name'] = $class . $access . $callback['function'][1] . '()'; $ref = new ReflectionMethod($class, $callback['function'][1]); } else { if (is_object($callback['function'])) { if (is_a($callback['function'], 'Closure')) { $ref = new ReflectionFunction($callback['function']); $file = QM_Util::standard_dir($ref->getFileName(), ''); /* translators: 1: Line number, 2: File name */ $callback['name'] = sprintf(__('Closure on line %1$d of %2$s', 'query-monitor'), $ref->getStartLine(), $file); } else { // the object should have a __invoke() method $class = get_class($callback['function']); $callback['name'] = $class . '->__invoke()'; $ref = new ReflectionMethod($class, '__invoke'); } } else { $callback['name'] = $callback['function'] . '()'; $ref = new ReflectionFunction($callback['function']); } } $callback['file'] = $ref->getFileName(); $callback['line'] = $ref->getStartLine(); // https://github.com/facebook/hhvm/issues/5856 $name = trim($ref->getName()); if ('__lambda_func' === $name || 0 === strpos($name, 'lambda_')) { if (preg_match('|(?P<file>.*)\\((?P<line>[0-9]+)\\)|', $callback['file'], $matches)) { $callback['file'] = $matches['file']; $callback['line'] = $matches['line']; $file = trim(QM_Util::standard_dir($callback['file'], ''), '/'); /* translators: 1: Line number, 2: File name */ $callback['name'] = sprintf(__('Anonymous function on line %1$d of %2$s', 'query-monitor'), $callback['line'], $file); } else { // https://github.com/facebook/hhvm/issues/5807 unset($callback['line'], $callback['file']); $callback['name'] = $name . '()'; $callback['error'] = new WP_Error('unknown_lambda', __('Unable to determine source of lambda function', 'query-monitor')); } } if (!empty($callback['file'])) { $callback['component'] = self::get_file_component($callback['file']); } else { $callback['component'] = (object) array('type' => 'php', 'name' => 'PHP', 'context' => ''); } } catch (ReflectionException $e) { $callback['error'] = new WP_Error('reflection_exception', $e->getMessage()); } return $callback; }
public function error_handler($errno, $message, $file = null, $line = null) { switch ($errno) { case E_WARNING: case E_USER_WARNING: $type = 'warning'; break; case E_NOTICE: case E_USER_NOTICE: $type = 'notice'; break; case E_STRICT: $type = 'strict'; break; case QM_E_DEPRECATED: case QM_E_USER_DEPRECATED: $type = 'deprecated'; break; default: return false; break; } if (!class_exists('QM_Backtrace')) { return false; } if (!isset(self::$unexpected_error)) { // These strings are from core. They're passed through `__()` as variables so they get translated at runtime // but do not get seen by GlotPress when it populates its database of translatable strings for QM. $unexpected_error = 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.'; $wordpress_couldnt = '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)'; self::$unexpected_error = __($unexpected_error); self::$wordpress_couldnt = __($wordpress_couldnt); } // Intentionally skip reporting these core warnings. They're a distraction when developing offline. // The failed HTTP request will still appear in QM's output so it's not a big problem hiding these warnings. if (self::$unexpected_error === $message) { return false; } if (self::$unexpected_error . ' ' . self::$wordpress_couldnt === $message) { return false; } $trace = new QM_Backtrace(array('ignore_current_filter' => false)); $caller = $trace->get_caller(); $key = md5($message . $file . $line . $caller['id']); $filename = QM_Util::standard_dir($file, ''); if (isset($this->data['errors'][$type][$key])) { $this->data['errors'][$type][$key]->calls++; } else { $this->data['errors'][$type][$key] = (object) array('errno' => $errno, 'type' => $type, 'message' => $message, 'file' => $file, 'filename' => $filename, 'line' => $line, 'trace' => $trace, 'calls' => 1); } return apply_filters('qm/collect/php_errors_return_value', false); }
public function testCurrentUrl() { $url = add_query_arg('foo', 'bar', home_url('baz')); $this->go_to($url); $this->assertSame(QM_Util::get_current_url(), $url); }
public function is_active() { if (!$this->user_can_view()) { return false; } if (!$this->did_footer) { return false; } if (QM_Util::is_async()) { return false; } # Don't process if the minimum required actions haven't fired: if (is_admin()) { if (!did_action('admin_init')) { return false; } } else { if (!(did_action('wp') || did_action('login_init'))) { return false; } } # Back-compat filter. Please use `qm/dispatch/html` instead if (!apply_filters('qm/process', true, is_admin_bar_showing())) { return false; } return true; }
public function process_db_object($id, wpdb $db) { global $EZSQL_ERROR; $rows = array(); $types = array(); $total_time = 0; $has_result = false; $has_trace = false; $i = 0; foreach ((array) $db->queries as $query) { # @TODO: decide what I want to do with this: if (false !== strpos($query[2], 'wp_admin_bar') and !isset($_REQUEST['qm_display_admin_bar'])) { continue; } $sql = $query[0]; $ltime = $query[1]; $stack = $query[2]; $has_trace = isset($query['trace']); $has_result = isset($query['result']); if (isset($query['result'])) { $result = $query['result']; } else { $result = null; } $total_time += $ltime; if (isset($query['trace'])) { $trace = $query['trace']; $component = $query['trace']->get_component(); $caller = $query['trace']->get_caller(); $caller_name = $caller['id']; $caller = $caller['display']; } else { $trace = null; $component = null; $callers = explode(',', $stack); $caller = trim(end($callers)); if (false !== strpos($caller, '(')) { $caller_name = substr($caller, 0, strpos($caller, '(')) . '()'; } else { $caller_name = $caller; } } $sql = trim($sql); $type = QM_Util::get_query_type($sql); $this->log_type($type); $this->log_caller($caller_name, $ltime, $type); $this->maybe_log_dupe($sql, $i); if ($component) { $this->log_component($component, $ltime, $type); } if (!isset($types[$type]['total'])) { $types[$type]['total'] = 1; } else { $types[$type]['total']++; } if (!isset($types[$type]['callers'][$caller])) { $types[$type]['callers'][$caller] = 1; } else { $types[$type]['callers'][$caller]++; } $row = compact('caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component', 'trace'); if (is_wp_error($result)) { $this->data['errors'][] = $row; } if (self::is_expensive($row)) { $this->data['expensive'][] = $row; } $rows[$i] = $row; $i++; } if ('$wpdb' === $id && !$has_result && !empty($EZSQL_ERROR) && is_array($EZSQL_ERROR)) { // Fallback for displaying database errors when wp-content/db.php isn't in place foreach ($EZSQL_ERROR as $error) { $row = array('caller' => 'Unknown', 'caller_name' => 'Unknown', 'stack' => '', 'sql' => $error['query'], 'result' => new WP_Error('qmdb', $error['error_str']), 'type' => '', 'component' => false, 'trace' => null); $this->data['errors'][] = $row; } } $total_qs = count($rows); $this->data['total_qs'] += $total_qs; $this->data['total_time'] += $total_time; # @TODO put errors in here too: # @TODO proper class instead of (object) $this->data['dbs'][$id] = (object) compact('rows', 'types', 'has_result', 'has_trace', 'total_time', 'total_qs'); }
/** * @dataProvider clientVersionData * */ public function testClientVersion($client, $expected) { $ver = QM_Util::get_client_version($client); $this->assertEquals($expected, array_values($ver)); }
public static function populate_callback(array $callback) { if (is_string($callback['function']) and false !== strpos($callback['function'], '::')) { $callback['function'] = explode('::', $callback['function']); } try { if (is_array($callback['function'])) { if (is_object($callback['function'][0])) { $class = get_class($callback['function'][0]); $access = '->'; } else { $class = $callback['function'][0]; $access = '::'; } $callback['name'] = $class . $access . $callback['function'][1] . '()'; $ref = new ReflectionMethod($class, $callback['function'][1]); } else { if (is_object($callback['function'])) { if (is_a($callback['function'], 'Closure')) { $ref = new ReflectionFunction($callback['function']); $file = trim(QM_Util::standard_dir($ref->getFileName(), ''), '/'); $callback['name'] = sprintf(__('Closure on line %1$d of %2$s', 'query-monitor'), $ref->getStartLine(), $file); } else { // the object should have a __invoke() method $class = get_class($callback['function']); $callback['name'] = $class . '->__invoke()'; $ref = new ReflectionMethod($class, '__invoke'); } } else { $callback['name'] = $callback['function'] . '()'; $ref = new ReflectionFunction($callback['function']); } } $callback['file'] = $ref->getFileName(); $callback['line'] = $ref->getStartLine(); if ('__lambda_func' === $ref->getName()) { if (preg_match('|(?P<file>.*)\\((?P<line>[0-9]+)\\)|', $callback['file'], $matches)) { $callback['file'] = $matches['file']; $callback['line'] = $matches['line']; $file = trim(QM_Util::standard_dir($callback['file'], ''), '/'); $callback['name'] = sprintf(__('Anonymous function on line %1$d of %2$s', 'query-monitor'), $callback['line'], $file); } } $callback['component'] = self::get_file_component($callback['file']); } catch (ReflectionException $e) { $callback['error'] = new WP_Error('reflection_exception', $e->getMessage()); } return $callback; }
public function active() { if (!$this->qm->user_can_view()) { return false; } if (!(did_action('wp_footer') or did_action('admin_footer') or did_action('login_footer'))) { return false; } if (QM_Util::is_async()) { return false; } return true; }
public function output() { $data = $this->collector->get_data(); if (empty($data['dupes'])) { return; } $colspan = empty($data['dupe_components']) ? 4 : 5; echo '<div class="qm" id="' . esc_attr($this->collector->id()) . '">'; echo '<table cellspacing="0">'; echo '<thead>'; echo '<tr>'; echo '<th colspan="' . absint($colspan) . '">' . esc_html($this->collector->name()) . '</th>'; echo '</tr>'; echo '<tr>'; echo '<th>' . esc_html__('Query', 'query-monitor') . '</th>'; echo '<th class="qm-num">' . esc_html__('Count', 'query-monitor') . '</th>'; echo '<th>' . esc_html__('Callers', 'query-monitor') . '</th>'; if (!empty($data['dupe_components'])) { echo '<th>' . esc_html__('Components', 'query-monitor') . '</th>'; } echo '<th>' . esc_html__('Potential Troublemakers', 'query-monitor') . '</th>'; echo '</tr>'; echo '</thead>'; echo '<tbody>'; /* translators: %s: Number of calls to a PHP function */ $call_text = _n_noop('%s call', '%s calls', 'query-monitor'); foreach ($data['dupes'] as $sql => $queries) { // This should probably happen in the collector's processor $type = QM_Util::get_query_type($sql); $sql_out = self::format_sql($sql); if ('SELECT' !== $type) { $sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>"; } echo '<tr>'; echo '<td class="qm-row-sql qm-ltr qm-wrap">'; echo $sql_out; // WPCS: XSS ok; echo '</td>'; echo '<td class="qm-num">'; echo esc_html(number_format_i18n(count($queries), 0)); echo '</td>'; echo '<td class="qm-row-caller qm-nowrap qm-ltr">'; foreach ($data['dupe_callers'][$sql] as $caller => $calls) { printf('<a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="%s">%s</a><br><span class="qm-info"> %s</span><br>', esc_attr($caller), esc_html($caller), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; if (isset($data['dupe_components'][$sql])) { echo '<td class="qm-row-component qm-nowrap">'; foreach ($data['dupe_components'][$sql] as $component => $calls) { printf('%s<br><span class="qm-info"> %s</span><br>', esc_html($component), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; } echo '<td class="qm-row-caller qm-nowrap qm-ltr">'; foreach ($data['dupe_sources'][$sql] as $source => $calls) { printf('%s<br><span class="qm-info"> %s</span><br>', esc_html($source), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; echo '</tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; }
public function process() { global $wp, $wp_query, $current_blog, $current_site; $qo = get_queried_object(); if (is_multisite()) { $this->data['multisite']['current_blog'] = array('title' => sprintf('Current blog: #%d', $current_blog->blog_id), 'data' => $current_blog); } if (QM_Util::is_multi_network()) { $this->data['multisite']['current_site'] = array('title' => sprintf('Current site: #%d', $current_site->id), 'data' => $current_site); } if (is_admin()) { $this->data['request']['request'] = $_SERVER['REQUEST_URI']; foreach (array('query_string') as $item) { $this->data['request'][$item] = $wp->{$item}; } } else { foreach (array('request', 'matched_rule', 'matched_query', 'query_string') as $item) { $this->data['request'][$item] = $wp->{$item}; } } $plugin_qvars = array_flip(apply_filters('query_vars', array())); $qvars = $wp_query->query_vars; $query_vars = array(); foreach ($qvars as $k => $v) { if (isset($plugin_qvars[$k])) { if ('' !== $v) { $query_vars[$k] = $v; } } else { if (!empty($v)) { $query_vars[$k] = $v; } } } ksort($query_vars); # First add plugin vars to $this->data['qvars']: foreach ($query_vars as $k => $v) { if (isset($plugin_qvars[$k])) { $this->data['qvars'][$k] = $v; $this->data['plugin_qvars'][$k] = $v; } } # Now add all other vars to $this->data['qvars']: foreach ($query_vars as $k => $v) { if (!isset($plugin_qvars[$k])) { $this->data['qvars'][$k] = $v; } } switch (true) { case is_null($qo): // Nada break; case is_a($qo, 'WP_Post'): // Single post $this->data['queried_object']['title'] = sprintf(__('Single %s: #%d', 'query-monitor'), get_post_type_object($qo->post_type)->labels->singular_name, $qo->ID); break; case is_a($qo, 'WP_User'): // Author archive $this->data['queried_object']['title'] = sprintf(__('Author archive: %s', 'query-monitor'), $qo->user_nicename); break; case is_a($qo, 'WP_Term'): case property_exists($qo, 'term_id'): // Term archive $this->data['queried_object']['title'] = sprintf(__('Term archive: %s', 'query-monitor'), $qo->slug); break; case property_exists($qo, 'has_archive'): // Post type archive $this->data['queried_object']['title'] = sprintf(__('Post type archive: %s', 'query-monitor'), $qo->name); break; default: // Unknown, but we have a queried object $this->data['queried_object']['title'] = __('Unknown queried object', 'query-monitor'); break; } if (!is_null($qo)) { $this->data['queried_object']['data'] = $qo; } }
public function filter_trace(array $trace) { if (!self::$filtered and function_exists('did_action') and did_action('plugins_loaded')) { # Only run apply_filters on these once self::$ignore_class = apply_filters('qm/trace/ignore_class', self::$ignore_class); self::$ignore_method = apply_filters('qm/trace/ignore_method', self::$ignore_method); self::$ignore_func = apply_filters('qm/trace/ignore_func', self::$ignore_func); self::$show_args = apply_filters('qm/trace/show_args', self::$show_args); self::$filtered = true; } $return = $trace; if (isset($trace['class'])) { if (isset(self::$ignore_class[$trace['class']])) { $return = null; } else { if (isset(self::$ignore_method[$trace['class']][$trace['function']])) { $return = null; } else { if (0 === strpos($trace['class'], 'QM_')) { $return = null; } else { $return['id'] = $trace['class'] . $trace['type'] . $trace['function'] . '()'; $return['display'] = $trace['class'] . $trace['type'] . $trace['function'] . '()'; } } } } else { if (isset(self::$ignore_func[$trace['function']])) { $return = null; } else { if (isset(self::$show_args[$trace['function']])) { $show = self::$show_args[$trace['function']]; if ('dir' === $show) { if (isset($trace['args'][0])) { $arg = QM_Util::standard_dir($trace['args'][0], '~/'); $return['id'] = $trace['function'] . '()'; $return['display'] = $trace['function'] . "('{$arg}')"; } } else { $args = array(); for ($i = 0; $i < $show; $i++) { if (isset($trace['args'][$i])) { $args[] = '\'' . $trace['args'][$i] . '\''; } } $return['id'] = $trace['function'] . '()'; $return['display'] = $trace['function'] . '(' . implode(',', $args) . ')'; } } else { $return['id'] = $trace['function'] . '()'; $return['display'] = $trace['function'] . '()'; } } } if ($return) { $return['calling_file'] = $this->calling_file; $return['calling_line'] = $this->calling_line; } if (isset($trace['line'])) { $this->calling_line = $trace['line']; } if (isset($trace['file'])) { $this->calling_file = $trace['file']; } return $return; }
public function process() { global $wp_version; $mysql_vars = array('key_buffer_size' => true, 'max_allowed_packet' => false, 'max_connections' => false, 'query_cache_limit' => true, 'query_cache_size' => true, 'query_cache_type' => 'ON'); if ($dbq = QM_Collectors::get('db_queries')) { foreach ($dbq->db_objects as $id => $db) { $variables = $db->get_results("\n\t\t\t\t\tSHOW VARIABLES\n\t\t\t\t\tWHERE Variable_name IN ( '" . implode("', '", array_keys($mysql_vars)) . "' )\n\t\t\t\t"); if (is_resource($db->dbh)) { # Old mysql extension $extension = 'mysql'; } else { if (is_object($db->dbh)) { # mysqli or PDO $extension = get_class($db->dbh); } else { # Who knows? $extension = null; } } if (method_exists($db, 'db_version')) { $server = $db->db_version(); } else { $server = null; } if (isset($db->use_mysqli) && $db->use_mysqli) { $client = mysqli_get_client_version(); } else { if (preg_match('|[0-9]{1,2}\\.[0-9]{1,2}\\.[0-9]{1,2}|', mysql_get_client_info(), $matches)) { $client = $matches[0]; } else { $client = null; } } if ($client) { $client_version = implode('.', QM_Util::get_client_version($client)); $client_version = sprintf('%s (%s)', $client, $client_version); } else { $client_version = null; } $info = array('extension' => $extension, 'server version' => $server, 'client version' => $client_version, 'user' => $db->dbuser, 'host' => $db->dbhost, 'database' => $db->dbname); $this->data['db'][$id] = array('info' => $info, 'vars' => $mysql_vars, 'variables' => $variables); } } $this->data['php']['version'] = phpversion(); $this->data['php']['sapi'] = php_sapi_name(); $this->data['php']['user'] = self::get_current_user(); if (defined('HHVM_VERSION')) { $this->data['php']['hhvm'] = HHVM_VERSION; } foreach ($this->php_vars as $setting) { $this->data['php']['variables'][$setting]['after'] = ini_get($setting); } $this->data['php']['error_reporting'] = error_reporting(); $this->data['wp'] = array('version' => $wp_version, 'WP_DEBUG' => self::format_bool_constant('WP_DEBUG'), 'WP_DEBUG_DISPLAY' => self::format_bool_constant('WP_DEBUG_DISPLAY'), 'WP_DEBUG_LOG' => self::format_bool_constant('WP_DEBUG_LOG'), 'SCRIPT_DEBUG' => self::format_bool_constant('SCRIPT_DEBUG'), 'WP_CACHE' => self::format_bool_constant('WP_CACHE'), 'CONCATENATE_SCRIPTS' => self::format_bool_constant('CONCATENATE_SCRIPTS'), 'COMPRESS_SCRIPTS' => self::format_bool_constant('COMPRESS_SCRIPTS'), 'COMPRESS_CSS' => self::format_bool_constant('COMPRESS_CSS'), 'WP_LOCAL_DEV' => self::format_bool_constant('WP_LOCAL_DEV')); if (is_multisite()) { $this->data['wp']['SUNRISE'] = self::format_bool_constant('SUNRISE'); } $server = explode(' ', $_SERVER['SERVER_SOFTWARE']); $server = explode('/', reset($server)); if (isset($server[1])) { $server_version = $server[1]; } else { $server_version = null; } if (isset($_SERVER['SERVER_ADDR'])) { $address = $_SERVER['SERVER_ADDR']; } else { $address = null; } $this->data['server'] = array('name' => $server[0], 'version' => $server_version, 'address' => $address, 'host' => php_uname('n')); }
public static function populate_callback(array $callback) { $access = '->'; if (is_string($callback['function']) and false !== strpos($callback['function'], '::')) { $callback['function'] = explode('::', $callback['function']); $access = '::'; } try { if (is_array($callback['function'])) { if (is_object($callback['function'][0])) { $class = get_class($callback['function'][0]); } else { $class = $callback['function'][0]; } $callback['name'] = $class . $access . $callback['function'][1] . '()'; $ref = new ReflectionMethod($class, $callback['function'][1]); } else { if (is_object($callback['function']) and is_a($callback['function'], 'Closure')) { $ref = new ReflectionFunction($callback['function']); $file = trim(QM_Util::standard_dir($ref->getFileName(), ''), '/'); $callback['name'] = sprintf(__('{closure}() on line %1$d of %2$s', 'query-monitor'), $ref->getEndLine(), $file); } else { $callback['name'] = $callback['function'] . '()'; $ref = new ReflectionFunction($callback['function']); } } $callback['file'] = $ref->getFileName(); $callback['line'] = $ref->getStartLine(); $callback['component'] = self::get_file_component($ref->getFileName()); } catch (ReflectionException $e) { $callback['error'] = new WP_Error('reflection_exception', $e->getMessage()); } return $callback; }
public function test_populate_callback_invalid_static_class_string() { $function = 'Invalid_Class::goodbye'; $callback = self::get_callback($function); $actual = QM_Util::populate_callback($callback); $this->assertWPError($actual['error']); }
/** * Returns a file path, name, and line number. Safe for output. * * If clickable file links are enabled, a link such as this is returned: * * <a href="subl://open/?line={line}&url={file}">{text}</a> * * Otherwise, the display text and file details such as this is returned: * * {text}<br>{file}:{line} * * @param string $text The display text, such as a function name or file name. * @param string $file The full file path and name. * @param int $line Optional. A line number, if appropriate. * @return string The fully formatted file link or file name, safe for output. */ public static function output_filename($text, $file, $line = 0) { if (empty($file)) { return esc_html($text); } # Further reading: # http://simonwheatley.co.uk/2012/07/clickable-stack-traces/ # https://github.com/grych/subl-handler $link_line = $line ? $line : 1; if (!isset(self::$file_link_format)) { $format = ini_get('xdebug.file_link_format'); $format = apply_filters('qm/output/file_link_format', $format); if (empty($format)) { self::$file_link_format = false; } else { self::$file_link_format = str_replace(array('%f', '%l'), array('%1$s', '%2$d'), $format); } } if (false === self::$file_link_format) { $fallback = QM_Util::standard_dir($file, ''); if ($line) { $fallback .= ':' . $line; } $return = esc_html($text); if ($fallback !== $text) { $return .= '<br><span class="qm-info"> ' . esc_html($fallback) . '</span>'; } return $return; } $link = sprintf(self::$file_link_format, urlencode($file), intval($link_line)); return sprintf('<a href="%s">%s</a>', esc_attr($link), esc_html($text)); }