Fixed bug #14050: CleanUp - CGL format of t3lib files - t3lib_timetrack
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_timetrack.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2010 Kasper Skårhøj (kasperYYYY@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 Skårhøj
32 * XHTML compliant
33 *
34 * @author Kasper Skårhøj <kasperYYYY@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 * 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)
53 *
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='')
61 *
62 * TOTAL FUNCTIONS: 15
63 * (This index is automatically created/updated by the extension "extdeveval")
64 *
65 */
66
67
68 /**
69 * Frontend Timetracking functions
70 *
71 * Is used to register how much time is used with operations in TypoScript
72 * Used by index_ts
73 *
74 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
75 * @package TYPO3
76 * @subpackage t3lib
77 * @see t3lib_tsfeBeUserAuth, tslib_fe, tslib_cObj, TSpagegen
78 */
79 class t3lib_timeTrack {
80 var $starttime = 0; // Is loaded with the millisecond time when this object is created
81
82 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
83 var $printConf = array(
84 'showParentKeys' => 1,
85 'contentLength' => 10000, // Determines max lenght of displayed content before it gets cropped.
86 '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.
87 'flag_tree' => 1,
88 'flag_messages' => 1,
89 'flag_queries' => 0,
90 'flag_content' => 0,
91 'allTime' => 0,
92 'keyLgd' => 40,
93 'factor' => 10,
94 'col' => '#D9D5C9',
95 'highlight_col' => '#FF9933'
96 );
97
98 var $wrapError = array();
99 var $wrapIcon = array();
100 var $uniqueCounter = 0;
101 var $tsStack = array(array());
102 var $tsStackLevel = 0;
103 var $tsStackLevelMax = array();
104 var $tsStackLog = array();
105 var $tsStackPointer = 0;
106 var $currentHashPointer = array();
107
108 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.
109
110
111 /*******************************************
112 *
113 * Logging parsing times in the scripts
114 *
115 *******************************************/
116
117 /**
118 * Constructor
119 * Sets the starting time
120 *
121 * @return void
122 */
123 public function start() {
124 $this->wrapError = array(
125 0 => array('', ''),
126 1 => array('<strong>', '</strong>'),
127 2 => array('<strong style="color:#ff6600;">', '</strong>'),
128 3 => array('<strong style="color:#ff0000;">', '</strong>')
129 );
130
131 $this->wrapIcon = array(
132 0 => '',
133 1 => '<img src="' . TYPO3_mainDir . 'gfx/icon_note.gif" width="18" height="16" align="absmiddle" alt="" />',
134 2 => '<img src="' . TYPO3_mainDir . 'gfx/icon_warning.gif" width="18" height="16" align="absmiddle" alt="" />',
135 3 => '<img src="' . TYPO3_mainDir . 'gfx/icon_fatalerror.gif" width="18" height="16" align="absmiddle" alt="" />'
136 );
137
138 $this->starttime = $this->getMilliseconds();
139 }
140
141 /**
142 * Pushes an element to the TypoScript tracking array
143 *
144 * @param string Label string for the entry, eg. TypoScript property name
145 * @param string Additional value(?)
146 * @return void
147 * @see tslib_cObj::cObjGetSingle(), pull()
148 */
149 public function push($tslabel, $value = '') {
150 array_push($this->tsStack[$this->tsStackPointer], $tslabel);
151 array_push($this->currentHashPointer, 'timetracker_' . $this->uniqueCounter++);
152
153 $this->tsStackLevel++;
154 $this->tsStackLevelMax[] = $this->tsStackLevel;
155
156 // setTSlog
157 $k = end($this->currentHashPointer);
158 $this->tsStackLog[$k] = array(
159 'level' => $this->tsStackLevel,
160 'tsStack' => $this->tsStack,
161 'value' => $value,
162 'starttime' => microtime(TRUE),
163 'stackPointer' => $this->tsStackPointer
164 );
165 }
166
167 /**
168 * Pulls an element from the TypoScript tracking array
169 *
170 * @param string The content string generated within the push/pull part.
171 * @return void
172 * @see tslib_cObj::cObjGetSingle(), push()
173 */
174 public function pull($content = '') {
175 $k = end($this->currentHashPointer);
176 $this->tsStackLog[$k]['endtime'] = microtime(TRUE);
177 $this->tsStackLog[$k]['content'] = $content;
178
179 $this->tsStackLevel--;
180 array_pop($this->tsStack[$this->tsStackPointer]);
181 array_pop($this->currentHashPointer);
182 }
183
184 /**
185 * Logs the TypoScript entry
186 *
187 * @param string The message string
188 * @param integer Message type: 0: information, 1: message, 2: warning, 3: error
189 * @return void
190 * @see tslib_cObj::CONTENT()
191 */
192 public function setTSlogMessage($content, $num = 0) {
193 end($this->currentHashPointer);
194 $k = current($this->currentHashPointer);
195
196 if (strlen($content) > 30) { // Enlarge the "details" column by adding a wide clear.gif
197 $placeholder = '<br /><img src="' . TYPO3_mainDir . 'clear.gif" width="300" height="1" alt="" />';
198 }
199 $this->tsStackLog[$k]['message'][] = $this->wrapIcon[$num] . $this->wrapError[$num][0] . htmlspecialchars($content) . $this->wrapError[$num][1] . $placeholder;
200 }
201
202 /**
203 * Set TSselectQuery - for messages in TypoScript debugger.
204 *
205 * @param array Query array
206 * @param string Message/Label to attach
207 * @return void
208 */
209 public function setTSselectQuery(array $data, $msg = '') {
210 end($this->currentHashPointer);
211 $k = current($this->currentHashPointer);
212
213 if (strlen($msg)) {
214 $data['msg'] = $msg;
215 }
216
217 $this->tsStackLog[$k]['selectQuery'][] = $data;
218 }
219
220 /**
221 * Increases the stack pointer
222 *
223 * @return void
224 * @see decStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
225 */
226 public function incStackPointer() {
227 $this->tsStackPointer++;
228 $this->tsStack[$this->tsStackPointer] = array();
229 }
230
231 /**
232 * Decreases the stack pointer
233 *
234 * @return void
235 * @see incStackPointer(), TSpagegen::renderContent(), tslib_cObj::cObjGetSingle()
236 */
237 public function decStackPointer() {
238 unset($this->tsStack[$this->tsStackPointer]);
239 $this->tsStackPointer--;
240 }
241
242 /**
243 * Returns the current time in milliseconds
244 *
245 * @return integer
246 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, use getDifferenceToStarttime() instead
247 */
248 protected function mtime() {
249 t3lib_div::logDeprecatedFunction();
250
251 return $this->getDifferenceToStarttime();
252 }
253
254 /**
255 * Returns microtime input to milliseconds
256 *
257 * @param string PHP microtime string
258 * @return integer
259 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, use getMilliseconds() instead that expects microtime as float instead of a string
260 */
261 public function convertMicrotime($microtime) {
262 t3lib_div::logDeprecatedFunction();
263
264 $parts = explode(' ', $microtime);
265 return round(($parts[0] + $parts[1]) * 1000);
266 }
267
268 /**
269 * Gets a microtime value as milliseconds value.
270 *
271 * @param float $microtime: The microtime value - if not set the current time is used
272 * @return integer The microtime value as milliseconds value
273 */
274 public function getMilliseconds($microtime = NULL) {
275 if (!isset($microtime)) {
276 $microtime = microtime(TRUE);
277 }
278 return round($microtime * 1000);
279 }
280
281 /**
282 * Gets the difference between a given microtime value and the starting time as milliseconds.
283 *
284 * @param float $microtime: The microtime value - if not set the current time is used
285 * @return integer The difference between a given microtime value and starting time as milliseconds
286 */
287 public function getDifferenceToStarttime($microtime = NULL) {
288 return ($this->getMilliseconds($microtime) - $this->starttime);
289 }
290
291
292 /*******************************************
293 *
294 * Printing the parsing time information (for Admin Panel)
295 *
296 *******************************************/
297
298 /**
299 * Print TypoScript parsing log
300 *
301 * @return string HTML table with the information about parsing times.
302 * @see t3lib_tsfeBeUserAuth::extGetCategory_tsdebug()
303 */
304 public function printTSlog() {
305 // Calculate times and keys for the tsStackLog
306 foreach ($this->tsStackLog as $uniqueId => &$data) {
307 $data['endtime'] = $this->getDifferenceToStarttime($data['endtime']);
308 $data['starttime'] = $this->getDifferenceToStarttime($data['starttime']);
309 $data['deltatime'] = $data['endtime'] - $data['starttime'];
310 $data['key'] = implode($data['stackPointer'] ? '.' : '/', end($data['tsStack']));
311 }
312
313 // Create hierarchical array of keys pointing to the stack
314 $arr = array();
315 foreach ($this->tsStackLog as $uniqueId => $data) {
316 $this->createHierarchyArray($arr, $data['level'], $uniqueId);
317 }
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]);
320
321 // Displaying the tree:
322 $outputArr = array();
323 $outputArr[] = $this->fw('TypoScript Key');
324 $outputArr[] = $this->fw('Value');
325
326 if ($this->printConf['allTime']) {
327 $outputArr[] = $this->fw('Time');
328 $outputArr[] = $this->fw('Own');
329 $outputArr[] = $this->fw('Sub');
330 $outputArr[] = $this->fw('Total');
331 } else {
332 $outputArr[] = $this->fw('Own');
333 }
334
335 $outputArr[] = $this->fw('Details');
336
337 $out = '';
338 foreach ($outputArr as $row) {
339 $out .= '
340 <th style="text-align:center; background:#ABBBB4;"><strong>' . $row . '</strong></th>';
341 }
342 $out = '<tr>' . $out . '</tr>';
343
344 $flag_tree = $this->printConf['flag_tree'];
345 $flag_messages = $this->printConf['flag_messages'];
346 $flag_content = $this->printConf['flag_content'];
347 $flag_queries = $this->printConf['flag_queries'];
348 $keyLgd = $this->printConf['keyLgd'];
349 $factor = $this->printConf['factor'];
350 $col = $this->printConf['col'];
351 $highlight_col = $this->printConf['highlight_col'];
352
353 $c = 0;
354 foreach ($this->tsStackLog as $uniqueId => $data) {
355 $bgColor = ' background-color:' . ($c % 2 ? t3lib_div::modifyHTMLColor($col, $factor, $factor, $factor) : $col) . ';';
356 if ($this->highlightLongerThan && intval($data['owntime']) > intval($this->highlightLongerThan)) {
357 $bgColor = ' background-color:' . $highlight_col . ';';
358 }
359
360 $item = '';
361 if (!$c) { // If first...
362 $data['icons'] = '';
363 $data['key'] = 'Script Start';
364 $data['value'] = '';
365 }
366
367
368 // key label:
369 $keyLabel = '';
370 if (!$flag_tree && $data['stackPointer']) {
371 $temp = array();
372 foreach ($data['tsStack'] as $k => $v) {
373 $temp[] = t3lib_div::fixed_lgd_cs(implode($v, $k ? '.' : '/'), -$keyLgd);
374 }
375 array_pop($temp);
376 $temp = array_reverse($temp);
377 array_pop($temp);
378 if (count($temp)) {
379 $keyLabel = '<br /><span style="color:#999999;">' . implode($temp, '<br />') . '</span>';
380 }
381 }
382 if ($flag_tree) {
383 $tmp = t3lib_div::trimExplode('.', $data['key'], 1);
384 $theLabel = end($tmp);
385 } else {
386 $theLabel = $data['key'];
387 }
388 $theLabel = t3lib_div::fixed_lgd_cs($theLabel, -$keyLgd);
389 $theLabel = $data['stackPointer'] ? '<span style="color:maroon;">' . $theLabel . '</span>' : $theLabel;
390 $keyLabel = $theLabel . $keyLabel;
391 $item .= '<td valign="top" style="text-align:left; white-space:nowrap; padding-left:2px;' . $bgColor . '">' . ($flag_tree ? $data['icons'] : '') . $this->fw($keyLabel) . '</td>';
392
393 // key value:
394 $keyValue = $data['value'];
395 $item .= '<td valign="top" style="text-align:left; white-space:nowrap;' . $bgColor . '">' . $this->fw(htmlspecialchars($keyValue)) . '</td>';
396
397 if ($this->printConf['allTime']) {
398 $item .= '<td valign="top" style="text-align:right; white-space:nowrap;' . $bgColor . '"> ' . $this->fw($data['starttime']) . '</td>';
399 $item .= '<td valign="top" style="text-align:right; white-space:nowrap;' . $bgColor . '"> ' . $this->fw($data['owntime']) . '</td>';
400 $item .= '<td valign="top" style="text-align:left; white-space:nowrap;' . $bgColor . '"> ' . $this->fw($data['subtime'] ? '+' . $data['subtime'] : '') . '</td>';
401 $item .= '<td valign="top" style="text-align:left; white-space:nowrap;' . $bgColor . '"> ' . $this->fw($data['subtime'] ? '=' . $data['deltatime'] : '') . '</td>';
402 } else {
403 $item .= '<td valign="top" style="text-align:right; white-space:nowrap;' . $bgColor . '"> ' . $this->fw($data['owntime']) . '</td>';
404 }
405
406
407 // messages:
408 $msgArr = array();
409 $msg = '';
410 if ($flag_messages && is_array($data['message'])) {
411 foreach ($data['message'] as $v) {
412 $msgArr[] = nl2br($v);
413 }
414 }
415 if ($flag_queries && is_array($data['selectQuery'])) {
416 $msgArr[] = t3lib_utility_Debug::viewArray($data['selectQuery']);
417 }
418 if ($flag_content && strcmp($data['content'], '')) {
419 $maxlen = 120;
420 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...)
421 foreach ($reg[1] as $key => $match) {
422 $match = preg_replace('/(.{' . $maxlen . '})/', '$1 ', $match);
423 $data['content'] = str_replace($reg[0][$key], $match, $data['content']);
424 }
425 }
426 $msgArr[] = '<span style="color:#000066;">' . nl2br($data['content']) . '</span>';
427 }
428 if (count($msgArr)) {
429 $msg = implode($msgArr, '<hr />');
430 }
431 $item .= '<td valign="top" style="text-align:left;' . $bgColor . '">' . $this->fw($msg) . '</td>';
432 $out .= '<tr>' . $item . '</tr>';
433 $c++;
434 }
435 $out = '<table border="0" cellpadding="0" cellspacing="0" summary="">' . $out . '</table>';
436 return $out;
437 }
438
439 /**
440 * Recursively generates the content to display
441 *
442 * @param array Array which is modified with content. Reference
443 * @param string Current content string for the level
444 * @param string Prefixed icons for new PM icons
445 * @param boolean Set this for the first call from outside.
446 * @param string Seems to be the previous tsStackLog key
447 * @return string Returns the $content string generated/modified. Also the $arr array is modified!
448 */
449 protected function fixContent(&$arr, $content, $depthData = '', $first = 0, $vKey = '') {
450 $ac = 0;
451 $c = 0;
452 // First, find number of entries
453 foreach ($arr as $k => $v) {
454 if (t3lib_div::testInt($k)) {
455 $ac++;
456 }
457 }
458 // Traverse through entries
459 $subtime = 0;
460 foreach ($arr as $k => $v) {
461 if (t3lib_div::testInt($k)) {
462 $c++;
463
464 $deeper = is_array($arr[$k . '.']) ? 1 : 0;
465 $PM = 'join';
466 $LN = ($ac == $c) ? 'blank' : 'line';
467 $BTM = ($ac == $c) ? 'bottom' : '';
468 $PM = is_array($arr[$k . '.']) ? ($deeper ? 'minus' : 'plus') : 'join';
469 $this->tsStackLog[$v]['icons'] = $depthData . ($first ? '' : '<img src="' . TYPO3_mainDir . 'gfx/ol/' . $PM . $BTM . '.gif" width="18" height="16" align="top" border="0" alt="" />');
470
471 if (strlen($this->tsStackLog[$v]['content'])) {
472 $content = str_replace($this->tsStackLog[$v]['content'], $v, $content);
473 }
474 if (is_array($arr[$k . '.'])) {
475 $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);
476 } else {
477 $this->tsStackLog[$v]['content'] = $this->fixCLen($this->tsStackLog[$v]['content'], $this->tsStackLog[$v]['value']);
478 $this->tsStackLog[$v]['subtime'] = '';
479 $this->tsStackLog[$v]['owntime'] = $this->tsStackLog[$v]['deltatime'];
480 }
481 $subtime += $this->tsStackLog[$v]['deltatime'];
482 }
483 }
484 // Set content with special chars
485 if (isset($this->tsStackLog[$vKey])) {
486 $this->tsStackLog[$vKey]['subtime'] = $subtime;
487 $this->tsStackLog[$vKey]['owntime'] = $this->tsStackLog[$vKey]['deltatime'] - $subtime;
488 }
489 $content = $this->fixCLen($content, $this->tsStackLog[$vKey]['value']);
490
491 // Traverse array again, this time substitute the unique hash with the red key
492 foreach ($arr as $k => $v) {
493 if (t3lib_div::testInt($k)) {
494 if (strlen($this->tsStackLog[$v]['content'])) {
495 $content = str_replace($v, '<strong style="color:red;">[' . $this->tsStackLog[$v]['key'] . ']</strong>', $content);
496 }
497 }
498 }
499 // return the content
500 return $content;
501 }
502
503 /**
504 * 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"
505 *
506 * @param string The content string
507 * @param string Command: If "FILE" then $this->printConf['contentLength_FILE'] is used for content length comparison, otherwise $this->printConf['contentLength']
508 * @return string
509 */
510 protected function fixCLen($c, $v) {
511 $len = $v == 'FILE' ? $this->printConf['contentLength_FILE'] : $this->printConf['contentLength'];
512 if (strlen($c) > $len) {
513 $c = '<span style="color:green;">' . htmlspecialchars(t3lib_div::fixed_lgd_cs($c, $len)) . '</span>';
514 } else {
515 $c = htmlspecialchars($c);
516 }
517 return $c;
518 }
519
520 /**
521 * Wraps input string in a <span> tag with black verdana font
522 *
523 * @param string The string to be wrapped
524 * @return string
525 */
526 protected function fw($str) {
527 return '<span style="font-family:Verdana,Arial,Helvetica,sans-serif; font-size:10px; color:black; vertical-align:top;">' . $str . '&nbsp;</span>';
528 }
529
530 /**
531 * Helper function for internal data manipulation
532 *
533 * @param array Array (passed by reference) and modified
534 * @param integer Pointer value
535 * @param string Unique ID string
536 * @return void
537 * @access private
538 * @see printTSlog()
539 */
540 protected function createHierarchyArray(&$arr, $pointer, $uniqueId) {
541 if (!is_array($arr)) {
542 $arr = array();
543 }
544 if ($pointer > 0) {
545 end($arr);
546 $k = key($arr);
547 $this->createHierarchyArray($arr[intval($k) . '.'], $pointer - 1, $uniqueId);
548 } else {
549 $arr[] = $uniqueId;
550 }
551 }
552
553 /**
554 * This prints out a TYPO3 error message.
555 *
556 * @param string Header string
557 * @param string Message string
558 * @param boolean If set, then this will produce a alert() line for inclusion in JavaScript.
559 * @param string URL for the <base> tag (if you want it)
560 * @return string
561 * @deprecated since TYPO3 4.5, will be removed in TYPO3 4.7 - use RuntimeException from now on
562 */
563 public function debug_typo3PrintError($header, $text, $js, $baseUrl = '') {
564 if ($js) {
565 $errorMessage = 'alert(\'' . t3lib_div::slashJS($header . '\n' . $text) . '\');';
566 } else {
567 t3lib_div::logDeprecatedFunction();
568 $messageObj = t3lib_div::makeInstance('t3lib_message_ErrorPageMessage', $text, $header);
569 $errorMessage = $messageObj->render();
570 }
571
572 // Hook to modify error message
573 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_timetrack.php']['debug_typo3PrintError'])) {
574 $params = array(
575 'header' => $header,
576 'text' => $text,
577 'js' => $js,
578 'baseUrl' => $baseUrl,
579 'errorMessage' => &$errorMessage
580 );
581 $null = NULL;
582 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_timetrack.php']['debug_typo3PrintError'] as $hookMethod) {
583 t3lib_div::callUserFunction($hookMethod, $params, $null);
584 }
585 }
586
587 echo $errorMessage;
588 }
589 }
590
591 // XCLASSing is not possible for this class
592
593 ?>