FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Home  »  WordPress  »  AskApache Debug Viewer Plugin for WordPress

by 1 comment

Screen Shots | PHP Debug Functions

AskApache Debug Viewer Plugin for WordPressThe story behind this plugin is sorta wack, but in a good way :). While doing tons of security research on permissions, authorization, access, etc.. for the Password Protection plugin (still being worked on), I needed to have unheard of debugging capabilities while working on the plugin on the various websites, webhosts, and test servers that I use to test in different environments. So I hacked together a bunch of php code that helped me debug, actually I pretty much went overkill and tried to get as much debugging info as programmatically possible, and it ended up being so much code that I took it out of my Password Protection code and made it its own plugin.

I've been using it for several months now while working on a plugin or diagnosing some issue, and decided that I'd share it with everyone. Hopefully it will help other plugin authors and php programmers in general to start writing more robust and error-proof code, which would in turn help me! To help those not using WordPress, I've included most of the debugging functions below, but you'll need the AskApacheDebug class for them to work. Hope you find it useful! I do. Download AskApache Debug Viewer



Screenshots and Debug Output

The plugin outputs the debugging info in the admin footer by hooking into the 'in_admin_footer' action.
AskApache Debug Viewer Plugin for WordPress

AskApache Debug Viewer Plugin for WordPressAskApache Debug Viewer Plugin for WordPress

AskApache Debug Viewer Plugin for WordPressAskApache Debug Viewer Plugin for WordPress

AskApache Debug Viewer Plugin for WordPressAskApache Debug Viewer Plugin for WordPress

AskApache Debug Viewer Plugin for WordPressAskApache Debug Viewer Plugin for WordPress

PHP Debugging Functions

Ok so for those interested more in the php flavor, here are a few of the functions that produce the debugging output. I'll start with my customized _stat function, which took a lot of research to write, but you can read that story at Chmod, Umask, Stat, Fileperms, and File Permissions.

function _stat($fl)
{
  static $ftypes = false;
  if (!$ftypes)
  {
    $this->logg(__FUNCTION__ . ':' . __LINE__);
    $ftypes = array(S_IFSOCK => 'ssocket', S_IFLNK => 'llink', S_IFREG => '-file', S_IFBLK => 'bblock', S_IFDIR => 'ddir', S_IFCHR => 'cchar', S_IFIFO => 'pfifo');
  }
 
  $s = $ss = array();
  if (($ss = stat($fl)) === false) return $this->logg(__FUNCTION__ . ':' . __LINE__ . " Couldnt stat {$fl}", 0);
  $p = $ss['mode'];
  $t = decoct($p & S_IFMT);
  $q = octdec($t);
  $type = (array_key_exists($q, $ftypes)) ? substr($ftypes[$q], 0, 1) : '?';
$s = array(
'filename' => $fl,
 
'human' => ($type .
(($p & S_IRUSR) ? 'r' : '-') . (($p & S_IWUSR) ? 'w' : '-') . (($p & S_ISUID) ? (($p & S_IXUSR) ? 's' : 'S') : (($p & S_IXUSR) ? 'x' : '-')) .
(($p & S_IRGRP) ? 'r' : '-') . (($p & S_IWGRP) ? 'w' : '-') . (($p & S_ISGID) ? (($p & S_IXGRP) ? 's' : 'S') : (($p & S_IXGRP) ? 'x' : '-')) .
(($p & S_IROTH) ? 'r' : '-') . (($p & S_IWOTH) ? 'w' : '-') . (($p & S_ISVTX) ? (($p & S_IXOTH) ? 't' : 'T') : (($p & S_IXOTH) ? 'x' : '-'))),
'octal' => sprintf("%o", ($ss['mode'] & 007777)),
'hex' => sprintf("0x%x", $ss['mode']),
'decimal' => sprintf("%d", $ss['mode']),
'binary' => sprintf("%b", $ss['mode']),
'base_convert' => base_convert($ss['mode'],10,8),
'fileperms' => fileperms($fl),
'mode' => $p,
 
'type_octal' => sprintf("%07o", $q),  'fileuid' => $ss['uid'],
 
'type' => $type,
'filegid' => $ss['gid'],
'owner_name' => $this->get_posix_info('user', $ss['uid'],
'name'),
'group_name' => $this->get_posix_info('group', $ss['gid'],
'name'),
'dirname' => dirname($fl),
'is_file' => is_file($fl) ? 1 : 0,
'is_dir' => is_dir($fl) ? 1 : 0,
'is_link' => is_link($fl) ? 1 : 0,
'is_readable' => is_readable($fl) ? 1 : 0,
'is_writable' =>
is_writable($fl) ? 1 : 0,'device' => $ss['dev'],
'device_number' => $ss['rdev'],
'inode' => $ss['ino'],
'link_count' => $ss['nlink'],
'size' => $ss['size'],
'blocks' => $ss['blocks'],
'block_size' => $ss['blksize'],
'accessed' => date('Y M D H:i:s', $ss['atime']),
'modified' => date('Y M D H:i:s', $ss['mtime']),
'created' => date('Y M D H:i:s', $ss['ctime']),
'mtime' => $ss['mtime'], 'atime' => $ss['atime'],
'ctime' => $ss['ctime'], );
  if (is_link($fl)) $s['link_to'] = readlink($fl);
  if (realpath($fl) != $fl) $s['real_filename'] = realpath($fl);
 
  return $s;
}

