Skip to content
A PHP API for logging debug messages
PHP HTML CSS
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
test
CONFIG.md
README.md
debug.ini
debug.php
debug_cfg.php
debug_config.php
debug_simple.php
debug_test.php
index.html
index.php
style.css

README.md

A Small yet Versatile Debug API for PHP Programs

  "Debugging software is not exactly a fun job for developers. The most 
widely used debugger for PHP still seems to be a var_dump() statement, 
possibly in conjunction with die() to halt program execution at a certain 
point.
  "While there is nothing wrong using var_dump() statements in itself, you 
still need to change the program code to debug a PHP script. And worse, after 
you have finished debugging, you must remove all var_dump() statements again 
(well you should, at least). It may well be that a few days later you'll find 
yourself adding the very same var_dump() statements to your code again 
because you need to go hunting another bug.
  "Of course, you could just comment out the var_dump() statements, but that 
looks really ugly in the code. Another option would be to wrap the var_dump() 
in conditional clauses, and only execute them when, say, a constant DEBUG is 
defined. This affects performance, because even if the var_dump() statements 
are not executed, the conditional clause must be executed. And besides, it 
looks even uglier in the code."
  -- Zend Developer Zone

A Modest Proposal

This presents some debug code as a way to have all the benefits of var_dump() statements as Zend Developer Zone says, but without any of the drawbacks they outline. This debug code creates no global data (with one optional exception explained below). It is an API and not a Class.

Instead of var_dump() you use debug() which works similarly, but with a few major exceptions. The displayed data:

  • Can be turned off (the default).
  • Can be displayed at program termination (the default).
  • Can be displayed in HTML comments.
  • Can be displayed as a single string in a DIV.
  • Can be formatted in a variety of ways.
  • Displays call stack (file/line/function) with each message.

The result is a list of diagnostic data displayed unobtrusively and under control, providing a complete runtime view of the code being debugged.

This is a single file API and not a Class.

Code Status

Latest version is 2.3.3. See Change Log. (December, 2018.)

This code has grown really large and complex - over 900 lines and 26 functions. It is a very sloppy in places and needs a near complete re-write.

See Go debug and Perl debug for smaller implementations.

Also note that these APIs are meant to be modified and customized by users and used for development only and not for including in a distribution
(though one can).

Code Setup

There is really only one function, with the basic way to use the code is to include the API, debug.php, and to strategically place debug() calls throughout your code.

include 'debug.php';
debug("message in diagnostic output");

If you do just that, nothing will happen and any performance hit should be very small.

Most of the debug API is controlled by defines, prefixed by DEBUG_. This provides a way to control the debug API during inclusion.

To enable debug output, define DEBUG_LOG:

define('DEBUG_LOG',1);
include 'debug.php';
debug("message in diagnostic output");

When the code terminates, the final output (to STDERR if in a terminal) will be like:

message log:
(index.php,20,-) message in diagnostic output

I use the term "message" or "diagnostic" to refer to what debug() logs, but the output depends on it's type. See The Output.

There is a "control function" to enable, disable or adjust the output during run-time.

The test program covers almost all options and output variations and should be used before installing the API: http://localhost/debug/index.php.

The Functions

The diagnostic function is:

  • debug($msg [,$arg])

And it produces all the debugging diagnostics based on $msg, with the second argument changing how the $msg diagnostic is displayed.

All PHP variable types are displayed in a meaningful way.

The second argument changes the format of the diagnostic explained later.

The log control function is:

  • debuglog($log)

Which sets the debug logging value. It can be called a second time to turn logging off (or to change the type of output).

With no arguments the debug log value is returned.

For all configuration defines and debug function options see CONFIG.md.

The Output

Here is example output from the test program:

