Login   Register  
PHP Classes
elePHPant
Icontem

File: class/odebugger.cls.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Johan Barbier  >  PHP Debugger and Helper  >  class/odebugger.cls.php  >  Download  
File: class/odebugger.cls.php
Role: Class source
Content type: text/plain
Description: Debugger class
Class: PHP Debugger and Helper
Log errors and check PHP code
Author: By
Last change: Modifications on checkCode()
Date: 8 years ago
Size: 18,899 bytes
 

Contents

Class file image Download
<?php
/**
* CLASS odebugger
*
* @author : johan <barbier_johan@hotmail.com>
*/
class odebugger {

	/**
	* private (string) sAssertion
	* Check if error comes from an essertion or not, if yes, will conatin the filename of the evaluated script
	*/
	private $sAssertion = null;
	/**
	* private (string) sLang
	* localization string
	*/
	private $sLang = 'EN';

	/**
	* private (int) iNbLines
	* Number of lines displayed before and after the line of the error
	*/
	private $iNbLines = 2;

	/**
	* private (array) aOptions
	* Options array
	*/
	private $aOptions = array (
		'REALTIME' => true,
		'LOG_FILE' => true,
		'ERROR' => true,
		'EXCEPTION' => true
		);

	/**
	* private (string) sTemplateHTML
	* HTML template file for the realtime log
	*/
	private $sTemplateHTML = 'default';
	/**
	* private (string) sTemplateCSS
	* CSS template file for the realtime log
	*/
	private $sTemplateCSS = 'default';
	/**
	* private (string) sTemplateHTMLLOG
	* HTML template file for the whole log file
	*/
	private $sTemplateHTMLLOG = 'default_log';
	/**
	* private (string) sTemplateCSSLOG
	* CSS template file for the whole log file
	*/
	private $sTemplateCSSLOG = 'default_log';

	/**
	* private (string) sCurDir
	* Current directory of the script
	*/
	private $sCurDir = '';

	/**
	* private (string) sCurId
	* Current file unique id
	*/
	private $sCurId = '';

	/**
	* private (object) oXMLDOC
	* XML LOG Object (DOMDocument object)
	*/
	private $oXMLDOC = null;
	/**
	* private (object) oXMLROOT
	* XML LOG root Object (DOMDocument object)
	*/
	private $oXMLROOT = null;
	/**
	* private (object) oCurrentNode
	* Current node Object (DOMDocument object)
	*/
	private $oCurrentNode = null;

	/**
	* private (array) aCanBeSet
	* class properties that can be set via odebugger::__set()
	*/
	private $aCanBeSet = array (
		'LINES' => 'iNbLines',
		'REALTIME' => "aOptions['REALTIME']",
		'LOGFILE' => "aOptions['LOG_FILE']",
		'HTML' => 'sTemplateHTML',
		'CSS' => 'sTemplateCSS',
		'HTMLLOG' => 'sTemplateHTMLLOG',
		'CSSLOG' => 'sTemplateCSSLOG',
		'ERROR' => "aOptions['ERROR']",
		'EXCEPTION' => "aOptions['EXCEPTION']"
		);

	/**
	* private (object) oXMLTYPES
	* XML DOMDocument object with the list of error types and their translation
	*/
	private $oXMLTYPES = null;

	/**
	* private (object) oXMLERRORS
	* XML DOMDocument object with the list of errors and their translation
	*/
	private $oXMLERRORS = null;

