Index: trunk/kernel/include/debugger.php =================================================================== --- trunk/kernel/include/debugger.php (revision 2677) +++ trunk/kernel/include/debugger.php (revision 2678) @@ -1,984 +1,1007 @@ <?php if( !class_exists('Debugger') ) { function dbg_ConstOn($const_name) { return defined($const_name) && constant($const_name); } function dbg_safeDefine($const_name,$const_value) { if(!defined($const_name)) define($const_name,$const_value); } unset($_REQUEST['debug_host']); // 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_' ) { dbg_safeDefine('DBG_ZEND_PRESENT', 1); break; } } dbg_safeDefine('DBG_ZEND_PRESENT',0); // set default values for debugger constants $dbg_constMap=Array('DBG_OPTIONS'=>0, 'DBG_USE_HIGHLIGHT'=>1, 'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1, 'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1, 'DBG_IGNORE_STRICT_ERRORS'=>1, 'DBG_DOMVIEWER'=>'/temp/domviewer.html', 'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack 'DBG_LOCAL_BASE_PATH'=>'w:'); foreach($dbg_constMap as $dbg_constName=>$dbg_constValue) { dbg_safeDefine($dbg_constName,$dbg_constValue); } // only for IE, in case if no windows php script editor defined /*if(!defined('WINDOWS_EDITOR')) { $dbg_editor = 0; $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L'); $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F'); define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']); unset($dbg_editors,$dbg_editor); }*/ class Debugger { /** * Debugger data for building report * * @var Array */ var $Data = Array(); var $ProfilerData = Array(); var $ProfilerTotals = Array(); var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results var $TraceNextError=false; var $Options = 0; var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2, 'output_buffer' => 4, 'highlight_output' => 8); var $longErrors=Array(); /** * Amount of memory used by debugger itself * * @var Array * @access private */ var $memoryUsage=Array(); var $IncludesData=Array(); var $IncludeLevel=0; function Debugger() { $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4'); $this->profileStart('script_runtime', 'Script runtime'); ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1); $this->memoryUsage['error_handling']=0; // memory amount used by error handler $this->appendRequest(); } function initOptions() { } function mapLongError($msg) { $key=$this->generateID(); $this->longErrors[$key]=$msg; return $key; } function setOption($name,$value) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>'); if($value) { $this->Options|=$this->OptionsMap[$name]; } else { $this->Options=$this->Options&~$this->OptionsMap[$name]; } } function getOption($name) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>'); return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name]; } /** * Set's flag, that next error that occurs will * be prepended by backtrace results * */ function traceNext() { $this->TraceNextError=true; } 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( print_r($Data['value'], true) ); break; case 'trace': ini_set('memory_limit','500M'); $trace =& $Data['trace']; //return 'sorry'; //return $this->highlightString(print_r($trace,true)); $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']; - $ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name); + $args_link = $has_args ? '<a href="javascript: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'; } // ensure parameter value is not longer then 200 symbols + if($has_args) + { $this->processTraceArguments($traceRec['args']); $args = $this->highlightString(print_r($traceRec['args'], true)); $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 return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s'; break; default: return 'incorrect debug data'; break; } } + function isApplication(&$object) + { + $app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication'; + return get_class($object) == $app_class; + } + function processTraceArguments(&$traceArgs) { if(!$traceArgs) return ''; - foreach ($traceArgs as $argID => $argValue) + + $array_keys = array_keys($traceArgs); + foreach($array_keys as $argID) { + $argValue =& $traceArgs[$argID]; + if( is_array($argValue) || is_object($argValue) ) { if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) ) { - if( get_class($argValue) == 'kfactory' || get_class($argValue) == 'debugger' ) continue; + array_push($this->RecursionStack, get_class($argValue)); + + if( get_class($argValue) == 'kfactory' || $this->isApplication($argValue) || get_class($argValue) == 'templateparser' ) + { + $argValue = null; + continue; + } // object & not in stack - ok - array_push($this->RecursionStack, get_class($argValue)); settype($argValue,'array'); $this->processTraceArguments($argValue); array_pop($this->RecursionStack); } elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) ) { // object & in stack - recursion $traceArgs[$argID] = '**** RECURSION ***'; } else { // normal array here $this->processTraceArguments($argValue); } } else { $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]); } } } 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( dbg_ConstOn('DBG_USE_HIGHLIGHT') ) { $string = str_replace('\\','_no_match_string_',$string); $string = highlight_string('<?php '.$string.'?>', true); $string = str_replace('_no_match_string_','\\',$string); return preg_replace('/<\?(.*)php (.*)\?>/s','$2',$string); } else { return $string; } } function getFileLink($file, $lineno = 1, $title = '') { if(!$title) $title = $file; $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false; if($is_mozilla) { return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>'; } else { return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>'; } } function getLocalFile($remoteFile) { return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile); } 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'); } 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() { $script = $_SERVER['SCRIPT_FILENAME']; $this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)'); $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;"/> <button class="button" onclick="return dbg_OpenDOMViewer();">Show</button>'); ob_start(); ?> <table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: 100%;"> <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(print_r($value, true)); } $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') ); echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>'; } ?> </table> <?php $this->appendHTML( ob_get_contents() ); ob_end_clean(); } 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) { $timeStamp = $this->getMoment(); $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description); $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler'); } function profileFinish($key) { $this->ProfilerData[$key]['ends'] = $this->getMoment(); } function profilerAddTotal($total_key, $key=null, $value=null) { if (!isset($this->ProfilerTotals[$total_key])) { $this->ProfilerTotals[$total_key] = 0; } if (!isset($value)) { $value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins']; } $this->ProfilerTotals[$total_key] += $value; } 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($errorCode) { switch($errorCode) { case E_USER_ERROR: return 'Fatal Error'; break; case E_WARNING: case E_USER_WARNING: return 'Warning'; break; case E_NOTICE: case E_USER_NOTICE: return 'Notice'; break; case E_STRICT: return 'PHP5 Strict'; break; default: return ''; break; } } /** * Generates report * */ function printReport($returnResult = false) { if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return; $this->profileFinish('script_runtime'); if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return; dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0); dbg_safeDefine('DBG_WINDOW_WIDTH', 700); $this->memoryUsage['debugger_start']=memory_get_usage(); // show php session if any $this->appendSession(); // ensure, that 1st line of debug output always is this one: $this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>'); $this->moveToBegin(1); if( dbg_ConstOn('DBG_SQL_PROFILE') && getArrayValue($this->ProfilerTotals, 'sql') ) { $this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']); } if( dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb'); } if( dbg_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( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) { $this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':'')); $totals = Array( 'mem' => 0, 'time' => 0); $totals_configs = Array( 'mem' => 0, 'time' => 0); if ( dbg_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(' -> ', ($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'])); } $i = 0; $lineCount = count($this->Data); ob_start(); ?> <style type="text/css"> .dbg_flat_table { border-collapse: collapse; width: auto; } .dbg_flat_table TD { border: 1px solid buttonface; padding: 4px; } .debug_layer_table { border-collapse: collapse; width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px; } .debug_text, .debug_row_even TD, .debug_row_odd TD { color: #000000; font-family: Verdana; font-size: 11px; word-wrap: break-word; } .debug_cell { border: 1px solid #FF0000; padding: 4px; word-wrap: break-word; } .debug_row_even { background-color: #CCCCFF; } .debug_row_odd { background-color: #FFFFCC; } .debug_layer_container { left: 2px; top: 1px; width: <?php echo DBG_WINDOW_WIDTH; ?>px; z-index: +1000; position: absolute; overflow: auto; border: 2px solid; padding: 3px; border-top-color: threedlightshadow; border-left-color: threedlightshadow; border-right-color: threeddarkshadow; border-bottom-color: threeddarkshadow; background-color: buttonface; } .debug_layer { padding: 0px; width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px; } .debug_error { color: #FF0000; } </style> <div id="debug_layer" class="debug_layer_container" style="display: none;"> <div class="debug_layer"> <table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table"> <?php while ($i < $lineCount) { echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>'; $i++; } ?> </table> </div> </div> <script language="javascript"> function dbg_OpenDOMViewer() { var $value = document.getElementById('dbg_domviewer').value; DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value); window.open('<?php echo constant('DBG_DOMVIEWER'); ?>'); return false; } function getEventKeyCode($e) { var $KeyCode = 0; if($e.keyCode) $KeyCode = $e.keyCode; else if($e.which) $KeyCode = $e.which; return $KeyCode; } function keyProcessor($e) { if(!$e) $e = window.event; var $KeyCode = getEventKeyCode($e); if($KeyCode==123||$KeyCode==27) // F12 or ESC { toggleDebugLayer($KeyCode); $e.cancelBubble = true; if($e.stopPropagation) $e.stopPropagation(); } } function toggleDebugLayer($KeyCode) { var $isVisible=false; var $DebugLayer = document.getElementById('debug_layer'); if( typeof($DebugLayer) != 'undefined' ) { $isVisible = ($DebugLayer.style.display == 'none')?false:true; if(!$isVisible&&$KeyCode==27) return false; resizeDebugLayer(null); $DebugLayer.style.display = $isVisible?'none':'block'; } } function prepareSizes($Prefix) { var $ret = ''; $ret = eval('document.body.'+$Prefix+'Top')+'; '; $ret += eval('document.body.'+$Prefix+'Left')+'; '; $ret += eval('document.body.'+$Prefix+'Height')+'; '; $ret += eval('document.body.'+$Prefix+'Width')+'; '; return $ret; } function resizeDebugLayer($e) { if(!$e) $e = window.event; var $DebugLayer = document.getElementById('debug_layer'); var $TopMargin = 1; var $pageWidth = document.all ? document.body.offsetWidth - 4 : window.innerWidth; var $pageHeight = document.all ? document.body.clientHeight : window.innerHeight; // document.body.offsetHeight - 2 var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY; if( typeof($DebugLayer) != 'undefined' ) { if(document.all) { $DebugLayer.style.top = ($pageTop + 2) + 'px'; $DebugLayer.style.height = ($pageHeight - 2 - 4) + 'px'; } else { $DebugLayer.style.top = ($pageTop + 2) + 'px'; $DebugLayer.style.height = ($pageHeight - 2 - 15) + 'px'; } } // window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client'); // window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight; return true; } function SetClipboard(copyText) { if(window.clipboardData) { // IE send-to-clipboard method. window.clipboardData.setData('Text', copyText); } else if (window.netscape) { // You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true); netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); // Store support string in an object. var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); if (!str) return false; str.data=copyText; // Make transferable. var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if (!trans) return false; // Specify what datatypes we want to obtain, which is text in this case. trans.addDataFlavor("text/unicode"); trans.setTransferData("text/unicode",str,copyText.length*2); var clipid=Components.interfaces.nsIClipboard; var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid); if (!clip) return false; clip.setData(trans,null,clipid.kGlobalClipboard); } } function showProps($Obj, $Name) { var $ret = ''; for($Prop in $Obj) { $ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n"; } return $ret; } function editFile($fileName,$lineNo) { if(!document.all) { alert('Only works in IE'); return; } var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>'; if($editorPath) { var $obj = new ActiveXObject("LaunchinIE.Launch"); $editorPath = $editorPath.replace('%F',$fileName); $editorPath = $editorPath.replace('%L',$lineNo); $obj.LaunchApplication($editorPath); } else { alert('Editor path not defined!'); } } function toggleTraceArgs($ArgsLayerID) { var $ArgsLayer = document.getElementById($ArgsLayerID); $ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none'; } document.onkeydown = keyProcessor; window.onresize = resizeDebugLayer; window.onscroll = resizeDebugLayer; window.focus(); if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> ) { toggleDebugLayer(); } if( typeof($isFatalError) != 'undefined' && $isFatalError == 1) { document.getElementById('debug_layer').scrollTop = 10000000; } </script> <?php dbg_safeDefine('DBG_SHOW_MEMORY_USAGE', 1); if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) { $this->memoryUsage['debugger_finish']=memory_get_usage(); $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start']; $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling']; $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total']; } if($returnResult) { $ret = ob_get_contents(); ob_clean(); if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret .= $this->getMemoryUsageReport(); return $ret; } else { if( !dbg_ConstOn('DBG_HIDE_FULL_REPORT') ) { ob_end_flush(); } else { ob_clean(); } if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport(); } } /** * Format's memory usage report by debugger * * @return string * @access private */ function getMemoryUsageReport() { if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return ''; $info = Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report', 'saveError'=>'error_handling', 'Total'=>'total', 'Application'=>'application'); $ret=Array(); foreach($info as $title => $value_key) { $ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>'; } return '<table class="dbg_flat_table">'.implode('',$ret).'</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 = '') { $memory_used=Array(); $memory_used['begin']=memory_get_usage(); $errorType = $this->getErrorNameByCode($errno); if(!$errorType) { trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR); return false; } if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return; $long_id_pos=strrpos($errstr,'#'); if($long_id_pos!==false) { // replace short message with long one (due triger_error limitations on message size) $long_id=substr($errstr,$long_id_pos+1,strlen($errstr)); $errstr=$this->longErrors[$long_id]; unset($this->longErrors[$long_id]); } /*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line [PRE-PARSED block, $line 13]: Undefined variable: IdField*/ /* if( strpos($errfile,'runtime-created') !== false ) { $errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> '; }*/ 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); } // if($this->TraceNextError || $errno == E_USER_ERROR) if($this->TraceNextError) { $this->appendTrace(); $this->TraceNextError=false; } $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error'); $memory_used['end']=memory_get_usage(); $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin']; if( substr($errorType,0,5) == 'Fatal') { echo '<script language="javascript">var $isFatalError = 1;</script>'; exit; } } 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; } } if( !function_exists('memory_get_usage') ) { function memory_get_usage(){ return -1; } } $debugger = new Debugger(); if( dbg_ConstOn('DBG_HANDLE_ERRORS') ) { if( class_exists('kApplication') ) { $application =& kApplication::Instance(); $application->Debugger =& $debugger; $application->errorHandlers[] = Array(&$debugger, 'saveError'); } else { set_error_handler( Array(&$debugger, 'saveError') ); } } if( dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) register_shutdown_function( Array(&$debugger, 'printReport') ); } ?> \ No newline at end of file Property changes on: trunk/kernel/include/debugger.php ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.40 \ No newline at end of property +1.41 \ No newline at end of property Index: trunk/core/kernel/utility/debugger.php =================================================================== --- trunk/core/kernel/utility/debugger.php (revision 2677) +++ trunk/core/kernel/utility/debugger.php (revision 2678) @@ -1,984 +1,1007 @@ <?php if( !class_exists('Debugger') ) { function dbg_ConstOn($const_name) { return defined($const_name) && constant($const_name); } function dbg_safeDefine($const_name,$const_value) { if(!defined($const_name)) define($const_name,$const_value); } unset($_REQUEST['debug_host']); // 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_' ) { dbg_safeDefine('DBG_ZEND_PRESENT', 1); break; } } dbg_safeDefine('DBG_ZEND_PRESENT',0); // set default values for debugger constants $dbg_constMap=Array('DBG_OPTIONS'=>0, 'DBG_USE_HIGHLIGHT'=>1, 'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1, 'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1, 'DBG_IGNORE_STRICT_ERRORS'=>1, 'DBG_DOMVIEWER'=>'/temp/domviewer.html', 'DOC_ROOT'=> str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack 'DBG_LOCAL_BASE_PATH'=>'w:'); foreach($dbg_constMap as $dbg_constName=>$dbg_constValue) { dbg_safeDefine($dbg_constName,$dbg_constValue); } // only for IE, in case if no windows php script editor defined /*if(!defined('WINDOWS_EDITOR')) { $dbg_editor = 0; $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L'); $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F'); define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']); unset($dbg_editors,$dbg_editor); }*/ class Debugger { /** * Debugger data for building report * * @var Array */ var $Data = Array(); var $ProfilerData = Array(); var $ProfilerTotals = Array(); var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results var $TraceNextError=false; var $Options = 0; var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2, 'output_buffer' => 4, 'highlight_output' => 8); var $longErrors=Array(); /** * Amount of memory used by debugger itself * * @var Array * @access private */ var $memoryUsage=Array(); var $IncludesData=Array(); var $IncludeLevel=0; function Debugger() { $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4'); $this->profileStart('script_runtime', 'Script runtime'); ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1); $this->memoryUsage['error_handling']=0; // memory amount used by error handler $this->appendRequest(); } function initOptions() { } function mapLongError($msg) { $key=$this->generateID(); $this->longErrors[$key]=$msg; return $key; } function setOption($name,$value) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>'); if($value) { $this->Options|=$this->OptionsMap[$name]; } else { $this->Options=$this->Options&~$this->OptionsMap[$name]; } } function getOption($name) { if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>'); return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name]; } /** * Set's flag, that next error that occurs will * be prepended by backtrace results * */ function traceNext() { $this->TraceNextError=true; } 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( print_r($Data['value'], true) ); break; case 'trace': ini_set('memory_limit','500M'); $trace =& $Data['trace']; //return 'sorry'; //return $this->highlightString(print_r($trace,true)); $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']; - $ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name); + $args_link = $has_args ? '<a href="javascript: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'; } // ensure parameter value is not longer then 200 symbols - $this->processTraceArguments($traceRec['args']); - $args = $this->highlightString(print_r($traceRec['args'], true)); - $ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>'; + if($has_args) + { + $this->processTraceArguments($traceRec['args']); + $args = $this->highlightString(print_r($traceRec['args'], true)); + $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 return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s'; break; default: return 'incorrect debug data'; break; } } + function isApplication(&$object) + { + $app_class = defined('APPLICATION_CLASS') ? strtolower(APPLICATION_CLASS) : 'kApplication'; + return get_class($object) == $app_class; + } + function processTraceArguments(&$traceArgs) { if(!$traceArgs) return ''; - foreach ($traceArgs as $argID => $argValue) + + $array_keys = array_keys($traceArgs); + foreach($array_keys as $argID) { + $argValue =& $traceArgs[$argID]; + if( is_array($argValue) || is_object($argValue) ) { if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) ) { - if( get_class($argValue) == 'kfactory' || get_class($argValue) == 'debugger' ) continue; + array_push($this->RecursionStack, get_class($argValue)); + + if( get_class($argValue) == 'kfactory' || $this->isApplication($argValue) || get_class($argValue) == 'templateparser' ) + { + $argValue = null; + continue; + } // object & not in stack - ok - array_push($this->RecursionStack, get_class($argValue)); settype($argValue,'array'); $this->processTraceArguments($argValue); array_pop($this->RecursionStack); } elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) ) { // object & in stack - recursion $traceArgs[$argID] = '**** RECURSION ***'; } else { // normal array here $this->processTraceArguments($argValue); } } else { $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]); } } } 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( dbg_ConstOn('DBG_USE_HIGHLIGHT') ) { $string = str_replace('\\','_no_match_string_',$string); $string = highlight_string('<?php '.$string.'?>', true); $string = str_replace('_no_match_string_','\\',$string); return preg_replace('/<\?(.*)php (.*)\?>/s','$2',$string); } else { return $string; } } function getFileLink($file, $lineno = 1, $title = '') { if(!$title) $title = $file; $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false; if($is_mozilla) { return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>'; } else { return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>'; } } function getLocalFile($remoteFile) { return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile); } 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'); } 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() { $script = $_SERVER['SCRIPT_FILENAME']; $this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)'); $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;"/> <button class="button" onclick="return dbg_OpenDOMViewer();">Show</button>'); ob_start(); ?> <table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: 100%;"> <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(print_r($value, true)); } $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') ); echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>'; } ?> </table> <?php $this->appendHTML( ob_get_contents() ); ob_end_clean(); } 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) { $timeStamp = $this->getMoment(); $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description); $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler'); } function profileFinish($key) { $this->ProfilerData[$key]['ends'] = $this->getMoment(); } function profilerAddTotal($total_key, $key=null, $value=null) { if (!isset($this->ProfilerTotals[$total_key])) { $this->ProfilerTotals[$total_key] = 0; } if (!isset($value)) { $value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins']; } $this->ProfilerTotals[$total_key] += $value; } 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($errorCode) { switch($errorCode) { case E_USER_ERROR: return 'Fatal Error'; break; case E_WARNING: case E_USER_WARNING: return 'Warning'; break; case E_NOTICE: case E_USER_NOTICE: return 'Notice'; break; case E_STRICT: return 'PHP5 Strict'; break; default: return ''; break; } } /** * Generates report * */ function printReport($returnResult = false) { if( dbg_ConstOn('DBG_SKIP_REPORTING') ) return; $this->profileFinish('script_runtime'); if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return; dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0); dbg_safeDefine('DBG_WINDOW_WIDTH', 700); - + $this->memoryUsage['debugger_start']=memory_get_usage(); // show php session if any $this->appendSession(); // ensure, that 1st line of debug output always is this one: $this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>'); $this->moveToBegin(1); if( dbg_ConstOn('DBG_SQL_PROFILE') && getArrayValue($this->ProfilerTotals, 'sql') ) { $this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']); } if( dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb'); } if( dbg_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( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) { $this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':'')); $totals = Array( 'mem' => 0, 'time' => 0); $totals_configs = Array( 'mem' => 0, 'time' => 0); if ( dbg_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(' -> ', ($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'])); } $i = 0; $lineCount = count($this->Data); ob_start(); ?> <style type="text/css"> .dbg_flat_table { border-collapse: collapse; width: auto; } .dbg_flat_table TD { border: 1px solid buttonface; padding: 4px; } .debug_layer_table { border-collapse: collapse; width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px; } .debug_text, .debug_row_even TD, .debug_row_odd TD { color: #000000; font-family: Verdana; font-size: 11px; word-wrap: break-word; } .debug_cell { border: 1px solid #FF0000; padding: 4px; word-wrap: break-word; } .debug_row_even { background-color: #CCCCFF; } .debug_row_odd { background-color: #FFFFCC; } .debug_layer_container { left: 2px; top: 1px; width: <?php echo DBG_WINDOW_WIDTH; ?>px; z-index: +1000; position: absolute; overflow: auto; border: 2px solid; padding: 3px; border-top-color: threedlightshadow; border-left-color: threedlightshadow; border-right-color: threeddarkshadow; border-bottom-color: threeddarkshadow; background-color: buttonface; } .debug_layer { padding: 0px; width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px; } .debug_error { color: #FF0000; } </style> <div id="debug_layer" class="debug_layer_container" style="display: none;"> <div class="debug_layer"> <table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table"> <?php while ($i < $lineCount) { echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>'; $i++; } ?> </table> </div> </div> <script language="javascript"> function dbg_OpenDOMViewer() { var $value = document.getElementById('dbg_domviewer').value; DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value); window.open('<?php echo constant('DBG_DOMVIEWER'); ?>'); return false; } function getEventKeyCode($e) { var $KeyCode = 0; if($e.keyCode) $KeyCode = $e.keyCode; else if($e.which) $KeyCode = $e.which; return $KeyCode; } function keyProcessor($e) { if(!$e) $e = window.event; var $KeyCode = getEventKeyCode($e); if($KeyCode==123||$KeyCode==27) // F12 or ESC { toggleDebugLayer($KeyCode); $e.cancelBubble = true; if($e.stopPropagation) $e.stopPropagation(); } } function toggleDebugLayer($KeyCode) { var $isVisible=false; var $DebugLayer = document.getElementById('debug_layer'); if( typeof($DebugLayer) != 'undefined' ) { $isVisible = ($DebugLayer.style.display == 'none')?false:true; if(!$isVisible&&$KeyCode==27) return false; resizeDebugLayer(null); $DebugLayer.style.display = $isVisible?'none':'block'; } } function prepareSizes($Prefix) { var $ret = ''; $ret = eval('document.body.'+$Prefix+'Top')+'; '; $ret += eval('document.body.'+$Prefix+'Left')+'; '; $ret += eval('document.body.'+$Prefix+'Height')+'; '; $ret += eval('document.body.'+$Prefix+'Width')+'; '; return $ret; } function resizeDebugLayer($e) { if(!$e) $e = window.event; var $DebugLayer = document.getElementById('debug_layer'); var $TopMargin = 1; var $pageWidth = document.all ? document.body.offsetWidth - 4 : window.innerWidth; var $pageHeight = document.all ? document.body.clientHeight : window.innerHeight; // document.body.offsetHeight - 2 var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY; if( typeof($DebugLayer) != 'undefined' ) { if(document.all) { $DebugLayer.style.top = ($pageTop + 2) + 'px'; $DebugLayer.style.height = ($pageHeight - 2 - 4) + 'px'; } else { $DebugLayer.style.top = ($pageTop + 2) + 'px'; $DebugLayer.style.height = ($pageHeight - 2 - 15) + 'px'; } } // window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client'); // window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight; return true; } function SetClipboard(copyText) { if(window.clipboardData) { // IE send-to-clipboard method. window.clipboardData.setData('Text', copyText); } else if (window.netscape) { // You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true); netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); // Store support string in an object. var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); if (!str) return false; str.data=copyText; // Make transferable. var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if (!trans) return false; // Specify what datatypes we want to obtain, which is text in this case. trans.addDataFlavor("text/unicode"); trans.setTransferData("text/unicode",str,copyText.length*2); var clipid=Components.interfaces.nsIClipboard; var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid); if (!clip) return false; clip.setData(trans,null,clipid.kGlobalClipboard); } } function showProps($Obj, $Name) { var $ret = ''; for($Prop in $Obj) { $ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n"; } return $ret; } function editFile($fileName,$lineNo) { if(!document.all) { alert('Only works in IE'); return; } var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>'; if($editorPath) { var $obj = new ActiveXObject("LaunchinIE.Launch"); $editorPath = $editorPath.replace('%F',$fileName); $editorPath = $editorPath.replace('%L',$lineNo); $obj.LaunchApplication($editorPath); } else { alert('Editor path not defined!'); } } function toggleTraceArgs($ArgsLayerID) { var $ArgsLayer = document.getElementById($ArgsLayerID); $ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none'; } document.onkeydown = keyProcessor; window.onresize = resizeDebugLayer; window.onscroll = resizeDebugLayer; window.focus(); if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> ) { toggleDebugLayer(); } if( typeof($isFatalError) != 'undefined' && $isFatalError == 1) { document.getElementById('debug_layer').scrollTop = 10000000; } </script> <?php dbg_safeDefine('DBG_SHOW_MEMORY_USAGE', 1); if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) { $this->memoryUsage['debugger_finish']=memory_get_usage(); $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start']; $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling']; $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total']; } if($returnResult) { $ret = ob_get_contents(); ob_clean(); if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret .= $this->getMemoryUsageReport(); return $ret; } else { if( !dbg_ConstOn('DBG_HIDE_FULL_REPORT') ) { ob_end_flush(); } else { ob_clean(); } if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport(); } } /** * Format's memory usage report by debugger * * @return string * @access private */ function getMemoryUsageReport() { if( !dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) return ''; $info = Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report', 'saveError'=>'error_handling', 'Total'=>'total', 'Application'=>'application'); $ret=Array(); foreach($info as $title => $value_key) { $ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>'; } return '<table class="dbg_flat_table">'.implode('',$ret).'</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 = '') { $memory_used=Array(); $memory_used['begin']=memory_get_usage(); $errorType = $this->getErrorNameByCode($errno); if(!$errorType) { trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR); return false; } if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return; $long_id_pos=strrpos($errstr,'#'); if($long_id_pos!==false) { // replace short message with long one (due triger_error limitations on message size) $long_id=substr($errstr,$long_id_pos+1,strlen($errstr)); $errstr=$this->longErrors[$long_id]; unset($this->longErrors[$long_id]); } /*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line [PRE-PARSED block, $line 13]: Undefined variable: IdField*/ /* if( strpos($errfile,'runtime-created') !== false ) { $errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> '; }*/ 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); } // if($this->TraceNextError || $errno == E_USER_ERROR) if($this->TraceNextError) { $this->appendTrace(); $this->TraceNextError=false; } $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error'); $memory_used['end']=memory_get_usage(); $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin']; if( substr($errorType,0,5) == 'Fatal') { echo '<script language="javascript">var $isFatalError = 1;</script>'; exit; } } 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; } } if( !function_exists('memory_get_usage') ) { function memory_get_usage(){ return -1; } } $debugger = new Debugger(); if( dbg_ConstOn('DBG_HANDLE_ERRORS') ) { if( class_exists('kApplication') ) { $application =& kApplication::Instance(); $application->Debugger =& $debugger; $application->errorHandlers[] = Array(&$debugger, 'saveError'); } else { set_error_handler( Array(&$debugger, 'saveError') ); } } if( dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC') ) register_shutdown_function( Array(&$debugger, 'printReport') ); } ?> \ No newline at end of file Property changes on: trunk/core/kernel/utility/debugger.php ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.20 \ No newline at end of property +1.21 \ No newline at end of property Index: trunk/core/kernel/application.php =================================================================== --- trunk/core/kernel/application.php (revision 2677) +++ trunk/core/kernel/application.php (revision 2678) @@ -1,1340 +1,1340 @@ <?php /** * Basic class for Kernel3-based Application * * This class is a Facade for any other class which needs to deal with Kernel3 framework.<br> * The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br> * <br> * The class is a singleton, which means that there could be only one instance of KernelApplication in the script.<br> * This could be guranteed by NOT calling the class constuctor directly, but rather calling KernelApplication::Instance() method, * which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br> * See singleton pattern by GOF. * @package kernel4 */ class kApplication { /** * Is true, when Init method was called already, prevents double initialization * * @var bool */ var $InitDone = false; /** * Holds internal TemplateParser object * @access private * @var TemplateParser */ var $Parser; /** * Holds parser output buffer * @access private * @var string */ var $HTML; /** * Prevents request from beeing proceeded twice in case if application init is called mere then one time * * @var bool * @todo This is not good anyway (by Alex) */ var $RequestProcessed = false; /** * The main Factory used to create * almost any class of kernel and * modules * * @access private * @var kFactory */ var $Factory; /** * Reference to debugger * * @var Debugger */ var $Debugger = null; /** * Holds all phrases used * in code and template * * @var PhrasesCache */ var $Phrases; /** * Holds DBConnection * * @var kDBConnection */ var $DB; /** * Maintains list of user-defined error handlers * * @var Array */ var $errorHandlers = Array(); /** * Returns kApplication instance anywhere in the script. * * This method should be used to get single kApplication object instance anywhere in the * Kernel-based application. The method is guranteed to return the SAME instance of kApplication. * Anywhere in the script you could write: * <code> * $application =& kApplication::Instance(); * </code> * or in an object: * <code> * $this->Application =& kApplication::Instance(); * </code> * to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class. * To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant * BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would * create and return default KernelApplication instance. * @static * @access public * @return kApplication */ function &Instance() { static $instance = false; if(!$instance) { if (!defined('APPLICATION_CLASS')) define('APPLICATION_CLASS', 'kApplication'); $class = APPLICATION_CLASS; $instance = new $class(); } return $instance; } /** * Initializes the Application * * @access public * @see HTTPQuery * @see Session * @see TemplatesCache * @return bool Was Init actually made now or before */ function Init() { if($this->InitDone) return false; if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $GLOBALS['debugger']->appendMemoryUsage('Application before Init:'); } if( !$this->isDebugMode() ) { error_reporting(0); ini_set('display_errors', 0); } $error_handler = set_error_handler( Array(&$this,'handleError') ); if($error_handler) $this->errorHandlers[] = $error_handler; $this->DB = new kDBConnection(SQL_TYPE, Array(&$this,'handleSQLError') ); $this->DB->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB); $this->DB->debugMode = $this->isDebugMode(); $this->Factory = new kFactory(); $this->registerDefaultClasses(); $this->SetDefaultConstants(); // 1. to read configs before doing any recallObject (called from "SetDefaultConstants" anyway) //$config_reader =& $this->recallObject('kUnitConfigReader'); if( !$this->GetVar('m_lang') ) $this->SetVar('m_lang', $this->GetDefaultLanguageId() ); if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId() ); if( $this->GetVar('m_cat_id') === false ) $this->SetVar('m_cat_id', 0); $this->Phrases = new PhrasesCache( $this->GetVar('m_lang') ); $this->SetVar('lang.current_id', $this->GetVar('m_lang') ); $language =& $this->recallObject('lang.current', null, Array('live_table'=>true) ); if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId() ); $this->SetVar('theme.current_id', $this->GetVar('m_theme') ); if( !$this->RecallVar('UserGroups') ) { $ses =& $this->recallObject('Session'); $user_groups = trim($ses->GetField('GroupList'), ','); if (!$user_groups) $user_groups = $this->ConfigValue('User_GuestGroup'); $this->StoreVar('UserGroups', $user_groups); } if( !$this->RecallVar('curr_iso') ) $this->StoreVar('curr_iso', $this->GetPrimaryCurrency() ); $this->SetVar('visits_id', $this->RecallVar('visit_id') ); $this->ValidateLogin(); // TODO: write that method if( $this->isDebugMode() ) { $GLOBALS['debugger']->profileFinish('kernel4_startup'); } if( defined('CMS') && CMS == 1 && !$this->GetVar('admin') && !$this->IsAdmin() ) { define('MOD_REWRITE', 1); } $this->InitDone = true; return true; } function GetDefaultLanguageId() { $table = $this->getUnitOption('lang','TableName'); $id_field = $this->getUnitOption('lang','IDField'); return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryLang = 1'); } function GetDefaultThemeId() { if (defined('DBG_FORCE_THEME') && DBG_FORCE_THEME){ return DBG_FORCE_THEME; } $table = $this->getUnitOption('theme','TableName'); $id_field = $this->getUnitOption('theme','IDField'); return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryTheme = 1'); } function GetPrimaryCurrency() { $this->setUnitOption('mod','AutoLoad',false); $module =& $this->recallObject('mod'); $this->setUnitOption('mod','AutoLoad',true); if( $module->Load('In-Commerce') && $module->GetDBField('Loaded') == 1 ) { $table = $this->getUnitOption('curr','TableName'); return $this->DB->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 1'); } else { return 'USD'; } } /** * Registers default classes such as ItemController, GridController and LoginController * * Called automatically while initializing Application * @access private * @return void */ function RegisterDefaultClasses() { $this->registerClass('kArray',KERNEL_PATH.'/utility/params.php'); $this->registerClass('Params',KERNEL_PATH.'/utility/params.php'); $this->registerClass('HTTPQuery', KERNEL_PATH.'/utility/http_query.php', 'HTTPQuery', Array('Params') ); $this->registerClass('Session', KERNEL_PATH.'/session/session.php'); $this->registerClass('SessionStorage', KERNEL_PATH.'/session/session.php'); $this->registerClass('kEventManager', KERNEL_PATH.'/event_manager.php', 'EventManager'); $this->registerClass('kUnitConfigReader', KERNEL_PATH.'/utility/unit_config_reader.php'); $this->registerClass('Params', KERNEL_PATH.'/utility/params.php', 'kActions'); $this->registerClass('kFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kOptionsFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kUploadFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kPictureFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kDateFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kLEFTFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kMultiLanguage', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kPasswordFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kCCDateFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kUnitFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kFilesizeFormatter', KERNEL_PATH.'/utility/formatters.php'); $this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php'); $event_manager =& $this->recallObject('EventManager'); $event_manager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild'); $this->registerClass('TemplatesCache',KERNEL_PATH.'/parser/template.php'); $this->registerClass('Template',KERNEL_PATH.'/parser/template.php'); $this->registerClass('TemplateParser',KERNEL_PATH.'/parser/template_parser.php'); $this->registerClass('MainProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor'); $this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php'); $this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php'); $this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php'); $this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php'); $this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php'); $this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php'); $this->registerClass('kEmailMessage',KERNEL_PATH.'/utility/email.php'); $this->registerClass('kSmtpClient',KERNEL_PATH.'/utility/smtp_client.php'); if (file_exists(MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php')) { $this->registerClass('kCurrencyRates',MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php'); } $this->registerClass('FCKeditor', FULL_PATH.'/admin/editor/cmseditor/fckeditor.php'); // need this? } /** * Defines default constants if it's not defined before - in config.php * * @access private */ function SetDefaultConstants() { if (!defined('SERVER_NAME')) define('SERVER_NAME', $_SERVER['HTTP_HOST']); $admin_dir = $this->ConfigValue('AdminDirectory'); if(!$admin_dir) $admin_dir = 'admin'; safeDefine('ADMIN_DIR', $admin_dir); $this->registerModuleConstants(); } /** * Registers each module specific constants if any found * */ function registerModuleConstants() { $unit_config_reader =& $this->recallObject('kUnitConfigReader'); foreach($unit_config_reader->modules_installed as $module_path) { $contants_file = FULL_PATH.$module_path.'constants.php'; if( file_exists($contants_file) ) k4_include_once($contants_file); } } function ProcessRequest() { $event_manager =& $this->recallObject('EventManager'); if( $this->isDebugMode() && dbg_ConstOn('DBG_SHOW_HTTPQUERY') ) { global $debugger; $http_query =& $this->recallObject('HTTPQuery'); $debugger->appendHTML('HTTPQuery:'); $debugger->dumpVars($http_query->_Params); } $event_manager->ProcessRequest(); $event_manager->RunRegularEvents(reBEFORE); $this->RequestProcessed = true; } /** * Actually runs the parser against current template and stores parsing result * * This method gets t variable passed to the script, loads the template given in t variable and * parses it. The result is store in {@link $this->HTML} property. * @access public * @return void */ function Run() { if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $GLOBALS['debugger']->appendMemoryUsage('Application before Run:'); } if (!$this->RequestProcessed) $this->ProcessRequest(); $this->InitParser(); $template_cache =& $this->recallObject('TemplatesCache'); $t = $this->GetVar('t'); if(defined('CMS') && CMS) { $cms_handler =& $this->recallObject('cms_EventHandler'); if( !$template_cache->TemplateExists($t) ) { $t = $cms_handler->GetDesignTemplate(); } else { $cms_handler->SetCatByTemplate(); } } if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $GLOBALS['debugger']->appendMemoryUsage('Application before Parsing:'); } $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t), $t ); if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $GLOBALS['debugger']->appendMemoryUsage('Application after Parsing:'); } } function InitParser() { if( !is_object($this->Parser) ) $this->Parser =& $this->recallObject('TemplateParser'); } /** * Send the parser results to browser * * Actually send everything stored in {@link $this->HTML}, to the browser by echoing it. * @access public * @return void */ function Done() { if( $this->isDebugMode() && dbg_ConstOn('DBG_PROFILE_MEMORY') ) { $GLOBALS['debugger']->appendMemoryUsage('Application before Done:'); } if( $this->GetVar('admin') ) { $reg = '/('.preg_quote(BASE_PATH, '/').'.*\.html)(#.*){0,1}(")/sU'; $this->HTML = preg_replace($reg, "$1?admin=1$2$3", $this->HTML); } //eval("?".">".$this->HTML); echo $this->HTML; $this->Phrases->UpdateCache(); flush(); $event_manager =& $this->recallObject('EventManager'); $event_manager->RunRegularEvents(reAFTER); $session =& $this->recallObject('Session'); $session->SaveData(); //$this->SaveBlocksCache(); } function SaveBlocksCache() { /*if (defined('EXPERIMENTAL_PRE_PARSE')) { $data = serialize($this->PreParsedCache); $this->DB->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("blocks_cache", '.$this->DB->qstr($data).', '.time().')'); }*/ } // Facade /** * Returns current session id (SID) * @access public * @return longint */ function GetSID() { $session =& $this->recallObject('Session'); return $session->GetID(); } function DestroySession() { $session =& $this->recallObject('Session'); $session->Destroy(); } /** * Returns variable passed to the script as GET/POST/COOKIE * * @access public * @param string $var Variable name * @return mixed */ function GetVar($var,$mode=FALSE_ON_NULL) { $http_query =& $this->recallObject('HTTPQuery'); return $http_query->Get($var,$mode); } /** * Returns ALL variables passed to the script as GET/POST/COOKIE * * @access public * @return array */ function GetVars() { $http_query =& $this->recallObject('HTTPQuery'); return $http_query->GetParams(); } /** * Set the variable 'as it was passed to the script through GET/POST/COOKIE' * * This could be useful to set the variable when you know that * other objects would relay on variable passed from GET/POST/COOKIE * or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br> * * This method is formerly known as $this->Session->SetProperty. * @param string $var Variable name to set * @param mixed $val Variable value * @access public * @return void */ function SetVar($var,$val) { $http_query =& $this->recallObject('HTTPQuery'); $http_query->Set($var,$val); } /** * Deletes Session variable * * @param string $var */ function RemoveVar($var) { $session =& $this->recallObject('Session'); return $session->RemoveVar($var); } /** * Deletes HTTPQuery variable * * @param string $var * @todo think about method name */ function DeleteVar($var) { $http_query =& $this->recallObject('HTTPQuery'); return $http_query->Remove($var); } /** * Returns session variable value * * Return value of $var variable stored in Session. An optional default value could be passed as second parameter. * * @see SimpleSession * @access public * @param string $var Variable name * @param mixed $default Default value to return if no $var variable found in session * @return mixed */ function RecallVar($var,$default=false) { $session =& $this->recallObject('Session'); return $session->RecallVar($var,$default); } /** * Stores variable $val in session under name $var * * Use this method to store variable in session. Later this variable could be recalled. * @see RecallVar * @access public * @param string $var Variable name * @param mixed $val Variable value */ function StoreVar($var, $val) { $session =& $this->recallObject('Session'); $session->StoreVar($var, $val); } function StoreVarDefault($var, $val) { $session =& $this->recallObject('Session'); $session->StoreVarDefault($var, $val); } /** * Links HTTP Query variable with session variable * * If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session. * This method could be used for making sure that GetVar will return query or session value for given * variable, when query variable should overwrite session (and be stored there for later use).<br> * This could be used for passing item's ID into popup with multiple tab - * in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id'). * After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session * @access public * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value */ function LinkVar($var, $ses_var=null, $default='') { if (!isset($ses_var)) $ses_var = $var; if ($this->GetVar($var) !== false) { $this->StoreVar($ses_var, $this->GetVar($var)); } else { $this->SetVar($var, $this->RecallVar($ses_var, $default)); } } /** * Returns variable from HTTP Query, or from session if not passed in HTTP Query * * The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed. * Returns the default value if variable does not exist in session and was not passed in HTTP Query * * @see LinkVar * @access public * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @return mixed */ function GetLinkedVar($var, $ses_var=null, $default='') { if (!isset($ses_var)) $ses_var = $var; $this->LinkVar($var, $ses_var, $default); return $this->GetVar($var); } function AddBlock($name, $tpl) { $this->cache[$name] = $tpl; } function SetTemplateBody($title,$body) { $templates_cache =& $this->recallObject('TemplatesCache'); $templates_cache->SetTemplateBody($title,$body); } function ProcessTag($tag_data) { $a_tag = new Tag($tag_data,$this->Parser); return $a_tag->DoProcessTag(); } function ProcessParsedTag($prefix, $tag, $params) { $a_tag = new Tag('',$this->Parser); $a_tag->Tag = $tag; $a_tag->Processor = $prefix; $a_tag->NamedParams = $params; return $a_tag->DoProcessTag(); } /** * Return ADODB Connection object * * Returns ADODB Connection object already connected to the project database, configurable in config.php * @access public * @return kDBConnection */ function &GetADODBConnection() { return $this->DB; } function ParseBlock($params,$pass_params=0,$as_template=false) { if (substr($params['name'], 0, 5) == 'html:') return substr($params['name'], 6); return $this->Parser->ParseBlock($params, $pass_params, $as_template); } /** * Return href for template * * @access public * @param string $t Template path * @var string $prefix index.php prefix - could be blank, 'admin' */ function HREF($t, $prefix='', $params=null, $index_file=null) { global $HTTP_SERVER_VARS; if (defined('ADMIN') && $prefix == '') $prefix='/admin'; if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = ''; $index_file = isset($index_file) ? $index_file : (defined('INDEX_FILE') ? INDEX_FILE : basename($_SERVER['SCRIPT_NAME'])); if( isset($params['index_file']) ) $index_file = $params['index_file']; $ssl = isset($params['__SSL__']) ? $params['__SSL__'] : null; if ($ssl && PROTOCOL == 'http://') { $session =& $this->recallObject('Session'); $cookie_url = $session->CookieDomain.$session->CookiePath; $ssl_url = $this->ConfigValue('SSL_URL'); if (!preg_match('#'.preg_quote($cookie_url).'#', $ssl_url)) { $session->SetMode(smGET_ONLY); } } unset($params['__SSL__']); if (getArrayValue($params, 'opener') == 'u') { $opener_stack=$this->RecallVar('opener_stack'); if($opener_stack) { $opener_stack=unserialize($opener_stack); if (count($opener_stack) > 0) { list($index_file, $env) = explode('|', $opener_stack[count($opener_stack)-1]); $ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.ENV_VAR_NAME.'='.$env; if( getArrayValue($params,'escape') ) $ret = addslashes($ret); return $ret; } else { //define('DBG_REDIRECT', 1); $t = $this->GetVar('t'); } } else { //define('DBG_REDIRECT', 1); $t = $this->GetVar('t'); } } $pass = isset($params['pass']) ? $params['pass'] : ''; $pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url if (defined('MOD_REWRITE') && MOD_REWRITE) { $env = $this->BuildEnv('', $params, $pass, $pass_events, false); $env = ltrim($env, ':-'); $session =& $this->recallObject('Session'); $sid = $session->NeedQueryString() ? '?sid='.$this->GetSID() : ''; // $env = str_replace(':', '/', $env); $ret = rtrim($this->BaseURL($prefix, $ssl).$t.'.html/'.$env.'/'.$sid, '/'); } else { $env = $this->BuildEnv($t, $params, $pass, $pass_events); $ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env; } return $ret; } function BuildEnv($t, $params, $pass='all', $pass_events=false, $env_var=true) { $session =& $this->recallObject('Session'); $sid = $session->NeedQueryString() && !(defined('MOD_REWRITE') && MOD_REWRITE) ? $this->GetSID() : ''; if( getArrayValue($params,'admin') == 1 ) $sid = $this->GetSID(); $ret = ''; if ($env_var) { $ret = ENV_VAR_NAME.'='; } $ret .= defined('INPORTAL_ENV') ? $sid.'-'.$t : $sid.':'.$t; $pass = str_replace('all', trim($this->GetVar('passed'), ','), $pass); if(strlen($pass) > 0) { $pass_info = array_unique( explode(',',$pass) ); // array( prefix[.special], prefix[.special] ... foreach($pass_info as $pass_element) { $ret.=':'; list($prefix)=explode('.',$pass_element); $query_vars = $this->getUnitOption($prefix,'QueryString'); //if pass events is off and event is not implicity passed if(!$pass_events && !isset($params[$pass_element.'_event'])) { $params[$pass_element.'_event'] = ''; // remove event from url if requested //otherwise it will use value from get_var } if($query_vars) { $tmp_string=Array(0=>$pass_element); foreach($query_vars as $index => $var_name) { //if value passed in params use it, otherwise use current from application $tmp_string[$index] = isset( $params[$pass_element.'_'.$var_name] ) ? $params[$pass_element.'_'.$var_name] : $this->GetVar($pass_element.'_'.$var_name); if ( isset($params[$pass_element.'_'.$var_name]) ) { unset( $params[$pass_element.'_'.$var_name] ); } } $escaped = array(); foreach ($tmp_string as $tmp_val) { $escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val); } if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) { $ret.= array_shift($escaped).array_shift($escaped).'-'.implode('-',$escaped); } else { $ret.=implode('-',$escaped); } } } } unset($params['pass']); unset($params['opener']); unset($params['m_event']); if ($this->GetVar('admin') && !isset($params['admin'])) { $params['admin'] = 1; } if( getArrayValue($params,'escape') ) { $ret = addslashes($ret); unset($params['escape']); } foreach ($params as $param => $value) { $ret .= '&'.$param.'='.$value; } return $ret; } function BaseURL($prefix='', $ssl=null) { if ($ssl === null) { return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').BASE_PATH.$prefix.'/'; } else { if ($ssl) { if (PROTOCOL == 'http://') { $this->StoreVar('HTTP_SERVER_NAME', SERVER_NAME); $this->StoreVar('HTTP_BASE_PATH', BASE_PATH); } return $this->ConfigValue('SSL_URL').$prefix.'/'; } else { return 'http://'.$this->RecallVar('HTTP_SERVER_NAME').(defined('PORT')?':'.PORT : '').$this->RecallVar('HTTP_BASE_PATH').$prefix.'/'; } } } function Redirect($t='', $params=null, $prefix='', $index_file=null) { if ($t == '' || $t === true) $t = $this->GetVar('t'); // pass prefixes and special from previous url if (!isset($params['pass'])) $params['pass'] = 'all'; $location = $this->HREF($t, $prefix, $params, $index_file); $a_location = $location; $location = "Location: $location"; //echo " location : $location <br>"; if( $this->isDebugMode() && dbg_ConstOn('DBG_REDIRECT') ) { $GLOBALS['debugger']->appendTrace(); echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>"; } else { if(headers_sent() != '') { echo '<script language="javascript" type="text/javascript">window.location.href = \''.$a_location.'\';</script>'; } else { header("$location"); } } $session =& $this->recallObject('Session'); $session->SaveData(); $this->SaveBlocksCache(); exit; } function Phrase($label) { return $this->Phrases->GetPhrase($label); } /** * Replace language tags in exclamation marks found in text * * @param string $text * @param bool $force_escape force escaping, not escaping of resulting string * @return string * @access public */ function ReplaceLanguageTags($text, $force_escape=null) { return $this->Phrases->ReplaceLanguageTags($text,$force_escape); } /** * Validtates user in session if required * */ function ValidateLogin() { if (defined('LOGIN_REQUIRED')) { // Original Kostja call //$login_controller =& $this->Factory->MakeClass(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login')); // Call proposed by Alex //$login_controller =& $this->RecallObject(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login')); //$login_controller->CheckLogin(); } } /** * Returns configuration option value by name * * @param string $name * @return string */ function ConfigValue($name) { return $this->DB->GetOne('SELECT VariableValue FROM '.TABLE_PREFIX.'ConfigurationValues WHERE VariableName = '.$this->DB->qstr($name) ); } /** * Allows to process any type of event * * @param kEvent $event * @access public * @author Alex */ function HandleEvent(&$event, $params=null, $specificParams=null) { if ( isset($params) ) { $event = new kEvent( $params, $specificParams ); } $event_manager =& $this->recallObject('EventManager'); $event_manager->HandleEvent($event); } /** * Registers new class in the factory * * @param string $real_class Real name of class as in class declaration * @param string $file Filename in what $real_class is declared * @param string $pseudo_class Name under this class object will be accessed using getObject method * @param Array $dependecies List of classes required for this class functioning * @access public * @author Alex */ function registerClass($real_class, $file, $pseudo_class = null, $dependecies = Array() ) { $this->Factory->registerClass($real_class, $file, $pseudo_class, $dependecies); } /** * Add $class_name to required classes list for $depended_class class. * All required class files are included before $depended_class file is included * * @param string $depended_class * @param string $class_name * @author Alex */ function registerDependency($depended_class, $class_name) { $this->Factory->registerDependency($depended_class, $class_name); } /** * Registers Hook from subprefix event to master prefix event * * @param string $hookto_prefix * @param string $hookto_special * @param string $hookto_event * @param string $mode * @param string $do_prefix * @param string $do_special * @param string $do_event * @param string $conditional * @access public * @todo take care of a lot parameters passed * @author Kostja */ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional) { $event_manager =& $this->recallObject('EventManager'); $event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional); } /** * Allows one TagProcessor tag act as other TagProcessor tag * * @param Array $tag_info * @author Kostja */ function registerAggregateTag($tag_info) { $aggregator =& $this->recallObject('TagsAggregator', 'kArray'); $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial'))); } /** * Returns object using params specified, * creates it if is required * * @param string $name * @param string $pseudo_class * @param Array $event_params * @return Object * @author Alex */ function &recallObject($name,$pseudo_class=null,$event_params=Array()) { $func_args = func_get_args(); $result =& ref_call_user_func_array( Array(&$this->Factory, 'getObject'), $func_args ); return $result; } /** * Checks if object with prefix passes was already created in factory * * @param string $name object presudo_class, prefix * @return bool * @author Kostja */ function hasObject($name) { return isset($this->Factory->Storage[$name]); } /** * Removes object from storage by given name * * @param string $name Object's name in the Storage * @author Kostja */ function removeObject($name) { $this->Factory->DestroyObject($name); } /** * Get's real class name for pseudo class, * includes class file and creates class * instance * * @param string $pseudo_class * @return Object * @access public * @author Alex */ function &makeClass($pseudo_class) { $func_args = func_get_args(); $result =& ref_call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args); return $result; } /** * Checks if application is in debug mode * * @return bool * @access public * @author Alex */ function isDebugMode() { - return defined('DEBUG_MODE') && DEBUG_MODE; + return defined('DEBUG_MODE') && DEBUG_MODE && is_object($this->Debugger); } /** * Checks if it is admin * * @return bool * @author Alex */ function IsAdmin() { return defined('ADMIN') && ADMIN; } /** * Reads unit (specified by $prefix) * option specified by $option * * @param string $prefix * @param string $option * @return string * @access public * @author Alex */ function getUnitOption($prefix,$option) { $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $unit_config_reader->getUnitOption($prefix,$option); } /** * Set's new unit option value * * @param string $prefix * @param string $name * @param string $value * @author Alex * @access public */ function setUnitOption($prefix,$option,$value) { $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $unit_config_reader->setUnitOption($prefix,$option,$value); } /** * Read all unit with $prefix options * * @param string $prefix * @return Array * @access public * @author Alex */ function getUnitOptions($prefix) { $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $unit_config_reader->getUnitOptions($prefix); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ function prefixRegistred($prefix) { $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $unit_config_reader->prefixRegistred($prefix); } /** * Splits any mixing of prefix and * special into correct ones * * @param string $prefix_special * @return Array * @access public * @author Alex */ function processPrefix($prefix_special) { return $this->Factory->processPrefix($prefix_special); } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @access public */ function setEvent($prefix_special,$event_name) { $event_manager =& $this->recallObject('EventManager'); $event_manager->setEvent($prefix_special,$event_name); } /** * SQL Error Handler * * @param int $code * @param string $msg * @param string $sql * @return bool * @access private * @author Alex */ function handleSQLError($code,$msg,$sql) { global $debugger; if($debugger) { $errorLevel=defined('DBG_SQL_FAILURE') && DBG_SQL_FAILURE ? E_USER_ERROR : E_USER_WARNING; $debugger->dumpVars($_REQUEST); $debugger->appendTrace(); $error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$debugger->formatSQL($sql); $long_id=$debugger->mapLongError($error_msg); trigger_error( substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel); return true; } else { //$errorLevel = defined('IS_INSTALL') && IS_INSTALL ? E_USER_WARNING : E_USER_ERROR; $errorLevel = E_USER_WARNING; trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel); /*echo '<b>xProcessing SQL</b>: '.$sql.'<br>'; echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/ return $errorLevel == E_USER_ERROR ? false : true; } } /** * Default error handler * * @param int $errno * @param string $errstr * @param string $errfile * @param int $errline * @param Array $errcontext */ function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '') { if( defined('SILENT_LOG') && SILENT_LOG ) { $fp = fopen(FULL_PATH.'/silent_log.txt','a'); $time = date('d/m/Y H:i:s'); fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n"); fclose($fp); } if( !$this->errorHandlers ) return true; $i = 0; // while (not foreach) because it is array of references in some cases $eh_count = count($this->errorHandlers); while($i < $eh_count) { if( is_array($this->errorHandlers[$i]) ) { $object =& $this->errorHandlers[$i][0]; $method = $this->errorHandlers[$i][1]; $object->$method($errno, $errstr, $errfile, $errline, $errcontext); } else { $function = $this->errorHandlers[$i]; $function($errno, $errstr, $errfile, $errline, $errcontext); } $i++; } } /** * Returns & blocks next ResourceId available in system * * @return int * @access public * @author Eduard */ function NextResourceId() { $this->DB->Query('LOCK TABLES '.TABLE_PREFIX.'IdGenerator WRITE'); $this->DB->Query('UPDATE '.TABLE_PREFIX.'IdGenerator SET lastid = lastid+1'); $id = $this->DB->GetOne("SELECT lastid FROM ".TABLE_PREFIX."IdGenerator"); $this->DB->Query('UNLOCK TABLES'); return $id; } /** * Returns main prefix for subtable prefix passes * * @param string $current_prefix * @return string * @access public * @author Kostja */ function GetTopmostPrefix($current_prefix) { while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) { $current_prefix = $parent_prefix; } return $current_prefix; } function EmailEventAdmin($email_event_name, $to_user_id = -1, $send_params = false) { return $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params); } function EmailEventUser($email_event_name, $to_user_id = -1, $send_params = false) { return $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params); } function EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false) { $event = new kEvent('emailevents:OnEmailEvent'); $event->setEventParam('EmailEventName', $email_event_name); $event->setEventParam('EmailEventToUserId', $to_user_id); $event->setEventParam('EmailEventType', $email_event_type); if ($send_params){ $event->setEventParam('DirectSendParams', $send_params); } $this->HandleEvent($event); return $event; } function LoggedIn() { $user =& $this->recallObject('u'); return ($user->GetDBField('PortalUserId') > 0); } function CheckPermission($name, $cat_id = null) { if( !isset($cat_id) ) { $cat_id = $this->GetVar('m_cat_id'); } if( $cat_id == 0 ) { $cat_hierarchy = Array(0); } else { $sql = 'SELECT ParentPath FROM '.$this->getUnitOption('c', 'TableName').' WHERE CategoryId = '.$cat_id; $cat_hierarchy = $this->DB->GetOne($sql); $cat_hierarchy = explode('|', $cat_hierarchy); array_shift($cat_hierarchy); array_pop($cat_hierarchy); $cat_hierarchy = array_reverse($cat_hierarchy); array_push($cat_hierarchy, 0); } $groups = $this->RecallVar('UserGroups'); foreach($cat_hierarchy as $category_id) { $sql = 'SELECT PermissionValue FROM '.TABLE_PREFIX.'Permissions WHERE Permission = "'.$name.'" AND CatId = '.$category_id.' AND GroupId IN ('.$groups.')'; $res = $this->DB->GetOne($sql); if($res !== false) { return $res; } } return 0; } /** * Set's any field of current visit * * @param string $field * @param mixed $value */ function setVisitField($field, $value) { $visit =& $this->recallObject('visits'); $visit->SetDBField($field, $value); $visit->Update(); } } ?> \ No newline at end of file Property changes on: trunk/core/kernel/application.php ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.56 \ No newline at end of property +1.57 \ No newline at end of property Index: trunk/core/kernel/parser/template_parser.php =================================================================== --- trunk/core/kernel/parser/template_parser.php (revision 2677) +++ trunk/core/kernel/parser/template_parser.php (revision 2678) @@ -1,535 +1,537 @@ <?php k4_include_once(KERNEL_PATH.'/parser/tags.php'); k4_include_once(KERNEL_PATH.'/parser/construct_tags.php'); class TemplateParser extends kBase { var $Template; var $Output = ''; var $Position = 0; var $LastPosition = 0; var $Ses; var $Recursion = Array(); var $RecursionIndex = 0; var $SkipMode = 0; var $Params = Array(); var $Pattern = Array(); var $ForSort = Array(); var $Values = Array(); var $Buffers = Array(); var $Args; var $ParamsRecursionIndex = 0; var $ParamsStack = Array(); var $CompiledBuffer; var $DataExists = false; function TemplateParser() { parent::kBase(); $this->Ses =& $this->Application->recallObject('Session'); } function AddParam($pattern, $value, $dont_sort=0) { $this->ForSort[] = Array($pattern, $value); if (!$dont_sort) //used when mass-adding params, to escape sorting after every new param $this->SortParams(); //but do sort by default! } //We need to sort params by its name length desc, so that params starting with same word get parsed correctly function SortParams() { uasort($this->ForSort, array ("TemplateParser", "CmpParams")); $this->Pattern = Array(); $this->Values = Array(); foreach($this->ForSort as $pair) { $this->Pattern[] = $pair[0]; $this->Values[] = $pair[1]; } } function CmpParams($a, $b) { $a_len = strlen($a[0]); $b_len = strlen($b[0]); if ($a_len == $b_len) return 0; return $a_len > $b_len ? -1 : 1; } function SetParams($params) { if (!is_array($params)) $params = Array(); $this->Params = $params; foreach ($params as $key => $val) { $this->AddParam('/[{]{0,1}\$'.$key.'[}]{0,1}/i', $val, 1); //Do not sort every time } $this->SortParams(); //Sort once after adding is done } function GetParam($name) { //return isset($this->Params[strtolower($name)]) ? $this->Params[strtolower($name)] : false; return isset($this->Params[$name]) ? $this->Params[$name] : false; } function SetParam($name, $value) { $this->Params[strtolower($name)] = $value; } function SetBuffer($body) { $this->Buffers[$this->RecursionIndex] = $body; } function GetBuffer() { return $this->Buffers[$this->RecursionIndex]; } function GetCode() { return $this->Code[$this->RecursionIndex]; } function AppendBuffer($append) { $this->Buffers[$this->RecursionIndex] .= $append; $this->AppendCode( $this->ConvertToCode($append) ); } function AppendOutput($append, $append_code=false) { if ($this->SkipMode == parse) { $this->Output .= $append; //append to Ouput only if we are parsing if ($append_code) $this->AppendCompiledHTML($append); } elseif ($this->SkipMode == skip) { if ($append_code) $this->AppendCompiledHTML($append); } elseif ($this->SkipMode == skip_tags) { $this->AppendBuffer($append); //append to buffer if we are skipping tags } } function ConvertToCode($data) { $code = '$o .= \''. str_replace("'", "\'", $data) .'\';'; $code = explode("\n", $code); return $code; } function AppendCode($code) { if (defined('EXPERIMENTAL_PRE_PARSE')) { if (!isset($this->Code[$this->RecursionIndex])) { $this->Code[$this->RecursionIndex] = Array(); } if (is_array($code)) { foreach ($code as $line) { $this->Code[$this->RecursionIndex][] = rtrim($line, "\n")."\n"; } } else { $this->Code[$this->RecursionIndex][] .= rtrim($code, "\n")."\n"; } } } function AppendCompiledFunction($f_name, $f_body) { $real_name = 'f_'.abs(crc32($this->TemplateName)).'_'.$f_name; if (defined('EXPERIMENTAL_PRE_PARSE')) { // if such function already compiled if ( isset($this->Application->CompiledFunctions[$f_name]) || function_exists($real_name) ) { if (!isset($this->Application->CompiledFunctions[$f_name])) { $real_name = $real_name.'_'; } else { $real_name = $this->Application->CompiledFunctions[$f_name].'_'; } } $this->CompiledBuffer .= 'if (!function_exists(\''.$real_name.'\')) {'."\n"; $this->CompiledBuffer .= "\t".'$application->PreParsedBlocks[\''.$f_name.'\'] = \''.$real_name.'\';'; $this->CompiledBuffer .= "\n\t".'function '.$real_name.'($params)'."\n\t{\n"; $this->CompiledBuffer .= $f_body; $this->CompiledBuffer .= "\t}\n\n"; $this->CompiledBuffer .= '}'."\n"; $this->Application->CompiledFunctions[$f_name] = $real_name; } } function AppendCompiledCode($code) { if (defined('EXPERIMENTAL_PRE_PARSE')) { if (is_array($code)) { foreach ($code as $line) { $this->CompiledBuffer .= "\t".rtrim($line, "\n")."\n"; } } else { $this->CompiledBuffer .= $code; } $this->CompiledBuffer .= "\t".'echo $o;'."\n\t".'$o = \'\';'."\n"; } } function AppendCompiledHTML($append) { if (defined('EXPERIMENTAL_PRE_PARSE')) { $this->CompiledBuffer .= '?'.'>'."\n"; $this->CompiledBuffer .= rtrim($append, "\t"); $this->CompiledBuffer .= '<'.'?php'."\n"; } } function ResetCode() { $this->Code[$this->RecursionIndex] = Array(); } function FindTag2() { $openings = Array('<%' => '%>', '<inp2:' => Array('>', '/>'), '</inp2:' => '>', '</inp2>' => ''); $tag_open_pos = false; foreach ($openings as $an_opening => $closings) { $pos = strpos($this->Template, $an_opening, $this->Position); if ($pos !== false && ($tag_open_pos === false || (int) $pos <= (int) $tag_open_pos)) { $tag_open_pos = $pos; $open_len = strlen($an_opening); $opening_tag = $an_opening; $tag_closings = $closings; } } if ($tag_open_pos === false) { //If no tags left - adding all other data $this->AppendOutput(substr($this->Template, $this->Position), true); return false; } //Adding all data before tag open $this->AppendOutput(substr($this->Template, $this->Position, $tag_open_pos - $this->Position), true); if (is_array($tag_closings)) { $tag_close_pos = false; foreach ($tag_closings as $a_closing) { $pos = strpos($this->Template, $a_closing, $tag_open_pos); if ($pos !== false && ($tag_close_pos === false || (int) $pos <= (int) $tag_close_pos)) { $tag_close_pos = $pos; $closing_tag = $a_closing; } } } elseif ($opening_tag == '</inp2>') { $closing_tag = ''; $tag_close_pos = $tag_open_pos + $open_len; } else { $closing_tag = $tag_closings; $tag_close_pos = strpos($this->Template, $closing_tag, $tag_open_pos); } $close_len = strlen($closing_tag); //Cutting out the tag itself $tag = substr($this->Template, $tag_open_pos + $open_len, $tag_close_pos - $tag_open_pos - $open_len); if ($opening_tag == '<inp2:') { //getting prefix_tag upto first space, tab or line break into regs[1] preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs); $tag_part = $regs[1]; if (strpos($tag_part, '_') !== false) { list($prefix, $the_tag) = explode('_', $tag, 2); $tag = $prefix.':'.$the_tag; } else { $the_tag = $tag; $tag = ':'.$tag; } } if ($opening_tag == '</inp2>') { //empty closing means old style in-portal if <inp2:tag>....</inp2> $tag = 'm:endif'; } if ($opening_tag == '</inp2:') { preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs); $tag_part = $regs[1]; if (strpos($tag_part, '_') !== false) { list($prefix, $the_tag) = explode('_', $tag, 2); $tag = $prefix.':'.$the_tag; } $tag .= ' _closing_tag_="1"'; } // if there is no prefix for the tag if (strpos($tag, ':') === 0) { $prefix = getArrayValue($this->Params, 'PrefixSpecial'); $tag = $prefix.$tag; } // temporary - for backward compatability with in-portal style if if ($opening_tag == '<inp2:' && $closing_tag == '>' && $tag_part != 'm_if' && $tag_part != 'm_DefineElement') { if (strpos($the_tag, ' ') !== false) { list($function, $params) = explode(' ', $the_tag, 2); } else { $function = $the_tag; $params = ''; } $tag = 'm:if prefix="'.$prefix.'" function="'.$function.'" '.$params; } $this->Position = $tag_close_pos + $close_len; return $tag; } function CurrentLineNumber() { return substr_count(substr($this->Template, 0, $this->Position), "\n")+1; } function SkipModeName() { switch ($this->SkipMode) { case skip: return 'skip'; case skip_tags: return 'skip_tags'; case parse: return 'parse'; } } function CheckDir($dir) { if (file_exists($dir)) { return; } else { $segments = explode('/', $dir); $cur_path = ''; foreach ($segments as $segment) { $cur_path .= '/'.$segment; if (!file_exists($cur_path)) { mkdir($cur_path); } } } } function Parse($template, $name='unknown', $pre_parse = 1) { $this->Template = $template; $this->TemplateName = $name; $this->Position = 0; $this->Output = ''; $this->TagHolder = new MyTagHolder(); $has_inp_tags = false; if ($this->GetParam('from_inportal')) $pre_parse = 0; if (defined('EXPERIMENTAL_PRE_PARSE') && $pre_parse) { $template_cache =& $this->Application->recallObject('TemplatesCache'); $fname = $template_cache->GetRealFilename($this->TemplateName).'.php'; $fname = str_replace(FULL_PATH, FULL_PATH.'/kernel/cache', $fname); if (!defined('SAFE_MODE') || !SAFE_MODE) { $this->CheckDir(dirname($fname)); } $tname = $template_cache->GetRealFilename($this->TemplateName).'.tpl'; $output = ''; $is_cached = false; ob_start(); if (defined('SAFE_MODE') && SAFE_MODE) { $conn =& $this->Application->GetADODBConnection(); $cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$fname.'"'); if ($cached !== false && $cached['Cached'] > filemtime($tname)) { eval('?'.'>'.$cached['Data'].'<'.'?'); $is_cached = true; } } else { if (file_exists($fname) && filemtime($fname) > filemtime($tname)) { include($fname); $is_cached = true; } } $output = ob_get_contents(); ob_end_clean(); if ( $is_cached && !$this->GetParam('from_inportal') ) { if ( strpos($output, '<inp:') !== false) { $inp1_parser =& $this->Application->recallObject('Inp1Parser'); $output = $inp1_parser->Parse($name, $output); } return $output; } $this->CompiledBuffer .= '<'.'?php'."\n"; $this->CompiledBuffer .= 'global $application;'."\n"; $this->CompiledBuffer .= '$o = \'\';'."\n"; } if (!getArrayValue($this->Params, 'PrefixSpecial')) { $this->Params['PrefixSpecial'] = '$PrefixSpecial'; } //While we have more tags while ($tag_data = $this->FindTag2()) { //Create tag object from passed tag data if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') ) { global $debugger; $debugger->appendHTML('mode: '.$this->SkipModeName().' tag '.$debugger->highlightString($tag_data).' in '.$debugger->getFileLink($debugger->getLocalFile(FULL_PATH.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true)); } // $tag =& new MyTag($tag_data, $this); $tag =& $this->TagHolder->GetTag($tag_data, $this); if (!$this->CheckRecursion($tag)) //we do NOT process closing tags { $tag->Process(); } } if ( !$this->GetParam('from_inportal') ) { if ( strpos($this->Output, '<inp:') !== false) { $inp1_parser =& $this->Application->recallObject('Inp1Parser'); $this->Output = $inp1_parser->Parse($name, $this->Output); $has_inp_tags = true; } } if (defined('EXPERIMENTAL_PRE_PARSE') && $pre_parse && !$has_inp_tags) { // $this->CompiledBuffer .= 'echo $o;'."\n"; $this->CompiledBuffer .= '?'.'>'."\n"; if (defined('SAFE_MODE') && SAFE_MODE) { if (!isset($conn)) $conn =& $this->Application->GetADODBConnection(); $conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ('.$conn->qstr($fname).','.$conn->qstr(str_replace('<'.'?php','<'.'?',$this->CompiledBuffer)).','.mktime().')'); } else { $compiled = fopen($fname, 'w'); fwrite($compiled, $this->CompiledBuffer); fclose($compiled); } } return $this->Output; } function ParseBlock($params, $force_pass_params=0, $as_template=false) { if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') ) { global $debugger; $debugger->appendHTML('ParseBlock '.$params['name'].' pass_params is '.$params['pass_params'].' force is '.$force_pass_params.' in '.$debugger->getFileLink($debugger->getLocalFile(FULL_PATH.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true)); } /*if ( $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRE_PARSE') ) { global $debugger; $debugger->CurrentPreParsedBlock = $params['name']; }*/ if (defined('EXPERIMENTAL_PRE_PARSE')) { $this->MainParser = false; if (isset($this->Application->PreParsedBlocks[$params['name']]) ) { if ($this->ParamsRecursionIndex == 0) { $this->ParamsStack[$this->ParamsRecursionIndex] = $this->Params; } if (isset($params['pass_params']) || $force_pass_params) { $pass_params = array_merge($this->ParamsStack[$this->ParamsRecursionIndex], $params); } else { $pass_params = $params; } $this->ParamsStack[++$this->ParamsRecursionIndex] = $pass_params; $this->Params = $pass_params; $f = $this->Application->PreParsedBlocks[$params['name']]; // $this->ParamsRecursionIndex--; //$this->SetParams($params); + if( !isset($pass_params['PrefixSpecial']) ) $pass_params['PrefixSpecial'] = $pass_params['prefix']; + $ret = $f($pass_params); unset($this->ParamsStack[$this->ParamsRecursionIndex--]); $this->Params = $this->ParamsStack[$this->ParamsRecursionIndex]; $this->MainParser = true; return $ret; } } $BlockParser =& $this->Application->makeClass('TemplateParser'); if (isset($params['pass_params']) || $force_pass_params) { $BlockParser->SetParams(array_merge($this->Params, $params)); } else $BlockParser->SetParams($params); $this->Application->Parser =& $BlockParser; if (!isset($params['name'])) trigger_error('<b>***Error: Block name not passed to ParseBlock</b>', E_USER_ERROR); $templates_cache =& $this->Application->recallObject('TemplatesCache'); $template_name = $as_template ? $params['name'] : $templates_cache->GetTemplateFileName($params['name']) . '-block:'.$params['name']; $silent = getArrayValue($params, 'from_inportal') && !defined('DBG_TEMPLATE_FAILURE'); $o = $BlockParser->Parse( $templates_cache->GetTemplateBody($params['name'], $silent), $template_name ); if (getArrayValue($params, 'BlockNoData') && !$BlockParser->DataExists) { $template_name = $as_template ? $params['BlockNoData'] : $templates_cache->GetTemplateFileName($params['BlockNoData']) . '-block:'.$params['BlockNoData']; $o = $BlockParser->Parse( $templates_cache->GetTemplateBody($params['BlockNoData'], $silent), $template_name ); } $this->Application->Parser =& $this; $this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists; return $o; } function Recurve(&$tag) { $this->Recursion[++$this->RecursionIndex] =& $tag; } function CheckRecursion(&$tag) { if ($this->RecursionIndex > 0) { //If we are inside the recursion if ($this->Recursion[$this->RecursionIndex]->CheckRecursion($tag)) { //If we can close this recursion unset($this->Recursion[$this->RecursionIndex--]); //unsetting current recursion level and decreasing it at the same time return true; //we should inform not to process closing tag } } return false; } function SetSkipMode($mode) { $this->SkipMode = $mode; } } ?> \ No newline at end of file Property changes on: trunk/core/kernel/parser/template_parser.php ___________________________________________________________________ Modified: cvs2svn:cvs-rev ## -1 +1 ## -1.12 \ No newline at end of property +1.13 \ No newline at end of property