diff --git a/Classes/DataCollectors/AuthCollector.php b/Classes/DataCollectors/AuthCollector.php
new file mode 100644
index 0000000..a3c65df
--- /dev/null
+++ b/Classes/DataCollectors/AuthCollector.php
@@ -0,0 +1,61 @@
+
+ */
+class AuthCollector extends BaseCollector implements DataCollectorInterface, Renderable
+{
+
+ /**
+ * Called by the DebugBar when data needs to be collected
+ *
+ * @return string Collected data
+ */
+ function collect()
+ {
+ return $this->getUserInformation();
+ }
+
+ /**
+ * Returns the unique name of the collector
+ *
+ * @return string
+ */
+ function getName()
+ {
+ return 'auth';
+ }
+
+ /**
+ * Returns a hash where keys are control names and their values
+ * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
+ *
+ * @return array
+ */
+ function getWidgets()
+ {
+ $name = $this->getName();
+
+ return [
+ "{$name}" => [
+ 'icon' => 'user',
+ 'tooltip' => 'Auth status',
+ 'map' => 'auth.name',
+ 'default' => '',
+ ],
+ ];
+ }
+
+ private function getUserInformation()
+ {
+ return [
+ 'name' => htmlspecialchars($this->getBackendUser()->user['username']),
+ ];
+ }
+}
diff --git a/Classes/DataCollectors/BaseCollector.php b/Classes/DataCollectors/BaseCollector.php
new file mode 100644
index 0000000..0e4bf0b
--- /dev/null
+++ b/Classes/DataCollectors/BaseCollector.php
@@ -0,0 +1,94 @@
+
+ */
+abstract class BaseCollector extends DataCollector implements Renderable
+{
+
+ /**
+ * The constructor
+ */
+ public function __construct()
+ {
+ $this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_tsfe.xlf');
+ }
+
+ /**
+ * Returns the current BE user.
+ *
+ * @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
+ */
+ protected function getBackendUser()
+ {
+ return $GLOBALS['BE_USER'];
+ }
+
+ /**
+ * Returns LanguageService
+ *
+ * @return \TYPO3\CMS\Lang\LanguageService
+ */
+ protected function getLanguageService()
+ {
+ return GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
+ }
+
+ /**
+ * Translate given key
+ *
+ * @param string $key Key for a label in the $LOCAL_LANG array of "sysext/lang/Resources/Private/Language/locallang_tsfe.xlf
+ * @param bool $convertWithHtmlspecialchars If TRUE the language-label will be sent through htmlspecialchars
+ * @return string The value for the $key
+ */
+ protected function extGetLL($key, $convertWithHtmlspecialchars = true)
+ {
+ $labelStr = $this->getLanguageService()->getLL($key);
+ if ($convertWithHtmlspecialchars) {
+ $labelStr = htmlspecialchars($labelStr);
+ }
+ return $labelStr;
+ }
+
+ /**
+ * @return TimeTracker
+ */
+ protected function getTimeTracker()
+ {
+ return GeneralUtility::makeInstance(TimeTracker::class);
+ }
+
+ /**
+ * Returns the value for an Admin Panel setting.
+ *
+ * @param string $sectionName Module key
+ * @param string $val Setting key
+ * @return mixed The setting value
+ */
+ public function extGetFeAdminValue($sectionName, $val = '')
+ {
+ $beUser = $this->getBackendUser();
+
+ // Override all settings with user TSconfig
+ if ($val && isset($beUser->extAdminConfig['override.'][$sectionName . '.'][$val])) {
+ return $beUser->extAdminConfig['override.'][$sectionName . '.'][$val];
+ }
+ if (!$val && isset($beUser->extAdminConfig['override.'][$sectionName])) {
+ return $beUser->extAdminConfig['override.'][$sectionName];
+ }
+
+ $returnValue = $val ? $beUser->uc['TSFE_adminConfig'][$sectionName . '_' . $val] : 1;
+
+ // Exception for preview
+ return !$val ? true : $returnValue;
+ }
+
+}
diff --git a/Classes/DataCollectors/InfoCollector.php b/Classes/DataCollectors/InfoCollector.php
new file mode 100644
index 0000000..afb1042
--- /dev/null
+++ b/Classes/DataCollectors/InfoCollector.php
@@ -0,0 +1,94 @@
+
+ */
+class InfoCollector extends BaseCollector
+{
+
+ /**
+ * Called by the DebugBar when data needs to be collected
+ *
+ * @return array Collected data
+ */
+ function collect()
+ {
+ $output = [];
+ $frontendController = $this->getTypoScriptFrontendController();
+ if ($this->extGetFeAdminValue('cache', 'noCache')) {
+ $theBytes = 0;
+ $count = 0;
+ if (!empty($frontendController->imagesOnPage)) {
+ $tableArr[] = [$this->extGetLL('info_imagesOnPage'), count($frontendController->imagesOnPage), true];
+ foreach ($GLOBALS['TSFE']->imagesOnPage as $file) {
+ $fs = @filesize($file);
+ $tableArr[] = [TAB . $file, GeneralUtility::formatSize($fs)];
+ $theBytes += $fs;
+ $count++;
+ }
+ }
+ // Add an empty line
+ $output[$this->extGetLL('info_imagesSize')] = GeneralUtility::formatSize($theBytes);
+ $output[$this->extGetLL('info_DocumentSize')] = GeneralUtility::formatSize(strlen($frontendController->content));
+ $output[''] = '';
+ }
+
+ $output[$this->extGetLL('info_id')] = $frontendController->id;
+ $output[$this->extGetLL('info_type')] = $frontendController->type;
+ $output[$this->extGetLL('info_groupList')] = $frontendController->gr_list;
+ $output[$this->extGetLL('info_noCache')] = $this->extGetLL('info_noCache_' . ($frontendController->no_cache ? 'no' : 'yes'));
+ $output[$this->extGetLL('info_countUserInt')] = count($frontendController->config['INTincScript']);
+
+ if (!empty($frontendController->fe_user->user['uid'])) {
+ $output[$this->extGetLL('info_feuserName')] = htmlspecialchars($frontendController->fe_user->user['username']);
+ $output[$this->extGetLL('info_feuserId')] = htmlspecialchars($frontendController->fe_user->user['uid']);
+ }
+
+ $output[$this->extGetLL('info_totalParsetime')] = $this->getTimeTracker()->getParseTime() . ' ms';
+
+ return $output;
+ }
+
+ /**
+ * Returns the unique name of the collector
+ *
+ * @return string
+ */
+ function getName()
+ {
+ return 'info';
+ }
+
+ /**
+ * Returns a hash where keys are control names and their values
+ * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
+ *
+ * @return array
+ */
+ function getWidgets()
+ {
+ $name = $this->getName();
+
+ return [
+ "$name" => [
+ 'icon' => 'info',
+ 'widget' => 'PhpDebugBar.Widgets.VariableListWidget',
+ 'map' => 'info',
+ "default" => '[]',
+ ],
+ ];
+ }
+
+ /**
+ * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
+ */
+ protected function getTypoScriptFrontendController()
+ {
+ return $GLOBALS['TSFE'];
+ }
+}
diff --git a/Classes/DataCollectors/MySqliCollector.php b/Classes/DataCollectors/MySqliCollector.php
new file mode 100644
index 0000000..a0b7a25
--- /dev/null
+++ b/Classes/DataCollectors/MySqliCollector.php
@@ -0,0 +1,122 @@
+
+ */
+class MySqliCollector extends BaseCollector implements DataCollectorInterface, Renderable
+{
+
+ protected $connections = [];
+
+ protected $renderSqlWithParams = false;
+
+ protected $sqlQuotationChar = '<>';
+
+ /** @var DebugStack $sqlLogger */
+ protected $sqlLogger;
+
+ /**
+ * The constructor
+ *
+ * @param null $mysqli
+ * @param TimeDataCollector|null $timeDataCollector
+ */
+ public function __construct($mysqli = null, TimeDataCollector $timeDataCollector = null)
+ {
+ parent::__construct();
+
+ $this->sqlLogger = $this->getSqlLoggerFromDatabaseConfiguration();
+ }
+
+ /**
+ * Called by the DebugBar when data needs to be collected
+ *
+ * @return array Collected data
+ */
+ function collect()
+ {
+ $totalTime = 0;
+ $queries = $this->sqlLogger->queries;
+ $statements = [];
+
+ foreach ($queries as $query) {
+ $totalTime += $query['executionMS'];
+
+ $statements[] = [
+ 'sql' => $query['sql'],
+ 'params' => $query['params'],
+ 'duration' => $query['executionMS'],
+ 'duration_str' => $this->formatDuration($query['executionMS']),
+ 'connection' => key($this->connections),
+ ];
+ }
+
+ $data = [
+ 'nb_statements' => count($queries),
+ 'nb_failed_statements' => 0,
+ 'accumulated_duration' => $totalTime,
+ 'accumulated_duration_str' => $this->formatDuration($totalTime),
+ 'statements' => $statements,
+ ];
+
+ return $data;
+ }
+
+ /**
+ * Returns the unique name of the collector
+ *
+ * @return string
+ */
+ function getName()
+ {
+ return 'mysqli';
+ }
+
+ /**
+ * Returns a hash where keys are control names and their values
+ * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
+ *
+ * @return array
+ */
+ function getWidgets()
+ {
+ return [
+ 'database' => [
+ 'icon' => 'database',
+ 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget',
+ 'map' => 'mysqli',
+ 'default' => '[]',
+ ],
+ 'database:badge' => [
+ 'map' => 'mysqli.nb_statements',
+ 'default' => 0,
+ ],
+ ];
+ }
+
+ private function getSqlLoggerFromDatabaseConfiguration()
+ {
+ $this->getConnections();
+
+ return $this->connections['Default']->getConfiguration()->getSQLLogger();
+ }
+
+ private function getConnections()
+ {
+ $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+
+ foreach ($connectionPool->getConnectionNames() as $connectionName) {
+ $this->connections[$connectionName] = $connectionPool->getConnectionByName($connectionName);
+ }
+ }
+}
diff --git a/Classes/DataCollectors/SessionCollector.php b/Classes/DataCollectors/SessionCollector.php
new file mode 100644
index 0000000..d831cb7
--- /dev/null
+++ b/Classes/DataCollectors/SessionCollector.php
@@ -0,0 +1,60 @@
+getSession();
+ }
+
+ /**
+ * Returns the unique name of the collector
+ *
+ * @return string
+ */
+ function getName()
+ {
+ return 'session';
+ }
+
+ /**
+ * Returns a hash where keys are control names and their values
+ * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
+ *
+ * @return array
+ */
+ function getWidgets()
+ {
+ $name = $this->getName();
+
+ return [
+ "$name" => [
+ 'icon' => 'archive',
+ 'widget' => 'PhpDebugBar.Widgets.VariableListWidget',
+ 'map' => 'session',
+ "default" => '[]',
+ ],
+ ];
+ }
+
+ /**
+ * @return mixed
+ */
+ private function getSession()
+ {
+ return $GLOBALS['TSFE']->fe_user->getSession();
+ }
+}
diff --git a/Classes/DataCollectors/Typo3Collector.php b/Classes/DataCollectors/Typo3Collector.php
new file mode 100644
index 0000000..473268e
--- /dev/null
+++ b/Classes/DataCollectors/Typo3Collector.php
@@ -0,0 +1,79 @@
+
+ */
+class Typo3Collector extends BaseCollector implements DataCollectorInterface, Renderable
+{
+
+ /**
+ * Called by the DebugBar when data needs to be collected
+ *
+ * @return array Collected data
+ */
+ function collect()
+ {
+ return [
+ 'version' => VersionNumberUtility::getCurrentTypo3Version(),
+ 'environment' => $this->getEnvironmentInformation(),
+ 'locale' => $this->getLocale(),
+ ];
+ }
+
+ /**
+ * Returns the unique name of the collector
+ *
+ * @return string
+ */
+ function getName()
+ {
+ return 'typo3';
+ }
+
+ /**
+ * Returns a hash where keys are control names and their values
+ * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
+ *
+ * @return array
+ */
+ function getWidgets()
+ {
+ return [
+ 'version' => [
+ 'icon' => 'tag',
+ 'tooltip' => 'Version',
+ 'map' => 'typo3.version',
+ 'default' => '',
+ ],
+ 'environment' => [
+ 'icon' => 'desktop',
+ 'tooltip' => 'Environment',
+ 'map' => 'typo3.environment',
+ 'default' => '',
+ ],
+ 'locale' => [
+ 'icon' => 'flag',
+ 'tooltip' => 'Current locale',
+ 'map' => 'typo3.locale',
+ 'default' => '',
+ ],
+ ];
+ }
+
+ private function getEnvironmentInformation()
+ {
+ return $GLOBALS['_ENV']['TYPO3_CONTEXT'];
+ }
+
+ private function getLocale()
+ {
+ return $GLOBALS['TSFE']->config['config']['locale_all'];
+ }
+}
diff --git a/Classes/Overrides/FrontendUserAuthentication.php b/Classes/Overrides/FrontendUserAuthentication.php
new file mode 100644
index 0000000..a02bc6e
--- /dev/null
+++ b/Classes/Overrides/FrontendUserAuthentication.php
@@ -0,0 +1,12 @@
+sessionData;
+ }
+}
diff --git a/Classes/Typo3DebugBar.php b/Classes/Typo3DebugBar.php
new file mode 100644
index 0000000..f4071e6
--- /dev/null
+++ b/Classes/Typo3DebugBar.php
@@ -0,0 +1,372 @@
+objectManager = GeneralUtility::makeInstance(ObjectManager::class);
+ $this->extensionConfiguration = $this->objectManager
+ ->get(ConfigurationUtility::class)
+ ->getCurrentConfiguration(self::EXTENSION_KEY);
+ $this->extensionPath = ExtensionManagementUtility::siteRelPath(self::EXTENSION_KEY);
+
+ $this->pathToCssResourceFolder = $this->extensionPath . 'Resources/Public/Css/';
+ $this->pathToJsResourceFolder = $this->extensionPath . 'Resources/Public/JavaScript/';
+ $this->backendUser = $backendUser;
+ }
+
+ /**
+ * @throws DebugBarException
+ */
+ public function boot()
+ {
+ if ($this->booted) {
+ return;
+ }
+
+ /** @var DebugBar $debugBar */
+ $debugBar = $this;
+
+ $this->setDefaultAssets();
+
+ $this->javascriptRenderer = $debugBar->getJavascriptRenderer();
+
+ if ($this->shouldCollect('info')) {
+ try {
+ $this->addCollector(new InfoCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add InfoCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('phpinfo')) {
+ try {
+ $this->addCollector(new PhpInfoCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add PhpInfoCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('messages')) {
+ try {
+ $this->addCollector(new MessagesCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add MessagesCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('time')) {
+ try {
+ $this->addCollector(new TimeDataCollector());
+
+ $debugBar->startMeasure('application', 'Application');
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add TimeDataCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('memory')) {
+ try {
+ $this->addCollector(new MemoryCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add MemoryCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('exceptions')) {
+ try {
+ $exceptionCollector = new ExceptionsCollector();
+ $exceptionCollector->setChainExceptions(true);
+ $this->addCollector($exceptionCollector);
+ } catch (\Exception $e) {
+ }
+ }
+
+ if ($this->shouldCollect('auth')) {
+ try {
+ $this->addCollector(new AuthCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add AuthCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('session')) {
+ try {
+ $this->addCollector(new SessionCollector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add SessionCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('typo3')) {
+ try {
+ $this->addCollector(new Typo3Collector());
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add Typo3Collector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ if ($this->shouldCollect('db')) {
+ try {
+ $this->addCollector(new MySqliCollector());
+ $this->cssAssets[] = $this->pathToCssResourceFolder . 'sqlqueries/widget.css';
+ $this->jsAssets[] = $this->pathToJsResourceFolder . 'sqlqueries/widget.js';
+ } catch (DebugBarException $e) {
+ $this->addThrowable(
+ new Exception('Can not add MySqliCollector to TYPO3 DebugBar:' . $e->getMessage(), $e->getCode(), $e)
+ );
+ }
+ }
+
+ $this->booted = true;
+ }
+
+ /**
+ * Starts a measure
+ *
+ * @param string $name Internal name, used to stop the measure
+ * @param string $label Public name
+ * @throws \DebugBar\DebugBarException
+ */
+ public function startMeasure($name, $label = null)
+ {
+ if ($this->hasCollector('time')) {
+ /** @var \DebugBar\DataCollector\TimeDataCollector $collector */
+ $collector = $this->getCollector('time');
+ $collector->startMeasure($name, $label);
+ }
+ }
+
+ /**
+ * Stops a measure
+ *
+ * @param string $name
+ * @throws \DebugBar\DebugBarException
+ */
+ public function stopMeasure($name)
+ {
+ if ($this->hasCollector('time')) {
+ /** @var \DebugBar\DataCollector\TimeDataCollector $collector */
+ $collector = $this->getCollector('time');
+ try {
+ $collector->stopMeasure($name);
+ } catch (\Exception $e) {
+ // $this->addThrowable($e);
+ }
+ }
+ }
+
+ public function shouldCollect($name)
+ {
+ return (bool) $this->extensionConfiguration[$name]['value'];
+ }
+
+ public function isEnabled()
+ {
+ if ($this->enabled === null) {
+ $isEnabled = (bool) $this->extensionConfiguration['enabled']['value'];
+
+ $this->enabled = $this->isFrontendMode() && $this->isAdminLoggedIn() && $isEnabled;
+ }
+
+ return $this->enabled;
+ }
+
+ /**
+ * @param PageRenderer $pageRenderer
+ */
+ public function injectAssets(PageRenderer $pageRenderer)
+ {
+ if (!$this->isEnabled()) {
+ return;
+ }
+
+ $this->javascriptRenderer->dumpCssAssets($this->cssAssets[0]);
+ $this->javascriptRenderer->dumpJsAssets($this->jsAssets[0]);
+
+ foreach ($this->cssAssets as $cssAsset) {
+ $pageRenderer->addHeaderData(sprintf('', $cssAsset));
+ }
+
+ foreach ($this->jsAssets as $jsAsset) {
+ $pageRenderer->addHeaderData(sprintf('', $jsAsset));
+ }
+ }
+
+ public function injectDebugBar(TypoScriptFrontendController $typoScriptFrontendController)
+ {
+ $typoScriptFrontendController->content = str_ireplace('