	/**
	* private (array) aIndex
	* replacement array for the templates
	*/
	private $aIndex = array (
		0 => array (
			'{DATE_TITRE}',
			'{DATE_VALUE}'
			),
		1 => array (
			'{TYPE_TITRE}',
			'{TYPE_VALUE}'
			),
		2 => array (
			'{MSG_TITRE}',
			'{MSG_VALUE}'
			),
		3 => array (
			'{FILE_TITRE}',
			'{FILE_VALUE}'
			),
		4 => array (
			'{LINE_TITRE}',
			'{LINE_VALUE}'
			),
		5 => array (
			'{MEM_TITRE}',
			'{MEM_VALUE}'
			),
		6 => array (
			'{TRANS_TITRE}',
			'{TRANS_VALUE}'
			),
		7 => array (
			'{SUGG_TITRE}',
			'{SUGG_VALUE}'
			),
		8 => array (
			'{CONTEXT_TITRE}',
			'{CONTEXT_VALUE}'
			),
		9 => array (
			'{SOURCE_TITRE}',
			'{SOURCE_VALUE}'
			),
		100 => '{TOTAL_STATS}',
		101 => '{PHP_VERSION}'
		);

	/**
	* public function __construct ()
	* contsructor
	* sets the error_reporting to 0
	* gets the localization dir
	* import all the xml files
	* set the error handler
	* @Param (string) sLang : the localization used
	*/
	public function __construct ($sLang = 'EN') {
		@error_reporting (0);

		$aLnDir = scandir ('xml');
		if (in_array ($sLang, $aLnDir)) {
			$this -> sLang = $sLang;
		}
		$this -> oXMLERRORS = DOMDocument::load ('xml/'.$this -> sLang.'/errors.xml');
		$this -> oXMLTYPES = DOMDocument::load ('xml/'.$this -> sLang.'/types.xml');

		$this -> oXMLDOC = new DOMDocument ('1.0', 'utf-8');
		$root = $this -> oXMLDOC -> createElement ('ERRORLOG');
		$this -> oXMLROOT = $this -> oXMLDOC -> appendChild ($root);
		if (!is_dir ('logs')) {
			@mkdir ('logs', 0744);
		}
		$sTemp = dirname (__FILE__);
		$aTemp = explode ('\\', $sTemp);
		array_pop ($aTemp);
		$this -> sCurDir = implode ('/', $aTemp).'/';
		$this -> sCurId = date ('Ymd').'_'.uniqid();

		set_error_handler (array ($this, 'myErrorHandler'));
		set_exception_handler (array ($this, 'myExceptionHandler'));
	}

	/**
	* public function checkCode ()
	* use the assert () function to get the errors in a given string, or a given file
	* @Param (string) sString : the string with the PHP code to evaluate, or the file to evaluate. Usually, it will come from a file via file_get_contents () for example
	* @Return : false if given parameter is not a string.
	*/
	public function checkCode ($sCode) {
		if (file_exists ($sCode)) {
			$sString = file_get_contents ($sCode);
			$this -> sAssertion = $sCode;
		} elseif (!is_string ($sCode)) {
			return false;
		} else {
			$sString = $sCode;
		}
		$sString = str_replace (array ('<?php', '<?', '?>'), '', $sString);
		assert_options(ASSERT_ACTIVE, 1);
		assert_options(ASSERT_WARNING, 0);
		assert_options(ASSERT_QUIET_EVAL, 1);
		//assert_options (ASSERT_CALLBACK, array ($this, 'myAssertHandler')); Waiting a bit to improve this part
		assert ($sString);
		assert_options(ASSERT_ACTIVE, 0);
	}

	/**
	* public function myAssertHandler ()
	* activate the assertion. Right now, does nothing...and is not used.
	* @Param (string) file : the file from which comes the code
	* @Param (int) line : the error line
	* @Param (string) code : the error code
	* @Return : true
	*/
	public function myAssertHandler ($file, $line, $code){
		return true;
	}