message log:
(index.php,25,-) Debug v2.3.3
(index.php,105,-)(index.php,167,test) type tests:
(index.php,105,-)(index.php,169,test) (true)
(index.php,105,-)(index.php,169,test) (false)
(index.php,105,-)(index.php,169,test) (null)
(index.php,105,-)(index.php,169,test) (empty)
(index.php,105,-)(index.php,169,test) array ( 0 => 'a', 1 => 'b', 2 => 'c',)
(index.php,171,test)(test/test.php,4,filetest) filetest
(index.php,172,test)(index.php,194,objtest) Object DateTime
(index.php,172,test)(index.php,195,objtest) object(DateTime)#1 (3) { ["date"]=> string(26) ... } 
(index.php,180,test)(-,-,is_string) Error: is_string() expects exactly 1 parameter, 0 given

The last shows how the API's PHP error handler can capture and place PHP error messages into the output. The "objtest" messages show the two levels of detail that can be used to display an object (the 2nd one truncated for clarity).

The following list is how debug() displays it's first argument by default:

type          output

string        "$msg"
NULL          "(null)"
TRUE          "(true)"
FALSE         "(false)"
empty string  "(empty)"
array()       "array()"
array         "array ( ... )"
object        "Object ".get_class($msg)
resource      "Resource ".get_resource_type($msg)

See CONFIG.md for ways to change the output.

Data Dumps

In addition to debug messages, data can be displayed as well. The data can be internal PHP data such as $_SERVER or $_POST or user constants.

The function:

  • debugdump($dump [, $data])

Will append any data to the output, where $dump is a constant indicating what PHP data to display.

The $data option is a space delimited string for global variables or functions that return data.

See CONFIG.md for more information.

Output Interference

If debugging is enabled and there is a redirect of some kind, the diagnostic output may interfere. In those cases logging should be turned off.

    header("Location: $url");
    debuglog(0);
    exit;
    header('Content-Type: text/plain');
    header('Content-Length: '.strlen($data));
    header('Content-Disposition: attachment; filename="'.$file.'"');
    echo($data);
    debuglog(0);
    exit;

Output Modification

When there is no redirect and the output is HTML – like for an error message – and one wants to see the output clean, one can do something like:

    header("HTTP/1.1 404 Not Found");
    readfile("404.html");
    debuglog(DBG_HTML_COMMENT);
    exit;

The debug log is there to be seen by viewing the source.

Test Code

There is a browser based test program, index.php, and it's use should be self-explanatory. It lets one see some real-time output with the ability to change most options via the URL.

It's equivalent for running in a terminal is debug_test.php.

The State of the Code

This code is badly in need of a re-write. Though it's basic design is very simple – log diagnostic messages with format depending on variable type and short call trace to be displayed at termination – it grew, of course, in an evolutionary manner.

The code has the following problems:

  • The brace style is poor.
  • A few functions are not useful.
  • Some parts of it have not been fully tested.
  • There are perhaps too many ways to configure it.
  • The way the code intertwines HTML vs. terminal is terrible.
  • and more

A few recommended changes are:

  1. Remove the useless functions.
  2. Add some code for command line options.
  3. Split debug() into two parts, moving the "format" portion to a seperate function.
  4. Split the API into one for HTML and one for terminal; though it might mean duplicate code.
  5. Allow for simpler user extension/customization of the debug(), debug_datadump() and debug_msgs() functions.
  6. All while making the code smaller and just one file.

Working with Other Code

All constants used are prefixed with DEBUG_ or DBG_ and all functions with debug (with the exception of the internally used function _debug()). Only one global is defined and only under a specific condition.

Oops... There are some DMUP_ prefixed constants that need to be changed...

The following programs have been tested:

  • WordPress - no conflicts.
  • SilverScript - no conflicts.
  • Joomla - no conflicts.
  • Drupal - it has a function named debug(), this code works with it by renaming this API's function.

Drupal also, during it's install process, makes an Ajax call to itself and any debug output with that will corrupt the expected data. (See Output Interference.)

(More here later.)

Debugging WordPress

The code can be used with WordPress but there are three caveats.