get_debug_functions

These are various security and user related information. Nice.

function get_debug_functions($vb=false)
{
  $functions=$oa=array();
  $functions = array(
'PHP script Process ID' => 'getmypid',
'PHP script owners UID' => 'getmyuid',
'php_sapi_name' => 'php_sapi_name',
'PHP Uname' => 'php_uname',
'Zend Version' => 'zend_version',
'PHP INI Loaded' => 'php_ini_loaded_file',
'Current Working Directory' => 'getcwd',
'Last Mod' => 'getlastmod',
'Script Inode' => 'getmyinode',
'Script GID' => 'getmygid',
'Script Owner' => 'get_current_user',
'Get Rusage' => 'getrusage',
'Error Reporting' => 'error_reporting',
'Path name of controlling terminal' => 'posix_ctermid',
'Error number set by the last posix function that failed' => 'posix_get_last_error',
'Pathname of current directory' => 'posix_getcwd',
'posix_getpid' => 'posix_getpid',
'posix_uname' => 'posix_uname',
'posix_times' =>'posix_times',
'posix_errno' => 'posix_errno',
'Effective group ID of the current process' => 'posix_getegid',
'Effective user ID of the current process' => 'posix_geteuid',
'Real group ID of the current process' => 'posix_getgid',
'Group set of the current process' => 'posix_getgroups',
'Login name' => 'posix_getlogin',
'Current process group identifier' => 'posix_getpgrp',
'Current process identifier' => 'posix_getpid',
'Parent process identifier' => 'posix_getppid',
'System Resource limits' => 'posix_getrlimit',
'Return the real user ID of the current process' => 'posix_getuid',
'Magic Quotes GPC' => 'get_magic_quotes_gpc',
'Magic Quotes Runtime' => 'get_magic_quotes_runtime', );
 
  foreach ($functions as $title => $func_name) {
    $val = '';
    if ( ( $this->checkfunction($func_name) && ($val = $func_name()) !== false) ){
      if (empty($val)) $val=$func_name;
      $oa[$title] = $val;
    }
  }
 
  return $oa;
}

get_debug_permissions

This is a function designed to get as much information about file/user/group permissions as possible.

