<?php
/// used for basic debuging
/** For people besides me, things don't always go perfectly. As such, this class is exclusively for you. Measure things. Find new and unexpected features. Explore the error messages*/
class Debug{
/// measurements on time and memory
static $measures;
static $out;
///allows for the decision to throw or trigger error based on the config
/**
@param error error string
@param throw whether to throw the error (true) or trigger it (false)
@param type either level of the error or the exception class to use
*/
static function throwError($error,$throw=null,$type=null){
$throw = $throw === null ? Config::$x['throwErrors'] : $throw;
if($throw){
$type = $type ? $type : 'Exception';
throw new $type($error);
}
$type = $type ? $type : E_USER_ERROR;
trigger_error($error, $type);
}
///Take a measure
/** Allows you to time things and get memory usage
@param name the name of the measure to be printed out with results. To get the timing between events, the name should be the same.
*/
static function measure($name='std'){
$next = count(self::$measures[$name]);
self::$measures[$name][$next]['time'] = microtime(true);
self::$measures[$name][$next]['mem'] = memory_get_usage();
self::$measures[$name][$next]['peakMem'] = memory_get_peak_usage();
}
///get the measurement results
/**
@param type the way in which to print out results if any. options are "html" and "console"
@return returns an array with results
*/
static function measureResults($type='html'){
foreach(self::$measures as $name=>$measure){
$totalTime = 0;
while(($instance = current($measure)) && next($measure)){
$nextInstance = current($measure);
if($nextInstance){
$currentCount = count($out[$name]);
$totalTime += $nextInstance['time'] - $instance['time'];
$out[$name][$currentCount]['timeChange'] = $nextInstance['time'] - $instance['time'];
$out[$name][$currentCount]['memoryChange'] = $nextInstance['mem'] - $instance['mem'];
$out[$name][$currentCount]['peakMemoryChange'] = $nextInstance['peakMem'] - $instance['peakMem'];
$out[$name][$currentCount]['peakMemoryLevel'] = $instance['peakMem'];
}
}
$out[$name]['total']['time'] = $totalTime;
}
if($type == 'html'){
echo '<pre>'.print_r($out,true).'</pre>';
}elseif($type == 'console'){
echo "\n";
print_r($out);
echo "\n";
}
return $out;
}
///put variable into the log file for review
/** Sometimes printing out the value of a variable to the screen isn't and option. As such, this function can be useful.
@param var variable to print out to file
@param title title to use in addition to other context information
*/
static function toLog($var,$title='Titleless'){
$fh = fopen(Config::$x['logLocation'],'a+');
$bTrace = debug_backtrace();
$details = '('.$bTrace[0]['line'].') '.preg_replace('@'.$_SERVER['DOCUMENT_ROOT'].'@','',$bTrace[0]['file']);
fwrite($fh,"\n--------(".Config::$x['instanceName'].", ".$title.', '.date("Y-m-d H:i:s").") TO FILE ".$details."--------\n".var_export($var,1)."\n");
}
///get a line from a file
/**
@param file file path
@param line line number
*/
static function getLine($file,$line){
if($file){
$f = file($file);
$code = substr($f[$line-1],0,-1);
return preg_replace('@^\s*@','',$code);
}
}
///print a boatload of information to the load so that even your grandma could fix that bug
/**
@param eLevel error level
@param eStr error string
@param eFile error file
@param eLine error line
*/
static function handleError($eLevel,$eStr,$eFile,$eLine){
if(ini_get('error_reporting') == 0){# @ Error control operator used
return;
}
$code = self::getLine($eFile,$eLine);
$eFile = preg_replace('@'.PU.'@','',$eFile);
$eFile = preg_replace('@'.PR.'@','',$eFile);
$err = "\n\n=====================================================================\n";
$err .= "--------(".INSTANCE.") ERROR ".$eLevel.' ('.date("Y-m-d H:i:s").")--------\n=== $eStr ===\n";
$err .= "=====================================================================\n";
$bTrace = debug_backtrace();
if($bTrace[0]['function'] == 'handleError' && $bTrace[0]['class'].$bTrace[0]['type'] == __class__.'::'){
array_shift($bTrace);
}
if(!$bTrace[0]['class'] && $bTrace[0]['function'] == 'trigger_error'){
array_shift($bTrace);
}
foreach($bTrace as $v){
$err .= "\n".'(-'.$v['line'].'-) '.preg_replace(array('@'.PU.'@','@'.PR.'@'),'',$v['file'])."\n";
$code = self::getLine($v['file'],$v['line']);
if($v['class']){
$err .= "\t".'Class: '.$v['class'].$v['type']."\n";
}
$err .= "\t".'Function: '.$v['function']."\n";
if($code){
$err .= "\t".'Line: '.$code."\n";
}
if($v['args']){
$err .= "\t".'Arguments: '."\n";
ob_start();
var_export($v['args']);
$err .= preg_replace(
array("@^array \(\n@","@\n\)$@","@\n@"),
array("\t\t",'',"\n\t\t"),
ob_get_clean())."\n";
}
}
$err.= "\nServer Var:\n:".var_export($_SERVER,1);
$err.= "\nRequest-----\nUri:".$_SERVER['REQUEST_URI']."\nVar:".var_export($_REQUEST,1);
$err.= "\n\nFile includes:\n".var_export(Files::getIncluded(),1);
$file = Config::$x['logLocation'];
if(!file_exists($file) || filesize($file)>Tool::byteSize(Config::$x['maxLogSize'])){
$mode = 'w';
}else{
$mode = 'a+';
}
$fh = fopen($file,$mode);
fwrite($fh,$err);
if(Config::$x['errorPage']){
Config::loadUserFiles(Config::$x['errorPage']);
}elseif(Config::$x['errorMessage']){
if(is_array(Config::$x['errorMessage'])){
$message = Config::$x['errorMessage'][rand(0,count(Config::$x['errorMessage'])-1)];
}else{
$message = Config::$x['errorMessage'];
}
echo $message;
}
exit;
}
///print a variable and kill the script
/** first cleans the output buffer in case there was one. Echo in <pre> tag
@param var any type of var that var_export prints
*/
function print_d($var=null){
$content=ob_get_clean();
if($var){
$content .= "\n".var_export($var,1);
}
die('<pre>'.$content.'</pre>');
}
///print a variable with file and line context, along with count
/**
@param var any type of var that print_r prints
*/
function out($var){
$trace = debug_backtrace();
$file = array_pop(explode('/',$trace[0]['file']));
self::$out['i']++;
echo "\n<br/>[".$file.','.$trace[0]['line']."] ".self::$out['i'].": ".print_r($var,true)."</br>\n";
}
}