2 /***************************************************************
5 * (c) 1999-2004 Kasper Skaarhoj (kasperYYYY@typo3.com)
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 * Contains class with time tracking functions
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
34 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
37 * [CLASS/FUNCTION INDEX of SCRIPT]
41 * 88: class t3lib_timeTrack
43 * SECTION: Logging parsing times in the scripts
44 * 144: function start()
45 * 157: function push($tslabel, $value='')
46 * 182: function pull($content='')
47 * 200: function setTSlogMessage($content,$num=0)
48 * 214: function setTSselectQuery($query,$msg)
49 * 227: function incStackPointer()
50 * 238: function decStackPointer()
51 * 248: function mtime()
52 * 258: function convertMicrotime($microtime)
54 * SECTION: Printing the parsing time information (for Admin Panel)
55 * 291: function printTSlog()
56 * 436: function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='')
57 * 500: function fixCLen($c,$v)
58 * 516: function fw($str)
59 * 530: function createHierarchyArray(&$arr,$pointer,$uniqueId)
60 * 550: function debug_typo3PrintError($header,$text,$js,$baseUrl='')
63 * (This index is automatically created/updated by the extension "extdeveval")
78 * Frontend Timetracking functions
80 * Is used to register how much time is used with operations in TypoScript
83 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
86 * @see t3lib_tsfeBeUserAuth, tslib_fe, tslib_cObj, TSpagegen
88 class t3lib_timeTrack
{
89 var $starttime = 0; // Is loaded with the millisecond time when this object is created
91 var $LR = 1; // Log Rendering flag. If set, ->push() and ->pull() is called from the cObj->cObjGetSingle(). This determines whether or not the TypoScript parsing activity is logged. But it also slows down the rendering
93 'showParentKeys' => 1,
94 'contentLength' => 10000, // Determines max lenght of displayed content before it gets cropped.
95 'contentLength_FILE' => 400, // Determines max lenght of displayed content FROM FILE cObjects before it gets cropped. Reason is that most FILE cObjects are huge and often used as template-code.
106 var $wrapError =array(
108 1 => array('<b>','</b>'),
109 2 => array('<b><font color="#ff6600">','</font></b>'),
110 3 => array('<b><font color="#ff0000">','</font></b>')
112 var $wrapIcon =array(
114 1 => '<img src="t3lib/gfx/icon_note.gif" width="18" height="16" align="absmiddle" alt="" />',
115 2 => '<img src="t3lib/gfx/icon_warning.gif" width="18" height="16" align="absmiddle" alt="" />',
116 3 => '<img src="t3lib/gfx/icon_fatalerror.gif" width="18" height="16" align="absmiddle" alt="" />'
119 var $uniqueCounter=0;
120 var $tsStack = array(array());
121 var $tsStackLevel = 0;
122 var $tsStackLevelMax=array();
123 var $tsStackLog = array();
124 var $tsStackPointer=0;
125 var $currentHashPointer=array();
132 /*******************************************
134 * Logging parsing times in the scripts
136 *******************************************/
140 * Sets the starting time
146 $this->starttime
=$this->mtime();
150 * Pushes an element to the TypoScript tracking array
152 * @param string Label string for the entry, eg. TypoScript property name
153 * @param string Additional value(?)
155 * @see tslib_cObj::cObjGetSingle(), pull()
157 function push($tslabel, $value='') {
158 array_push($this->tsStack
[$this->tsStackPointer
], $tslabel);
159 array_push($this->currentHashPointer
, 'timetracker_'.$this->uniqueCounter++
);
161 $this->tsStackLevel++
;
162 $this->tsStackLevelMax
[] = $this->tsStackLevel
;
165 $k = end($this->currentHashPointer
);
166 $this->tsStackLog
[$k] = array(
167 'level' => $this->tsStackLevel
,
168 'tsStack' => $this->tsStack
,
170 'starttime' => microtime(),
171 'stackPointer' => $this->tsStackPointer
176 * Pulls an element from the TypoScript tracking array
178 * @param string The content string generated within the push/pull part.
180 * @see tslib_cObj::cObjGetSingle(), push()
182 function pull($content='') {
183 $k = end($this->currentHashPointer
);
184 $this->tsStackLog
[$k]['endtime'] = microtime();
185 $this->tsStackLog
[$k]['content'] = $content;
187 $this->tsStackLevel
--;
188 array_pop($this->tsStack
[$this->tsStackPointer
]);
189 array_pop($this->currentHashPointer
);
193 * Logs the TypoScript entry
195 * @param string The message string
196 * @param integer Message type: 0: information, 1: message, 2: warning, 3: error
198 * @see tslib_cObj::CONTENT()
200 function setTSlogMessage($content,$num=0) {
201 end($this->currentHashPointer
);
202 $k = current($this->currentHashPointer
);
204 $this->tsStackLog
[$k]['message'][] = $this->wrapIcon
[$num].$this->wrapError
[$num][0].htmlspecialchars($content).$this->wrapError
[$num][1];
208 * Set TSselectQuery - for messages in TypoScript debugger.
210 * @param string Query string
211 * @param string Message/Label to attach
214 function setTSselectQuery($query,$msg) {
215 end($this->currentHashPointer
);
216 $k = current($this->currentHashPointer
);
218 $this->tsStackLog
[$k]['selectQuery'][] = array('query'=>$query,'msg'=>$msg);
222 * Increases the stack pointer
225 * @see decStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
227 function incStackPointer() {
228 $this->tsStackPointer++
;
229 $this->tsStack
[$this->tsStackPointer
]=array();
233 * Decreases the stack pointer
236 * @see incStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
238 function decStackPointer() {
239 unset($this->tsStack
[$this->tsStackPointer
]);
240 $this->tsStackPointer
--;
244 * Returns the current time in milliseconds
249 return $this->convertMicrotime(microtime())-$this->starttime
;
253 * Returns microtime input to milliseconds
255 * @param string PHP microtime string
258 function convertMicrotime($microtime) {
259 $parts = explode(' ',$microtime);
260 return round(($parts[0]+
$parts[1])*1000);
279 /*******************************************
281 * Printing the parsing time information (for Admin Panel)
283 *******************************************/
286 * Print TypoScript parsing log
288 * @return string HTML table with the information about parsing times.
289 * @see t3lib_tsfeBeUserAuth::extGetCategory_tsdebug()
291 function printTSlog() {
292 // Calculate times and keys for the tsStackLog
293 reset($this->tsStackLog
);
295 while(list($uniqueId,$data)=each($this->tsStackLog
)) {
296 $this->tsStackLog
[$uniqueId]['endtime'] = $this->convertMicrotime($this->tsStackLog
[$uniqueId]['endtime'])-$this->starttime
;
297 $this->tsStackLog
[$uniqueId]['starttime'] = $this->convertMicrotime($this->tsStackLog
[$uniqueId]['starttime'])-$this->starttime
;
298 $this->tsStackLog
[$uniqueId]['deltatime'] = $this->tsStackLog
[$uniqueId]['endtime']-$this->tsStackLog
[$uniqueId]['starttime'];
299 $this->tsStackLog
[$uniqueId]['key'] = implode(end($data['tsStack']),$this->tsStackLog
[$uniqueId]['stackPointer']?
'.':'/');
300 $preEndtime = $this->tsStackLog
[$uniqueId]['endtime'];
303 // Create hierarchical array of keys pointing to the stack
305 reset($this->tsStackLog
);
306 while(list($uniqueId,$data)=each($this->tsStackLog
)) {
307 $this->createHierarchyArray($arr,$data['level'], $uniqueId);
309 // Parsing the registeret content and create icon-html for the tree
310 $this->tsStackLog
[$arr['0.'][0]]['content'] = $this->fixContent($arr['0.']['0.'], $this->tsStackLog
[$arr['0.'][0]]['content'], '', 0, $arr['0.'][0]);
312 // Displaying the tree:
313 reset($this->tsStackLog
);
315 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('TypoScript Key').'</b></td>
316 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Value').'</b></td>';
317 if ($this->printConf
['allTime']) {
319 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Time').'</b></td>
320 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Own').'</b></td>
321 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Sub').'</b></td>
322 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Total').'</b></td>';
325 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Own').'</b></td>';
329 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Details').'</b></td>
334 $flag_tree=$this->printConf
['flag_tree'];
335 $flag_messages=$this->printConf
['flag_messages'];
336 $flag_content=$this->printConf
['flag_content'];
337 $flag_queries=$this->printConf
['flag_queries'];
338 $keyLgd=$this->printConf
['keyLgd'];
339 $factor=$this->printConf
['factor'];
340 $col=$this->printConf
['col'];
343 while(list($uniqueId,$data)=each($this->tsStackLog
)) {
344 $bgColor = ' bgcolor="'.($c%2 ? t3lib_div
::modifyHTMLColor($col,$factor,$factor,$factor) : $col).'"';
346 if (!$c) { // If first...
348 $data['key']= 'Script Start';
355 if (!$flag_tree && $data['stackPointer']) {
357 reset($data['tsStack']);
358 while(list($k,$v)=each($data['tsStack'])) {
359 $temp[]=t3lib_div
::fixed_lgd_pre(implode($v,$k?
'.':'/'),$keyLgd);
362 $temp = array_reverse($temp);
365 $keyLabel='<br /><font color="#999999">'.implode($temp,'<br />').'</font>';
368 $theLabel = $flag_tree ?
end(t3lib_div
::trimExplode('.',$data['key'],1)) : $data['key'];
369 $theLabel = t3lib_div
::fixed_lgd_pre($theLabel, $keyLgd);
370 $theLabel = $data['stackPointer'] ?
'<font color="maroon">'.$theLabel.'</font>' : $theLabel;
371 $keyLabel=$theLabel.$keyLabel;
372 $item.='<td valign="top" nowrap="nowrap"'.$bgColor.'>'.($flag_tree?
$data['icons']:'').$this->fw($keyLabel).'</td>';
375 $keyValue=$data['value'];
376 $item.='<td valign="top" nowrap="nowrap"'.$bgColor.'>'.$this->fw(htmlspecialchars($keyValue)).'</td>';
378 if ($this->printConf
['allTime']) {
380 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['starttime']).'</td>';
381 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['owntime']).'</td>';
382 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['subtime'] ?
'+'.$data['subtime'] : '').'</td>';
383 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['subtime'] ?
'='.$data['deltatime'] : '').'</td>';
386 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['owntime']).'</td>';
393 if ($flag_messages && is_array($data['message'])) {
394 reset($data['message']);
395 while(list(,$v)=each($data['message'])) {
399 if ($flag_queries && is_array($data['selectQuery'])) {
400 reset($data['selectQuery']);
401 while(list(,$v)=each($data['selectQuery'])) {
402 $res = $GLOBALS['TYPO3_DB']->sql_query('EXPLAIN '.$v['query']);
403 $v['mysql_error'] = $GLOBALS['TYPO3_DB']->sql_error();
404 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
405 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
406 $v['explain'][]=$row;
409 $msgArr[]=t3lib_div
::view_array($v);
412 if ($flag_content && strcmp($data['content'],'')) {
413 $msgArr[]='<font color="#000066">'.nl2br($data['content']).'</font>';
415 if (count($msgArr)) {
416 $msg=implode($msgArr,'<hr />');
418 $item.='<td valign="top"'.$bgColor.'>'.$this->fw($msg).'</td>';
419 $out.='<tr>'.$item.'</tr>';
422 $out='<table border="0" cellpadding="0" cellspacing="0">'.$out.'</table>';
427 * Recursively generates the content to display
429 * @param array Array which is modified with content. Reference
430 * @param string Current content string for the level
431 * @param string Prefixed icons for new PM icons
432 * @param boolean Set this for the first call from outside.
433 * @param string Seems to be the previous tsStackLog key
434 * @return string Returns the $content string generated/modified. Also the $arr array is modified!
436 function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='') {
439 // First, find number of entries
441 while(list($k,$v)=each($arr)) {
442 if (t3lib_div
::testInt($k)) {
446 // Traverse through entries
449 while(list($k,$v)=each($arr)) {
450 if (t3lib_div
::testInt($k)) {
453 $deeper = is_array($arr[$k.'.']) ?
1 : 0;
455 $LN = ($ac==$c)?
'blank':'line';
456 $BTM = ($ac==$c)?
'bottom':'';
457 $PM = is_array($arr[$k.'.']) ?
($deeper ?
'minus':'plus') : 'join';
458 $this->tsStackLog
[$v]['icons']=$depthData.($first?
'':'<img src="t3lib/gfx/ol/'.$PM.$BTM.'.gif" width="18" height="16" align="top" border="0" alt="" />');
460 if (strlen($this->tsStackLog
[$v]['content'])) {
461 $content = str_replace($this->tsStackLog
[$v]['content'],$v, $content);
463 if (is_array($arr[$k.'.'])) {
464 $this->tsStackLog
[$v]['content'] = $this->fixContent($arr[$k.'.'], $this->tsStackLog
[$v]['content'], $depthData.($first?
'':'<img src="t3lib/gfx/ol/'.$LN.'.gif" width="18" height="16" align="top" border="0" alt="" />'), 0, $v);
466 $this->tsStackLog
[$v]['content'] = $this->fixCLen($this->tsStackLog
[$v]['content'], $this->tsStackLog
[$v]['value']);
467 $this->tsStackLog
[$v]['subtime']='';
468 $this->tsStackLog
[$v]['owntime']=$this->tsStackLog
[$v]['deltatime'];
470 $subtime+
=$this->tsStackLog
[$v]['deltatime'];
473 // Set content with special chars
474 if (isset($this->tsStackLog
[$vKey])) {
475 $this->tsStackLog
[$vKey]['subtime']=$subtime;
476 $this->tsStackLog
[$vKey]['owntime']=$this->tsStackLog
[$vKey]['deltatime']-$subtime;
478 $content=$this->fixCLen($content, $this->tsStackLog
[$vKey]['value']);
480 // Traverse array again, this time substitute the unique hash with the red key
482 while(list($k,$v)=each($arr)) {
483 if (t3lib_div
::testInt($k)) {
484 if (strlen($this->tsStackLog
[$v]['content'])) {
485 $content = str_replace($v, '<font color="red"><b>['.$this->tsStackLog
[$v]['key'].']</b></font>', $content);
489 // return the content
494 * Wraps the input content string in green colored font-tags IF the length o fthe input string exceeds $this->printConf['contentLength'] (or $this->printConf['contentLength_FILE'] if $v == "FILE"
496 * @param string The content string
497 * @param string Command: If "FILE" then $this->printConf['contentLength_FILE'] is used for content length comparison, otherwise $this->printConf['contentLength']
500 function fixCLen($c,$v) {
501 $len = $v=='FILE'?
$this->printConf
['contentLength_FILE']:$this->printConf
['contentLength'];
502 if (strlen($c)>$len) {
503 $c='<font color="green">'.htmlspecialchars(t3lib_div
::fixed_lgd($c,$len)).'</font>';
505 $c=htmlspecialchars($c);
511 * Wraps input string in a <font> tag with verdana, black and size 1
513 * @param string The string to be wrapped
517 return '<font face="verdana" color="black" size="1" style="color:black;">'.$str.' </font>';
521 * Helper function for internal data manipulation
523 * @param array Array (passed by reference) and modified
524 * @param integer Pointer value
525 * @param string Unique ID string
530 function createHierarchyArray(&$arr,$pointer,$uniqueId) {
531 if (!is_array($arr)) $arr=array();
535 $this->createHierarchyArray($arr[intval($k).'.'],$pointer-1,$uniqueId);
542 * This prints out a TYPO3 error message.
544 * @param string Header string
545 * @param string Message string
546 * @param boolean If set, then this will produce a alert() line for inclusion in JavaScript.
547 * @param string URL for the <base> tag (if you want it)
550 function debug_typo3PrintError($header,$text,$js,$baseUrl='') {
552 echo"alert('".t3lib_div
::slashJS($header."\n".$text)."');";
557 '.($baseUrl ?
'<base href="'.htmlspecialchars($baseUrl).'" />' : '').'
558 <title>Error!</title>
560 <body bgcolor="white">
562 <table border="0" cellspacing="0" cellpadding="0" width="333" bgcolor="#ffffff">
564 <td><img src="t3lib/gfx/typo3logo.gif" width="333" height="43" vspace="10" border="0" alt="" /></td>
568 <table width="100%" border="0" cellspacing="1" cellpadding="10">
570 <td bgcolor="#F4F0E8">
571 <font face="verdana,arial,helvetica" size="2">';
572 echo '<b><center><font size="+1">'.$header.'</font></center></b><br />'.$text;