/core/Debug.class.php
PHP | 525 lines | 213 code | 57 blank | 255 comment | 17 complexity | 3957e610580cc688454cae2e41b9a229 MD5 | raw file
Possible License(s): LGPL-2.0
- <?php
- class M_Debug extends M_Object {
- /**
- * Stores if debug-mode is on/off
- *
- * @var bool
- */
- private static $_debugMode = false;
-
- /**
- * Stores if queries need to be logged or not
- *
- * @var bool
- */
- private static $_logQueries = false;
- /**
- * Stores if a growl notification needs to be sent when catching an
- * {@link M_Excpetion}
- *
- * @var bool
- */
- private static $_growlNotifications = false;
-
- /**
- * Holds the recipient to which mails will be sent if
- * {@link M_Debug::getDebugMode()} is enabled
- *
- * @var string
- */
- private static $_debugEmailRecipient;
- /**
- * Stores if cache-busting on/off
- *
- * @var bool
- */
- private static $_cacheBusting = false;
-
- /**
- * Stores the date which is used for cachebusting
- *
- * @var M_Date
- */
- private static $_cacheBustingDate;
-
- /**
- * the ip addresses that wil effectively show
- * the debug message
- *
- * @var array
- */
- private static $_safeIps = array('81.83.0.140', '::1', '127.0.0.1');
- /**
- * Enable/disable debug-mode
- *
- * @param bool $arg
- */
- public static function setDebugMode($arg) {
- self::$_debugMode = (bool)$arg;
- }
- /**
- * Check if debug mode is enabled/disabled
- *
- * @return bool
- */
- public static function getDebugMode() {
- return self::$_debugMode;
- }
- /**
- * Tell the db-driver wether or not to log queries
- *
- * @param bool $arg
- */
- public static function setLogQueries($arg) {
- self::$_logQueries = (bool)$arg;
- }
- /**
- * Enable/disable cache busting
- *
- * Cache busting will append a timestamp to all javascript and css
- * references.
- *
- * E.g. <link rel="stylesheet" href="http://domain/application/resources/css/all.css" type="text/css" media="screen" />
- * will be transformed into:
- * E.g. <link rel="stylesheet" href="http://domain/application/resources/css/all.css?20111114" type="text/css" media="screen" />
- *
- *
- * @see M_ViewHtmlResource::fetch()
- * @param bool $mode Set to true to enable cachebusting
- * @param M_Date $date Pass a date to use as variable in the link
- */
- public static function setCacheBusting($mode = true, M_Date $date = null) {
- self::$_cacheBusting = $mode;
-
- if(!is_null($date)) {
- self::$_cacheBustingDate = $date;
- }
- }
-
- /**
- * Add safe ip
- *
- * by default the ip from multimedium and your localhost
- * are enabled. By adding extra IP addresses they can see
- * the debug messages as well.
- *
- * @param type $ip
- */
- public static function addSafeIp($ip) {
- self::$_safeIps[] = (string) $ip;
- }
-
- /**
- * Check if cache busting is enabled
- *
- * @return bool
- */
- public static function getCacheBusting() {
- return self::$_cacheBusting;
- }
-
- /**
- * Get cache busting date
- *
- * @return M_Date
- */
- public static function getCacheBustingDate() {
- return self::$_cacheBustingDate;
- }
- /**
- * Is the db-driver logging queries?
- *
- * @return bool
- */
- public static function getLogQueries() {
- return self::$_logQueries;
- }
-
-
- /**
- * Enable/disable growl notifications
- *
- * @param bool $arg
- */
- public static function setGrowlNotifications($arg) {
- self::$_growlNotifications = (bool)$arg;
- }
- /**
- * Check if growl notifications are enabled/disabled
- *
- * @return bool
- */
- public static function getGrowlNotifications() {
- return self::$_growlNotifications;
- }
- /**
- * Enable maintenance mode
- *
- * In maintenance mode all traffic will be redirected to maintenance.php,
- * and a header 302 will be sent (temporary redirect).
- *
- * You will call this method before dispatch, all traffic will then be
- * redirected.
- *
- * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- * @param string $excludeIp
- * Check the ip and do not redirect if the users' ip matches the $excludeIp
- * @return void
- */
- public static function maintenanceMode($excludeIp = null) {
- //do not redirect if users' ip matches the exclude-ip
- if(!is_null($excludeIp) && $excludeIp == M_Client::getIp()) {
- //display a message to remind the developer maintenance mode is enabled
- $msg = '<div style="padding:10px;background-color:#dd0000;margin-bottom:20px;color:#fff;text-align:center;">';
- $msg .= 'Maintenance mode enabled';
- $msg .= '</div>';
- echo $msg;
- return false;
- }
- $date = new M_Date();
- $date->addTime(1, M_Date::HOUR);
- M_Header::sendHttpStatus(503);
- M_Header::send('Retry-After: '.$date->getRfc2822());
- echo file_get_contents(M_Request::getLink('maintenance'));
- die();
- }
- /**
- * Set the recipient to which all mail will be redirected if
- * {@link M_Debug::getDebugMode()} is enabled
- *
- * @param string
- */
- public static function setDebugEmailRecipient($arg) {
- self::$_debugEmailRecipient = (string)$arg;
- }
- /**
- * Set the recipient to which all mail will be redirected if
- * {@link M_Debug::getDebugMode()} is enabled
- *
- * Note: if empty (or invalid) the mail won't be redirected automaticcally
- *
- * @return string
- */
- public static function getDebugEmailRecipient() {
- return self::$_debugEmailRecipient;
- }
-
- /**
- * Output array to screen
- *
- * @param array $array
- * @return void
- */
- public static function printArray($array) {
- if (self::isSafeIp()) {
- echo "<pre>";
- print_r((array)$array);
- echo"</pre>";
- }
- }
-
- /**
- * Alias for {@link M_Debug::printArray()}
- *
- * @access public
- * @param array $array
- * @return void
- */
- public static function printr($array) {
- self::printArray($array);
- }
-
- /**
- * Output var_dump(); to screen
- *
- * @param mixed $mixed
- * @param str $message
- */
- public static function printVarDump($mixed, $message = null) {
- if (self::isSafeIp()) {
- echo "<pre>";
- if ($message) echo $message.'<hr>';
- var_dump($mixed);
- echo"</pre>";
- }
- }
-
- /**
- * Alias for {@link M_Debug::printVarDump()}
- *
- * @access public
- * @param mixed $mixed
- * @param string $message
- * @return void
- */
- public static function dump($mixed, $message = null) {
- self::printVarDump($mixed, $message);
- }
-
- /**
- * is safe ip
- *
- * will return true if the current user ip is Multimedium,
- * localhost or added trough {link M_Debug::addSafeIp()}
- *
- * @param string $ip
- * optional, the ip to check, if none given,
- * the current Client ip will be used
- * @return bool
- */
- public static function isSafeIp($ip = null) {
- $ip = $ip ? (string) $ip : M_Client::getIp();
- return in_array($ip, self::$_safeIps) || strpos($ip, '192.168.') !== false;;
- }
- /* -- Query logging -- */
- /**
- * Get a log of all queries which have been run during runtime
- *
- * Each query is stored in an array containing the sql statement,
- * execution time and backtrace
- *
- * @author Ben Brughmans
- * @return M_ArrayIterator
- */
- public static function getQueryLog() {
- return M_Registry::getInstance()->get(
- 'queries',
- new M_ArrayIterator()
- );
- }
- /**
- * Update the query log with a new set of queries
- *
- * @param M_ArrayIterator $log
- */
- protected static function _setQueryLog(M_ArrayIterator $log) {
- M_Registry::getInstance()->__set('queries', $log);
- }
- /**
- * Add a query to the registry-log
- *
- * By storing queries (and optionally their execution time and backtrace)
- * in the registry we can create a log of all queries which have been
- * executed during runtime.
- *
- * This is done automatically during debug-mode.
- *
- * If debug-mode is disabled you could also do this yourself.
- *
- * @see M_Debug::getQueryLog()
- * @param string $sql
- * @param float $executionTime
- * @param array $backtrace
- * @author Ben Brughmans
- */
- public static function addToQueryLog($sql, $executionTime = null, $backtrace = null) {
- $log = self::getQueryLog();
- //append new values to query log
- $log->append(array(
- 'sql' => (string)$sql ,
- 'executiontime' => floatval($executionTime),
- 'backtrace' => $backtrace
- ));
- //update query log with new query
- self::_setQueryLog($log);
- }
- /**
- * Print a list of queries which have been executed during runtime
- *
- * @return void
- * @see M_Debug::getQueryLog()
- * @author Ben Brughmans
- * @todo: toggle backtrace (backtrace row is hidden now)
- */
- public static function printQueryLog() {
- // only for safge ip's
- if (! self::isSafeIp()) {
- return false;
- }
-
- // Fetch the query log
- $queryLog = self::getQueryLog();
-
- // Working variables
- $totalExecutionTime = 0;
- $str = '';
-
- // Working variables to detect double queries
- $queryStrings = array();
- $doubleQueries = array();
-
- // Loop through the query log
- foreach($queryLog AS $i => $log) {
- // If this query has been run before
- if(in_array($log['sql'], $queryStrings)) {
- // Is this the first time this query has been duplicated?
- if(! array_key_exists($log['sql'], $doubleQueries)) {
- // Log the double query
- $doubleQueries[$log['sql']] = array(
- 'index' => $i,
- 'count' => 2
- );
- }
- // Otherwise, simply increase the count
- else {
- $doubleQueries[$log['sql']]['count']++;
- }
- // Otherwise, store it
- } else {
- // Log the query as a string, to detect doubles
- $queryStrings[] = $log['sql'];
- }
-
- // Fetch the execution time
- $executiontime = M_Helper::getArrayElement('executiontime', $log);
- //store the total amount of executiontime
- $totalExecutionTime += $executiontime;
- $str .= '<tr onclick="document.getElementById(\'debug-row-'. $i .'\').style.display = (document.getElementById(\'debug-row-'. $i .'\').style.display == \'none\' ? \'block\' : \'none\')">';
- $str .= '<td>'.$log['sql'].'</td>';
- $str .= '<td>'.$executiontime.'</td>';
- $str .= '</tr>';
- //get backtrace, and print if available
- $backtrace = M_Helper::getArrayElement('backtrace', $log);
- //if a backtrace is set, print it
- if (is_array($backtrace)):
- $str .= '<tr style="display:none;" id="debug-row-'. $i .'">';
- $str .= '<td colspan="2">';
- $str .= '<table>';
- foreach($backtrace AS $backtraceItem) {
- $str .= '<tr>';
- $str .= '<td>'.M_Helper::getArrayElement('file', $backtraceItem).'</td>';
- $str .= '<td>'.M_Helper::getArrayElement('class', $backtraceItem).'::'.M_Helper::getArrayElement('function', $backtraceItem).'</td>';
- $str .= '<td>'.M_Helper::getArrayElement('line', $backtraceItem).'</td>';
- $str .= '</tr>';
- }
- $str .= '</table>';
- $str .= '</tr>';
- endif;
- }
- //output the log in a table, with the totals on top
- $table = '<table border="1" cellpadding="2" style="background:#fff;color:#000;border:1px black solid;clear:both;">';
- $table .= '<tr>';
- $table .= '<td style="background-color:#ccc;font-weight:bold;">' . count($queryLog) . ' queries executed (' . (count($doubleQueries) > 0 ? 'double queries detected; check below' : 'no double queries') . ')</td>';
- $table .= '<td style="background-color:#ccc;font-weight:bold;">'.$totalExecutionTime.'</td>';
- $table .= '</tr>';
- $table .= $str;
- $table .= '</table>';
- // Echo the table
- echo $table;
-
- // If there are any double queries:
- if(count($doubleQueries) > 0) {
- echo '<br/>';
-
- // Reset the working variables
- $totalExecutionTime = 0;
- $redundantCount = 0;
- $str = '';
-
- // Loop through the double queries
- $i = 0;
- foreach($doubleQueries as $sql => $elem) {
- $i++;
-
- // Fetch the log
- $log = $queryLog[$elem['index']];
-
- // Fetch the execution time and update the redundant count
- $executiontime = M_Helper::getArrayElement('executiontime', $log);
- $redundantCount += $elem['count'];
-
- //store the total amount of executiontime
- $totalExecutionTime += $executiontime;
- $str .= '<tr onclick="document.getElementById(\'debug-row-doubles-'. $i .'\').style.display = (document.getElementById(\'debug-row-doubles-'. $i .'\').style.display == \'none\' ? \'block\' : \'none\')">';
- $str .= '<td>'.$log['sql'].'</td>';
- $str .= '<td>'.$executiontime.'</td>';
- $str .= '<td>'.$elem['count'].'</td>';
- $str .= '</tr>';
- //get backtrace, and print if available
- $backtrace = M_Helper::getArrayElement('backtrace', $log);
- //if a backtrace is set, print it
- if (is_array($backtrace)):
- $str .= '<tr style="display:none;" id="debug-row-doubles-'. $i .'">';
- $str .= '<td colspan="2">';
- $str .= '<table>';
- foreach($backtrace AS $backtraceItem) {
- $str .= '<tr>';
- $str .= '<td>'.M_Helper::getArrayElement('file', $backtraceItem).'</td>';
- $str .= '<td>'.M_Helper::getArrayElement('class', $backtraceItem).'::'.M_Helper::getArrayElement('function', $backtraceItem).'</td>';
- $str .= '<td>'.M_Helper::getArrayElement('line', $backtraceItem).'</td>';
- $str .= '</tr>';
- }
- $str .= '</table>';
- $str .= '</tr>';
- endif;
- }
-
- // Output the double queries in a table, with the total on top:
- $table = '<table border="1" cellpadding="2" style="background:#fff;color:#000;border:1px black solid;clear:both;width:100%;">';
- $table .= '<tr>';
- $table .= '<td style="background-color:#ccc;font-weight:bold;">' . count($doubleQueries) . ' duplicate queries ('. ($redundantCount - count($doubleQueries)) .' redundant)</td>';
- $table .= '<td style="background-color:#ccc;font-weight:bold;">'.$totalExecutionTime.'</td>';
- $table .= '<td style="background-color:#ccc;font-weight:bold;"># executed</td>';
- $table .= '</tr>';
- $table .= $str;
- $table .= '</table>';
-
- // Finally, echo the doubles table
- echo $table;
- }
- }
-
- /**
- * Print Query log to console
- *
- * This will write a list off all performed SQL queries to the console. An
- * optional name parameter can be provided for the name of the log file,
- * which will default to 'qryLog'.
- *
- * Note that timing information and check for double queries will NOT be
- * available here. Also the setLogQueries needs to be set to TRUE for this
- * to work.
- *
- * This can be sepecially useful for debugging ajax request, live websites, or
- * controllers that do a Redirect.
- *
- * @param string $console
- */
- public static function printQueryLogToConsole($console = 'qryLog') {
- $log = self::getQueryLog();
- $console = M_Console::getInstance($console);
- foreach ($log as $qry) {
- if (array_key_exists('sql', $qry)) {
- $console->write($qry['sql']);
- }
- }
- }
- }