<?php
/**
* Debug sites live.
* @example See file "debug_example.php" for usage examples
* @author Artur Barseghyan www@foreverchild.info
* @version 0.2
* @copyright Artur Barseghyan
* @license GPL
*/
class Debug {
/**
* Boolean. Default value of the <$_UseBuffer> flag.
*/
const USE_BUFFER = false;
/**
* Boolean. Default value of the <$_DisplayNone> flag.
*/
const DISPLAY_NONE = true;
/**
* Boolean. Default value of <$_DisplayFullTrace> flag.
*/
const DISPLAY_FULL_TRACE = false;
/**
* Boolean. Default value for <$_AddDebugInfo> flag.
*/
const ADD_DEBUG_INFO = true;
/**
* String. Default value for <$_DumpFunction> value.
*/
const DUMP_FUNCTION = 'print_r';
/**
* String.
*/
const ACCESS_CHECK_IP = 'ip';
/**
* String.
*/
const ACCESS_CHECK_FINGERPRINT = 'fingerprint';
/**
* String.
*/
const FINGERPRINT_PREFIX = 'lgdl*4399@FJ-00%dasdsa^';
/**
* Holds an instance of Debug object.
*
* @var Debug object
*/
private static $_Instance;
/**
* Enable debugging flag.
*
* @var Bool
*/
private $_enable;
/**
* Access control parameters.
* @var Associative Array of Strings
*/
private $_accessParams;
private $_errorLog = array();
/**
* Access control IPs
*
* @var Array of Associative Arrays of Strings
*/
private $_ips = array();
/**
* If set to true, debug info will be added.
*
* @var Bool
*/
private $_addDebugInfo = self::ADD_DEBUG_INFO;
/**
* If set to true, output will be included in the scope of ≷div> tags
* with CSS property set to display:none;
*
* @var Bool
*/
private $_displayNone = self::DISPLAY_NONE;
/**
* If set to true, full debug trace will be added.
*
* @var Bool
*/
private $_displayFullTrace = self::DISPLAY_FULL_TRACE;
/**
* If set to true, debug info will be buffered instead of direct output.
*
* @var Bool
*/
private $_useBuffer = self::USE_BUFFER;
/**
* Dump function to use.
*
* @var String
*/
private $_dumpFunction = self::DUMP_FUNCTION;
/**
* List of allowed dump functions.
*
* @var Array
*/
private $_dumpFunctions = array( 'print_r' => 'print_r',
'var_dump' => 'var_dump');
/**
* Buffer data.
*
* @var Array of Strings
*/
private $_bufferData = array();
/**
* What access control checks to perform.
*
* @var Array of Strings
*/
private $_accessChecks = array(self::ACCESS_CHECK_IP);
/**
* Allowed values for access control checks.
*
* @var Array of Strings
*/
private $_accessChecksValues = array(self::ACCESS_CHECK_IP,
self::ACCESS_CHECK_FINGERPRINT
);
/**
* Fingerprints, defined by user for checks.
*
* @var Array of Strings
*/
private $_fingerprints;
/**
* Collection of commands and results
*
* @var Array of Objects
*/
private $_collection = array();
private $_languageConstructs = array('die', 'exit', 'echo');
/**
* Contructor.
*/
private function __construct() {
}
/**
* Initializes an object, returns the instance.
*
* @param Bool $addDebugInfo
* @param Bool $displayFullTrace
* @param Bool $useBuffer
* @param String $dumpFunction
* @return Debug object
*/
public static function Call() {
if (!self::$_Instance instanceof self) {
self::$_Instance = new self();
}
return self::$_Instance;
}
/**
* Enables debugging.
*/
public static function Enable() {
self::Call()->$_enabled = true;
}
/**
* Disables debugging.
*/
public static function Disable() {
self::Call()->$_enabled = false;
}
/**
* Catches calls (for PHP version >= 5.3 only).
* Allows to call functions statically:
* Debug::YourFunctionName(Arguments)
* All other PHP versions please use:
* Debug::Call()->YourFunctionName(Arguments)
*
* @param String $name
* @param Array $arguments
*/
public function __callStatic($name, $arguments) {
if (!$this->accessIsGranted()) {
return false;
}
$exception = new Exception();
return $this->_executeFunction($name, $arguments, $exception);
}
/**
* Catches calls. Example of usage:
* Debug::Call()->YourFunctionName(Arguments)
*
* @param String $name
* @param Array $arguments
*/
public function __call($name, $arguments) {
if (!$this->accessIsGranted()) {
return false;
}
$exception = new Exception();
return $this->_executeFunction($name, $arguments, $exception);
}
/**
* Sets parameters for access control. Example of usage:
* Debug::SetAccessParam('IP', '206.190.60.37');
*
* @param String $key
* @param String $var
*/
public function setAccessParam($key, $var) {
$this->_accessParams[$key] = $var;
}
/**
* Sets parameters for access control. Similar to <SetAccessParam>
*
* @param Associative Array of Strings $params
*/
public function setAccessParams(array $params) {
$this->_accessParams = $params;
}
/**
* Gets a parameters. Similar to <GetAccessParam>.
*
* @return Associative Array of Strings
*/
public function getAccessParams() {
return $this->_accessParams;
}
private function _logError($error) {
if (empty($this->_errorLog)) {
$this->_errorLog = array();
}
$this->_errorLog[] = $error;
}
private function _cleanErrorLog() {
$this->_errorLog = null;
}
private function _getErrorLog() {
return $this->_errorLog;
}
private function _getLastLoggedError() {
return end($this->_errorLog);
}
/**
* Gets access parameters.
*
* @param String $key
* @return String
*/
public function getAccessParam($key) {
return isset($this->_accessParams[$key]) ? $this->_accessParams[$key] : null;
}
/**
* Performs function execution.
*
* @param String $name
* @param Associative Array $params
* @param Exception object $exception
*/
private function _executeFunction($name, $arguments, $exception) {
$this->_cleanErrorLog();
if ($this->_useBuffer) {
ob_start();
}
$result = null;
if ($this->_displayNone) {
echo '<div style="display:none;">' . "\n";
}
if ($this->_addDebugInfo) {
$trace = $exception->getTrace();
$details = '';
if ($this->_displayFullTrace) {
$details = $exception->getTraceAsString();
} else if (isset($trace[1])) {
if (isset($trace[1]['file'])) {
$details .= ' File: ' . $trace[1]['file'] . "\n";
}
if (isset($trace[1]['line'])) {
$details .= ' Line: ' . $trace[1]['line'] . "\n";
}
}
echo 'Function call details:' . "\n" .
' Function: ' . $name . "\n" .
$details .
' Arguments:' . "\n" .
$this->_printFunctionArguments($arguments);
echo "\n\n" . 'Call results the following output: ' . "\n";
}
if (function_exists($name)) {
$result = $name($arguments);
} else if (in_array($name, $this->_languageConstructs)) {
$result = $name($arguments);
} else {
$this->_logError('Function "' . $name . '" does not exist!');
echo $this->_getLastLoggedError();
}
if ($this->_displayNone) {
echo "\n" . '</div>';
}
if ($this->_useBuffer) {
$this->_bufferData[] = ob_get_clean();
}
// Adding to collections.
$this->_collection[] = new DebugCollection($name, $arguments, $result, $this->_getErrorLog(), $exception->getTrace());
return $result;
}
/**
* Sets flag to use the buffer for debugging.
*/
public static function UseBuffer() {
self::Call()->_useBuffer = true;
}
/**
* Unsets the flag to use the buffer for debugging.
*/
public static function NoBuffer() {
self::Call()->_useBuffer = false;
}
/**
* Resets Debug information display configuration.
*/
public static function ResetDisplayConfiguration() {
self::Call()->_addDebugInfo = self::ADD_DEBUG_INFO;
self::Call()->_displayFullTrace = self::DISPLAY_FULL_TRACE;
self::Call()->_useBuffer = self::USE_BUFFER;
}
/**
* Resets Debug access control parameters.
*/
public static function ResetAccessParams() {
self::Call()->_accessParams = array();
}
/**
* Resets Debug access control parameters.
*/
public static function ResetCollection() {
self::Call()->_collection = array();
}
/**
* Resets Debug dump function.
*/
public static function ResetDumpFunction() {
self::Call()->_dumpFunction = self::DUMP_FUNCTION;
}
/**
* Global reset of the whole Debug object.
*/
public static function Reset() {
self::ResetDisplayConfiguration();
self::ResetAccessParams();
self::EmptyBuffer();
self::ResetFingerprints();
self::ResetIps();
self::NoBuffer();
self::ResetCollection();
}
/**
* Resets <self::$_Ips> array of allowed IPs.
*/
public static function ResetIps() {
self::Call()->_ips = array();
}
/**
* Empties the debug buffer.
*/
public static function EmptyBuffer() {
self::Call()->_bufferData = array();
}
/**
* Returns debug buffer content.
*
* @param Bool $asString
* @return Array || String
*/
public static function GetBuffer($asString = false) {
return ($asString) ? implode("\n", self::Call()->_bufferData) : self::Call()->_bufferData;
}
/**
* Prints out the function arguments in readable way.
*
* @param Array $arguments
* @return String
*/
private function _printFunctionArguments($arguments) {
$dumpFunction = $this->_dumpFunction;
$return = '';
foreach ($arguments as $index => $argument) {
$return .= 'Argument [' . $index . '] => ' .
$dumpFunction($argument, true);
}
return $return;
}
/**
* Sets property <$_DumpFunction>.
*
* @param String $dumpFunction
*/
public static function SetDumpFunction($dumpFunction) {
if (isset(self::Call()->_dumpFunctions[$dumpFunction])) {
self::Call()->_dumpFunction = $dumpFunction;
}
}
/**
* Sets property <$_AddDebugInfo>.
*
* @param Bool $addDebugInfo
* @return Debug object.
*/
public function showInfo($addDebugInfo = self::ADD_DEBUG_INFO) {
$this->_addDebugInfo = $addDebugInfo;
return $this;
}
/**
* Sets property <$_DisplayNone>.
*
* @param Bool $displayNone
* @return Debug object
*/
public function displayNone($displayNone = self::DISPLAY_NONE) {
$this->_displayNone = $displayNone;
return $this;
}
/**
* Sets property <$_UseBuffer>.
*
* @param Bool $bufferData
* @return Debug object.
*/
public function buffer($bufferData = self::USE_BUFFER) {
$this->_useBuffer = $bufferData;
return $this;
}
/**
* Sets property <$_DisplayFullTrace>.
*
* @param Bool $displayFullTrace
* @return Debug object
*/
public function trace($displayFullTrace = self::DISPLAY_FULL_TRACE) {
$this->_displayFullTrace = $displayFullTrace;
return $this;
}
/**
* Sets property <$_DumpFunction>.
*
* @param String $dumpFunction
* @return Debug object
*/
public function dump($dumpFunction = self::DUMP_FUNCTION) {
self::SetDumpFunction($dumpFunction);
return $this;
}
/**
* Sets value of property <$_DisplayNone>.
*
* @param Bool $displayNone
*/
public static function SetDisplayNone($displayNone = self::DISPLAY_NONE) {
self::Call()->_displayNone = $displayNone;
}
/**
* Sets value of property <$_AddDebugInfo>.
*
* @param Bool $addDebugInfo
*/
public static function SetAddDebugInfo($addDebugInfo = self::ADD_DEBUG_INFO) {
self::Call()->_addDebugInfo = $addDebugInfo;
}
/**
* Sets value of property <$_DisplayFullTrace>.
*
* @param <type> $displayFullTrace
*/
public static function SetDisplayFullTrace($displayFullTrace = self::DISPLAY_FULL_TRACE) {
self::Call()->_displayFullTrace = $displayFullTrace;
}
/**
* Adds an IP to check.
*
* @param String $ip
* @param Bool $access
*/
public static function AddIp($ip) {
self::Call()->_ips[$ip] = $ip;
}
/**
* Adds a fingerprint to check.
*
* @param String $fingerprint
*/
public static function AddFingerprint($fingerprint) {
self::Call()->_fingerprints[$fingerprint] = $fingerprint;
}
/**
* Resets the <self::$_Fingerprints> array.
*/
public static function ResetFingerprints() {
self::Call()->_fingerprints = array();
}
/**
* Removes an IP from check.
*
* @param String $ip
*/
public static function RemoveIp($ip) {
if (isset(self::Call()->_ips[$ip])) {
self::Call()->_ips[$ip] = null; // Setting object to null
unset(self::Call()->_ips[$ip]); // Unsetting the variable
}
}
/**
* Gets an array of all IPs
*
* @return Array of DebugIpContainer objects
*/
public static function GetIps() {
return self::Call()->_ips;
}
/**
* Peroforms the access control check. Returns true if one of the checks is
* successful.
*
* @return Bool
*/
public function accessIsGranted() {
$result = false;
foreach ($this->_accessChecks as $check) {
$checkFunction = '_Perform' . ucfirst($check) . 'Check';
if ($this->$checkFunction()) {
$result = true;
}
}
return $result;
}
/**
* Performs an IP check. Returns boolean true on success.
*
* @return Bool
*/
private static function _PerformIpCheck() {
$currentIp = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
if (in_array($currentIp, array_keys(self::Call()->_ips))) {
return true;
} else {
return false;
}
}
/**
* Performs a fingerprint check. Returns boolean true on success.
*
* @return Bool
*/
private static function _PerformFingerprintCheck() {
if (in_array(self::GenerateFingerprint(), self::Call()->_fingerprints)) {
return true;
} else {
return false;
}
}
/**
* Encodes a fingerprint.
*
* @return String
*/
public static function GenerateFingerprint() {
return sha1(self::_GetFingerPrint());
}
/**
* Gets a fingerprint string based on <$_SERVER> data.
*
* @return String
*/
private static function _GetFingerprint() {
$fingerprint = self::FINGERPRINT_PREFIX .
(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '') .
(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '') .
(isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : '') .
(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '');
return $fingerprint;
}
/**
* Adds an access control check.
*
* @param String $check
*/
public static function AddAccessCheck($check) {
if (in_array($check, self::Call()->_accessChecksValues)) {
self::Call()->_accessChecks[$check] = $check;
}
}
/**
* Unsets an access control check.
*
* @param String $check
*/
public static function RemoveAccessCheck($check) {
if (in_array($check, self::Call()->_accessChecksValues)) {
unset(self::Call()->_accessChecks[$check]);
}
}
public function getCollection() {
return $this->_collection;
}
}
class DebugCollection {
private $_function = null;
private $_arguments = array();
private $_return = null;
private $_trace = null;
private $_error = null;
public function __construct($function, $arguments, $return, $error = null, $trace = null) {
$this->_function = $function;
$this->_arguments = $arguments;
$this->_return = $return;
$this->_error = $error;
$this->_trace = $trace;
}
public function getFunction() {
return $this->_function;
}
public function getArguments($asString = false) {
$asString = (bool)$asString;
return ($asString) ? implode(', ', $this->_arguments) : $this->_arguments;
}
public function getReturn() {
return $this->_return;
}
public function getTrace() {
return $this->_trace;
}
public function getError() {
return $this->_error;
}
}
?>
|