[TASK] BACK_PATH DocumentTemplate
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / Classes / Controller / ModuleController.php
1 <?php
2 namespace TYPO3\CMS\Dbal\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18
19 /**
20 * Script class; Backend module for DBAL extension
21 */
22 class ModuleController extends \TYPO3\CMS\Backend\Module\BaseScriptClass {
23
24 /**
25 * @var string
26 */
27 protected $thisScript;
28
29 /**
30 * The name of the module
31 *
32 * @var string
33 */
34 protected $moduleName = 'tools_txdbalM1';
35
36 /**
37 * Initializes this module.
38 *
39 * @return void
40 */
41 public function init() {
42 $this->MCONF = array(
43 'name' => $this->moduleName,
44 );
45 $this->getLanguageService()->includeLLFile('EXT:dbal/Resources/Private/Language/locallang.xlf');
46 parent::init();
47 }
48
49 /**
50 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
51 *
52 * @return void
53 */
54 public function menuConfig() {
55 $languageService = $this->getLanguageService();
56 $this->MOD_MENU = array(
57 'function' => array(
58 0 => $languageService->getLL('Debug_log'),
59 'info' => $languageService->getLL('Cached_info'),
60 'sqlcheck' => $languageService->getLL('SQL_check')
61 )
62 );
63 parent::menuConfig();
64 }
65
66 /**
67 * Main function of the module. Write the content to $this->content
68 *
69 * @return void
70 */
71 public function main() {
72 $languageService = $this->getLanguageService();
73 $this->thisScript = BackendUtility::getModuleUrl($this->MCONF['name']);
74 // Clean up settings:
75 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('SET'), $this->MCONF['name']);
76 // Draw the header
77 $this->doc = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
78 $this->doc->form = '<form action="" method="post">';
79 // DBAL page title:
80 $this->content .= $this->doc->startPage($languageService->getLL('title'));
81 $this->content .= $this->doc->header($languageService->getLL('title'));
82 $this->content .= $this->doc->spacer(5);
83 $this->content .= $this->doc->section('', $this->doc->funcMenu('', BackendUtility::getFuncMenu(0, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function'])));
84 // Debug log:
85 switch ($this->MOD_SETTINGS['function']) {
86 case 'info':
87 $this->content .= $this->doc->section($languageService->getLL('Cached_info'), $this->printCachedInfo());
88 break;
89 case 'sqlcheck':
90 $this->content .= $this->doc->section($languageService->getLL('SQL_check'), $this->printSqlCheck());
91 break;
92 case 0:
93 $this->content .= $this->doc->section($languageService->getLL('Debug_log'), $this->printLogMgm());
94 break;
95 }
96 // ShortCut
97 if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
98 $this->content .= $this->doc->spacer(20) . $this->doc->section('', $this->doc->makeShortcutIcon('id', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']));
99 }
100 $this->content .= $this->doc->spacer(10);
101 }
102
103 /**
104 * Prints out the module HTML
105 *
106 * @return string HTML output
107 */
108 public function printContent() {
109 $this->content .= $this->doc->endPage();
110 echo $this->content;
111 }
112
113 /**
114 * Displays a form to check DBAL SQL methods and parse raw SQL.
115 *
116 * @return string HTML output
117 */
118 protected function printSqlCheck() {
119 $input = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_dbal');
120 $out = '
121 <form name="sql_check" action="' . $this->thisScript . '" method="post" enctype="multipart/form-data">
122 <script type="text/javascript">
123 /*<![CDATA[*/
124 function updateQryForm(s) {
125 document.getElementById(\'tx-dbal-result\').style.display = \'none\';
126 switch(s) {
127 case \'SELECT\':
128 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
129 document.getElementById(\'tx-dbal-qryfields\').style.display = \'table-row\';
130 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
131 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
132 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
133 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
134 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
135 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
136 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
137 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
138 break;
139 case \'INSERT\':
140 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
141 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
142 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'table-row\';
143 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
144 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
145 document.getElementById(\'tx-dbal-qryinto\').style.display = \'table-row\';
146 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
147 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
148 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
149 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
150 break;
151 case \'UPDATE\':
152 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
153 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
154 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
155 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'table-row\';
156 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
157 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
158 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
159 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
160 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
161 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
162 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
163 break;
164 case \'DELETE\':
165 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
166 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
167 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
168 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
169 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
170 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
171 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
172 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
173 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
174 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
175 break;
176 }
177 }
178 /*]]>*/
179 </script>
180 <table>
181 <tr class="tableheader bgColor5"><th colspan="2">Easy SQL check</th></tr>
182 <tr><td colspan="2">
183 <select name="tx_dbal[QUERY]"size="1" onchange="updateQryForm(this.options[this.selectedIndex].value)">
184 <option value="SELECT" ' . ($input['QUERY'] === 'SELECT' ? 'selected="selected"' : '') . '>SELECT</option>
185 <option value="INSERT" ' . ($input['QUERY'] === 'INSERT' ? 'selected="selected"' : '') . '>INSERT</option>
186 <option value="UPDATE" ' . ($input['QUERY'] === 'UPDATE' ? 'selected="selected"' : '') . '>UPDATE</option>
187 <option value="DELETE" ' . ($input['QUERY'] === 'DELETE' ? 'selected="selected"' : '') . '>DELETE</option>
188 </select>
189 </td></tr>
190 <tr id="tx-dbal-qryupdate" style="display:none;"><td></td><td><input name="tx_dbal[UPDATE]" value="' . $input['UPDATE'] . '" type="text" size="30" maxsize="100" /></td></tr>
191 <tr id="tx-dbal-qryfields"><td></td><td><input name="tx_dbal[FIELDS]" value="' . $input['FIELDS'] . '" type="text" size="30" maxsize="100" /></td></tr>
192 <tr id="tx-dbal-qryinsertvalues" style="display:none;"><td></td><td><textarea name="tx_dbal[INSERTVALUES]" cols="30" rows="4">' . $input['INSERTVALUES'] . '</textarea></td></tr>
193 <tr id="tx-dbal-qryupdatevalues" style="display:none;"><th>SET</th><td><textarea name="tx_dbal[UPDATEVALUES]" cols="30" rows="4">' . $input['UPDATEVALUES'] . '</textarea></td></tr>
194 <tr id="tx-dbal-qryfrom"><th>FROM</th><td><input name="tx_dbal[FROM]" value="' . $input['FROM'] . '" type="text" size="30" maxsize="100" /></td></tr>
195 <tr id="tx-dbal-qryinto" style="display:none;"><th>INTO</th><td><input name="tx_dbal[INTO]" value="' . $input['INTO'] . '" type="text" size="30" maxsize="100" /></td></tr>
196 <tr id="tx-dbal-qrywhere"><th>WHERE</th><td><input name="tx_dbal[WHERE]" value="' . $input['WHERE'] . '" type="text" size="30" maxsize="100" /></td></tr>
197 <tr id="tx-dbal-qrygroup"><th>GROUP BY</th><td><input name="tx_dbal[GROUP]" value="' . $input['GROUP'] . '" type="text" size="30" maxsize="100" /></td></tr>
198 <tr id="tx-dbal-qryorder"><th>ORDER BY</th><td><input name="tx_dbal[ORDER]" value="' . $input['ORDER'] . '" type="text" size="30" maxsize="100" /></td></tr>
199 <tr id="tx-dbal-qrylimit"><th>LIMIT</th><td><input name="tx_dbal[LIMIT]" value="' . $input['LIMIT'] . '" type="text" size="30" maxsize="100" /></td></tr>
200 <tr>
201 <td></td>
202 <td style="text-align:right;">
203 <input class="btn btn-default" type="submit" value="CHECK" />
204 </td>
205 </tr>
206 <script type="text/javascript">
207 /*<![CDATA[*/
208 updateQryForm(\'' . $input['QUERY'] . '\');
209 /*]]>*/
210 </script>
211 ';
212 $out .= '<tr id="tx-dbal-result" class="bgColor4"><th>Result:</th><td>';
213 switch ($input['QUERY']) {
214 case 'SELECT':
215 $qry = $GLOBALS['TYPO3_DB']->SELECTquery($input['FIELDS'], $input['FROM'], $input['WHERE'], $input['GROUP'], $input['ORDER'], $input['LIMIT']);
216 break;
217 case 'INSERT':
218 $qry = $GLOBALS['TYPO3_DB']->INSERTquery($input['INTO'], $this->createFieldsValuesArray($input['INSERTVALUES']));
219 break;
220 case 'UPDATE':
221 $qry = $GLOBALS['TYPO3_DB']->UPDATEquery($input['UPDATE'], $input['WHERE'], $this->createFieldsValuesArray($input['UPDATEVALUES']));
222 break;
223 case 'DELETE':
224 $qry = $GLOBALS['TYPO3_DB']->DELETEquery($input['FROM'], $input['WHERE']);
225 break;
226 }
227 $out .= '<pre>' . htmlspecialchars($qry) . '</pre></td></tr>';
228 $out .= '
229 <tr class="tableheader bgColor5">
230 <th colspan="2">RAW SQL check</th>
231 </tr>
232 <tr>
233 <td colspan="2" style="text-align:right;">
234 <textarea name="tx_dbal[RAWSQL]" cols="60" rows="5">' . $input['RAWSQL'] . '</textarea>
235 <br />
236 <input class="btn btn-default" type="submit" value="CHECK" />
237 </td>
238 </tr>';
239 if (!empty($input['RAWSQL'])) {
240 $out .= '<tr class="bgColor4">';
241 $parseResult = $GLOBALS['TYPO3_DB']->SQLparser->parseSQL($input['RAWSQL']);
242 if (is_array($parseResult)) {
243 $newQuery = $GLOBALS['TYPO3_DB']->SQLparser->compileSQL($parseResult);
244 $testResult = $GLOBALS['TYPO3_DB']->SQLparser->debug_parseSQLpartCompare($input['RAWSQL'], $newQuery);
245 if (!is_array($testResult)) {
246 $out .= '<td colspan="2">' . $newQuery;
247 } else {
248 $out .= '<td colspan="2">' . htmlspecialchars($testResult[0]) . '</td></tr>
249 <tr><th>Error:</th><td style="border:2px solid #f00;">Input query did not match the parsed and recompiled query exactly (not observing whitespace):<br />' . htmlspecialchars($testResult[1]);
250 }
251 } else {
252 $out .= '<th>Result:</th><td style="border:2px solid #f00;">' . $parseResult;
253 }
254 $out .= '</td></tr>';
255 }
256 $out .= '</table></form>';
257 return $out;
258 }
259
260 /**
261 * Parses a very simple text format into an array.
262 *
263 * Each line is seen as a key/value pair that is exploded at =. This is used
264 * in the simple SQL check to input values for INSERT and UPDATE statements.
265 *
266 * @param string $in String to parse into key/value array.
267 * @return array Array created from the input string.
268 */
269 protected function createFieldsValuesArray($in) {
270 $ret = array();
271 $in = explode(LF, $in);
272 foreach ($in as $v) {
273 $fv = explode('=', $v);
274 $ret[$fv[0]] = $fv[1];
275 }
276 return $ret;
277 }
278
279 /**
280 * Prints out the cached information about the database.
281 *
282 * The DBAL caches a lot of information, e.g. about auto increment fields,
283 * field types and primary keys. This method formats all this into a HTML
284 * table to display in the BE.
285 *
286 * @return string HTML output
287 */
288 protected function printCachedInfo() {
289 // Get cmd:
290 if ((string)\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('cmd') === 'clear') {
291 $GLOBALS['TYPO3_DB']->clearCachedFieldInfo();
292 $GLOBALS['TYPO3_DB']->cacheFieldInfo();
293 }
294 $out = '<a name="autoincrement"></a><h2>auto_increment</h2>';
295 $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field</th></tr>';
296 ksort($GLOBALS['TYPO3_DB']->cache_autoIncFields);
297 foreach ($GLOBALS['TYPO3_DB']->cache_autoIncFields as $table => $field) {
298 $out .= '<tr>';
299 $out .= '<td>' . $table . '</td>';
300 $out .= '<td>' . $field . '</td>';
301 $out .= '</tr>';
302 }
303 $out .= '</tbody></table>';
304 $out .= $this->doc->spacer(5);
305 $out .= '<a name="primarykeys"></a><h2>Primary keys</h2>';
306 $out .= '<table border="1" cellspacing="0"><tbody><tr><th>Table</th><th>Field(s)</th></tr>';
307 ksort($GLOBALS['TYPO3_DB']->cache_primaryKeys);
308 foreach ($GLOBALS['TYPO3_DB']->cache_primaryKeys as $table => $field) {
309 $out .= '<tr>';
310 $out .= '<td>' . $table . '</td>';
311 $out .= '<td>' . $field . '</td>';
312 $out .= '</tr>';
313 }
314 $out .= '</tbody></table>';
315 $out .= $this->doc->spacer(5);
316 $out .= '<a name="fieldtypes"></a><h2>Field types</h2>';
317 $out .= '<table border="1" cellspacing="0"><tbody><tr><th colspan="5">Table</th></tr><tr><th>Field</th><th>Type</th><th><a href="#metatypes">Metatype</a></th><th>NOT NULL</th><th>Default</th></th></tr>';
318 ksort($GLOBALS['TYPO3_DB']->cache_fieldType);
319 foreach ($GLOBALS['TYPO3_DB']->cache_fieldType as $table => $fields) {
320 $out .= '<th colspan="5">' . $table . '</th>';
321 foreach ($fields as $field => $data) {
322 $out .= '<tr>';
323 $out .= '<td>' . $field . '</td>';
324 $out .= '<td>' . $data['type'] . '</td>';
325 $out .= '<td>' . $data['metaType'] . '</td>';
326 $out .= '<td>' . ($data['notnull'] ? 'NOT NULL' : '') . '</td>';
327 $out .= '<td>' . $data['default'] . '</td>';
328 $out .= '</tr>';
329 }
330 }
331 $out .= '</tbody></table>';
332 $out .= $this->doc->spacer(5);
333 $out .= '<a name="metatypes"></a><h2>Metatype explanation</h2>';
334 $out .= '<pre>
335 C: Varchar, capped to 255 characters.
336 X: Larger varchar, capped to 4000 characters (to be compatible with Oracle).
337 XL: For Oracle, returns CLOB, otherwise the largest varchar size.
338
339 C2: Multibyte varchar
340 X2: Multibyte varchar (largest size)
341
342 B: BLOB (binary large object)
343
344 D: Date (some databases do not support this, and we return a datetime type)
345 T: Datetime or Timestamp
346 L: Integer field suitable for storing booleans (0 or 1)
347 I: Integer (mapped to I4)
348 I1: 1-byte integer
349 I2: 2-byte integer
350 I4: 4-byte integer
351 I8: 8-byte integer
352 F: Floating point number
353 N: Numeric or decimal number</pre>';
354 $menu = '<a href="' . $this->thisScript . '&amp;cmd=clear">CLEAR DATA</a><hr />';
355 $menu .= '<a href="#autoincrement">auto_increment</a> | <a href="#primarykeys">Primary keys</a> | <a href="#fieldtypes">Field types</a> | <a href="#metatypes">Metatype explanation</a><hr />';
356 return $menu . $out;
357 }
358
359 /**
360 * Printing the debug-log from the DBAL extension
361 *
362 * To enabled debugging, you will have to enabled it in the configuration!
363 *
364 * @return string HTML content
365 */
366 protected function printLogMgm() {
367 // Disable debugging in any case...
368 $GLOBALS['TYPO3_DB']->debug = FALSE;
369 // Get cmd:
370 $cmd = (string)\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('cmd');
371 switch ($cmd) {
372 case 'flush':
373 $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog');
374 $res = $GLOBALS['TYPO3_DB']->exec_TRUNCATEquery('tx_dbal_debuglog_where');
375 $outStr = 'Log FLUSHED!';
376 break;
377 case 'joins':
378 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('table_join,exec_time,query,script', 'tx_dbal_debuglog', 'table_join!=\'\'', 'table_join,script,exec_time,query');
379 // Init vars in which to pick up the query result:
380 $tableIndex = array();
381 $tRows = array();
382 $tRows[] = '
383 <tr>
384 <td>Execution time</td>
385 <td>Table joins</td>
386 <td>Script</td>
387 <td>Query</td>
388 </tr>';
389 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
390 $tableArray = $GLOBALS['TYPO3_DB']->SQLparser->parseFromTables($row['table_join']);
391 // Create table name index:
392 foreach ($tableArray as $a) {
393 foreach ($tableArray as $b) {
394 if ($b['table'] != $a['table']) {
395 $tableIndex[$a['table']][$b['table']] = 1;
396 }
397 }
398 }
399 // Create output row
400 $tRows[] = '
401 <tr>
402 <td>' . htmlspecialchars($row['exec_time']) . '</td>
403 <td>' . htmlspecialchars($row['table_join']) . '</td>
404 <td>' . htmlspecialchars($row['script']) . '</td>
405 <td>' . htmlspecialchars($row['query']) . '</td>
406 </tr>';
407 }
408 // Printing direct joins:
409 $outStr .= '<h4>Direct joins:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
410 // Printing total dependencies:
411 foreach ($tableIndex as $priTable => $a) {
412 foreach ($tableIndex as $tableN => $v) {
413 foreach ($v as $tableP => $vv) {
414 if ($tableP == $priTable) {
415 $tableIndex[$priTable] = array_merge($v, $a);
416 }
417 }
418 }
419 }
420 $outStr .= '<h4>Total dependencies:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
421 // Printing data rows:
422 $outStr .= '
423 <table border="1" cellspacing="0">' . implode('', $tRows) . '
424 </table>';
425 break;
426 case 'errors':
427 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('serdata,exec_time,query,script', 'tx_dbal_debuglog', 'errorFlag>0', '', 'tstamp DESC');
428 // Init vars in which to pick up the query result:
429 $tRows = array();
430 $tRows[] = '
431 <tr>
432 <td>Execution time</td>
433 <td>Error data</td>
434 <td>Script</td>
435 <td>Query</td>
436 </tr>';
437 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
438 // Create output row
439 $tRows[] = '
440 <tr>
441 <td>' . htmlspecialchars($row['exec_time']) . '</td>
442 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
443 <td>' . htmlspecialchars($row['script']) . '</td>
444 <td>' . htmlspecialchars($row['query']) . '</td>
445 </tr>';
446 }
447 // Printing data rows:
448 $outStr .= '
449 <table border="1" cellspacing="0">' . implode('', $tRows) . '
450 </table>';
451 break;
452 case 'parsing':
453 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('query,serdata', 'tx_dbal_debuglog', 'errorFlag&2=2');
454 $tRows = array();
455 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
456 // Create output row
457 $tRows[] = '
458 <tr>
459 <td>' . htmlspecialchars($row['query']) . '</td>
460 </tr>';
461 }
462 // Printing data rows:
463 $outStr .= '
464 <table border="1" cellspacing="0">' . implode('', $tRows) . '
465 </table>';
466 break;
467 case 'where':
468 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script,tablename,whereclause', 'tx_dbal_debuglog_where', '', '', 'tstamp DESC');
469 $tRows = array();
470 $tRows[] = '
471 <tr>
472 <td>Time</td>
473 <td>Script</td>
474 <td>Table</td>
475 <td>WHERE clause</td>
476 </tr>';
477 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
478 $tRows[] = '
479 <tr>
480 <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
481 <td>' . htmlspecialchars($row['script']) . '</td>
482 <td>' . htmlspecialchars($row['tablename']) . '</td>
483 <td>' . str_replace(array('\'\'', '""', 'IS NULL', 'IS NOT NULL'), array('<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row['whereclause'])) . '</td>
484 </tr>';
485 }
486 $outStr = '
487 <table border="1" cellspacing="0">' . implode('', $tRows) . '
488 </table>';
489 break;
490 default:
491 // Look for request to view specific script exec:
492 $specTime = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('specTime');
493 if ($specTime) {
494 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('exec_time,errorFlag,table_join,serdata,query', 'tx_dbal_debuglog', 'tstamp=' . (int)$specTime);
495 $tRows = array();
496 $tRows[] = '
497 <tr>
498 <td>Execution time</td>
499 <td>Error</td>
500 <td>Table joins</td>
501 <td>Data</td>
502 <td>Query</td>
503 </tr>';
504 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
505 $tRows[] = '
506 <tr>
507 <td>' . htmlspecialchars($row['exec_time']) . '</td>
508 <td>' . ($row['errorFlag'] ? 1 : 0) . '</td>
509 <td>' . htmlspecialchars($row['table_join']) . '</td>
510 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row['serdata'])) . '</td>
511 <td>' . str_replace(array('\'\'', '""', 'IS NULL', 'IS NOT NULL'), array('<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>', '<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>', '<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row['query'])) . '</td>
512 </tr>';
513 }
514 } else {
515 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp,script, SUM(exec_time) as calc_sum, count(*) AS qrycount, MAX(errorFlag) as error', 'tx_dbal_debuglog', '', 'tstamp,script', 'tstamp DESC');
516 $tRows = array();
517 $tRows[] = '
518 <tr>
519 <td>Time</td>
520 <td># of queries</td>
521 <td>Error</td>
522 <td>Time (ms)</td>
523 <td>Script</td>
524 </tr>';
525 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
526 $tRows[] = '
527 <tr>
528 <td>' . BackendUtility::datetime($row['tstamp']) . '</td>
529 <td>' . htmlspecialchars($row['qrycount']) . '</td>
530 <td>' . ($row['error'] ? '<strong style="color:#f00">ERR</strong>' : '') . '</td>
531 <td>' . htmlspecialchars($row['calc_sum']) . '</td>
532 <td><a href="' . $this->thisScript . '&amp;specTime=' . (int)$row['tstamp'] . '">' . htmlspecialchars($row['script']) . '</a></td>
533 </tr>';
534 }
535 }
536 $outStr = '
537 <table border="1" cellspacing="0">' . implode('', $tRows) . '
538 </table>';
539 }
540 $menu = '
541 <a href="' . $this->thisScript . '&amp;cmd=flush">FLUSH LOG</a> -
542 <a href="' . $this->thisScript . '&amp;cmd=joins">JOINS</a> -
543 <a href="' . $this->thisScript . '&amp;cmd=errors">ERRORS</a> -
544 <a href="' . $this->thisScript . '&amp;cmd=parsing">PARSING</a> -
545 <a href="' . $this->thisScript . '">LOG</a> -
546 <a href="' . $this->thisScript . '&amp;cmd=where">WHERE</a> -
547
548 <a href="' . htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript()) . '" target="tx_debuglog">[New window]</a>
549 <hr />
550 ';
551 return $menu . $outStr;
552 }
553
554 /**
555 * Returns the language service.
556 *
557 * @return \TYPO3\CMS\Lang\LanguageService
558 */
559 protected function getLanguageService() {
560 return $GLOBALS['LANG'];
561 }
562
563 }