├── index.php ├── README.md ├── LICENSE └── debug-quick-look.php /index.php: -------------------------------------------------------------------------------- 1 | has_debug_constant() ) { 57 | add_action( 'wp_head', array( $this, 'add_warning_css' ) ); 58 | add_action( 'admin_head', array( $this, 'add_warning_css' ) ); 59 | } 60 | add_action( 'admin_init', array( $this, 'process_debug_type' ) ); 61 | add_action( 'admin_bar_menu', array( $this, 'admin_bar_links' ), 9999 ); 62 | } 63 | 64 | /** 65 | * Add the CSS to flag our warning message. 66 | */ 67 | public function add_warning_css() { 68 | 69 | // Bail if current user doesnt have cap or the constant is set. 70 | if ( ! current_user_can( 'manage_options' ) ) { 71 | return; 72 | } 73 | 74 | // Open the style tag. 75 | echo ''; 86 | } 87 | 88 | /** 89 | * Run a quick check to see if the debug log constant is set. 90 | * 91 | * @return boolean 92 | */ 93 | public function has_debug_constant() { 94 | return defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ? true : false; 95 | } 96 | 97 | /** 98 | * Run a quick check to see if the debug log file is empty. 99 | * 100 | * @return boolean 101 | */ 102 | public function check_file_data() { 103 | 104 | // If the constant isn't set, return false right away. 105 | if ( ! $this->has_debug_constant() ) { 106 | return false; 107 | } 108 | 109 | // Set my path file. 110 | $pfile = WP_CONTENT_DIR . '/debug.log'; 111 | 112 | // If no file exists at all, create an empty one. 113 | if ( false === file_exists( $pfile ) ) { 114 | file_put_contents( $pfile, '' ); 115 | } 116 | 117 | // If the file is empty, return that. 118 | return 0 === filesize( $pfile ) ? false : true; 119 | } 120 | 121 | /** 122 | * Handle our debug file actions based on query strings. 123 | * 124 | * @return HTML 125 | */ 126 | public function process_debug_type() { 127 | 128 | // Bail if current user doesnt have cap. 129 | if ( ! current_user_can( 'manage_options' ) ) { 130 | return; 131 | } 132 | 133 | // Bail without the query strings or not on admin. 134 | if ( ! is_admin() || empty( $_GET['quicklook'] ) || empty( $_GET['quickaction'] ) ) { 135 | return; 136 | } 137 | 138 | // Bail if we didn't pass the correct action type. 139 | if ( ! in_array( sanitize_key( $_GET['quickaction'] ), array( 'view', 'purge' ) ) ) { 140 | return; 141 | } 142 | 143 | // Create some basic CSS. 144 | $style = ' 145 | p.returnlink { text-align: center; font-size: 14px; line-height: 22px; } 146 | p.nofile { text-align: center; font-size: 14px; line-height: 22px; font-style: italic; } 147 | p.codeblock { background-color: #fff; color: #000; font-size: 14px; line-height: 22px; padding: 5px 15px; } 148 | p.codeblock .empty-space { display: block; width: 100%; height: 0; margin: 10px 0 -10px; padding: 0; border-top: 1px dotted #ccc; } 149 | p strong { font-weight: bold; } p em { font-style: italic; } 150 | code, pre { white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; } 151 | code pre, span.prewrap { color: #ff0000; } 152 | '; 153 | 154 | // Filter it. 155 | $style = apply_filters( 'debug_quick_look_css', $style ); 156 | 157 | // Set my empty. 158 | $build = ''; 159 | 160 | // Include a "back to admin" link. 161 | $build .= '
' . esc_html__( 'Return To Admin Dashboard', 'debug-quick-look' ) . '
'; 162 | 163 | // Check to make sure we have a file. 164 | if ( ! $this->check_file_data() ) { 165 | $build .= '' . esc_html__( 'Your debug file is empty.', 'debug-quick-look' ) . '
'; 166 | 167 | // We have a file. So start the additional checks. 168 | } else { 169 | 170 | // Set our file. 171 | $file = WP_CONTENT_DIR . '/debug.log'; 172 | 173 | // We requested a viewing. 174 | if ( 'view' === sanitize_key( $_GET['quickaction'] ) ) { 175 | $build .= $this->view_log( $file ); 176 | } 177 | 178 | // We requested a purging. 179 | if ( 'purge' === sanitize_key( $_GET['quickaction'] ) ) { 180 | $build .= $this->purge_log( $file ); 181 | } 182 | } 183 | 184 | // If we have CSS values, echo them. 185 | if ( ! empty( $style ) ) { 186 | echo ''; 187 | } 188 | 189 | // Echo out the build. 190 | echo wp_kses_post( $build ); 191 | 192 | // And die. 193 | die(); 194 | } 195 | 196 | /** 197 | * Our abstracted function for viewing the log file. 198 | * 199 | * @param string $file The filepath we are working with. 200 | * 201 | * @return string 202 | */ 203 | public function view_log( $file = '' ) { 204 | 205 | // Parse out the data. 206 | $data = $this->parse_log( $file ); 207 | 208 | // Trim and break it up. 209 | $data = nl2br( trim( $data ) ); 210 | 211 | // Now convert the line break markup to an empty div. 212 | $data = str_replace( array( '', '' ), array( '', '' ), $data ); 216 | 217 | // Generate and return the actual output. 218 | return '
' . $data . '
' . esc_html__( 'The log file has been purged.', 'debug-quick-look' ) . '
'; 235 | } 236 | 237 | /** 238 | * Parse my log file from the end in case it's too big. 239 | * 240 | * @link http://stackoverflow.com/questions/6451232/php-reading-large-files-from-end/6451391#6451391 241 | * 242 | * @param string $file The filepath we are working with. 243 | * @param integer $count Our line count that we're working with. 244 | * @param integer $size How many bytes we safely wanna check. 245 | * 246 | * @return string 247 | */ 248 | public function parse_log( $file = '', $count = 100, $size = 512 ) { 249 | 250 | // Set my empty. 251 | $lines = array(); 252 | 253 | // We will always have a fragment of a non-complete line, so keep this in here till we have our next entire line. 254 | $left = ''; 255 | 256 | // Open our file. 257 | $readf = fopen( $file, 'r' ); 258 | 259 | // Go to the end of the file. 260 | fseek( $readf, 0, SEEK_END ); 261 | 262 | do { 263 | 264 | // Confirm we can actually go back $size bytes 265 | $check = $size; 266 | 267 | if ( ftell( $readf ) <= $size ) { 268 | $check = ftell( $readf ); 269 | } 270 | 271 | // Bail on an empty file. 272 | if ( empty( $check ) ) { 273 | break; 274 | } 275 | 276 | // Go back as many bytes as we can and read them to $data, 277 | // and then move the file pointer back to where we were. 278 | fseek( $readf, - $check, SEEK_CUR ); 279 | 280 | // Set the data. 281 | $data = fread( $readf, $check ); 282 | 283 | // Include the "leftovers". 284 | $data .= $left; 285 | 286 | // Seek back into it. 287 | fseek( $readf, - $check, SEEK_CUR ); 288 | 289 | // Split lines by \n. Then reverse them, now the last line is most likely 290 | // not a complete line which is why we do not directly add it, but 291 | // append it to the data read the next time. 292 | $split = array_reverse( explode( "\n", $data ) ); 293 | $newls = array_slice( $split, 0, - 1 ); 294 | $lines = array_merge( $lines, $newls ); 295 | $left = $split[ count( $split ) - 1 ]; 296 | 297 | } while ( count( $lines ) < $count && ftell( $readf ) != 0 ); 298 | 299 | // Check and add the extra line. 300 | if ( ftell( $readf ) == 0 ) { 301 | $lines[] = $left; 302 | } 303 | 304 | // Close the file we just dealt with. 305 | fclose( $readf ); 306 | 307 | // Usually, we will read too many lines, correct that here. 308 | $array = array_slice( $lines, 0, $count ); 309 | $array = array_reverse( array_filter( $array, 'strlen' ) ); 310 | 311 | // Convert my array to a large string. 312 | return implode( "\n", $array ); 313 | } 314 | 315 | /** 316 | * Add the links for the debug log file. 317 | * 318 | * @param WP_Admin_Bar $wp_admin_bar The global WP_Admin_Bar object. 319 | * 320 | * @return void. 321 | */ 322 | public function admin_bar_links( WP_Admin_Bar $wp_admin_bar ) { 323 | 324 | // Bail if current user doesnt have cap. 325 | if ( ! current_user_can( 'manage_options' ) ) { 326 | return; 327 | } 328 | 329 | // Add a parent item. 330 | $wp_admin_bar->add_node( 331 | array( 332 | 'id' => 'debug-quick-look', 333 | 'title' => __( 'Debug Quick Look', 'debug-quick-look' ), 334 | ) 335 | ); 336 | 337 | // Load the two links if we have the logging constant defined. 338 | if ( $this->has_debug_constant() ) { 339 | 340 | // Make my links. 341 | $view = add_query_arg( array( 'quicklook' => 1, 'quickaction' => 'view' ), admin_url( '/' ) ); 342 | $purge = add_query_arg( array( 'quicklook' => 1, 'quickaction' => 'purge' ), admin_url( '/' ) ); 343 | 344 | // Add the "view" link. 345 | $wp_admin_bar->add_node( 346 | array( 347 | 'id' => 'quick-look-view', 348 | 'title' => __( 'View Log', 'debug-quick-look' ), 349 | 'href' => esc_url( $view ), 350 | 'position' => 0, 351 | 'parent' => 'debug-quick-look', 352 | 'meta' => array( 353 | 'title' => __( 'View Log', 'debug-quick-look' ), 354 | 'target' => '_blank', 355 | ), 356 | ) 357 | ); 358 | 359 | // Add the "purge" link. 360 | $wp_admin_bar->add_node( 361 | array( 362 | 'id' => 'quick-look-purge', 363 | 'title' => __( 'Purge Log', 'debug-quick-look' ), 364 | 'href' => esc_url( $purge ), 365 | 'position' => 0, 366 | 'parent' => 'debug-quick-look', 367 | 'meta' => array( 368 | 'title' => __( 'Purge Log', 'debug-quick-look' ), 369 | 'target' => '_blank', 370 | ), 371 | ) 372 | ); 373 | 374 | // Load a warning message if we haven't defined it. 375 | } else { 376 | 377 | // Add the text node with our warning. 378 | $wp_admin_bar->add_node( 379 | array( 380 | 'id' => 'quick-look-error', 381 | 'title' => __( 'The WP_DEBUG_LOG constant is not defined!', 'debug-quick-look' ), 382 | 'position' => 0, 383 | 'parent' => 'debug-quick-look', 384 | 'meta' => array( 385 | 'class' => 'debug-quick-look-missing', 386 | ), 387 | ) 388 | ); 389 | } 390 | } 391 | 392 | // End our class. 393 | } 394 | 395 | // Call our class. 396 | $DebugQuickLook = new DebugQuickLook(); 397 | $DebugQuickLook->init(); 398 | --------------------------------------------------------------------------------