function get_debug_permissions($vb=false)
{
  $oa=array();
 
  $user_info = $this->get_posix_info('user');
  $group_info = $this->get_posix_info('group');
 
$functions = array(
'Real Group ID' => posix_getgid(),
'Effective Group ID' => posix_getegid(),
'Parent Process ID' => posix_getppid(),
'Parent Process Group ID' => posix_getpgid(posix_getppid()),
'Real Process ID' => posix_getpid(),
'Real Process Group ID' => posix_getpgid(posix_getpid()),
'Process Effective User ID' => posix_geteuid(),
'Process Owner Username' => $user_info['name'],
'File Owner Username' => get_current_user(),
'User Info' => print_r($user_info, 1),
'Group Info' => print_r($group_info, 1),
'RealPath'  => realpath(__FILE__),
'SAPI Name' => (function_exists('php_sapi_name')) ? print_r(php_sapi_name(), 1) : '',
'Posix Process Owner' => print_r(posix_getpwuid(posix_geteuid()), 1),
'Scanned Ini' => (function_exists('php_ini_scanned_files')) ? str_replace("n", "", php_ini_scanned_files()) : '',
'PHP.ini Path' => get_cfg_var('cfg_file_path'),
'Sendmail Path' => get_cfg_var('sendmail_path'),
'Info about a group by group id' => posix_getgrgid(posix_getegid()),
'Process group id for Current process' => posix_getpgid(posix_getpid()),
'Process group id for Parent process' => posix_getpgid(posix_getppid()),
'Process group id of the session leader.' => posix_getsid(posix_getpid()),
'Info about a user by username' => posix_getpwnam(get_current_user()),
'Info about a user by user id' => posix_getpwuid(posix_geteuid()),
'Apache Version' => (function_exists('apache_get_version')) ? print_r(apache_get_version(), 1) : '',
'Apache Modules' => (function_exists('apache_get_modules')) ? print_r(apache_get_modules(), 1) : '',
'PHP_LOGO_GUI' => php_logo_guid(),
'ZEND_LOGO_GUI' => zend_logo_guid()
);
 
  foreach ($functions as $title => $v) $oa[$title] = $v;
 
  return $oa;
}

get_debug_defined

This gets all the defined constants, if verbose it gets more and gets the values for each.

function get_debug_defined($vb=false)
{
  $oa=array();
  foreach ((array)@get_defined_constants() as $k => $v){if (!$vb && in_array($k, array('ABSPATH', 'WP_ADMIN'))) $vb = true;  if($vb)$oa[$k]=$v;}
 
  foreach (
  array('WP_TEMP_DIR', 'WP_SITEURL', 'WP_HOME', 'ABSPATH', 'WP_CONTENT_URL',
  'WP_CONTENT_DIR', 'WP_PLUGIN_DIR', 'WP_PLUGIN_URL', 'WP_LANG_DIR', 'TEMPLATEPATH',
  'STYLESHEETPATH', 'WPINC', 'COOKIEPATH', 'SITECOOKIEPATH', 'ADMIN_COOKIE_PATH',
  'PLUGINS_COOKIE_PATH', 'PHP_SAPI', 'PHP_OS', 'PHP_VERSION'
  ) as $def) if (defined($def) && $val = constant($def) && !empty($val)) $oa[$def] = $val;
 
  return $oa;
}

get_debug_inis

This function gets the values of your php ini, if verbose it gets them all and shows the currently used value instead of both the global and local.

function get_debug_inis($vb=false)
{
  $oa=array();
 
  foreach (array('Error Log' => 'error_log',
'Session Data Path' => 'session.save_path',
'Upload Tmp Dir' => 'upload_tm_p_dir',
'Include Path' => 'include_path',
'Memory Limit' => 'memory_limit',
'Max Execution Time' => 'max_execution_time',
'Display Errors' => 'display_errors',
'Allow url fopen' => 'allow_url_fopen',
'Disabled Functions' => 'disable_functions',
'Safe Mode' => 'safe_mode',
'Open Basedir' => 'open_basedir',
'File Uploads' => 'file_uploads',
'Max Upload Filesize' => 'upload_max_filesize',
'Max POST Size' => 'post_max_size',
'Open Basedir' => 'open_basedir') as $title => $ini_name) if (($val = '' && $val = strval(ini_get($ini_name))) !== false && !empty($val)) $oa[$title] = $val;
 
  if($vb!==false){
    foreach ((array)@ini_get_all() as $k => $v) $oa[$k] = (($v['global_value'] == $v['local_value']) ? $v['global_value'] : $v);
  }
  return $oa;
}

get_debug_phpinfo

I'm particularly proud of this function because the preg_replace was tough and the result is a perfect array of values returned by the phpinfo command.

