af35c9b6deb02901ce450fc3311ab0882f0e641f
2 /***************************************************************
5 * (c) 1999-2007 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 * 164: function push($tslabel, $value='')
46 * 189: function pull($content='')
47 * 207: function setTSlogMessage($content,$num=0)
48 * 221: function setTSselectQuery($query,$msg)
49 * 234: function incStackPointer()
50 * 245: function decStackPointer()
51 * 255: function mtime()
52 * 265: function convertMicrotime($microtime)
54 * SECTION: Printing the parsing time information (for Admin Panel)
55 * 298: function printTSlog()
56 * 447: function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='')
57 * 511: function fixCLen($c,$v)
58 * 527: function fw($str)
59 * 541: function createHierarchyArray(&$arr,$pointer,$uniqueId)
60 * 561: 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.
104 'highlight_col' => '#FF9933'
107 var $wrapError = array();
108 var $wrapIcon = array();
109 var $uniqueCounter = 0;
110 var $tsStack = array(array());
111 var $tsStackLevel = 0;
112 var $tsStackLevelMax = array();
113 var $tsStackLog = array();
114 var $tsStackPointer = 0;
115 var $currentHashPointer = array();
117 var $highlightLongerThan = 0; // Log entries that take than this number of milliseconds (own time) will be highlighted during log display. Set 0 to disable highlighting.
125 /*******************************************
127 * Logging parsing times in the scripts
129 *******************************************/
133 * Sets the starting time
138 $this->wrapError
= array(
140 1 => array('<strong>','</strong>'),
141 2 => array('<strong style="color:#ff6600;">','</strong>'),
142 3 => array('<strong style="color:#ff0000;">','</strong>')
145 $this->wrapIcon
= array(
147 1 => '<img src="'.TYPO3_mainDir
.'gfx/icon_note.gif" width="18" height="16" align="absmiddle" alt="" />',
148 2 => '<img src="'.TYPO3_mainDir
.'gfx/icon_warning.gif" width="18" height="16" align="absmiddle" alt="" />',
149 3 => '<img src="'.TYPO3_mainDir
.'gfx/icon_fatalerror.gif" width="18" height="16" align="absmiddle" alt="" />'
152 $this->starttime
= 0;
153 $this->starttime
= $this->mtime();
157 * Pushes an element to the TypoScript tracking array
159 * @param string Label string for the entry, eg. TypoScript property name
160 * @param string Additional value(?)
162 * @see tslib_cObj::cObjGetSingle(), pull()
164 function push($tslabel, $value='') {
165 array_push($this->tsStack
[$this->tsStackPointer
], $tslabel);
166 array_push($this->currentHashPointer
, 'timetracker_'.$this->uniqueCounter++
);
168 $this->tsStackLevel++
;
169 $this->tsStackLevelMax
[] = $this->tsStackLevel
;
172 $k = end($this->currentHashPointer
);
173 $this->tsStackLog
[$k] = array(
174 'level' => $this->tsStackLevel
,
175 'tsStack' => $this->tsStack
,
177 'starttime' => microtime(),
178 'stackPointer' => $this->tsStackPointer
183 * Pulls an element from the TypoScript tracking array
185 * @param string The content string generated within the push/pull part.
187 * @see tslib_cObj::cObjGetSingle(), push()
189 function pull($content='') {
190 $k = end($this->currentHashPointer
);
191 $this->tsStackLog
[$k]['endtime'] = microtime();
192 $this->tsStackLog
[$k]['content'] = $content;
194 $this->tsStackLevel
--;
195 array_pop($this->tsStack
[$this->tsStackPointer
]);
196 array_pop($this->currentHashPointer
);
200 * Logs the TypoScript entry
202 * @param string The message string
203 * @param integer Message type: 0: information, 1: message, 2: warning, 3: error
205 * @see tslib_cObj::CONTENT()
207 function setTSlogMessage($content,$num=0) {
208 end($this->currentHashPointer
);
209 $k = current($this->currentHashPointer
);
211 if (strlen($content)>30) { // Enlarge the "details" column by adding a wide clear.gif
212 $placeholder = '<br /><img src="'.TYPO3_mainDir
.'clear.gif" width="300" height="1" alt="" />';
214 $this->tsStackLog
[$k]['message'][] = $this->wrapIcon
[$num].$this->wrapError
[$num][0].htmlspecialchars($content).$this->wrapError
[$num][1].$placeholder;
218 * Set TSselectQuery - for messages in TypoScript debugger.
220 * @param string Query string
221 * @param string Message/Label to attach
224 function setTSselectQuery($query,$msg) {
225 end($this->currentHashPointer
);
226 $k = current($this->currentHashPointer
);
228 $this->tsStackLog
[$k]['selectQuery'][] = array('query'=>$query,'msg'=>$msg);
232 * Increases the stack pointer
235 * @see decStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
237 function incStackPointer() {
238 $this->tsStackPointer++
;
239 $this->tsStack
[$this->tsStackPointer
]=array();
243 * Decreases the stack pointer
246 * @see incStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
248 function decStackPointer() {
249 unset($this->tsStack
[$this->tsStackPointer
]);
250 $this->tsStackPointer
--;
254 * Returns the current time in milliseconds
259 return $this->convertMicrotime(microtime())-$this->starttime
;
263 * Returns microtime input to milliseconds
265 * @param string PHP microtime string
268 function convertMicrotime($microtime) {
269 $parts = explode(' ',$microtime);
270 return round(($parts[0]+
$parts[1])*1000);
289 /*******************************************
291 * Printing the parsing time information (for Admin Panel)
293 *******************************************/
296 * Print TypoScript parsing log
298 * @return string HTML table with the information about parsing times.
299 * @see t3lib_tsfeBeUserAuth::extGetCategory_tsdebug()
301 function printTSlog() {
302 // Calculate times and keys for the tsStackLog
304 foreach($this->tsStackLog
as $uniqueId=>$data) {
305 $this->tsStackLog
[$uniqueId]['endtime'] = $this->convertMicrotime($this->tsStackLog
[$uniqueId]['endtime'])-$this->starttime
;
306 $this->tsStackLog
[$uniqueId]['starttime'] = $this->convertMicrotime($this->tsStackLog
[$uniqueId]['starttime'])-$this->starttime
;
307 $this->tsStackLog
[$uniqueId]['deltatime'] = $this->tsStackLog
[$uniqueId]['endtime']-$this->tsStackLog
[$uniqueId]['starttime'];
308 $this->tsStackLog
[$uniqueId]['key'] = implode($this->tsStackLog
[$uniqueId]['stackPointer']?
'.':'/', end($data['tsStack']));
309 $preEndtime = $this->tsStackLog
[$uniqueId]['endtime'];
312 // Create hierarchical array of keys pointing to the stack
314 reset($this->tsStackLog
);
315 while(list($uniqueId,$data)=each($this->tsStackLog
)) {
316 $this->createHierarchyArray($arr,$data['level'], $uniqueId);
318 // Parsing the registeret content and create icon-html for the tree
319 $this->tsStackLog
[$arr['0.'][0]]['content'] = $this->fixContent($arr['0.']['0.'], $this->tsStackLog
[$arr['0.'][0]]['content'], '', 0, $arr['0.'][0]);
321 // Displaying the tree:
322 reset($this->tsStackLog
);
324 $outputArr = array();
325 $outputArr[] = $this->fw('TypoScript Key');
326 $outputArr[] = $this->fw('Value');
328 if ($this->printConf
['allTime']) {
329 $outputArr[] = $this->fw('Time');
330 $outputArr[] = $this->fw('Own');
331 $outputArr[] = $this->fw('Sub');
332 $outputArr[] = $this->fw('Total');
334 $outputArr[] = $this->fw('Own');
337 $outputArr[] = $this->fw('Details');
340 foreach ($outputArr as $row) {
342 <th style="text-align:center; background:#ABBBB4;"><strong>'.$row.'</strong></th>';
344 $out = '<tr>'.$out.'</tr>';
346 $flag_tree = $this->printConf
['flag_tree'];
347 $flag_messages = $this->printConf
['flag_messages'];
348 $flag_content = $this->printConf
['flag_content'];
349 $flag_queries = $this->printConf
['flag_queries'];
350 $keyLgd = $this->printConf
['keyLgd'];
351 $factor = $this->printConf
['factor'];
352 $col = $this->printConf
['col'];
353 $highlight_col = $this->printConf
['highlight_col'];
356 while(list($uniqueId,$data)=each($this->tsStackLog
)) {
357 $bgColor = ' background-color:'.($c%2 ? t3lib_div
::modifyHTMLColor($col,$factor,$factor,$factor) : $col).';';
358 if ($this->highlightLongerThan
&& intval($data['owntime']) > intval($this->highlightLongerThan
)) {
359 $bgColor = ' background-color:'.$highlight_col.';';
363 if (!$c) { // If first...
365 $data['key'] = 'Script Start';
372 if (!$flag_tree && $data['stackPointer']) {
374 reset($data['tsStack']);
375 while(list($k,$v)=each($data['tsStack'])) {
376 $temp[] = t3lib_div
::fixed_lgd_pre(implode($v,$k?
'.':'/'),$keyLgd);
379 $temp = array_reverse($temp);
382 $keyLabel = '<br /><span style="color:#999999;">'.implode($temp,'<br />').'</span>';
386 $tmp = t3lib_div
::trimExplode('.',$data['key'],1);
387 $theLabel = end($tmp);
389 $theLabel = $data['key'];
391 $theLabel = t3lib_div
::fixed_lgd_pre($theLabel, $keyLgd);
392 $theLabel = $data['stackPointer'] ?
'<span style="color:maroon;">'.$theLabel.'</span>' : $theLabel;
393 $keyLabel = $theLabel.$keyLabel;
394 $item.= '<td valign="top" style="text-align:left; white-space:nowrap; padding-left:2px;'.$bgColor.'">'.($flag_tree?
$data['icons']:'').$this->fw($keyLabel).'</td>';
397 $keyValue = $data['value'];
398 $item.= '<td valign="top" style="text-align:left; white-space:nowrap;'.$bgColor.'">'.$this->fw(htmlspecialchars($keyValue)).'</td>';
400 if ($this->printConf
['allTime']) {
401 $item.= '<td valign="top" style="text-align:right; white-space:nowrap;'.$bgColor.'"> '.$this->fw($data['starttime']).'</td>';
402 $item.= '<td valign="top" style="text-align:right; white-space:nowrap;'.$bgColor.'"> '.$this->fw($data['owntime']).'</td>';
403 $item.= '<td valign="top" style="text-align:left; white-space:nowrap;'.$bgColor.'"> '.$this->fw($data['subtime'] ?
'+'.$data['subtime'] : '').'</td>';
404 $item.= '<td valign="top" style="text-align:left; white-space:nowrap;'.$bgColor.'"> '.$this->fw($data['subtime'] ?
'='.$data['deltatime'] : '').'</td>';
406 $item.= '<td valign="top" style="text-align:right; white-space:nowrap;'.$bgColor.'"> '.$this->fw($data['owntime']).'</td>';
413 if ($flag_messages && is_array($data['message'])) {
414 reset($data['message']);
415 while(list(,$v)=each($data['message'])) {
416 $msgArr[] = nl2br($v);
419 if ($flag_queries && is_array($data['selectQuery'])) {
420 reset($data['selectQuery']);
421 while(list(,$v)=each($data['selectQuery'])) {
422 $res = $GLOBALS['TYPO3_DB']->sql_query('EXPLAIN '.$v['query']);
423 $v['mysql_error'] = $GLOBALS['TYPO3_DB']->sql_error();
424 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
425 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
426 $v['explain'][]=$row;
429 $msgArr[] = t3lib_div
::view_array($v);
432 if ($flag_content && strcmp($data['content'],'')) {
434 if (preg_match_all('/(\S{'.$maxlen.',})/', $data['content'], $reg)) { // Break lines which are too longer than $maxlen chars (can happen if content contains long paths...)
435 foreach ($reg[1] as $key=>$match) {
436 $match = preg_replace('/(.{'.$maxlen.'})/', '$1 ', $match);
437 $data['content'] = str_replace($reg[0][$key], $match, $data['content']);
440 $msgArr[] = '<span style="color:#000066;">'.nl2br($data['content']).'</span>';
442 if (count($msgArr)) {
443 $msg = implode($msgArr,'<hr />');
445 $item.= '<td valign="top" style="text-align:left;'.$bgColor.'">'.$this->fw($msg).'</td>';
446 $out.= '<tr>'.$item.'</tr>';
449 $out = '<table border="0" cellpadding="0" cellspacing="0" summary="">'.$out.'</table>';
454 * Recursively generates the content to display
456 * @param array Array which is modified with content. Reference
457 * @param string Current content string for the level
458 * @param string Prefixed icons for new PM icons
459 * @param boolean Set this for the first call from outside.
460 * @param string Seems to be the previous tsStackLog key
461 * @return string Returns the $content string generated/modified. Also the $arr array is modified!
463 function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='') {
466 // First, find number of entries
468 while(list($k,$v)=each($arr)) {
469 if (t3lib_div
::testInt($k)) {
473 // Traverse through entries
476 while(list($k,$v)=each($arr)) {
477 if (t3lib_div
::testInt($k)) {
480 $deeper = is_array($arr[$k.'.']) ?
1 : 0;
482 $LN = ($ac==$c)?
'blank':'line';
483 $BTM = ($ac==$c)?
'bottom':'';
484 $PM = is_array($arr[$k.'.']) ?
($deeper ?
'minus':'plus') : 'join';
485 $this->tsStackLog
[$v]['icons'] = $depthData.($first?
'':'<img src="'.TYPO3_mainDir
.'gfx/ol/'.$PM.$BTM.'.gif" width="18" height="16" align="top" border="0" alt="" />');
487 if (strlen($this->tsStackLog
[$v]['content'])) {
488 $content = str_replace($this->tsStackLog
[$v]['content'],$v, $content);
490 if (is_array($arr[$k.'.'])) {
491 $this->tsStackLog
[$v]['content'] = $this->fixContent($arr[$k.'.'], $this->tsStackLog
[$v]['content'], $depthData.($first?
'':'<img src="'.TYPO3_mainDir
.'gfx/ol/'.$LN.'.gif" width="18" height="16" align="top" border="0" alt="" />'), 0, $v);
493 $this->tsStackLog
[$v]['content'] = $this->fixCLen($this->tsStackLog
[$v]['content'], $this->tsStackLog
[$v]['value']);
494 $this->tsStackLog
[$v]['subtime'] = '';
495 $this->tsStackLog
[$v]['owntime'] = $this->tsStackLog
[$v]['deltatime'];
497 $subtime+
= $this->tsStackLog
[$v]['deltatime'];
500 // Set content with special chars
501 if (isset($this->tsStackLog
[$vKey])) {
502 $this->tsStackLog
[$vKey]['subtime'] = $subtime;
503 $this->tsStackLog
[$vKey]['owntime'] = $this->tsStackLog
[$vKey]['deltatime']-$subtime;
505 $content=$this->fixCLen($content, $this->tsStackLog
[$vKey]['value']);
507 // Traverse array again, this time substitute the unique hash with the red key
509 while(list($k,$v)=each($arr)) {
510 if (t3lib_div
::testInt($k)) {
511 if (strlen($this->tsStackLog
[$v]['content'])) {
512 $content = str_replace($v, '<strong style="color:red;">['.$this->tsStackLog
[$v]['key'].']</strong>', $content);
516 // return the content
521 * Wraps the input content string in green colored span-tags IF the length o fthe input string exceeds $this->printConf['contentLength'] (or $this->printConf['contentLength_FILE'] if $v == "FILE"
523 * @param string The content string
524 * @param string Command: If "FILE" then $this->printConf['contentLength_FILE'] is used for content length comparison, otherwise $this->printConf['contentLength']
527 function fixCLen($c,$v) {
528 $len = $v=='FILE'?
$this->printConf
['contentLength_FILE']:$this->printConf
['contentLength'];
529 if (strlen($c)>$len) {
530 $c = '<span style="color:green;">'.htmlspecialchars(t3lib_div
::fixed_lgd($c,$len)).'</span>';
532 $c = htmlspecialchars($c);
538 * Wraps input string in a <span> tag with black verdana font
540 * @param string The string to be wrapped
544 return '<span style="font-family:Verdana,Arial,Helvetica,sans-serif; font-size:0.6em; color:black; vertical-align:top;">'.$str.' </span>';
548 * Helper function for internal data manipulation
550 * @param array Array (passed by reference) and modified
551 * @param integer Pointer value
552 * @param string Unique ID string
557 function createHierarchyArray(&$arr,$pointer,$uniqueId) {
558 if (!is_array($arr)) {
564 $this->createHierarchyArray($arr[intval($k).'.'],$pointer-1,$uniqueId);
571 * This prints out a TYPO3 error message.
573 * @param string Header string
574 * @param string Message string
575 * @param boolean If set, then this will produce a alert() line for inclusion in JavaScript.
576 * @param string URL for the <base> tag (if you want it)
579 function debug_typo3PrintError($header,$text,$js,$baseUrl='') {
581 echo "alert('".t3lib_div
::slashJS($header."\n".$text)."');";
583 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
584 "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
585 <?xml version="1.0" encoding="utf-8"?>
588 '.($baseUrl ?
'<base href="'.htmlspecialchars($baseUrl).'" />' : '').'
589 <title>Error!</title>
590 <style type="text/css"><!--/*--><![CDATA[/*><!--*/
591 body { font-family:Verdana,Arial,Helvetica,sans-serif; font-size: 90%; text-align: center; background-color: #ffffff; }
592 h1 { font-size: 1.2em; margin: 0 0 1em 0; }
593 p { margin: 0; text-align: left; }
594 img { border: 0; margin: 10px 0; }
595 div.center div { margin: 0 auto; }
596 .errorBox { width: 400px; padding: 0.5em; border: 1px solid black; background-color: #F4F0E8; }
601 <img src="'.TYPO3_mainDir
.'gfx/typo3logo.gif" width="123" height="34" alt="" />
602 <div class="errorBox">
613 // XCLASSing is not possible for this class