	/**
	* private function checkErrorMessage ()
	* try to find the correct trsnalation and suggestion from a given error message
	* @Param (string) sMsg : the PHP error message
	* @Return (array) aTempArr : array with the translation and the suggestion found
	*/
	private function checkErrorMessage ($sMsg) {
		$iLength = strlen ($sMsg);
		$xpath = new DOMXPath($this -> oXMLERRORS);
		$sQueryLabel = '//error/label';
		$oLabelLists = $xpath -> query ($sQueryLabel);
		$aMsg = explode (' ', $sMsg);
		foreach ($oLabelLists as $oLabel) {
			$aLabel = explode (' ', $oLabel -> nodeValue);
			$aDiff = array_diff ($aLabel, $aMsg);
			if (empty ($aDiff)) {
				$aTempArr['TRANSLATION'] = $oLabel -> nextSibling -> nextSibling -> nodeValue;
				$aTempArr['SUGGESTION'] = $oLabel -> nextSibling -> nextSibling -> nextSibling -> nextSibling -> nodeValue;
				return $aTempArr;
			}
		}
	}

	/**
	* private function checkTypeTrans ()
	* try to find the error type translation
	* @Param (int) cErrno : the PHP constant error type code
	* @Return (string) nodeValue : the translated error type
	*/
	private function checkTypeTrans ($cErrno) {
		$xpath = new DOMXPath($this -> oXMLTYPES);
		$sQueryLevel = '//type/level';
		$oLevelList = $xpath -> query ($sQueryLevel);
		foreach ($oLevelList as $oLevel) {
			if (constant ($oLevel -> nodeValue) === $cErrno) {
				return $oLevel -> nextSibling -> nextSibling -> nodeValue;
			}
		}
	}

	/**
	* public function myExceptionHandler ()
	* the exception handler : builds the XML error log
	* @Param (object) e : the Exception object
	*/
	public function myExceptionHandler ($e) {
		$sErrStr = $e -> getMessage ();
		$iErrLine = $e -> getLine ();
		$sType = 'Exception '.$e -> getCode ();
		if (is_null ($this -> sAssertion)) {
			$sErrFile = $e -> getFile ();
		} else {
			$sErrFile = $this -> sAssertion;
			$this -> sAssertion = null;
		}
		$sVars = $e -> getTraceAsString ();
		$aTempArr = array ('TRANSLATION' => '', 'SUGGESTION' => '');

		$this -> buildLog ($sType, $sErrStr, $sErrFile, $iErrLine, $aTempArr, $sVars);
	}

	/**
	* public function myErrorHandler ()
	* the error handler : builds the XML error log
	* @Param (int) cErrno : the PHP constant error type code
	* @Param (string) sErrStr : the PHP error message
	* @Param (string) sErrFile : the file in which the error has been detected
	* @Param (int) iErrLine : the line of the error
	* @Param (array) mVars : the context
	*/
	public function myErrorHandler ($cErrno, $sErrStr, $sErrFile, $iErrLine, $mVars) {
		$aTempArr = $this -> checkErrorMessage ($sErrStr);
		$sType = $this -> checkTypeTrans ($cErrno);
		$sVars = 'n/a';
		if (!is_null ($this -> sAssertion)) {
			$sErrFile = $this -> sAssertion;
			$this -> sAssertion = null;
		}
		$this -> buildLog ($sType, $sErrStr, $sErrFile, $iErrLine, $aTempArr, $sVars);
	}

