Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Plugin Name: Automattic Debug Helpers |
||
| 4 | * Description: <code>l( 'Code is Poetry' )</code> |
||
| 5 | * Version: 1.0 |
||
| 6 | * Author: Automattic |
||
| 7 | * Author URI: https://automattic.com/ |
||
| 8 | * Text Domain: jetpack |
||
| 9 | * |
||
| 10 | * @package Jetpack. |
||
| 11 | */ |
||
| 12 | |||
| 13 | // phpcs:disable WordPress.PHP.DevelopmentFunctions |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Sweet error logging |
||
| 17 | * |
||
| 18 | * The first call of l() will print an extra line containing a random ID & PID |
||
| 19 | * and the script name or URL. The ID prefixes every l() log entry thereafter. |
||
| 20 | * The extra line and ID will help you to identify and correlate log entries. |
||
| 21 | * |
||
| 22 | * l($something_to_log); // error_log(print_r($something_to_log, true)); |
||
| 23 | * l(compact('v1','v2'); // log several variables with labels |
||
| 24 | * l($thing5, $thing10); // log two things |
||
| 25 | * l(); // log the file:line |
||
| 26 | * l(null, $stuff, $ba); // log the file:line, then log two things. |
||
| 27 | * |
||
| 28 | * Example: |
||
| 29 | * wpsh> l('yo') |
||
| 30 | * wpsh> l('dude') |
||
| 31 | * /tmp/php-errors: |
||
| 32 | * [21-Jun-2012 14:45:13] 1566-32201 => /home/wpcom/public_html/bin/wpshell/wpshell.php |
||
| 33 | * [21-Jun-2012 14:45:13] 1566-32201 yo |
||
| 34 | * [21-Jun-2012 14:50:23] 1566-32201 dude |
||
| 35 | * |
||
| 36 | * l() returns its input so you can safely wrap most kinds of expressions to log them. |
||
| 37 | * l($arg1, $arg2) will call l($arg1) and l($arg2) and then return $arg1. |
||
| 38 | * |
||
| 39 | * A null argument will log the file and line number of the l() call. |
||
| 40 | * |
||
| 41 | * @param mixed $stuff Information to log. |
||
| 42 | */ |
||
| 43 | function l( $stuff = null ) { |
||
| 44 | // Do nothing when debugging is off. |
||
| 45 | if ( ! defined( 'WP_DEBUG' ) || WP_DEBUG === false ) { |
||
| 46 | return $stuff; |
||
| 47 | } |
||
| 48 | static $pageload; |
||
| 49 | // Call l() on each argument. |
||
| 50 | if ( func_num_args() > 1 ) { |
||
| 51 | foreach ( func_get_args() as $arg ) { // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection |
||
| 52 | l( $arg ); |
||
| 53 | } |
||
| 54 | return $stuff; |
||
| 55 | } |
||
| 56 | if ( ! isset( $pageload ) ) { |
||
| 57 | $pageload = substr( md5( wp_rand() ), 0, 4 ); |
||
| 58 | if ( ! empty( $_SERVER['argv'] ) ) { |
||
| 59 | $hint = implode( ' ', $_SERVER['argv'] ); |
||
| 60 | } elseif ( isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { |
||
| 61 | $hint = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; |
||
| 62 | } else { |
||
| 63 | $hint = php_sapi_name(); |
||
| 64 | } |
||
| 65 | error_log( sprintf( '[%s-%s => %s]', $pageload, getmypid(), $hint ) ); |
||
| 66 | } |
||
| 67 | $pid = $pageload . '-' . getmypid(); |
||
| 68 | if ( is_null( $stuff ) ) { |
||
| 69 | // Log the file and line number. |
||
| 70 | $backtrace = debug_backtrace( false ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection |
||
| 71 | View Code Duplication | while ( isset( $backtrace[1]['function'] ) && __FUNCTION__ === $backtrace[1]['function'] ) { |
|
| 72 | array_shift( $backtrace ); |
||
| 73 | } |
||
| 74 | $log = sprintf( '%s line %d', $backtrace[0]['file'], $backtrace[0]['line'] ); |
||
| 75 | } elseif ( is_bool( $stuff ) ) { |
||
| 76 | $log = $stuff ? 'TRUE' : 'FALSE'; |
||
| 77 | } elseif ( is_scalar( $stuff ) ) { |
||
| 78 | // Strings and numbers can be logged exactly. |
||
| 79 | $log = $stuff; |
||
| 80 | } else { |
||
| 81 | /* |
||
| 82 | * Are we in an output buffer handler? |
||
| 83 | * If so, print_r($stuff, true) is fatal so we must avoid that. |
||
| 84 | * This is not as slow as it looks: <1ms when !$in_ob_handler. |
||
| 85 | * Using json_encode_pretty() all the time is much slower. |
||
| 86 | */ |
||
| 87 | do { |
||
| 88 | $in_ob_handler = false; |
||
| 89 | $ob_status = ob_get_status( true ); |
||
| 90 | $obs = array(); |
||
| 91 | |||
| 92 | if ( ! $ob_status ) { |
||
|
0 ignored issues
–
show
|
|||
| 93 | break; |
||
| 94 | } |
||
| 95 | |||
| 96 | foreach ( $ob_status as $ob ) { |
||
| 97 | $obs[] = $ob['name']; |
||
| 98 | } |
||
| 99 | // This is not perfect: anonymous handlers appear as default. |
||
| 100 | if ( array( 'default output handler' ) === $obs ) { |
||
| 101 | break; |
||
| 102 | } |
||
| 103 | $backtrace = debug_backtrace( false ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection |
||
| 104 | $bts = array(); |
||
| 105 | foreach ( $backtrace as $level ) { |
||
| 106 | $caller = ''; |
||
| 107 | if ( isset( $level['class'] ) ) { |
||
| 108 | $caller = $level['class'] . '::'; |
||
| 109 | } |
||
| 110 | $caller .= $level['function']; |
||
| 111 | $bts[] = $caller; |
||
| 112 | } |
||
| 113 | if ( array_intersect( $obs, $bts ) ) { |
||
| 114 | $in_ob_handler = true; |
||
| 115 | } |
||
| 116 | } while ( false ); |
||
| 117 | if ( $in_ob_handler ) { |
||
| 118 | $log = l_json_encode_pretty( $stuff ); |
||
| 119 | } else { |
||
| 120 | $log = print_r( $stuff, true ); |
||
| 121 | } |
||
| 122 | } |
||
| 123 | error_log( sprintf( '[%s] %s', $pid, $log ) ); |
||
| 124 | return $stuff; |
||
| 125 | } |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Log only once (suppresses logging on subsequent calls from the same file+line). |
||
| 129 | * |
||
| 130 | * @param mixed $stuff Information to log. |
||
| 131 | */ |
||
| 132 | function lo( $stuff ) { |
||
| 133 | static $callers = array(); |
||
| 134 | $args = func_get_args(); |
||
| 135 | $backtrace = debug_backtrace( false ); |
||
| 136 | $caller = md5( $backtrace[0]['file'] . $backtrace[0]['line'] ); |
||
| 137 | if ( isset( $callers[ $caller ] ) ) { |
||
| 138 | return $stuff; |
||
| 139 | } |
||
| 140 | $callers[ $caller ] = true; |
||
| 141 | return call_user_func_array( 'l', $args ); |
||
| 142 | } |
||
| 143 | |||
| 144 | /** |
||
| 145 | * Pretty print for JSON (stolen from public.api) |
||
| 146 | * |
||
| 147 | * Previously, this function actually did stuff, but since JSON_PRETTY_PRINT is available as of PHP 5.4, let's use that. |
||
| 148 | * |
||
| 149 | * @param mixed $data Data to encode. |
||
| 150 | * |
||
| 151 | * @return false|string |
||
| 152 | */ |
||
| 153 | function l_json_encode_pretty( $data ) { |
||
| 154 | return wp_json_encode( $data, JSON_PRETTY_PRINT ); |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * A timer. |
||
| 159 | * |
||
| 160 | * Call once to start, call again to stop. Returns a float. |
||
| 161 | * Calling e($name) with different names permits simultaneous timers. |
||
| 162 | * |
||
| 163 | * e('stuff'); |
||
| 164 | * do_stuff(); |
||
| 165 | * $elapsed = e('stuff'); |
||
| 166 | * |
||
| 167 | * @param string $name Timer name. |
||
| 168 | * |
||
| 169 | * @return mixed void or elapsed time. |
||
| 170 | */ |
||
| 171 | function e( $name = '' ) { |
||
| 172 | static $times = array(); |
||
| 173 | if ( ! array_key_exists( $name, $times ) ) { |
||
| 174 | $times[ $name ] = microtime( true ); |
||
| 175 | return; |
||
| 176 | } |
||
| 177 | $elapsed = microtime( true ) - $times[ $name ]; |
||
| 178 | unset( $times[ $name ] ); |
||
| 179 | return $elapsed; |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * A wrapper for e() which also logs the result with l(). |
||
| 184 | * |
||
| 185 | * Each log entry begins with a tag common to that pageload. |
||
| 186 | * You can save a keystroke by calling e() then el(). |
||
| 187 | * |
||
| 188 | * e($name); |
||
| 189 | * do_stuff(); |
||
| 190 | * el($name); |
||
| 191 | * |
||
| 192 | * @param string $name Timer name. |
||
| 193 | */ |
||
| 194 | function el( $name = '' ) { |
||
| 195 | $elapsed = e( $name ); |
||
| 196 | if ( null !== $elapsed ) { |
||
| 197 | l( sprintf( "%9.6f e('%s')", $elapsed, $name ) ); |
||
| 198 | } |
||
| 199 | return $elapsed; |
||
| 200 | } |
||
| 201 | |||
| 202 | /** |
||
| 203 | * A persistent timer. After the initial call, each call to t() |
||
| 204 | * will log the file:line and time elapsed since the initial call. |
||
| 205 | */ |
||
| 206 | function t() { |
||
| 207 | static $start; |
||
| 208 | $now = microtime( true ); |
||
| 209 | if ( ! isset( $start ) ) { |
||
| 210 | $start = $now; |
||
| 211 | } |
||
| 212 | |||
| 213 | $backtrace = debug_backtrace( false ); |
||
| 214 | View Code Duplication | while ( isset( $backtrace[1]['function'] ) && __FUNCTION__ === $backtrace[1]['function'] ) { |
|
| 215 | array_shift( $backtrace ); |
||
| 216 | } |
||
| 217 | |||
| 218 | $file = $backtrace[0]['file']; |
||
| 219 | $line = $backtrace[0]['line']; |
||
| 220 | $format = 't() => %9.6f at %s line %d'; |
||
| 221 | $elapsed = $now - $start; |
||
| 222 | l( sprintf( $format, $elapsed, $file, $line ) ); |
||
| 223 | } |
||
| 224 | |||
| 225 | // phpcs:enable |
||
| 226 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.