function get_debug_phpinfo()
{
  $oa=array();
  ob_start();
  phpinfo(-1);
  $oa = preg_replace(array('#^.*<body>(.*)</body>.*$#ms', '#<h2>PHP License</h2>.*$#ms', '#<h1>Configuration</h1>#', "#r?n#", "#</(h1|h2|h3|tr)>#", '# +<#', "#[ t]+#", '# #', '#  +#', '# class=".*?"#', '%'%', '#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>' . '<h1>PHP Version (.*?)</h1>(?:n+?)</td></tr>#',
    '#<h1><a href="(?:.*?)?=(.*?)">PHP Credits</a></h1>#', '#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#', "#  +#", '#<tr>#', '#</tr>#'), array('$1', '', '', '', '</$1>' . "n", '<', ' ', ' ', ' ', '', ' ', '<h2>PHP Configuration</h2>' . "n" . '<tr><td>PHP Version</td><td>$2</td></tr>' . "n" . '<tr><td>PHP Egg</td><td>$1</td></tr>',
    '<tr><td>PHP Credits Egg</td><td>$1</td></tr>', '<tr><td>Zend Engine</td><td>$2</td></tr>' . "n" . '<tr><td>Zend Egg</td><td>$1</td></tr>', ' ', '%S%', '%E%'), ob_get_clean());
  $sections = explode('<h2>', strip_tags($oa, '<h2><th><td>'));
  unset($sections[0]);
  $oa = array();
  foreach ($sections as $section)
  {
    $n = substr($section, 0, strpos($section, '</h2>'));
    preg_match_all('#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#', $section, $askapache, PREG_SET_ORDER);
    foreach ($askapache as $m) $oa[$n][$m[1]] = (!isset($m[3]) || $m[2] == $m[3]) ? $m[2] : array_slice($m, 2);
  }
  return $oa;
}

get_debug_included

Gets a list of all the files included by php, if verbose it also super-stats them.

function get_debug_included($vb=false)
{
  $oa=array();
  foreach((array)@get_included_files() as $k=>$v) $oa[$v]=($vb===false) ? '' : $this->_stat($v);
  return $oa;
}

get_debug_classes

Gets a list of predefined classes declared in your php instance, if verbose it gets EVERY class and also gets the methods for each.

function get_debug_classes($vb=false)
{
  $classes=$oa=array();
  $classes= ($vb!==false) ? (array)@get_declared_classes() : array('WP','WP_Error','Walker','WP_Ajax_Response','wpdb','WP_Object_Cache','WP_Query','WP_Rewrite','WP_Locale');
  foreach ($classes as $k)  $oa[$k] = @get_class_methods($k);
 
  return $oa;
}

get_debug_globals

This function tries to get the values of every known (past and present) global variable in php.

function get_debug_globals($vb=false)
{
  $oa=array();
 
  $globs =
  array(
  'GET'     => isset( $_GET )?$_GET:'',
  'POST'    => isset( $_POST )?$_POST:'',
  'COOKIE'  => isset( $_COOKIE )?$_COOKIE:'',
  'SESSION'   => isset( $_SESSION )?$_SESSION:'',
  'ENV'     => isset( $_ENV )?$_ENV:'',
  'FILES'     => isset( $_FILES )?$_FILES:'',
  'SERVER'  => isset( $_SERVER )?$_SERVER:'',
  'SERVER'  => isset( $_SERVER )?$_SERVER:'',
  'UPLOAD'  => function_exists('wp_upload_dir') ? wp_upload_dir():'',
  'REQUEST'   => isset( $_REQUEST )?$_REQUEST:'',
  'HTTP_POST_FILES'   => isset( $HTTP_POST_FILES )?$HTTP_POST_FILES:'',
  'HTTP_POST_VARS'    => isset( $HTTP_POST_VARS )?$HTTP_POST_VARS:'',
  'HTTP_SERVER_VARS'  =>  isset( $HTTP_SERVER_VARS )?$HTTP_SERVER_VARS:'',
  'HTTP_RAW_POST_DATA' => isset( $HTTP_RAW_POST_DATA )?$HTTP_RAW_POST_DATA:'',
  'HTTP_GET_VARS'     => isset( $HTTP_GET_VARS )?$HTTP_GET_VARS:'',
  'HTTP_COOKIE_VARS'  =>  isset( $HTTP_COOKIE_VARS )?$HTTP_COOKIE_VARS:'',
  'HTTP_ENV_VARS'     => isset( $HTTP_ENV_VARS )?$HTTP_ENV_VARS:'',
  );
  foreach ($globs as $k => $v) if (isset($v) && sizeof($v) > 0) $oa[$k] = $v;
 
  foreach (array_keys($_SERVER) as $k) if ($val = strval($_SERVER[$k]) && !empty($val)) $oa[(substr($k, 0, 5) == 'HTTP_' ? 'HTTP' : 'SERVER')][$k] = $_SERVER[$k];
 
  return $oa;
}