	/**
	* private function buildLog ()
	* the error handler : builds the XML error log
	* @Param (string) sType : The type of error/exception
	* @Param (string) sErrStr : the PHP error message
	* @Param (string) sErrFile : the file in which the error has been detected
	* @Param (int) iErrLine : the line of the error
	* @Param (string) sVars : the context
	*/
	private function buildLog ($sType, $sErrStr, $sErrFile, $iErrLine, $aTempArr, $sVars) {
		$iErrLine --;
		if ($iErrLine < 0) {
			$iErrLine = 0;
		}
		$oNewLog = $this -> oXMLDOC -> createElement ('ERROR');
		$dump = $this -> oXMLROOT -> getElementsByTagName('ERROR');
		$iNewId = $dump -> length + 1;
		$oNewLog = $this -> oXMLROOT -> appendChild ($oNewLog);
		$oNewLog -> setAttribute ('xml:id', '_'.$iNewId);

		$aElem[] = $this -> oXMLDOC -> createElement ('DATE', date ('d-m-Y H:i:s'));
		$aElem[] = $this -> oXMLDOC -> createElement ('TYPE', $sType);
		$sErrStr = utf8_encode ($sErrStr);
		$aElem[] = $this -> oXMLDOC -> createElement ('PHP_MESSAGE', $sErrStr);
		$aElem[] = $this -> oXMLDOC -> createElement ('FILE', $sErrFile);
		$aElem[] = $this -> oXMLDOC -> createElement ('LINE', $iErrLine);
		if (function_exists ('memory_get_usage')) {
			$iMemory = @memory_get_usage ();
		} else {
			$iMemory = 'n/a';
		}
		$aElem[] = $this -> oXMLDOC -> createElement ('MEMORY', $iMemory);
		$aElem[] = $this -> oXMLDOC -> createElement ('TRANSLATION', $aTempArr['TRANSLATION']);
		$aElem[] = $this -> oXMLDOC -> createElement ('SUGGESTION', $aTempArr['SUGGESTION']);

		$aElem[] = $this -> oXMLDOC -> createElement ('CONTEXT', $sVars);
		$oSource = $this -> oXMLDOC -> createElement ('SOURCE');
		$aSourceElem = array ();
		foreach ($this -> getLine ($sErrFile, $iErrLine) as $iLine => $sLine) {
			$sLine = utf8_encode ($sLine);
			if ($iLine === ($iErrLine)) {
				$aSourceElem[] = $this -> oXMLDOC -> createElement ('SOURCE_LINE_ERROR', ' /** ERROR AROUND THIS LINE => */ '.$sLine);
			} else {
				$aSourceElem[] = $this -> oXMLDOC -> createElement ('SOURCE_LINE', $sLine);
			}
		}
		foreach ($aSourceElem as $oSourceElem) {
			$oSource -> appendChild ($oSourceElem);
		}
		foreach ($aElem as $oElem) {
			$oNewLog -> appendChild ($oElem);
		}
		$oNewLog -> appendChild ($oSource);
		$this -> oCurrentNode = $oNewLog;
		if (true === $this -> aOptions['REALTIME']) {
			$this -> printMe ();
		}
	}
	/**
	* private function getLine ()
	* method to get the lines around the detected error
	* @Param (string) sErrFile : the file in which the error has been detected
	* @Param (int) iErrLine : the line of the error
	* @Return (array) aSource : array with each line
	*/
	private function getLine ($sErrFile, $iErrLine) {
		$aSource = array ();
		if (file_exists ($sErrFile)) {
			$aLines = file ($sErrFile);
			for ($i = $iErrLine - $this -> iNbLines; $i<= $iErrLine + $this -> iNbLines; $i ++) {
				if (isset ($aLines[$i])) {
					$aSource[$i] = $aLines[$i];
				}
			}
		}
		return $aSource;
	}

	/**
	* public function loadXML ()
	* loads an external error log
	* @Param (string) sFile : the error log file to be loaded
	*/
	public function loadXML ($sFile) {
		if (!file_exists ('logs/'.$sFile)) {
			return false;
		}
		$this -> oXMLDOC -> load ('logs/'.$sFile);
	}

	/**
	* public function showAll ()
	* show the whole current xml log
	*/
	public function showAll () {
		$xpath = new DOMXPath($this -> oXMLDOC);
		$sQuery = '//ERROR';
		$oNodeLists = $xpath -> query ($sQuery);
		foreach ($oNodeLists as $oNodeList) {
			$this -> oCurrentNode = $oNodeList;
			$this -> printMe ();
		}
	}

