Tons of changes made to the CORE. All scripts has more a less been modified. Primaril...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_timetrack.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 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 * 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 * 549: 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].$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(htmlspecialchars($v));
397 }
398 }
399 if ($flag_queries && is_array($data['selectQuery'])) {
400 reset($data['selectQuery']);
401 while(list(,$v)=each($data['selectQuery'])) {
402 $res = mysql(TYPO3_db,'EXPLAIN '.$v['query']);
403 $v['mysql_error']=mysql_error();
404 if (!mysql_error()) {
405 while($row=mysql_fetch_assoc($res)) {
406 $v['explain'][]=$row;
407 }
408 }
409 $msgArr[]=t3lib_div::view_array($v);
410 }
411 }
412 if ($flag_content && strcmp($data['content'],'')) {
413 $msgArr[]='<font color="#000066">'.nl2br($data['content']).'</font>';
414 }
415 if (count($msgArr)) {
416 $msg=implode($msgArr,'<hr />');
417 }
418 $item.='<td valign="top"'.$bgColor.'>'.$this->fw($msg).'</td>';
419 $out.='<tr>'.$item.'</tr>';
420 $c++;
421 }
422 $out='<table border="0" cellpadding="0" cellspacing="0">'.$out.'</table>';
423 return $out;
424 }
425
426 /**
427 * Recursively generates the content to display
428 *
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!
435 */
436 function fixContent(&$arr, $content, $depthData='', $first=0, $vKey='') {
437 $ac=0;
438 $c=0;
439 // First, find number of entries
440 reset($arr);
441 while(list($k,$v)=each($arr)) {
442 if (t3lib_div::testInt($k)) {
443 $ac++;
444 }
445 }
446 // Traverse through entries
447 $subtime=0;
448 reset($arr);
449 while(list($k,$v)=each($arr)) {
450 if (t3lib_div::testInt($k)) {
451 $c++;
452
453 $deeper = is_array($arr[$k.'.']) ? 1 : 0;
454 $PM = 'join';
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="" />');
459
460 if (strlen($this->tsStackLog[$v]['content'])) {
461 $content = str_replace($this->tsStackLog[$v]['content'],$v, $content);
462 }
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);
465 } else {
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'];
469 }
470 $subtime+=$this->tsStackLog[$v]['deltatime'];
471 }
472 }
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;
477 }
478 $content=$this->fixCLen($content, $this->tsStackLog[$vKey]['value']);
479
480 // Traverse array again, this time substitute the unique hash with the red key
481 reset($arr);
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);
486 }
487 }
488 }
489 // return the content
490 return $content;
491 }
492
493 /**
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"
495 *
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']
498 * @return string
499 */
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>';
504 } else {
505 $c=htmlspecialchars($c);
506 }
507 return $c;
508 }
509
510 /**
511 * Wraps input string in a <font> tag with verdana, black and size 1
512 *
513 * @param string The string to be wrapped
514 * @return string
515 */
516 function fw($str) {
517 return '<font face="verdana" color="black" size="1" style="color:black;">'.$str.'&nbsp;</font>';
518 }
519
520 /**
521 * Helper function for internal data manipulation
522 *
523 * @param array Array (passed by reference) and modified
524 * @param integer Pointer value
525 * @param string Unique ID string
526 * @return void
527 * @access private
528 * @see printTSlog()
529 */
530 function createHierarchyArray(&$arr,$pointer,$uniqueId) {
531 if (!is_array($arr)) $arr=array();
532 if ($pointer>0) {
533 end($arr);
534 $k=key($arr);
535 $this->createHierarchyArray($arr[intval($k).'.'],$pointer-1,$uniqueId);
536 } else {
537 $arr[] = $uniqueId;
538 }
539 }
540
541 /**
542 * This prints out a TYPO3 error message.
543 *
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 * @return string
548 */
549 function debug_typo3PrintError($header,$text,$js) {
550 if ($js) {
551 echo"alert('".t3lib_div::slashJS($header."\n".$text)."');";
552 } else {
553 echo '
554 <html>
555 <head>
556 <title>Error!</title>
557 </head>
558 <body bgcolor="white">
559 <div align="center">
560 <table border="0" cellspacing="0" cellpadding="0" width="333" bgcolor="#cccccc">
561 <tr>
562 <td><img src="t3lib/gfx/typo3logo.gif" width="333" height="43" vspace="10" border="0" alt="" /></td>
563 </tr>
564 <tr>
565 <td bgcolor="black">
566 <table width="100%" border="0" cellspacing="1" cellpadding="10">
567 <tr>
568 <td bgcolor="#F4F0E8">
569 <font face="verdana,arial,helvetica" size="2">';
570 echo '<b><center><font size="+1">'.$header.'</font></center></b><br />'.$text;
571 echo ' </font>
572 </td>
573 </tr>
574 </table>
575 </td>
576 </tr>
577 </table>
578 </div>
579 </body>
580 </html>';
581 }
582 }
583 }
584 ?>