First, including the API and enabling debugging in wp-config.php (the recommended file for making customizations) means that many of WordPress' files cannot be debugged as they are loaded before wp-config.php. For temporary debugging, placing code like:

    include 'debug.php';
    debuglog(1);
    debugdump(1,'wp_smiliessearch wpsmiliestrans');

at the top of the file containing the code to debug works fine.

When debugging a function that is called many times, like wptexturize(), place the debug start code at the top of the file (formatting.php) and use something like this:

    static $debug = 0;
    if ($debug == 0) {
        debug($static_characters);
        debug($static_replacements);
        $debug = 1;
    }

(If you do that you may see a flaw in the data.)

Second, I think the test for being logged in as an administrator is is_super_admin(), but I have not tried that. (Including this debug code in your WordPress website might be too much work, but using it temporarily on a local setup works fine.)

Third, with the default output the diagnostics are displayed in a DIV after all other HTML, and with some themes it can mess up the display. (Viewing the page source works in that case or the DEBUG_OPEN define can be modified to suit.)

Change Log

Version 2.3.3

debug.php

  • where "Document Root" is is a little better
  • updated how DEBUG_TIMESTAMP works (see CONFIG.md)
  • added debug() option ".time"

Version 2.3.2

debug.php

  • added option to use debug_config.php

debug_config.php

  • finally finished and tested

Version 2.3.1

debug.php

  • fixed potential infinite loop in exception handler
  • fixed "dump data" to be STDERR in terminal mode
  • made code reductions in setup functions, error handlers, output
  • added color and formatting for exceptions
  • removed a few hard-coded call trace calls
  • removed ANSI escape strings (with "\e") from global data
  • changed debug_exit() to display context data

debug_test.php, index.php

  • added more tests, outputs

Known Bugs

With debug log value of DBG_HTML (diagnostics in HTML comments) the output of the error handler at not fully within them.

Version 2.3.0

debug.php

  • major rewrite
  • many more comments

Version 2.2.7

debug.php

  • Fixed data dumps to properly be within HTML comments if that option used.
  • Several minor enhancements.

Version 2.2.6

debug.php

  • Fixed error handler to not display HTML in a terminal.
  • Removed the error handler "call stack" kludge and reduced it's complexity.

Version 2.2.5

debug.php

  • Fixed error handler to display "call stack" correctly.
  • Fixed debuglog() to be able to set error handler only.
  • Fixed possible "Use of undefined constant DEBUG_TIMESTAMP" notice.
  • Fixed lack of comments for error handler messages and data if log value is DBG_HTML_COMMENT.
  • Added "debug level" feature.
  • Added color to PHP notices and warnings (for HTML).
  • Improved debug_config() and added DEBUG_INI define.
  • Removed DEBUG_SHOW... feature (which was undocumented)

Version 2.2.4

debug.php

  • Fixed (for real this time) terminal detection test from testing for $argv to $argv[0].
  • Fixed an "off by one" error in debug_calls().
  • Fixed diagnostic messages to not convert HTML entities if outputting within HTML comments.
  • Changed debug_basename() to check for file paths outside of the working directory.
  • Changed debug_error_handler() to either echo or log warnings and notices.

Version 2.2.3

debug.php

  • Fixed possible "invalid index" error in function debug().
  • Fixed terminal detection test from testing for $argv to $argv[0].
  • Changed define DEBUG_FUNC to DEBUG_FUNC_HOOK.
  • Changed all debug() "meta format" arguments from _text to .text.
  • Added ability to set startup argument to debugdump() via define DEBUG_DUMP_DATA.
  • Added function debuglog() to support argument of -1.

debug_simple.php

  • Applicable changes to debug.php.
  • Added defines for all inline function/global strings.
  • Added register function debug_dumps().

index.php

  • Updated to for some of the new changes.
  • Added more test options.

debug_config.php

This file was added as an example. With a slight modification of the code, it can be included before or by the main file to customize the operation.

--

oldest change log removed with each new release

You can’t perform that action at this time.