Only changes to function indexes, comments and stripping of trailing whitespace in...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_timetrack.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
6 * All rights reserved
7 *
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.
13 *
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.
18 *
19 *
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.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class with time tracking functions
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
32 * XHTML compliant
33 *
34 * @author Kasper Skaarhoj <kasper@typo3.com>
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 88: class t3lib_timeTrack
42 *
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)
53 *
54 * SECTION: Printing the parsing time information (for Admin Panel)
55 * 291: function printTSlog()
56 * 435: function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='')
57 * 499: function fixCLen($c,$v)
58 * 515: function fw($str)
59 * 529: function createHierarchyArray(&$arr,$pointer,$uniqueId)
60 * 548: function debug_typo3PrintError($header,$text,$js)
61 *
62 * TOTAL FUNCTIONS: 15
63 * (This index is automatically created/updated by the extension "extdeveval")
64 *
65 */
66
67
68
69
70
71
72
73
74
75
76
77 /**
78 * Frontend Timetracking functions
79 *
80 * Is used to register how much time is used with operations in TypoScript
81 * Used by index_ts
82 *
83 * @author Kasper Skaarhoj <kasper@typo3.com>
84 * @package TYPO3
85 * @subpackage t3lib
86 * @see t3lib_tsfeBeUserAuth, tslib_fe, tslib_cObj, TSpagegen
87 */
88 class t3lib_timeTrack {
89 var $starttime = 0; // Is loaded with the millisecond time when this object is created
90
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
92 var $printConf=array(
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.
96 'flag_tree' => 1,
97 'flag_messages' => 1,
98 'flag_queries' => 0,
99 'flag_content' => 0,
100 'allTime' => 0,
101 'keyLgd' => 40,
102 'factor' => 10,
103 'col' => '#D9D5C9'
104 );
105
106 var $wrapError =array(
107 0 => array('',''),
108 1 => array('<b>','</b>'),
109 2 => array('<b><font color="#ff6600">','</font></b>'),
110 3 => array('<b><font color="#ff0000">','</font></b>')
111 );
112 var $wrapIcon =array(
113 0 => '',
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="" />'
117 );
118
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();
126
127
128
129
130
131
132 /*******************************************
133 *
134 * Logging parsing times in the scripts
135 *
136 *******************************************/
137
138 /**
139 * Constructor
140 * Sets the starting time
141 *
142 * @return void
143 */
144 function start() {
145 $this->starttime=0;
146 $this->starttime=$this->mtime();
147 }
148
149 /**
150 * Pushes an element to the TypoScript tracking array
151 *
152 * @param string Label string for the entry, eg. TypoScript property name
153 * @param string Additional value(?)
154 * @return void
155 * @see tslib_cObj::cObjGetSingle(), pull()
156 */
157 function push($tslabel, $value='') {
158 array_push($this->tsStack[$this->tsStackPointer], $tslabel);
159 array_push($this->currentHashPointer, 'timetracker_'.$this->uniqueCounter++);
160
161 $this->tsStackLevel++;
162 $this->tsStackLevelMax[] = $this->tsStackLevel;
163
164 // setTSlog
165 $k = end($this->currentHashPointer);
166 $this->tsStackLog[$k] = array(
167 'level' => $this->tsStackLevel,
168 'tsStack' => $this->tsStack,
169 'value' => $value,
170 'starttime' => microtime(),
171 'stackPointer' => $this->tsStackPointer
172 );
173 }
174
175 /**
176 * Pulls an element from the TypoScript tracking array
177 *
178 * @param string The content string generated within the push/pull part.
179 * @return void
180 * @see tslib_cObj::cObjGetSingle(), push()
181 */
182 function pull($content='') {
183 $k = end($this->currentHashPointer);
184 $this->tsStackLog[$k]['endtime'] = microtime();
185 $this->tsStackLog[$k]['content'] = $content;
186
187 $this->tsStackLevel--;
188 array_pop($this->tsStack[$this->tsStackPointer]);
189 array_pop($this->currentHashPointer);
190 }
191
192 /**
193 * Logs the TypoScript entry
194 *
195 * @param string The message string
196 * @param integer Message type: 0: information, 1: message, 2: warning, 3: error
197 * @return void
198 * @see tslib_cObj::CONTENT()
199 */
200 function setTSlogMessage($content,$num=0) {
201 end($this->currentHashPointer);
202 $k = current($this->currentHashPointer);
203
204 $this->tsStackLog[$k]['message'][] = $this->wrapIcon[$num].$this->wrapError[$num][0].htmlspecialchars($content).$this->wrapError[$num][1];
205 }
206
207 /**
208 * Set TSselectQuery - for messages in TypoScript debugger.
209 *
210 * @param string Query string
211 * @param string Message/Label to attach
212 * @return void
213 */
214 function setTSselectQuery($query,$msg) {
215 end($this->currentHashPointer);
216 $k = current($this->currentHashPointer);
217
218 $this->tsStackLog[$k]['selectQuery'][] = array('query'=>$query,'msg'=>$msg);
219 }
220
221 /**
222 * Increases the stack pointer
223 *
224 * @return void
225 * @see decStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
226 */
227 function incStackPointer() {
228 $this->tsStackPointer++;
229 $this->tsStack[$this->tsStackPointer]=array();
230 }
231
232 /**
233 * Decreases the stack pointer
234 *
235 * @return void
236 * @see incStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
237 */
238 function decStackPointer() {
239 unset($this->tsStack[$this->tsStackPointer]);
240 $this->tsStackPointer--;
241 }
242
243 /**
244 * Returns the current time in milliseconds
245 *
246 * @return integer
247 */
248 function mtime() {
249 return $this->convertMicrotime(microtime())-$this->starttime;
250 }
251
252 /**
253 * Returns microtime input to milliseconds
254 *
255 * @param string PHP microtime string
256 * @return integer
257 */
258 function convertMicrotime($microtime) {
259 $parts = explode(' ',$microtime);
260 return round(($parts[0]+$parts[1])*1000);
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279 /*******************************************
280 *
281 * Printing the parsing time information (for Admin Panel)
282 *
283 *******************************************/
284
285 /**
286 * Print TypoScript parsing log
287 *
288 * @return string HTML table with the information about parsing times.
289 * @see t3lib_tsfeBeUserAuth::extGetCategory_tsdebug()
290 */
291 function printTSlog() {
292 // Calculate times and keys for the tsStackLog
293 reset($this->tsStackLog);
294 $preEndtime=0;
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'];
301 }
302
303 // Create hierarchical array of keys pointing to the stack
304 $arr = array();
305 reset($this->tsStackLog);
306 while(list($uniqueId,$data)=each($this->tsStackLog)) {
307 $this->createHierarchyArray($arr,$data['level'], $uniqueId);
308 }
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]);
311
312 // Displaying the tree:
313 reset($this->tsStackLog);
314 $out='<tr>
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']) {
318 $out.='
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>';
323 } else {
324 $out.='
325 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Own').'</b></td>';
326 }
327
328 $out.='
329 <td bgcolor="#ABBBB4" align="center"><b>'.$this->fw('Details').'</b></td>
330 </tr>';
331
332
333
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'];
341
342 $c=0;
343 while(list($uniqueId,$data)=each($this->tsStackLog)) {
344 $bgColor = ' bgcolor="'.($c%2 ? t3lib_div::modifyHTMLColor($col,$factor,$factor,$factor) : $col).'"';
345 $item='';
346 if (!$c) { // If first...
347 $data['icons']='';
348 $data['key']= 'Script Start';
349 $data['value'] = '';
350 }
351
352
353 // key label:
354 $keyLabel='';
355 if (!$flag_tree && $data['stackPointer']) {
356 $temp=array();
357 reset($data['tsStack']);
358 while(list($k,$v)=each($data['tsStack'])) {
359 $temp[]=t3lib_div::fixed_lgd_pre(implode($v,$k?'.':'/'),$keyLgd);
360 }
361 array_pop($temp);
362 $temp = array_reverse($temp);
363 array_pop($temp);
364 if (count($temp)) {
365 $keyLabel='<br /><font color="#999999">'.implode($temp,'<br />').'</font>';
366 }
367 }
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>';
373
374 // key value:
375 $keyValue=$data['value'];
376 $item.='<td valign="top" nowrap="nowrap"'.$bgColor.'>'.$this->fw(htmlspecialchars($keyValue)).'</td>';
377
378 if ($this->printConf['allTime']) {
379 // deltatime:
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>';
384 } else {
385 // deltatime:
386 $item.='<td valign="top" align="right" nowrap="nowrap"'.$bgColor.'>'.$this->fw($data['owntime']).'</td>';
387 }
388
389
390 // messages:
391 $msgArr=array();
392 $msg='';
393 if ($flag_messages && is_array($data['message'])) {
394 reset($data['message']);
395 while(list(,$v)=each($data['message'])) {
396 $msgArr[]=nl2br($v);
397 }
398 }
399 if ($flag_queries && is_array($data['selectQuery'])) {
400 reset($data['selectQuery']);
401 while(list(,$v)=each($data['selectQuery'])) {
402 $v['mysql_error'] = $GLOBALS['TYPO3_DB']->sql_error();
403 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
404 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
405 $v['explain'][]=$row;
406 }
407 }
408 $msgArr[]=t3lib_div::view_array($v);
409 }
410 }
411 if ($flag_content && strcmp($data['content'],'')) {
412 $msgArr[]='<font color="#000066">'.nl2br($data['content']).'</font>';
413 }
414 if (count($msgArr)) {
415 $msg=implode($msgArr,'<hr />');
416 }
417 $item.='<td valign="top"'.$bgColor.'>'.$this->fw($msg).'</td>';
418 $out.='<tr>'.$item.'</tr>';
419 $c++;
420 }
421 $out='<table border="0" cellpadding="0" cellspacing="0">'.$out.'</table>';
422 return $out;
423 }
424
425 /**
426 * Recursively generates the content to display
427 *
428 * @param array Array which is modified with content. Reference
429 * @param string Current content string for the level
430 * @param string Prefixed icons for new PM icons
431 * @param boolean Set this for the first call from outside.
432 * @param string Seems to be the previous tsStackLog key
433 * @return string Returns the $content string generated/modified. Also the $arr array is modified!
434 */
435 function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='') {
436 $ac=0;
437 $c=0;
438 // First, find number of entries
439 reset($arr);
440 while(list($k,$v)=each($arr)) {
441 if (t3lib_div::testInt($k)) {
442 $ac++;
443 }
444 }
445 // Traverse through entries
446 $subtime=0;
447 reset($arr);
448 while(list($k,$v)=each($arr)) {
449 if (t3lib_div::testInt($k)) {
450 $c++;
451
452 $deeper = is_array($arr[$k.'.']) ? 1 : 0;
453 $PM = 'join';
454 $LN = ($ac==$c)?'blank':'line';
455 $BTM = ($ac==$c)?'bottom':'';
456 $PM = is_array($arr[$k.'.']) ? ($deeper ? 'minus':'plus') : 'join';
457 $this->tsStackLog[$v]['icons']=$depthData.($first?'':'<img src="t3lib/gfx/ol/'.$PM.$BTM.'.gif" width="18" height="16" align="top" border="0" alt="" />');
458
459 if (strlen($this->tsStackLog[$v]['content'])) {
460 $content = str_replace($this->tsStackLog[$v]['content'],$v, $content);
461 }
462 if (is_array($arr[$k.'.'])) {
463 $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);
464 } else {
465 $this->tsStackLog[$v]['content'] = $this->fixCLen($this->tsStackLog[$v]['content'], $this->tsStackLog[$v]['value']);
466 $this->tsStackLog[$v]['subtime']='';
467 $this->tsStackLog[$v]['owntime']=$this->tsStackLog[$v]['deltatime'];
468 }
469 $subtime+=$this->tsStackLog[$v]['deltatime'];
470 }
471 }
472 // Set content with special chars
473 if (isset($this->tsStackLog[$vKey])) {
474 $this->tsStackLog[$vKey]['subtime']=$subtime;
475 $this->tsStackLog[$vKey]['owntime']=$this->tsStackLog[$vKey]['deltatime']-$subtime;
476 }
477 $content=$this->fixCLen($content, $this->tsStackLog[$vKey]['value']);
478
479 // Traverse array again, this time substitute the unique hash with the red key
480 reset($arr);
481 while(list($k,$v)=each($arr)) {
482 if (t3lib_div::testInt($k)) {
483 if (strlen($this->tsStackLog[$v]['content'])) {
484 $content = str_replace($v, '<font color="red"><b>['.$this->tsStackLog[$v]['key'].']</b></font>', $content);
485 }
486 }
487 }
488 // return the content
489 return $content;
490 }
491
492 /**
493 * 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"
494 *
495 * @param string The content string
496 * @param string Command: If "FILE" then $this->printConf['contentLength_FILE'] is used for content length comparison, otherwise $this->printConf['contentLength']
497 * @return string
498 */
499 function fixCLen($c,$v) {
500 $len = $v=='FILE'?$this->printConf['contentLength_FILE']:$this->printConf['contentLength'];
501 if (strlen($c)>$len) {
502 $c='<font color="green">'.htmlspecialchars(t3lib_div::fixed_lgd($c,$len)).'</font>';
503 } else {
504 $c=htmlspecialchars($c);
505 }
506 return $c;
507 }
508
509 /**
510 * Wraps input string in a <font> tag with verdana, black and size 1
511 *
512 * @param string The string to be wrapped
513 * @return string
514 */
515 function fw($str) {
516 return '<font face="verdana" color="black" size="1" style="color:black;">'.$str.'&nbsp;</font>';
517 }
518
519 /**
520 * Helper function for internal data manipulation
521 *
522 * @param array Array (passed by reference) and modified
523 * @param integer Pointer value
524 * @param string Unique ID string
525 * @return void
526 * @access private
527 * @see printTSlog()
528 */
529 function createHierarchyArray(&$arr,$pointer,$uniqueId) {
530 if (!is_array($arr)) $arr=array();
531 if ($pointer>0) {
532 end($arr);
533 $k=key($arr);
534 $this->createHierarchyArray($arr[intval($k).'.'],$pointer-1,$uniqueId);
535 } else {
536 $arr[] = $uniqueId;
537 }
538 }
539
540 /**
541 * This prints out a TYPO3 error message.
542 *
543 * @param string Header string
544 * @param string Message string
545 * @param boolean If set, then this will produce a alert() line for inclusion in JavaScript.
546 * @return string
547 */
548 function debug_typo3PrintError($header,$text,$js) {
549 if ($js) {
550 echo"alert('".t3lib_div::slashJS($header."\n".$text)."');";
551 } else {
552 echo '
553 <html>
554 <head>
555 <title>Error!</title>
556 </head>
557 <body bgcolor="white">
558 <div align="center">
559 <table border="0" cellspacing="0" cellpadding="0" width="333" bgcolor="#ffffff">
560 <tr>
561 <td><img src="t3lib/gfx/typo3logo.gif" width="333" height="43" vspace="10" border="0" alt="" /></td>
562 </tr>
563 <tr>
564 <td bgcolor="black">
565 <table width="100%" border="0" cellspacing="1" cellpadding="10">
566 <tr>
567 <td bgcolor="#F4F0E8">
568 <font face="verdana,arial,helvetica" size="2">';
569 echo '<b><center><font size="+1">'.$header.'</font></center></b><br />'.$text;
570 echo ' </font>
571 </td>
572 </tr>
573 </table>
574 </td>
575 </tr>
576 </table>
577 </div>
578 </body>
579 </html>';
580 }
581 }
582 }
583 ?>