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