Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Aug 16, 3:22 PM

in-portal

Index: branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/debugger.php
===================================================================
--- branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/debugger.php (nonexistent)
+++ branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/debugger.php (revision 7660)
@@ -0,0 +1,1185 @@
+<?php
+
+ if( !class_exists('Debugger') ) {
+ class Debugger {
+
+ /**
+ * Set to true if fatal error occured
+ *
+ * @var bool
+ */
+ var $IsFatalError = false;
+
+ /**
+ * Debugger data for building report
+ *
+ * @var Array
+ */
+ var $Data = Array();
+
+ var $ProfilerData = Array();
+ var $ProfilerTotals = Array();
+ var $ProfilerTotalCount = Array();
+
+ /**
+ * Prevent recursion when processing debug_backtrace() function results
+ *
+ * @var Array
+ */
+ var $RecursionStack = Array();
+
+ var $scrollbarWidth = 0;
+
+ /**
+ * Long errors are saved here, because trigger_error doesn't support error messages over 1KB in size
+ *
+ * @var Array
+ */
+ var $longErrors = Array();
+
+ var $IncludesData = Array();
+ var $IncludeLevel = 0;
+
+ var $reportDone = false;
+
+ /**
+ * Transparent spacer image used in case of none spacer image defined via SPACER_URL contant.
+ * Used while drawing progress bars (memory usage, time usage, etc.)
+ *
+ * @var string
+ */
+ var $dummyImage = '';
+
+ /**
+ * Temporary files created by debugger will be stored here
+ *
+ * @var string
+ */
+ var $tempFolder = '';
+
+ /**
+ * Debug rows will be separated using this string before writing to debug file
+ *
+ * @var string
+ */
+ var $rowSeparator = '@@';
+
+ /**
+ * Base URL for debugger includes
+ *
+ * @var string
+ */
+ var $baseURL = '';
+
+ function Debugger()
+ {
+ global $start, $dbg_options;
+ // check if user haven't defined DEBUG_MODE contant directly
+ if (defined('DEBUG_MODE') && DEBUG_MODE) {
+ die('error: contant DEBUG_MODE defined directly, please use <strong>$dbg_options</strong> array instead');
+ }
+
+ // check IP before enabling debug mode
+ $ip_match = false;
+ $ip_addresses = isset($dbg_options['DBG_IP']) ? explode(';', $dbg_options['DBG_IP']) : Array ();
+ foreach ($ip_addresses as $ip_address) {
+ if ($this->netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) {
+ $ip_match = true;
+ break;
+ }
+ }
+
+ if (!$ip_match) {
+ define('DEBUG_MODE', 0);
+ return ;
+ }
+
+ // debug is allowed for user, continue initialization
+ $this->InitDebugger();
+ $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start);
+ $this->profileStart('script_runtime', 'Script runtime', $start);
+
+ error_reporting(E_ALL);
+ ini_set('display_errors', $this->constOn('DBG_ZEND_PRESENT') ? 0 : 1); // show errors on screen in case if not in Zend Studio debugging
+
+ $this->scrollbarWidth = $this->isGecko() ? 22 : 25; // vertical scrollbar width differs in Firefox and other browsers
+ $this->appendRequest();
+ }
+
+ /**
+ * Set's default values to constants debugger uses
+ *
+ */
+ function InitDebugger()
+ {
+ global $dbg_options;
+
+ unset($_REQUEST['debug_host'], $_REQUEST['debug_fastfile'], $dbg_options['DBG_IP']); // this var messed up whole detection stuff :(
+
+ // Detect fact, that this session beeing debugged by Zend Studio
+ foreach ($_REQUEST as $rq_name => $rq_value) {
+ if (substr($rq_name, 0, 6) == 'debug_') {
+ $this->safeDefine('DBG_ZEND_PRESENT', 1);
+ break;
+ }
+ }
+
+ $this->safeDefine('DBG_ZEND_PRESENT', 0); // set this constant value to 0 (zero) to debug debugger using Zend Studio
+
+ // set default values for debugger constants
+ $dbg_constMap = Array(
+ 'DBG_USE_HIGHLIGHT' => 1, // highlight output same as php code using "highlight_string" function
+ 'DBG_WINDOW_WIDTH' => 700, // set width of debugger window (in pixels) for better viewing large amount of debug data
+ 'DBG_USE_SHUTDOWN_FUNC' => DBG_ZEND_PRESENT ? 0 : 1, // use shutdown function to include debugger code into output
+ 'DBG_HANDLE_ERRORS' => DBG_ZEND_PRESENT ? 0 : 1, // handle all allowed by php (see php manual) errors instead of default handler
+ 'DBG_IGNORE_STRICT_ERRORS' => 1, // ignore PHP5 errors about private/public view modified missing in class declarations
+ 'DBG_DOMVIEWER' => '/temp/domviewer.html', // path to DOMViewer on website
+ 'DOC_ROOT' => str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
+ 'DBG_LOCAL_BASE_PATH' => 'w:', // replace DOC_ROOT in filenames (in errors) using this path
+ );
+
+ // only for IE, in case if no windows php script editor defined
+ if (!defined('DBG_EDITOR')) {
+// $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\UltraEdit\uedit32.exe %F/%L';
+ $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe %F';
+ }
+
+ if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] && constOn('DBG_SKIP_AJAX')) {
+ $this->safeDefine('DBG_SKIP_REPORTING', 1);
+ }
+
+ // user defined options override debugger defaults
+ $dbg_constMap = $this->array_merge_recursive2($dbg_constMap, $dbg_options);
+
+ foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) {
+ $this->safeDefine($dbg_constName, $dbg_constValue);
+ }
+ }
+
+ function constOn($const_name)
+ {
+ return defined($const_name) && constant($const_name);
+ }
+
+ function safeDefine($const_name, $const_value) {
+ if (!defined($const_name)) {
+ define($const_name, $const_value);
+ }
+ }
+
+ function array_merge_recursive2($paArray1, $paArray2)
+ {
+ if (!is_array($paArray1) or !is_array($paArray2)) {
+ return $paArray2;
+ }
+
+ foreach ($paArray2 AS $sKey2 => $sValue2) {
+ $paArray1[$sKey2] = isset($paArray1[$sKey2]) ? array_merge_recursive2($paArray1[$sKey2], $sValue2) : $sValue2;
+ }
+
+ return $paArray1;
+ }
+
+ function netMatch($network, $ip) {
+
+ $network = trim($network);
+ $ip = trim($ip);
+
+ if ($network == $ip) {
+ // comparing 2 ip addresses directly
+ return true;
+ }
+
+ $d = strpos($network, '-');
+ if ($d === false) {
+ // sigle subnet specified
+ $ip_arr = explode('/', $network);
+
+ if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) {
+ $ip_arr[0] .= '.0'; // Alternate form 194.1.4/24
+ }
+
+ $network_long = ip2long($ip_arr[0]);
+ $x = ip2long($ip_arr[1]);
+
+ $mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1]));
+ $ip_long = ip2long($ip);
+
+ return ($ip_long & $mask) == ($network_long & $mask);
+ }
+ else {
+ // ip address range specified
+ $from = ip2long(trim(substr($network, 0, $d)));
+ $to = ip2long(trim(substr($network, $d + 1)));
+
+ $ip = ip2long($ip);
+ return ($ip >= $from && $ip <= $to);
+ }
+ }
+
+ function InitReport()
+ {
+ if (!class_exists('kApplication')) return false;
+
+ $application =& kApplication::Instance();
+
+ // string used to separate debugger records while in file (used in debugger dump filename too)
+ $this->rowSeparator = '@'.(is_object($application->Factory) ? $application->GetSID() : 0).'@';
+
+ // include debugger files from this url
+ $reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/';
+ $kernel_path = preg_replace($reg_exp, '', KERNEL_PATH, 1);
+ $this->baseURL = PROTOCOL.SERVER_NAME.rtrim(BASE_PATH, '/').$kernel_path.'/utility/debugger';
+
+ // save debug output in this folder
+ $this->tempFolder = defined('WRITEABLE') ? WRITEABLE.'/cache' : FULL_PATH.'/kernel/cache';
+ }
+
+ function mapLongError($msg)
+ {
+ $key = $this->generateID();
+ $this->longErrors[$key] = $msg;
+ return $key;
+ }
+
+ /**
+ * Appends all passed variable values (wihout variable names) to debug output
+ *
+ */
+ function dumpVars()
+ {
+ $dumpVars = func_get_args();
+ foreach ($dumpVars as $varValue) {
+ $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
+ }
+ }
+
+ function prepareHTML($dataIndex)
+ {
+ $Data =& $this->Data[$dataIndex];
+ if ($Data['debug_type'] == 'html') {
+ return $Data['html'];
+ }
+
+ switch ($Data['debug_type']) {
+ case 'error':
+ $fileLink = $this->getFileLink($Data['file'], $Data['line']);
+ $ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
+ $ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
+ return $ret;
+ break;
+
+ case 'var_dump':
+ return $this->highlightString( $this->print_r($Data['value'], true) );
+ break;
+
+ case 'trace':
+ ini_set('memory_limit', '500M');
+ $trace =& $Data['trace'];
+
+ $i = 0; $traceCount = count($trace);
+ $ret = '';
+ while ($i < $traceCount) {
+ $traceRec =& $trace[$i];
+ $argsID = 'trace_args_'.$dataIndex.'_'.$i;
+
+ $has_args = isset($traceRec['args']);
+
+ if (isset($traceRec['file'])) {
+ $func_name = isset($traceRec['class']) ? $traceRec['class'].$traceRec['type'].$traceRec['function'] : $traceRec['function'];
+ $args_link = $has_args ? '<a href="javascript:$Debugger.ToggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>' : '<b>Function</b>';
+
+ $ret .= $args_link.': '.$this->getFileLink($traceRec['file'], $traceRec['line'], $func_name);
+ $ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
+ }
+ else {
+ $ret .= 'no file information available';
+ }
+
+ if ($has_args) {
+ // if parameter value is longer then 200 symbols, then leave only first 50
+ $args = $this->highlightString($this->print_r($traceRec['args'], true, 50, 200));
+ $ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
+ }
+ $i++;
+ }
+ return $ret;
+ break;
+
+ case 'profiler':
+ $profileKey = $Data['profile_key'];
+ $Data =& $this->ProfilerData[$profileKey];
+ $runtime = ($Data['ends'] - $Data['begins']); // in seconds
+
+ $totals_key = getArrayValue($Data, 'totalsKey');
+ if ($totals_key) {
+ $total_before = $Data['totalsBefore'];
+ $total = $this->ProfilerTotals[$totals_key];
+
+ $div_width = Array();
+ $total_width = ($this->getWindowWidth()-10);
+ $div_width['before'] = round(($total_before / $total) * $total_width);
+ $div_width['current'] = round(($runtime / $total) * $total_width);
+ $div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width);
+
+ $ret = '<b>Name</b>: '.$Data['description'].'<br />';
+
+ if (isset($Data['file'])) {
+ $ret .= '[<b>Runtime</b>: '.$runtime.'s] [<b>File</b>: '.$Data['file'].']<br />';
+ }
+ else {
+ $ret .= '<b>Runtime</b>: '.$runtime.'s<br />';
+ }
+
+ $ret .= '<div class="dbg_profiler" style="width: '.$div_width['before'].'px; border-right: 0px; background-color: #298DDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
+ $ret .= '<div class="dbg_profiler" style="width: '.$div_width['current'].'px; border-left: 0px; border-right: 0px; background-color: #EF4A4A;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
+ $ret .= '<div class="dbg_profiler" style="width: '.$div_width['left'].'px; border-left: 0px; background-color: #DFDFDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
+
+ return $ret;
+ }
+ else {
+ return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
+ }
+ break;
+
+ default:
+ return 'incorrect debug data';
+ break;
+ }
+ }
+
+ function getWindowWidth()
+ {
+ return DBG_WINDOW_WIDTH - $this->scrollbarWidth - 8;
+ }
+
+ /**
+ * Tells debugger to skip objects that are heavy in plan of memory usage while printing debug_backtrace results
+ *
+ * @param Object $object
+ * @return bool
+ */
+ function IsBigObject(&$object)
+ {
+ $skip_classes = Array(
+ defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication',
+ 'kFactory',
+ 'kUnitConfigReader',
+ 'TemplateParser',
+ );
+
+ foreach ($skip_classes as $class_name) {
+ if (strtolower(get_class($object)) == strtolower($class_name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Advanced version of print_r (for debugger only). Don't print objects recursively
+ *
+ * @param Array $array
+ * @param bool $return_output return output or print it out
+ * @param int $cut_first cut first N symbols, don't cut anything if -1 specified
+ * @package int $cut_min_length cut only of this length of string or greather
+ * @return string
+ */
+ function print_r(&$array, $return_output = false, $cut_first = -1, $cut_min_length = -1)
+ {
+ static $first_line = true, $tab_count = -1;
+
+ if (is_null($array)) {
+ return 'NULL';
+ }
+ elseif (!is_array($array)) {
+ if ($cut_min_length != -1 && strlen($array) > $cut_min_length) {
+ $array = substr($array, 0, $cut_first).' ...';
+ }
+ return $array;
+ }
+
+ $output = '';
+
+ $tab_count++;
+ $output .= "Array\n".str_repeat(' ', $tab_count)."(\n";
+
+ $tab_count++;
+ $tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
+
+ $array_keys = array_keys($array);
+
+ foreach ($array_keys as $key) {
+ switch (gettype($array[$key])) {
+ case 'array':
+ $output .= $tabsign.'['.$key.'] = '.$this->print_r($array[$key], true, 50, 200);
+ break;
+
+ case 'boolean':
+ $output .= $tabsign.'['.$key.'] = '.($array[$key] ? 'true' : 'false')."\n";
+ break;
+
+ case 'integer':
+ case 'double':
+ case 'string':
+ if ($cut_min_length != -1 && strlen($array[$key]) > $cut_min_length) {
+ $array[$key] = substr($array[$key], 0, $cut_first).' ...';
+ }
+ $output .= $tabsign.'['.$key.'] = '.$array[$key]."\n";
+ break;
+
+ case 'NULL':
+ $output .= $tabsign.'['.$key."] = NULL\n";
+ break;
+
+ case 'object':
+ $attribute_names = get_class_vars( get_class($array[$key]) );
+ if (!$attribute_names) {
+ $output .= $tabsign.'['.$key."] = NO_ATTRIBUTES\n";
+ }
+ else {
+ if ($this->IsBigObject($array[$key])) {
+ $output .= $tabsign.'['.$key.'] = SKIPPED (class: '.get_class($array[$key]).")\n";
+ break;
+ }
+
+ // $attribute_value - default value for this attribute, not used here
+ foreach ($attribute_names as $attribute_name => $attribute_value) {
+ if (is_object($array[$key]->$attribute_name)) {
+ // it is object
+ $object_class = get_class($array[$key]->$attribute_name);
+ if (!in_array($object_class, $this->RecursionStack)) {
+ // object [not in recursion stack]
+ if ($this->IsBigObject($array[$key]->$attribute_name)) {
+ $output .= $tabsign.'['.$attribute_name.'] = SKIPPED (class: '.$object_class.")\n";
+ continue;
+ }
+
+ array_push($this->RecursionStack, $object_class);
+ $output .= $this->print_r($array[$key]->$attribute_name, true, 50, 200);
+ array_pop($this->RecursionStack);
+ }
+ else {
+ // object [in recursion stack]
+ $output .= $tabsign.'['.$attribute_name.'] = *** RECURSION *** (class: '.$object_class.")\n";
+ }
+ }
+ else {
+ $output .= $tabsign.'['.$attribute_name.'] = '.$this->print_r($array[$key]->$attribute_name, true, 50, 200)."\n";
+ }
+ }
+ }
+ break;
+
+ default:
+ $output .= $tabsign.'['.$key.'] unknown = '.gettype($array[$key])."\n";
+ break;
+ }
+ }
+
+ $tab_count--;
+ $output .= str_repeat(' ', $tab_count).")\n";
+
+ if ($first_line) {
+ $first_line = false;
+ $output .= "\n";
+ }
+
+ $tab_count--;
+
+ if ($return_output) {
+ return $output;
+ }
+ else {
+ echo $output;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns only first 200 chars of string, this allow to save amount of data sent to browser
+ *
+ * @param string $string
+ * @return string
+ */
+ function cutStringForHTML($string)
+ {
+ if (strlen($string) > 200) {
+ $string = substr($string,0,50).' ...';
+ }
+ return $string;
+ }
+
+ /**
+ * Format SQL Query using predefined formatting
+ * and highlighting techniques
+ *
+ * @param string $sql
+ * @return string
+ */
+ function formatSQL($sql)
+ {
+ $sql = preg_replace('/(\n|\t| )+/is', ' ', $sql);
+ $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ", $sql);
+ return $this->highlightString($sql);
+ }
+
+ function highlightString($string)
+ {
+ if (!$this->constOn('DBG_USE_HIGHLIGHT')) {
+ return $string;
+ }
+
+ $string = str_replace( Array('\\', '/') , Array('_no_match_string_', '_n_m_s_'), $string);
+ $string = highlight_string('<?php '.$string.'?>', true);
+ $string = str_replace( Array('_no_match_string_', '_n_m_s_'), Array('\\', '/'), $string);
+ return preg_replace('/&lt;\?(.*)php(.*)\?&gt;/Us', '\\2', $string);
+ }
+
+ /**
+ * Determine by php type of browser used to show debugger
+ *
+ * @return bool
+ */
+ function isGecko()
+ {
+ return strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false;
+ }
+
+ /**
+ * Returns link for editing php file (from error) in external editor
+ *
+ * @param string $file filename with path from root folder
+ * @param int $lineno line number in file where error is found
+ * @param string $title text to show on file edit link
+ * @return string
+ */
+ function getFileLink($file, $lineno = 1, $title = '')
+ {
+ if (!$title) {
+ $title = str_replace('/', '\\', $this->getLocalFile($file));
+ }
+
+ if ($this->isGecko()) {
+ return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
+ }
+ else {
+ return '<a href="javascript:$Debugger.editFile(\''.$this->getLocalFile($file).'\', '.$lineno.');" title="'.$file.'">'.$title.'</a>';
+ }
+
+ }
+
+ /**
+ * Converts filepath on server to filepath in mapped DocumentRoot on developer pc
+ *
+ * @param string $remoteFile
+ * @return string
+ */
+ function getLocalFile($remoteFile)
+ {
+ return preg_replace('/^'.preg_quote(DOC_ROOT, '/').'/', DBG_LOCAL_BASE_PATH, $remoteFile, 1);
+ }
+
+ /**
+ * Appends call trace till this method call
+ *
+ */
+ function appendTrace()
+ {
+ $trace = debug_backtrace();
+ array_shift($trace);
+
+ $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
+ }
+
+ function appendMemoryUsage($msg, $used = null)
+ {
+ if (!isset($used)) {
+ $used = round(memory_get_usage() / 1024);
+ }
+ $this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
+ }
+
+ /**
+ * Appends HTML code whithout transformations
+ *
+ * @param string $html
+ */
+ function appendHTML($html)
+ {
+ $this->Data[] = Array('html' => $html, 'debug_type' => 'html');
+ }
+
+ /**
+ * Change debugger info that was already generated before.
+ * Returns true if html was set.
+ *
+ * @param int $index
+ * @param string $html
+ * @param string $type = {'append','prepend','replace'}
+ * @return bool
+ */
+ function setHTMLByIndex($index, $html, $type = 'append')
+ {
+ if (!isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html') {
+ return false;
+ }
+
+ switch ($type) {
+ case 'append':
+ $this->Data[$index]['html'] .= '<br>'.$html;
+ break;
+
+ case 'prepend':
+ $this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
+ break;
+
+ case 'replace':
+ $this->Data[$index]['html'] = $html;
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Move $debugLineCount lines of input from debug output
+ * end to beginning.
+ *
+ * @param int $debugLineCount
+ */
+ function moveToBegin($debugLineCount)
+ {
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $this->Data = array_merge($lines,$this->Data);
+ }
+
+ function moveAfterRow($new_row, $debugLineCount)
+ {
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $rows_before = array_splice($this->Data,0,$new_row,$lines);
+ $this->Data = array_merge($rows_before,$this->Data);
+ }
+
+ function appendRequest()
+ {
+ if (isset($_SERVER['SCRIPT_FILENAME'])) {
+ $script = $_SERVER['SCRIPT_FILENAME'];
+ }
+ else {
+ $script = $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'];
+ }
+
+ $this->appendHTML('ScriptName: <b>'.$this->getFileLink($script, 1, basename($script)).'</b> (<b>'.dirname($script).'</b>)');
+ if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 'yes') {
+ $this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI'].' (QS Length:'.strlen($_SERVER['QUERY_STRING']).')');
+ }
+ $this->appendHTML('<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>: <input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>&nbsp;<button class="button" onclick="return $Debugger.OpenDOMViewer();">Show</button>');
+
+ ob_start();
+ ?>
+ <table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: <?php echo $this->getWindowWidth(); ?>px;">
+ <thead style="font-weight: bold;">
+ <td width="20">Src</td><td>Name</td><td>Value</td>
+ </thead>
+ <?php
+ foreach ($_REQUEST as $key => $value) {
+ if(!is_array($value) && trim($value) == '') {
+ $value = '<b class="debug_error">no value</b>';
+ }
+ else {
+ $value = htmlspecialchars($this->print_r($value, true));
+ }
+
+ $in_cookie = isset($_COOKIE[$key]);
+ $src = isset($_GET[$key]) && !$in_cookie ? 'GE' : (isset($_POST[$key]) && !$in_cookie ? 'PO' : ($in_cookie ? 'CO' : '?') );
+ echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
+ }
+ ?>
+ </table>
+ <?php
+ $this->appendHTML(ob_get_contents());
+ ob_end_clean();
+ }
+
+ /**
+ * Appends php session content to debugger output
+ *
+ */
+ function appendSession()
+ {
+ if (isset($_SESSION) && $_SESSION) {
+ $this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
+ $this->dumpVars($_SESSION);
+ $this->moveToBegin(2);
+ }
+ }
+
+ function profileStart($key, $description = null, $timeStamp = null)
+ {
+ if (!isset($timeStamp)) {
+ $timeStamp = $this->getMoment();
+ }
+ $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data));
+ if (isset($description)) {
+ $this->ProfilerData[$key]['description'] = $description;
+ }
+
+ if (substr($key, 0, 4) == 'sql_') {
+ // append place from what was called
+ $trace_results = debug_backtrace();
+ $trace_count = count($trace_results);
+ $i = 0;
+ while ($i < $trace_count) {
+ $trace_file = basename($trace_results[$i]['file']);
+ if ($trace_file != 'db_connection.php' && $trace_file != 'adodb.inc.php') {
+ break;
+ }
+ $i++;
+ }
+ $this->ProfilerData[$key]['file'] = $trace_file.':'.$trace_results[$i]['line'];
+ unset($trace_results);
+ }
+
+ $this->Data[] = Array('profile_key' => $key, 'debug_type' => 'profiler');
+ }
+
+ function profileFinish($key, $description = null, $timeStamp = null)
+ {
+ if (!isset($timeStamp)) {
+ $timeStamp = $this->getMoment();
+ }
+ $this->ProfilerData[$key]['ends'] = $timeStamp;
+
+ if (isset($description)) {
+ $this->ProfilerData[$key]['description'] = $description;
+ }
+ }
+
+ function profilerAddTotal($total_key, $key = null, $value = null)
+ {
+ if (!isset($this->ProfilerTotals[$total_key])) {
+ $this->ProfilerTotals[$total_key] = 0;
+ $this->ProfilerTotalCount[$total_key] = 0;
+ }
+
+ if (!isset($value)) {
+ $value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
+ }
+
+ if (isset($key)) {
+ $this->ProfilerData[$key]['totalsKey'] = $total_key;
+ $this->ProfilerData[$key]['totalsBefore'] = $this->ProfilerTotals[$total_key];
+ }
+
+ $this->ProfilerTotals[$total_key] += $value;
+ $this->ProfilerTotalCount[$total_key]++;
+ }
+
+ function getMoment()
+ {
+ list($usec, $sec) = explode(' ', microtime());
+ return ((float)$usec + (float)$sec);
+ }
+
+ function generateID()
+ {
+ list($usec, $sec) = explode(' ', microtime());
+
+ $id_part_1 = substr($usec, 4, 4);
+ $id_part_2 = mt_rand(1,9);
+ $id_part_3 = substr($sec, 6, 4);
+ $digit_one = substr($id_part_1, 0, 1);
+ if ($digit_one == 0) {
+ $digit_one = mt_rand(1,9);
+ $id_part_1 = ereg_replace("^0",'',$id_part_1);
+ $id_part_1=$digit_one.$id_part_1;
+ }
+ return $id_part_1.$id_part_2.$id_part_3;
+ }
+
+
+ function getErrorNameByCode($error_code)
+ {
+ $error_map = Array(
+ 'Fatal Error' => Array(E_USER_ERROR),
+ 'Warning' => Array(E_WARNING, E_USER_WARNING),
+ 'Notice' => Array(E_NOTICE, E_USER_NOTICE),
+ );
+
+ if (defined('E_STRICT')) {
+ $error_map['PHP5 Strict'] = Array(E_STRICT);
+ }
+
+ foreach ($error_map as $error_name => $error_codes) {
+ if (in_array($error_code, $error_codes)) {
+ return $error_name;
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Returns profile total key (check against unexisting key too)
+ *
+ * @param string $key
+ * @return int
+ */
+ function getProfilerTotal($key)
+ {
+ if (isset($this->ProfilerTotalCount[$key])) {
+ return (int)$this->ProfilerTotalCount[$key];
+ }
+ return 0;
+ }
+
+ /**
+ * Generates report
+ *
+ */
+ function printReport($returnResult = false, $clean_output_buffer = true)
+ {
+ if ($this->reportDone) {
+ // don't print same report twice (in case if shutdown function used + compression + fatal error)
+ return '';
+ }
+
+ $this->profileFinish('script_runtime');
+ $this->breakOutofBuffering();
+
+ $debugger_start = memory_get_usage();
+
+ if (defined('SPACER_URL')) {
+ $this->dummyImage = SPACER_URL;
+ }
+
+ $this->InitReport(); // set parameters required by AJAX
+
+ // defined here, because user can define this contant while script is running, not event before debugger is started
+ $this->safeDefine('DBG_RAISE_ON_WARNINGS', 0);
+ $this->safeDefine('DBG_TOOLBAR_BUTTONS', 1);
+
+ $this->appendSession(); // show php session if any
+
+ // ensure, that 1st line of debug output always is this one:
+ $top_line = '<table cellspacing="0" cellpadding="0" style="width: '.$this->getWindowWidth().'px; margin: 0px;"><tr><td align="left" width="50%">[<a href="javascript:window.location.reload();">Reload Frame</a>] [<a href="javascript:$Debugger.Toggle(27);">Hide Debugger</a>]</td><td align="right" width="50%">[Current Time: <b>'.date('H:i:s').'</b>] [File Size: <b>#DBG_FILESIZE#</b>]</td></tr></table>';
+
+ $this->appendHTML($top_line);
+ $this->moveToBegin(1);
+
+ if ($this->constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) {
+ // sql query profiling was enabled -> show totals
+ $this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql'].' <b>Number of queries</b>: '.$this->ProfilerTotalCount['sql']);
+ }
+
+ if ($this->constOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes'])) {
+ // included file profiling was enabled -> show totals
+ $this->appendHTML('<b>Included Files Total time:</b> '.$this->ProfilerTotals['includes'].' Number of includes: '.$this->ProfilerTotalCount['includes']);
+ }
+
+ if ($this->constOn('DBG_PROFILE_MEMORY')) {
+ // detailed memory usage reporting by objects was enabled -> show totals
+ $this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects'] / 1024, 2).'Kb');
+ }
+
+ /*if ($this->constOn('DBG_INCLUDED_FILES')) {
+ $files = get_included_files();
+ $this->appendHTML('<b>Included files:</b>');
+ foreach ($files as $file) {
+ $this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file) / 1024, 2).'Kb)');
+ }
+ }*/
+
+ /*if ($this->constOn('DBG_PROFILE_INCLUDES')) {
+ $this->appendHTML('<b>Included files statistics:</b>'.( $this->constOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
+ $totals = Array( 'mem' => 0, 'time' => 0);
+ $totals_configs = Array( 'mem' => 0, 'time' => 0);
+ if (is_array($this->IncludesData['mem'])) {
+ if ( $this->constOn('DBG_SORT_INCLUDES_MEM') ) {
+ array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
+ }
+ foreach ($this->IncludesData['file'] as $key => $file_name) {
+ $this->appendHTML( str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
+ if ($this->IncludesData['level'][$key] == 0) {
+ $totals['mem'] += $this->IncludesData['mem'][$key];
+ $totals['time'] += $this->IncludesData['time'][$key];
+ }
+ else if ($this->IncludesData['level'][$key] == -1) {
+ $totals_configs['mem'] += $this->IncludesData['mem'][$key];
+ $totals_configs['time'] += $this->IncludesData['time'][$key];
+ }
+ }
+ $this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
+ $this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
+ $this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
+ }
+ }*/
+
+ $is_ajax = isset($_GET['ajax']) && $_GET['ajax'] == 'yes';
+ $skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT');
+
+ if (($is_ajax && !constOn('DBG_SKIP_AJAX')) || !$skip_reporting) {
+ $debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt';
+ if (file_exists($debug_file)) unlink($debug_file);
+
+ $i = 0;
+ $fp = fopen($debug_file, 'a');
+ $lineCount = count($this->Data);
+ while ($i < $lineCount) {
+ fwrite($fp, $this->prepareHTML($i).$this->rowSeparator);
+ $i++;
+ }
+ fclose($fp);
+ }
+
+ if ($skip_reporting) {
+ // let debugger write report and then don't output anything
+ $this->reportDone = true;
+ return '';
+ }
+
+ $dbg_path = str_replace(FULL_PATH, '', $this->tempFolder);
+ ob_start();
+ ?>
+ <html><body></body></html>
+ <script type="text/javascript" src="<?php echo $this->baseURL; ?>/debugger.js"></script>
+ <link rel="stylesheet" rev="stylesheet" href="<?php echo $this->baseURL; ?>/debugger.css" type="text/css" media="screen" />
+ <div id="debug_layer" class="debug_layer_container" style="display: none; width: <?php echo DBG_WINDOW_WIDTH; ?>px;">
+ <div class="debug_layer" style="width: <?php echo $this->getWindowWidth(); ?>px;">
+ <table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table" style="width: <?php echo $this->getWindowWidth(); ?>px;" align="left">
+ <tbody id="debug_table"></tbody>
+ </table>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ var $Debugger = new Debugger(<?php echo "'".$this->rowSeparator."', ".$this->getProfilerTotal('error_handling').', '.($this->IsFatalError ? 'true' : 'false').', '.$this->getProfilerTotal('sql'); ?>);
+ $Debugger.DOMViewerURL = '<?php echo constant('DBG_DOMVIEWER'); ?>';
+ $Debugger.EditorPath = '<?php echo defined('DBG_EDITOR') ? addslashes(DBG_EDITOR) : '' ?>';
+ $Debugger.DebugURL = '<?php echo $this->baseURL.'/debugger_responce.php?sid='.$this->rowSeparator.'&path='.urlencode($dbg_path); ?>';
+
+ <?php
+ if ($this->IsFatalError || DBG_RAISE_ON_WARNINGS) {
+ echo '$Debugger.Toggle();';
+ }
+ if (DBG_TOOLBAR_BUTTONS) {
+ echo '$Debugger.AddToolbar("$Debugger");';
+ }
+ ?>
+ window.focus();
+ </script>
+ <?php
+ if (!isset($this->ProfilerTotals['error_handling'])) {
+ $memory_used = $debugger_start;
+ $this->ProfilerTotalCount['error_handling'] = 0;
+ }
+ else {
+ $memory_used = $debugger_start - $this->ProfilerTotals['error_handling'];
+ }
+
+ if ($returnResult) {
+ $ret = ob_get_contents();
+ if ($clean_output_buffer) {
+ ob_end_clean();
+ }
+ $ret .= $this->getShortReport($memory_used);
+
+ $this->reportDone = true;
+ return $ret;
+ }
+ else {
+ if (!$this->constOn('DBG_HIDE_FULL_REPORT')) {
+ $this->breakOutofBuffering();
+ }
+ elseif ($clean_output_buffer) {
+ ob_clean();
+ }
+ echo $this->getShortReport($memory_used);
+
+ $this->reportDone = true;
+ }
+ }
+
+ /**
+ * Format's memory usage report by debugger
+ *
+ * @return string
+ * @access private
+ */
+ function getShortReport($memory_used)
+ {
+ $info = Array(
+ 'Script Runtime' => 'PROFILE:script_runtime',
+ '-' => 'SEP:-',
+ 'Notice / Warning' => 'PROFILE_TC:error_handling',
+ 'SQLs Count' => 'PROFILE_TC:sql',
+ );
+
+ $ret = '<tr><td>Application:</td><td><b>'.$this->formatSize($memory_used).'</b> ('.$memory_used.')</td></tr>';
+ foreach ($info as $title => $value_key) {
+ list ($record_type, $record_data) = explode(':', $value_key, 2);
+ switch ($record_type) {
+ case 'PROFILE': // profiler totals value
+ $Data =& $this->ProfilerData[$record_data];
+ $profile_time = ($Data['ends'] - $Data['begins']); // in seconds
+ $ret .= '<tr><td>'.$title.':</td><td><b>'.sprintf('%.5f', $profile_time).' s</b></td></tr>';
+ break;
+
+ case 'PROFILE_TC': // profile totals record count
+ $record_cell = '<td>';
+ if ($record_data == 'error_handling' && $this->ProfilerTotalCount[$record_data] > 0) {
+ $record_cell = '<td class="debug_error">';
+ }
+ $ret .= '<tr>'.$record_cell.$title.':</td>'.$record_cell.'<b>'.$this->ProfilerTotalCount[$record_data].'</b></td></tr>';
+ break;
+
+ case 'SEP':
+ $ret .= '<tr><td colspan="2" style="height: 1px; background-color: #000000; padding: 0px;"><img src="'.$this->dummyImage.'" height="1" alt=""/></td></tr>';
+ break;
+ }
+ }
+
+ return '<br /><table class="dbg_stats_table"><tr><td style="border-color: #FFFFFF;"><table class="dbg_stats_table" align="left">'.$ret.'</table></td></tr></table>';
+ }
+
+ /**
+ * User-defined error handler
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $errcontext
+ */
+ function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
+ {
+ $this->ProfilerData['error_handling']['begins'] = memory_get_usage();
+
+ $errorType = $this->getErrorNameByCode($errno);
+ if (!$errorType) {
+ trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
+ return false;
+ }
+
+ if ($this->constOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT)) return;
+
+ if (preg_match('/(.*)#([\d]+)$/', $errstr, $rets) ) {
+ // replace short message with long one (due triger_error limitations on message size)
+ $long_id = $rets[2];
+ $errstr = $this->longErrors[$long_id];
+ unset($this->longErrors[$long_id]);
+ }
+
+ if (strpos($errfile,'eval()\'d code') !== false) {
+ $errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
+ $tmpStr = $errfile;
+ $pos = strpos($tmpStr,'(');
+ $errfile = substr($tmpStr, 0, $pos);
+ $pos++;
+ $errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
+ }
+
+ $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
+ $this->ProfilerData['error_handling']['ends'] = memory_get_usage();
+ $this->profilerAddTotal('error_handling', 'error_handling');
+ if (substr($errorType, 0, 5) == 'Fatal') {
+ $this->IsFatalError = true;
+ // append debugger report to data in buffer & clean buffer afterwards
+ die( $this->breakOutofBuffering(false) . $this->printReport(true) );
+ }
+ }
+
+ function breakOutofBuffering($flush = true)
+ {
+ $buffer_content = Array();
+ while (ob_get_level()) {
+ $buffer_content[] = ob_get_clean();
+ }
+ $ret = implode('', array_reverse($buffer_content));
+ if ($flush) {
+ echo $ret;
+ flush();
+ }
+ return $ret;
+ }
+
+ function saveToFile($msg)
+ {
+ $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
+ fwrite($fp, $msg."\n");
+ fclose($fp);
+ }
+
+ /**
+ * Formats file/memory size in nice way
+ *
+ * @param int $bytes
+ * @return string
+ * @access public
+ */
+ function formatSize($bytes)
+ {
+ if ($bytes >= 1099511627776) {
+ $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
+ $suffix = "TB";
+ } elseif ($bytes >= 1073741824) {
+ $return = round($bytes / 1024 / 1024 / 1024, 2);
+ $suffix = "GB";
+ } elseif ($bytes >= 1048576) {
+ $return = round($bytes / 1024 / 1024, 2);
+ $suffix = "MB";
+ } elseif ($bytes >= 1024) {
+ $return = round($bytes / 1024, 2);
+ $suffix = "KB";
+ } else {
+ $return = $bytes;
+ $suffix = "Byte";
+ }
+ $return .= ' '.$suffix;
+ return $return;
+ }
+
+ function printConstants($constants)
+ {
+ if (!is_array($constants)) {
+ $constants = explode(',', $constants);
+ }
+ $contant_tpl = '<tr><td>%s</td><td><b>%s</b></td></tr>';
+ $ret = '<table class="dbg_flat_table" style="width: '.$this->getWindowWidth().'px;">';
+ foreach ($constants as $constant_name) {
+ $ret .= sprintf($contant_tpl, $constant_name, constant($constant_name));
+ }
+ $ret .= '</table>';
+ $this->appendHTML($ret);
+ }
+
+ function AttachToApplication() {
+ if (!$this->constOn('DBG_HANDLE_ERRORS')) return true;
+
+ if (class_exists('kApplication')) {
+ restore_error_handler();
+ $application =& kApplication::Instance();
+ $application->Debugger =& $this;
+ $application->errorHandlers[] = Array(&$this, 'saveError');
+ }
+ else {
+ set_error_handler(Array(&$this, 'saveError'));
+ }
+ }
+ }
+
+ if (!function_exists('memory_get_usage')) {
+ function memory_get_usage(){ return -1; }
+ }
+
+ if (!Debugger::constOn('DBG_ZEND_PRESENT')) {
+ $debugger = new Debugger();
+ }
+
+ if (Debugger::constOn('DBG_USE_SHUTDOWN_FUNC')) {
+ register_shutdown_function( Array(&$debugger, 'printReport') );
+ }
+ }
+?>
\ No newline at end of file
Property changes on: branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/debugger.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.65
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/unit_config_reader.php
===================================================================
--- branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/unit_config_reader.php (nonexistent)
+++ branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/unit_config_reader.php (revision 7660)
@@ -0,0 +1,669 @@
+<?php
+
+class kUnitConfigReader extends kBase {
+
+ /**
+ * Configs readed
+ *
+ * @var Array
+ * @access private
+ */
+ var $configData=Array();
+ var $configFiles=Array();
+
+ var $CacheExpired = false;
+
+ var $prefixFiles = array();
+
+ var $ProcessAllConfigs = false;
+ var $FinalStage = false;
+ var $StoreCache = false;
+ var $AfterConfigProcessed = array();
+
+ /**
+ * Scan kernel and user classes
+ * for available configs
+ *
+ * @access protected
+ */
+ function Init($prefix,$special)
+ {
+ parent::Init($prefix,$special);
+ }
+
+ function CacheParsedData()
+ {
+ $event_manager =& $this->Application->recallObject('EventManager');
+ $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
+
+ $config_vars = Array(
+ 'SessionTimeout',
+ 'SessionCookieName',
+ 'SessionReferrerCheck',
+ 'CookieSessions',
+ 'UseCronForRegularEvent',
+ 'User_GuestGroup',
+ 'User_LoggedInGroup',
+ 'SessionTimeout',
+ 'UseModRewrite',
+ 'UseOutputCompression',
+ 'OutputCompressionLevel',
+ );
+
+ foreach ($config_vars as $var) {
+ $this->Application->ConfigValue($var);
+ }
+
+ $cache = Array(
+ 'Factory.Files' => $this->Application->Factory->Files,
+ 'Factory.realClasses' => $this->Application->Factory->realClasses,
+ 'Factory.Dependencies' => $this->Application->Factory->Dependencies,
+ 'ConfigReader.prefixFiles' => $this->prefixFiles,
+ 'EventManager.buildEvents' => $event_manager->buildEvents,
+ 'EventManager.beforeRegularEvents' => $event_manager->beforeRegularEvents,
+ 'EventManager.afterRegularEvents' => $event_manager->afterRegularEvents,
+ 'EventManager.beforeHooks' => $event_manager->beforeHooks,
+ 'EventManager.afterHooks' => $event_manager->afterHooks,
+ 'TagsAggregator.data' => $aggregator->_Array,
+
+ // the following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
+ 'Application.Caches.ConfigVariables' => $this->Application->Caches['ConfigVariables'],
+ 'Application.ConfigCacheIds' => $this->Application->ConfigCacheIds,
+ 'Application.ConfigHash' => $this->Application->ConfigHash,
+ 'Application.ReplacementTemplates' => $this->Application->ReplacementTemplates,
+ 'Application.ModuleInfo' => $this->Application->ModuleInfo,
+ );
+
+ $conn =& $this->Application->GetADODBConnection();
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("configs_parsed", '.$conn->qstr(serialize($cache)).', '.adodb_mktime().')');
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_files", '.$conn->qstr(serialize($this->configFiles)).', '.adodb_mktime().')');
+ unset($this->configFiles);
+ }
+
+ function RestoreParsedData()
+ {
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"');
+ if ($data && $data['Cached'] > 0 ) {
+ $cache = unserialize($data['Data']);
+ $this->Application->Factory->Files = $cache['Factory.Files'];
+ $this->Application->Factory->realClasses = $cache['Factory.realClasses'];
+ $this->Application->Factory->Dependencies = $cache['Factory.Dependencies'];
+ $this->prefixFiles = $cache['ConfigReader.prefixFiles'];
+
+ $event_manager =& $this->Application->recallObject('EventManager');
+ $event_manager->buildEvents = $cache['EventManager.buildEvents'];
+ $event_manager->beforeRegularEvents = $cache['EventManager.beforeRegularEvents'];
+ $event_manager->afterRegularEvents = $cache['EventManager.afterRegularEvents'];
+ $event_manager->beforeHooks = $cache['EventManager.beforeHooks'];
+ $event_manager->afterHooks = $cache['EventManager.afterHooks'];
+
+ $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
+ $aggregator->_Array = $cache['TagsAggregator.data'];
+
+ $this->Application->ConfigHash = $cache['Application.ConfigHash'];
+
+ $this->Application->Caches['ConfigVariables'] = $cache['Application.ConfigCacheIds'];
+ $this->Application->ConfigCacheIds = $cache['Application.ConfigCacheIds'];
+
+ $this->Application->ReplacementTemplates = $cache['Application.ReplacementTemplates'];
+
+ $this->Application->ModuleInfo = $cache['Application.ModuleInfo'];
+
+ return true;
+
+ }
+ else return false;
+ }
+
+ function ResetParsedData($include_sections = false)
+ {
+ $conn =& $this->Application->GetADODBConnection();
+ $conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"');
+
+ if ($include_sections) {
+ $conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"');
+ }
+ }
+
+ function scanModules($folderPath, $cache = true)
+ {
+ if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) {
+ // disable config caching during installation
+ $cache = false;
+ }
+
+ if ($cache) {
+ $restored = $this->RestoreParsedData();
+ if ($restored) return;
+ }
+
+ $this->ProcessAllConfigs = true;
+
+ $this->includeConfigFiles($folderPath, $cache);
+ $this->ParseConfigs();
+
+ // tell AfterConfigRead to store cache if neede
+ // can't store it here beacuse AfterConfigRead needs ability to change config data
+ $this->StoreCache = $cache;
+ }
+
+ function findConfigFiles($folderPath)
+ {
+ // if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted
+ $reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/';
+ $folderPath = preg_replace($reg_exp, '', $folderPath, 1); // this make sense, since $folderPath may NOT contain FULL_PATH
+
+ $fh = opendir(FULL_PATH.$folderPath);
+ while (($sub_folder = readdir($fh))) {
+ $full_path = FULL_PATH.$folderPath.'/'.$sub_folder;
+ if ($this->isDir($full_path)) {
+ //the following is to exclude OLD, not removed files when upgrading to 'core'
+ if (preg_match('/^\/kernel\/kernel4\//', $folderPath) || ($folderPath == '/kernel/units' && file_exists(FULL_PATH.$this->getConfigName('/core/units/'.$sub_folder)))) {
+ continue;
+ }
+ if (file_exists(FULL_PATH.$this->getConfigName($folderPath.'/'.$sub_folder))) {
+ $this->configFiles[] = $this->getConfigName($folderPath.'/'.$sub_folder);
+ }
+ $this->findConfigFiles($full_path);
+
+ // if (filemtime($full_path) > $cached) { }
+
+ }
+ }
+ }
+
+ function includeConfigFiles($folderPath, $cache = true)
+ {
+ $this->Application->refreshModuleInfo();
+
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_files"');
+ if ($cache && $data) {
+ $this->configFiles = unserialize($data['Data']);
+ shuffle($this->configFiles);
+ $files_cached = $data['Cached'];
+ }
+ else {
+ $this->findConfigFiles($folderPath); // search from base directory
+ }
+
+ foreach ($this->configFiles as $filename)
+ {
+ $prefix = $this->PreloadConfigFile($filename);
+ if (!$prefix) {
+ trigger_error('Prefix not defined in config file '.$filename, E_USER_ERROR);
+ }
+ }
+ }
+
+ /**
+ * Process all read config files - called ONLY when there is no cache!
+ *
+ */
+ function ParseConfigs()
+ {
+ $prioritized_configs = array();
+ foreach ($this->configData as $prefix => $config) {
+ if (isset($config['ConfigPriority'])) {
+ $prioritized_configs[$prefix] = $config['ConfigPriority'];
+ continue;
+ }
+ $this->parseConfig($prefix);
+ }
+
+ foreach ($this->configData as $prefix => $config) {
+ $this->ProcessDependencies($prefix);
+ $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
+ $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
+ }
+
+ asort($prioritized_configs);
+ foreach ($prioritized_configs as $prefix => $priority) {
+ $this->parseConfig($prefix);
+ }
+ }
+
+ function AfterConfigRead()
+ {
+// if (!$this->ProcessAllConfigs) return ;
+ $this->FinalStage = true;
+ foreach ($this->configData as $prefix => $config) {
+ if (in_array($prefix, $this->AfterConfigProcessed)) continue;
+ $this->Application->HandleEvent( new kEvent($prefix.':OnAfterConfigRead') );
+ $this->AfterConfigProcessed[] = $prefix;
+ }
+ if ($this->StoreCache) $this->CacheParsedData();
+ }
+
+ /**
+ * Register nessasary classes
+ * This method should only process the data which is cached!
+ *
+ * @param string $prefix
+ * @access private
+ */
+ function parseConfig($prefix)
+ {
+ $config =& $this->configData[$prefix];
+ $event_manager =& $this->Application->recallObject('EventManager');
+
+ $register_classes = getArrayValue($config,'RegisterClasses');
+ if (!$register_classes) $register_classes = Array();
+ $class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass');
+ foreach($class_params as $param_name)
+ {
+ if ( !(isset($config[$param_name]) ) ) continue;
+ $config[$param_name]['pseudo'] = $this->getPrefixByParamName($param_name,$prefix);
+ $register_classes[] = $config[$param_name];
+ }
+
+ foreach($register_classes as $class_info)
+ {
+ $require_classes = getArrayValue($class_info, 'require_classes');
+ if ($require_classes) {
+ if (!is_array($require_classes)) {
+ $require_classes = array($require_classes);
+ }
+ if (!isset($config['_Dependencies'][$class_info['class']])) {
+ $config['_Dependencies'][$class_info['class']] = array();
+ }
+ $config['_Dependencies'][$class_info['class']] = array_merge($config['_Dependencies'][$class_info['class']], $require_classes);
+ }
+ $this->Application->registerClass(
+ $class_info['class'],
+ $config['BasePath'].'/'.$class_info['file'],
+ $class_info['pseudo']/*,
+ getArrayValue($class_info, 'require_classes')*/
+ );
+ if (getArrayValue($class_info, 'build_event')) {
+ $event_manager->registerBuildEvent($class_info['pseudo'],$class_info['build_event']);
+ }
+ }
+
+ $regular_events = getArrayValue($config, 'RegularEvents');
+ if($regular_events)
+ {
+ foreach($regular_events as $short_name => $regular_event_info)
+ {
+ $event_manager->registerRegularEvent( $short_name, $config['Prefix'].':'.$regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'] );
+ }
+ }
+
+ $hooks = getArrayValue($config, 'Hooks');
+ if (is_array($hooks) && count($hooks) > 0) {
+ foreach ($hooks as $hook) {
+ if (isset($config['ParentPrefix']) && $hook['HookToPrefix'] == $config['ParentPrefix']) {
+ trigger_error('Depricated Hook Usage [prefix: <b>'.$config['Prefix'].'</b>; do_prefix: <b>'.$hook['DoPrefix'].'</b>] use <b>#PARENT#</b> as <b>HookToPrefix</b> value, where HookToPrefix is same as ParentPrefix', E_USER_NOTICE);
+ }
+
+ if ($hook['HookToPrefix'] == '') {
+ $hook['HookToPrefix'] = $config['Prefix']; // new: set hooktoprefix to current prefix if not set
+ }
+
+ if (isset($config['ParentPrefix'])) {
+ // new: allow to set hook to parent prefix what ever it is
+ if ($hook['HookToPrefix'] == '#PARENT#') {
+ $hook['HookToPrefix'] = $config['ParentPrefix'];
+ }
+
+ if ($hook['DoPrefix'] == '#PARENT#') {
+ $hook['DoPrefix'] = $config['ParentPrefix'];
+ }
+ }
+ elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') {
+ continue; // we need parent prefix but it's not set !
+ }
+
+ $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
+
+ if ( !is_array($hook['HookToEvent']) ) {
+ $hook_events = Array( $hook['HookToEvent'] );
+ }
+ else {
+ $hook_events = $hook['HookToEvent'];
+ }
+ foreach ($hook_events as $hook_event) {
+ $this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']);
+ }
+ }
+ }
+
+ if ( is_array(getArrayValue($config, 'AggregateTags')) ) {
+ foreach ($config['AggregateTags'] as $aggregate_tag) {
+ if (isset($config['ParentPrefix'])) {
+ if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) {
+ trigger_error('Depricated Aggregate Tag Usage [prefix: <b>'.$config['Prefix'].'</b>; AggregateTo: <b>'.$aggregate_tag['AggregateTo'].'</b>] use <b>#PARENT#</b> as <b>AggregateTo</b> value, where AggregateTo is same as ParentPrefix', E_USER_NOTICE);
+ }
+
+ if ($aggregate_tag['AggregateTo'] == '#PARENT#') {
+ $aggregate_tag['AggregateTo'] = $config['ParentPrefix'];
+ }
+ }
+ $aggregate_tag['LocalPrefix'] = $config['Prefix'];
+ $this->Application->registerAggregateTag($aggregate_tag);
+ }
+ }
+
+ if (isset($config['ReplacementTemplates']) && $config['ReplacementTemplates']) {
+ // replacement templates defined in this config
+ $this->Application->ReplacementTemplates = array_merge_recursive2($this->Application->ReplacementTemplates, $config['ReplacementTemplates']);
+ }
+
+ if ( $this->Application->isDebugMode() && constOn('DBG_VALIDATE_CONFIGS') && isset($config['TableName']) )
+ {
+ global $debugger;
+ $tablename = $config['TableName'];
+
+ $conn =& $this->Application->GetADODBConnection();
+ $res = $conn->Query("DESCRIBE $tablename");
+
+ foreach ($res as $field) {
+ $f_name = $field['Field'];
+ if (getArrayValue($config, 'Fields')) {
+ if ( !array_key_exists ($f_name, $config['Fields']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Field $f_name exists in the database, but is not defined in config file for prefix <b>".$config['Prefix']."</b>!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ else {
+ $options = $config['Fields'][$f_name];
+ if ($field['Null'] == '') {
+ if ( $f_name != $config['IDField'] && !isset($options['not_null']) && !isset($options['required']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Error: </b>Field $f_name in config for prefix <b>".$config['Prefix']."</b> is NOT NULL in the database, but is not configured as not_null or required!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ if ( isset($options['not_null']) && !isset($options['default']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Error: </b>Field $f_name in config for prefix <b>".$config['Prefix']."</b> is described as NOT NULL, but does not have DEFAULT value!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ function ProcessDependencies($prefix)
+ {
+ $config =& $this->configData[$prefix];
+ $deps = getArrayValue($config, '_Dependencies');
+ if (!$deps) return ;
+
+ foreach ($deps as $real_class => $requires) {
+ foreach ($requires as $class) {
+ $this->Application->registerDependency($real_class, $class);
+ }
+ }
+ unset($config['_Dependencies']);
+ }
+
+ function postProcessConfig($prefix, $config_key, $dst_prefix_var)
+ {
+ $main_config =& $this->configData[$prefix];
+ $sub_configs = getArrayValue($main_config, $config_key);
+ if (!$sub_configs) {
+ return array();
+ }
+ unset($main_config[$config_key]);
+
+ $processed = array();
+ foreach ($sub_configs as $sub_prefix => $sub_config) {
+ if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) {
+ $this->loadConfig($sub_prefix);
+ }
+ $sub_config['Prefix'] = $sub_prefix;
+ $this->configData[$sub_prefix] = array_merge_recursive2($this->configData[$$dst_prefix_var], $sub_config);
+
+ // when merging empty array to non-empty results non-empty array, but empty is required
+ foreach ($sub_config as $sub_key => $sub_value) {
+ if (!$sub_value) {
+ unset($this->configData[$sub_prefix][$sub_key]);
+ }
+ }
+ if ($config_key == 'Clones') {
+ $this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix];
+ }
+
+ $this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var);
+ if ($config_key == 'AggregateConfigs') {
+ $processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed);
+ }
+ elseif ($this->ProcessAllConfigs) {
+ $this->parseConfig($sub_prefix);
+ }
+ array_push($processed, $sub_prefix);
+ }
+
+ if (!$prefix) {
+ // configs, that used only for cloning & not used ifself
+ unset($this->configData[$prefix]);
+ }
+ return array_unique($processed);
+ }
+
+ function PreloadConfigFile($filename)
+ {
+ $config_found = file_exists(FULL_PATH.$filename) && $this->configAllowed($filename);
+
+ if( defined('DEBUG_MODE') && DEBUG_MODE && constOn('DBG_PROFILE_INCLUDES') )
+ {
+ if ( in_array($filename, get_required_files()) ) return;
+ global $debugger;
+ if($config_found) {
+ $file = FULL_PATH.$filename;
+ $debugger->ProfileStart('inc_'.crc32($file), $file);
+ include_once($file);
+ $debugger->ProfileFinish('inc_'.crc32($file));
+ $debugger->profilerAddTotal('includes', 'inc_'.crc32($file));
+ }
+ }
+ else
+ {
+ if ($config_found) include_once(FULL_PATH.$filename);
+ }
+
+ if ($config_found) {
+ if (isset($config) && $config) {
+ // config file is included for 1st time -> save it's content for future processing
+ $prefix = isset($config['Prefix']) ? $config['Prefix'] : '';
+
+ preg_match('/\/(.*)\//U', $filename, $rets);
+ $config['ModuleFolder'] = $rets[1];
+ $config['BasePath'] = dirname(FULL_PATH.$filename);
+ if (isset($config['AdminTemplatePath'])) {
+ // append template base folder for admin templates path of this prefix
+ $module_templates = $rets[1] == 'core' ? 'in-portal/' : $rets[1].'/';
+ $config['AdminTemplatePath'] = $module_templates.$config['AdminTemplatePath'];
+ }
+ $this->configData[$prefix] = $config;
+ $this->prefixFiles[$prefix] = $filename;
+ return $prefix;
+ }
+ elseif ($prefix = array_search($filename, $this->prefixFiles)) {
+ // attempt is made to include config file twice or more, but include_once prevents that,
+ // but file exists on hdd, then it is already saved to all required arrays, just return it's prefix
+ return $prefix;
+ }
+ }
+ return 'dummy';
+ }
+
+ function loadConfig($prefix)
+ {
+ if (!isset($this->prefixFiles[$prefix])) {
+ if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
+ trigger_error('Configuration file for prefix <b>'.$prefix.'</b> is unknown', E_USER_ERROR);
+ return ;
+ }
+ $file = $this->prefixFiles[$prefix];
+ $prefix = $this->PreloadConfigFile($file);
+
+ $clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
+ $clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones);
+
+ if ($this->FinalStage) {
+ array_unshift($clones, $prefix);
+ $clones = array_unique($clones);
+ foreach ($clones as $a_prefix) {
+ $this->Application->HandleEvent( new kEvent($a_prefix.':OnAfterConfigRead') );
+ }
+ }
+ }
+
+ /**
+ * Reads unit (specified by $prefix)
+ * option specified by $option
+ *
+ * @param string $prefix
+ * @param string $name
+ * @param mixed $default
+ * @return string
+ * @access public
+ */
+ function getUnitOption($prefix, $name, $default = false)
+ {
+ if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
+ if (!isset($this->configData[$rets[1]])) {
+ $this->loadConfig($rets[1]);
+ }
+ $ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false;
+// $ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]);
+ }
+ else {
+ if (!isset($this->configData[$prefix])) {
+ $this->loadConfig($prefix);
+ }
+ $ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false;
+// $ret = getArrayValue($this->configData, $prefix, $name);
+ }
+ return $ret === false ? $default : $ret;
+ }
+
+ /**
+ * Read all unit with $prefix options
+ *
+ * @param string $prefix
+ * @return Array
+ * @access public
+ */
+ function getUnitOptions($prefix)
+ {
+ if (!isset($this->configData[$prefix])) {
+ $this->loadConfig($prefix);
+ }
+
+ return $this->configData[$prefix];
+ }
+
+ /**
+ * Set's new unit option value
+ *
+ * @param string $prefix
+ * @param string $name
+ * @param string $value
+ * @access public
+ */
+ function setUnitOption($prefix, $name, $value)
+ {
+ if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
+ if (!isset($this->configData[$rets[1]])) {
+ $this->loadConfig($rets[1]);
+ }
+ $this->configData[$rets[1]][$name][$rets[2]] = $value;
+ }
+ else {
+ if (!isset($this->configData[$prefix])) {
+ $this->loadConfig($prefix);
+ }
+ $this->configData[$prefix][$name] = $value;
+ }
+
+ }
+
+ function getPrefixByParamName($paramName,$prefix)
+ {
+ $pseudo_class_map=Array(
+ 'ItemClass'=>'%s',
+ 'ListClass'=>'%s_List',
+ 'EventHandlerClass'=>'%s_EventHandler',
+ 'TagProcessorClass'=>'%s_TagProcessor'
+ );
+ return sprintf($pseudo_class_map[$paramName],$prefix);
+ }
+
+ /**
+ * Get's config file name based
+ * on folder name supplied
+ *
+ * @param string $folderPath
+ * @return string
+ * @access private
+ */
+ function getConfigName($folderPath)
+ {
+ return $folderPath.'/'.basename($folderPath).'_config.php';
+ }
+
+ /**
+ * is_dir ajustment to work with
+ * directory listings too
+ *
+ * @param string $folderPath
+ * @return bool
+ * @access private
+ */
+ function isDir($folderPath)
+ {
+ $base_name = basename($folderPath);
+ $ret = !( $base_name == '.' || $base_name == '..' );
+ return $ret && is_dir($folderPath);
+ }
+
+ /**
+ * Checks if config file is allowed for includion (if module of config is installed)
+ *
+ * @param string $config_path relative path from in-portal directory
+ */
+ function configAllowed($config_path)
+ {
+ if (defined('IS_INSTALL') && IS_INSTALL) {
+ // at installation start no modules in db and kernel configs could not be read
+ return true;
+ }
+
+ if (preg_match('#/plugins/|/core|/proj-|/custom/#', $config_path)) {
+ return true;
+ }
+
+ $module_found = false;
+ if (!$this->Application->ModuleInfo) return false;
+
+ foreach($this->Application->ModuleInfo as $module_name => $module_info)
+ {
+ $module_path = '/'.$module_info['Path'];
+ if (preg_match('/^'.preg_quote($module_path, '/').'/', $config_path)) {
+ // if (substr($config_path, 0, strlen($module_path)) == $module_path) {
+ // config file path starts with module folder path
+ $module_found = true;
+ break;
+ }
+ }
+ return $module_found;
+ }
+
+ /**
+ * Returns true if config exists and is allowed for reading
+ *
+ * @param string $prefix
+ * @return bool
+ */
+ function prefixRegistred($prefix)
+ {
+ return isset($this->prefixFiles[$prefix]) ? true : false;
+ }
+
+}
+
+
+?>
\ No newline at end of file
Property changes on: branches/unlabeled/unlabeled-1.65.2/core/kernel/utility/unit_config_reader.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.65
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property

Event Timeline