	/**
	* public function showLog ()
	* show the whole current log in a table, with stats (best used after odebugger::loadXML())
	* @Return (string) sHtml : the generated HTML
	*/
	public function showLog () {
		$sBaseHtml = file_get_contents ('templates/'.$this -> sTemplateHTMLLOG.'.dat');
		$iStartPos = strpos ($sBaseHtml, '<!-- LINES HERE -->');
		$sHtml = substr ($sBaseHtml, 0, $iStartPos);
		$iEndPos = strpos ($sBaseHtml, '<!-- STATS -->');
		$iLength = strlen ($sBaseHtml);
		$sTempHtml = substr ($sBaseHtml, $iStartPos,   - ($iLength - $iEndPos));
		$sTempHtmlTotal = '';
		$xpath = new DOMXPath($this -> oXMLDOC);
		$sQuery = '//ERROR';
		$oNodeLists = $xpath -> query ($sQuery);
		foreach ($oNodeLists as $oNodeList) {
			$this -> oCurrentNode = $oNodeList;
			$sTempHtmlTotal .= $this -> printMeLog ($sTempHtml);
		}
		$sHtml .= $sTempHtmlTotal;
		$sQuery = '//ERROR/TYPE';
		$oNodeLists = $xpath -> query ($sQuery);
		foreach ($oNodeLists as $oNodeList) {
			$aTypes[] = $oNodeList  -> nodeValue;
		}
		$sHtml .= substr ($sBaseHtml, $iEndPos, ($iLength - 1));
		$aCountType = array_count_values ($aTypes);
		$sCountType = '';
		foreach ($aCountType as $kType => $vType) {
			$sCountType .= $kType.' : '.$vType.'<br />';
		}
		$sVersion = @phpversion ();
		$sHtml = str_replace ($this -> aIndex[100], $sCountType, $sHtml);
		$sHtml = str_replace ($this -> aIndex[101], $sVersion , $sHtml);
		return $sHtml;
	}

	/**
	* private function printMe ()
	* display a caught error
	* @Return (string) sHtml : the generated HTML
	*/
	private function printMe () {
		$sHtml = file_get_contents ('templates/'.$this -> sTemplateHTML.'.dat');
		$nodeList = $this -> oCurrentNode -> childNodes;
		$iId = $this -> oCurrentNode -> getAttribute ('id');
		for ($i = 0; $i < $nodeList -> length; $i++) {
			$sName = $nodeList -> item($i) -> nodeName;
			if ($sName === 'SOURCE') {
				$sourceNodeList = $nodeList -> item($i) -> childNodes;
				$sValeur = '';
				for ($j = 0; $j < $sourceNodeList -> length; $j++) {
					$sValeur .= str_replace (array ('<?php', '?>', '<?'), '', $sourceNodeList -> item($j) -> nodeValue);
				}
				$sValeur = highlight_string ('<?php '."\r\n".$sValeur.'?>', true);
			} else {
				$sValeur = $nodeList -> item($i) -> nodeValue;
			}
			$sId = uniqid().'_'.$iId;
			$aReplacement = array ($sName, $sValeur);
			$sHtml = str_replace ($this -> aIndex[$i], $aReplacement, $sHtml);
			$sHtml = str_replace ('{ID}', $sId, $sHtml);
		}
		echo $sHtml;
	}

	/**
	* private function printMeLog ()
	* display a caught error, used by odebugger::showLog()
	* @Return (string) sHtml : the generated HTML
	*/
	private function printMeLog ($sHtml) {
		$nodeList = $this -> oCurrentNode -> childNodes;
		for ($i = 0; $i < $nodeList -> length; $i++) {
			if ($nodeList -> item($i) -> nodeName === 'SOURCE') {
				$sourceNodeList = $nodeList -> item($i) -> childNodes;
				$sValeur = '';
				for ($j = 0; $j < $sourceNodeList -> length; $j++) {
					$sValeur .= str_replace (array ('<?php', '?>', '<?'), '', $sourceNodeList -> item($j) -> nodeValue);
				}
				$sValeur = highlight_string ('<?php '."\r\n".$sValeur.'?>', true);
			} else {
				$sValeur = $nodeList -> item($i) -> nodeValue;
			}
			$sHtml = str_replace ($this -> aIndex[$i][1], $sValeur, $sHtml);
		}
		return $sHtml;
	}