get_debug_loaded_extensions

Returns a list of all the loaded extensions in php. If verbose it also returns their functions!

function get_debug_loaded_extensions($vb=false)
{
  $oa=array();
  foreach((array)@get_loaded_extensions() as $k=>$v) $oa[$v]= ($vb===false) ? '' : (array)@get_extension_funcs($v);
  return $oa;
}

Tags

December 21st, 2012

Comments Welcome

  • baron

    Works great, thank you

Popular Articles
My Online Tools

Related Articles
Newest Posts
Twitter


  • @askapache · Jul 21
    Magic spells for sending thoughts across time? Books
  • @askapache · Jul 20
    TV is just a relic of the previous generation. We just don't know it yet.
  • @askapache · Jul 20
    I will never go back on my ideals, no matter the cost. I'll never let the economic vultures steal my dreams. I'd rather give up the ghost
  • @askapache · Jul 18
    I don't want a better seat, I want control of the engine
  • @askapache · Jul 14
    No matter how good u r, there will always be someone 2x, 5x, 100x better. This is true for me and everyone. No direction but forward.
  • @askapache · Jul 12
    Heads up, I'll DDoS the f out of askapache next week, to see how resilient it really is :) - will try to overflow disk, net, and ip stack
  • RUN GCC! This is a typical shirt I wear, from the  t.co/46LYbFr4k2  shop. A clerk at the LQ recognized it!  t.co/jjmT0dkCPu 
  • Merlin the Magician  t.co/iMmRbanUi4 
  • ROGUE CODE - Latest novel from @markrussinovich  t.co/apkn0LoPIt 
  • RTFM - surprisingly very helpful and way more comprehensive than it looks! @redteamfieldman #pwnAllTheThings  t.co/xiaJ5g0aC9 
  • Dear Hacker - Letters to the Editor of 2600, from Emmanuel Goldstein  t.co/JCfLab7FAJ 
  • The Mythical Man-Month - Essays on Software Engineering, by Frederick P. Brooks, Jr.  t.co/ilWN5GHElr 
  • "where wizards stay up late" - The Origins of the Internet. Favorite book detailing the birth of the net and IMPs  t.co/gY9VTGJgZz 
  • ZERO DAY - read before Trojan horse  t.co/pPMLGDJv8P 
  • Trojan Horse, a novel!  t.co/Hf8EtYaZVa 
  • The Hacker Playbook - very nice high level overview of attacks  t.co/lHwNVWi61u 
  • Clean Code - A Handbook of Agile Software Craftsmanship  t.co/hnJX0x1qIc 
  • Secrets of the JavaScript Ninja - By my absolute favorite JS hacker John Resig!  t.co/tZ42ljmcCl 
  • Hacking Exposed 7: Network Security Secrets & SolutionsMy all time favorite, basic but thorough and accurate.  t.co/jycW0RDVtZ 
  • Empty words will be no surrogate for cold resolve. Pain is nothing.  t.co/qXjpRxbjCw 

Hacking and Hackers

The use of "hacker" to mean "security breaker" is a confusion on the part of the mass media. We hackers refuse to recognize that meaning, and continue using the word to mean someone who loves to program, someone who enjoys playful cleverness, or the combination of the two. See my article, On Hacking.
-- Richard M. Stallman






[hide]

It's very simple - you read the protocol and write the code. -Bill Joy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License, just credit with a link.
This site is not supported or endorsed by The Apache Software Foundation (ASF). All software and documentation produced by The ASF is licensed. "Apache" is a trademark of The ASF. NCSA HTTPd.
UNIX ® is a registered Trademark of The Open Group. POSIX ® is a registered Trademark of The IEEE.

| Google+ | askapache

Site Map | Contact Webmaster | License and Disclaimer | Terms of Service

↑ TOPMain