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 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 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 test_populate_callback_lambda() { $function = create_function('', ''); $callback = self::get_callback($function); $ref = new ReflectionFunction($function); $actual = QM_Util::populate_callback($callback); $file = trim(QM_Util::standard_dir(__FILE__, ''), '/'); preg_match('|(?P<file>.*)\\((?P<line>[0-9]+)\\)|', $ref->getFileName(), $matches); $line = $matches['line']; $name = sprintf('Anonymous function on line %1$d of %2$s', $line, $file); $this->assertEquals($function, $actual['function']); $this->assertEquals($name, $actual['name']); $this->assertEquals(__FILE__, $actual['file']); $this->assertEquals($line, $actual['line']); }
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 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 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 test_populate_callback_lambda() { $function = create_function('', ''); $callback = self::get_callback($function); $ref = new ReflectionFunction($function); $actual = QM_Util::populate_callback($callback); $file = trim(QM_Util::standard_dir(__FILE__, ''), '/'); preg_match('|(?P<file>.*)\\((?P<line>[0-9]+)\\)|', $ref->getFileName(), $matches); // https://github.com/facebook/hhvm/issues/5807 if (empty($matches) && defined('HHVM_VERSION')) { $this->assertWPError($actual['error']); $this->assertSame('unknown_lambda', $actual['error']->get_error_code()); } else { $line = $matches['line']; $name = sprintf('Anonymous function on line %1$d of %2$s', $line, $file); $this->assertEquals($function, $actual['function']); $this->assertEquals($name, $actual['name']); $this->assertEquals(__FILE__, $actual['file']); $this->assertEquals($line, $actual['line']); } }
/** * 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)); }
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 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; }