	/**
	* public function saveToFile ()
	* save the current log to a given file
	* @Param (string) sFile : name of the log file
	*/
	public function saveToFile ($sFile = null) {
		if ($sFile === null) {
			$sFile = $this -> sCurId.'_error_log.xml';
		}
		$this -> oXMLDOC -> save ($this -> sCurDir.'logs/'.$sFile);
	}

	/**
	* public function __destruct ()
	* destructor
	* will save the log to a file if the LOG_FILE option is set to true
	*/
	public function __destruct () {
		if (true === $this -> aOptions['LOG_FILE']) {
			$this -> saveToFile ();
		}
	}

	/**
	* public function __set ()
	* allows some properties to be set
	* @Param (string) sProp : name of the property
	* @Param (mixed) mVal : the value to be given to the property
	* @Return (boolean) false if failed, true if succeeded
	*/
	public function __set ($sProp, $mVal) {
		if (false === array_key_exists ($sProp, $this -> aCanBeSet)) {
			return false;
		}
		switch ($sProp) {
			case 'LINES' :
				if (!is_int ($mVal)) {
					return false;
				}
				$this -> iNbLines = $mVal;
				return true;
				break;
			case 'HTML' :
				if (!file_exists ('templates/'.$mVal.'.dat')) {
					return false;
				}
				$this -> sTemplateHTML = $mVal;
				return true;
				break;
			case 'HTMLLOG' :
				if (!file_exists ('templates/'.$mVal.'.dat')) {
					return false;
				}
				$this -> sTemplateHTMLLOG = $mVal;
				return true;
				break;
			case 'CSS' :
				if (!file_exists ('css/'.$mVal.'.dat')) {
					return false;
				}
				$this -> sTemplateCSS = $mVal;
				readfile ('css/'.$mVal.'.dat');
				return true;
				break;
			case 'CSSLOG' :
				if (!file_exists ('css/'.$mVal.'.dat')) {
					return false;
				}
				$this -> sTemplateCSSLOG = $mVal;
				readfile ('css/'.$mVal.'.dat');
				return true;
				break;
			case 'REALTIME' :
				if (!is_bool ($mVal)) {
					return false;
				}
				$this -> aOptions['REALTIME'] = $mVal;
				return true;
				break;
			case 'LOGFILE' :
				if (!is_bool ($mVal)) {
					return false;
				}
				$this -> aOptions['LOG_FILE'] = $mVal;
				return true;
				break;
			case 'ERROR' :
				if (!is_bool ($mVal)) {
					return false;
				}
				$this -> aOptions['ERROR'] = $mVal;
				if (true === $mVal) {
					set_error_handler (array ($this, 'myErrorHandler'));
				} else {
					restore_error_handler ();
				}
				return true;
				break;
			case 'EXCEPTION' :
				if (!is_bool ($mVal)) {
					return false;
				}
				$this -> aOptions['EXCEPTION'] = $mVal;
				if (true === $mVal) {
					set_exception_handler (array ($this, 'myExceptionHandler'));
				} else {
					restore_exception_handler ();
				}
				return true;
				break;
			default:
				return false;
		}
	}

	/**
	* public function __get ()
	* allows some properties to be get
	* @Param (string) sProp : name of the property
	* @Return (boolean) false if failed, value of the property if succeeded
	*/
	public function __get ($sProp) {
		if (false === array_key_exists ($sProp, $this -> aCanBeSet)) {
			return false;
		}
		$sRealProp = $this -> aCanBeSet[$sProp];
		return $this -> $sRealProp;
	}
}
?>