diff --git a/administrator/language/en-GB/en-GB.plg_system_debug.ini b/administrator/language/en-GB/en-GB.plg_system_debug.ini
index 7b3353d082504..ab78291512957 100644
--- a/administrator/language/en-GB/en-GB.plg_system_debug.ini
+++ b/administrator/language/en-GB/en-GB.plg_system_debug.ini
@@ -3,7 +3,10 @@
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8 - No BOM
+PLG_DEBUG_BYTES="Bytes"
+PLG_DEBUG_CALL_STACK="Call Stack"
PLG_DEBUG_ERRORS="Errors"
+PLG_DEBUG_EXPLAIN="Explain"
PLG_DEBUG_FIELD_ALLOWED_GROUPS_DESC="Optionally restrict users that can see debug information to those in the selected user groups. If none selected, all users see the debug information."
PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL="Allowed Groups"
PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_DESC="Display a list of the language files that are in error according to the Joomla ini specification."
@@ -12,6 +15,8 @@ PLG_DEBUG_FIELD_LANGUAGE_FILES_DESC="Display a list of the language files that J
PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL="Show Language Files"
PLG_DEBUG_FIELD_LANGUAGE_STRING_DESC="Display a list of the untranslated language strings."
PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL="Show Language String"
+PLG_DEBUG_FIELD_LOGS_DESC="Display a list of logged messages."
+PLG_DEBUG_FIELD_LOGS_LABEL="Show Log Entries"
PLG_DEBUG_FIELD_LOG_CATEGORIES_DESC="A comma separated list of log categories to include. Common log categories include but are not limited to: database, databasequery, deprecated, and jerror. If empty, all categories will be shown."
PLG_DEBUG_FIELD_LOG_CATEGORIES_LABEL="Log Categories"
PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_DESC="Select whether the listed categories should be included or excluded."
@@ -31,8 +36,6 @@ PLG_DEBUG_FIELD_LOG_PRIORITIES_INFO="Info"
PLG_DEBUG_FIELD_LOG_PRIORITIES_LABEL="Log Priorities"
PLG_DEBUG_FIELD_LOG_PRIORITIES_NOTICE="Notice"
PLG_DEBUG_FIELD_LOG_PRIORITIES_WARNING="Warning"
-PLG_DEBUG_FIELD_LOGS_DESC="Display a list of logged messages."
-PLG_DEBUG_FIELD_LOGS_LABEL="Show Log Entries"
PLG_DEBUG_FIELD_MEMORY_DESC="Display the total memory usage."
PLG_DEBUG_FIELD_MEMORY_LABEL="Show Memory Usage"
PLG_DEBUG_FIELD_PROFILING_DESC="Display the profiling waypoints."
@@ -47,24 +50,43 @@ PLG_DEBUG_FIELD_STRIP_PREFIX_DESC="Strip words from the beginning of the string.
PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL="Strip From Start"
PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC="Strip words from the end of the string. For multiple words, use the format: (word1|word2)"
PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL="Strip From End"
-PLG_DEBUG_LANG_LOADED="Loaded"
-PLG_DEBUG_LANG_NOT_LOADED="Not loaded"
PLG_DEBUG_LANGUAGE_FIELDSET_LABEL="Language Options"
PLG_DEBUG_LANGUAGE_FILES_IN_ERROR="Parsing errors in language files"
PLG_DEBUG_LANGUAGE_FILES_LOADED="Language Files Loaded"
+PLG_DEBUG_LANG_LOADED="Loaded"
+PLG_DEBUG_LANG_NOT_LOADED="Not loaded"
+PLG_DEBUG_LINK_FORMAT="Add xdebug.file_link_format directive to your php.ini file to have links for files"
PLG_DEBUG_LOGGING_FIELDSET_LABEL="Logging"
PLG_DEBUG_LOGS="Log Messages"
+PLG_DEBUG_MEMORY="Memory"
+PLG_DEBUG_MEMORY_USED_FOR_QUERY="Query memory: %s Memory before query: %s"
PLG_DEBUG_MEMORY_USAGE="Memory Usage"
+PLG_DEBUG_NO_PROFILE="No SHOW PROFILE (maybe because there are more than 100 queries)"
PLG_DEBUG_OTHER_QUERIES="OTHER Tables:"
+PLG_DEBUG_PROFILE="Profile"
PLG_DEBUG_PROFILE_INFORMATION="Profile Information"
PLG_DEBUG_QUERIES="Database Queries"
PLG_DEBUG_QUERIES_LOGGED="%d Queries Logged"
+PLG_DEBUG_QUERIES_TIME="Database queries total: %s"
+PLG_DEBUG_QUERY_AFTER_LAST="After last query: %s"
+PLG_DEBUG_QUERY_DUPLICATES="Duplicate queries"
+PLG_DEBUG_QUERY_DUPLICATES_FOUND="Duplicate found!"
+PLG_DEBUG_QUERY_DUPLICATES_NUMBER="%s duplicates"
+PLG_DEBUG_QUERY_DUPLICATES_TOTAL_NUMBER="%s duplicate found!"
+PLG_DEBUG_QUERY_EXPLAIN_NOT_POSSIBLE="EXPLAIN not possible on query: %s"
+PLG_DEBUG_QUERY_TIME="Query Time: %s"
PLG_DEBUG_QUERY_TYPES_LOGGED="%d Query Types Logged, Sorted by Occurrences."
PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES="%2$d × %1$s"
+PLG_DEBUG_ROWS_RETURNED_BY_QUERY="Rows returned: %s"
PLG_DEBUG_SELECT_QUERIES="SELECT Tables:"
PLG_DEBUG_SESSION="Session"
+PLG_DEBUG_TIME="Time"
PLG_DEBUG_TITLE="Joomla! Debug Console"
PLG_DEBUG_UNKNOWN_FILE="Unknown file"
PLG_DEBUG_UNTRANSLATED_STRINGS="Untranslated Strings"
+PLG_DEBUG_WARNING_NO_INDEX="NO INDEX KEY COULD BE USED"
+PLG_DEBUG_WARNING_NO_INDEX_DESC="This table has probably a missing index on WHERE equalities and/or JOIN ON column(s) or is written in a way that no index can be used, causing a time-consuming full table scan"
+PLG_DEBUG_WARNING_USING_FILESORT="Using filesort"
+PLG_DEBUG_WARNING_USING_FILESORT_DESC="This table has probably a missing index on WHERE/ON equality column(s) ending by the ORDER BY column(s) or is written in a way that no index can be used, causing a time-consuming filesort."
PLG_DEBUG_XML_DESCRIPTION="This plugin provides a variety of system information as well as assistance for the creation of translation files."
PLG_SYSTEM_DEBUG="System - Debug"
diff --git a/libraries/joomla/database/driver.php b/libraries/joomla/database/driver.php
index 1cbaa5ec917d1..dd3d0764eeb34 100644
--- a/libraries/joomla/database/driver.php
+++ b/libraries/joomla/database/driver.php
@@ -92,6 +92,19 @@ abstract class JDatabaseDriver extends JDatabase implements JDatabaseInterface
*/
protected $log = array();
+ /**
+ * @var array The log of executed SQL statements timings (start and stop microtimes) by the database driver.
+ * @since CMS 3.1.2
+ */
+ protected $timings = array();
+
+
+ /**
+ * @var array The log of executed SQL statements timings (start and stop microtimes) by the database driver.
+ * @since CMS 3.1.2
+ */
+ protected $callStacks = array();
+
/**
* @var string The character(s) used to quote SQL statement names such as table names or field names,
* etc. The child classes should define this as necessary. If a single character string the
@@ -170,6 +183,12 @@ abstract class JDatabaseDriver extends JDatabase implements JDatabaseInterface
*/
protected $transactionDepth = 0;
+ /**
+ * @var callable[] List of callables to call just before disconnecting database
+ * @since CMS 3.1.2
+ */
+ protected $disconnectHandlers = array();
+
/**
* Get a list of available database connectors. The list will only be populated with connectors that both
* the class exists and the static test method returns true. This gives us the ability to have a multitude
@@ -464,6 +483,19 @@ public function createDatabase($options, $utf = true)
*/
abstract public function disconnect();
+ /**
+ * Adds a function callable just before disconnecting the database. Parameter of the callable is $this JDatabaseDriver
+ *
+ * @param callable $callable Function to call in disconnect() method just before disconnecting from database
+ * @return void
+ *
+ * @since CMS 3.1.2
+ */
+ public function addDisconnectHandler($callable)
+ {
+ $this->disconnectHandlers[] = $callable;
+ }
+
/**
* Drops a table from the database.
*
@@ -648,6 +680,30 @@ public function getLog()
return $this->log;
}
+ /**
+ * Get the database driver SQL statement log.
+ *
+ * @return array SQL statements executed by the database driver.
+ *
+ * @since CMS 3.1.2
+ */
+ public function getTimings()
+ {
+ return $this->timings;
+ }
+
+ /**
+ * Get the database driver SQL statement log.
+ *
+ * @return array SQL statements executed by the database driver.
+ *
+ * @since CMS 3.1.2
+ */
+ public function getCallStacks()
+ {
+ return $this->callStacks;
+ }
+
/**
* Get the minimum supported database version.
*
diff --git a/libraries/joomla/database/driver/mysql.php b/libraries/joomla/database/driver/mysql.php
index b6fe969672438..dc8800a5af0c0 100644
--- a/libraries/joomla/database/driver/mysql.php
+++ b/libraries/joomla/database/driver/mysql.php
@@ -54,10 +54,7 @@ public function __construct($options)
*/
public function __destruct()
{
- if (is_resource($this->connection))
- {
- mysql_close($this->connection);
- }
+ $this->disconnect();
}
/**
@@ -98,6 +95,12 @@ public function connect()
// Set charactersets (needed for MySQL 4.1.2+).
$this->setUTF();
+
+ // Turn MySQL profiling ON in debug mode:
+ if ($this->debug)
+ {
+ mysqli_query($this->connection, "SET profiling = 1;");
+ }
}
/**
@@ -110,7 +113,15 @@ public function connect()
public function disconnect()
{
// Close the connection.
- mysql_close($this->connection);
+ if (is_resource($this->connection))
+ {
+ foreach ($this->disconnectHandlers as $h)
+ {
+ call_user_func_array($h, array( &$this));
+ }
+
+ mysql_close($this->connection);
+ }
$this->connection = null;
}
@@ -254,6 +265,10 @@ public function execute()
// Increment the query counter.
$this->count++;
+ // Reset the error values.
+ $this->errorNum = 0;
+ $this->errorMsg = '';
+
// If debugging is enabled then let's log the query.
if ($this->debug)
{
@@ -261,15 +276,19 @@ public function execute()
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
- }
- // Reset the error values.
- $this->errorNum = 0;
- $this->errorMsg = '';
+ $this->timings[] = microtime(true);
+ }
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
$this->cursor = @mysql_query($query, $this->connection);
+ if ($this->debug)
+ {
+ $this->timings[] = microtime(true);
+ $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ }
+
// If an error occurred handle it.
if (!$this->cursor)
{
diff --git a/libraries/joomla/database/driver/mysqli.php b/libraries/joomla/database/driver/mysqli.php
index 9cf5181f70678..82a6207f5be4d 100644
--- a/libraries/joomla/database/driver/mysqli.php
+++ b/libraries/joomla/database/driver/mysqli.php
@@ -82,10 +82,7 @@ public function __construct($options)
*/
public function __destruct()
{
- if (is_callable(array($this->connection, 'close')))
- {
- mysqli_close($this->connection);
- }
+ $this->disconnect();
}
/**
@@ -157,6 +154,13 @@ public function connect()
// Set charactersets (needed for MySQL 4.1.2+).
$this->setUTF();
+
+ // Turn MySQL profiling ON in debug mode:
+ if ($this->debug)
+ {
+ mysqli_query($this->connection, "SET profiling_history_size = 100;");
+ mysqli_query($this->connection, "SET profiling = 1;");
+ }
}
/**
@@ -169,8 +173,13 @@ public function connect()
public function disconnect()
{
// Close the connection.
- if (is_callable($this->connection, 'close'))
+ if ($this->connection)
{
+ foreach ($this->disconnectHandlers as $h)
+ {
+ call_user_func_array($h, array( &$this));
+ }
+
mysqli_close($this->connection);
}
@@ -496,6 +505,11 @@ public function execute()
// Increment the query counter.
$this->count++;
+ // Reset the error values.
+ $this->errorNum = 0;
+ $this->errorMsg = '';
+ $memoryBefore = null;
+
// If debugging is enabled then let's log the query.
if ($this->debug)
{
@@ -503,15 +517,26 @@ public function execute()
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
- }
- // Reset the error values.
- $this->errorNum = 0;
- $this->errorMsg = '';
+ $this->timings[] = microtime(true);
+
+ if (is_object($this->cursor))
+ {
+ $this->freeResult();
+ }
+ $memoryBefore = memory_get_usage();
+ }
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
$this->cursor = @mysqli_query($this->connection, $query);
+ if ($this->debug)
+ {
+ $this->timings[] = microtime(true);
+ $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ $this->callStacks[count($this->callStacks) - 1][0]['memory'] = array($memoryBefore, memory_get_usage(), is_object($this->cursor) ? $this->getNumRows() : null);
+ }
+
// If an error occurred handle it.
if (!$this->cursor)
{
@@ -757,6 +782,10 @@ protected function fetchObject($cursor = null, $class = 'stdClass')
protected function freeResult($cursor = null)
{
mysqli_free_result($cursor ? $cursor : $this->cursor);
+ if ((! $cursor) || ($cursor === $this->cursor))
+ {
+ $this->cursor = null;
+ }
}
/**
diff --git a/libraries/joomla/database/driver/pdo.php b/libraries/joomla/database/driver/pdo.php
index 91245a009bc13..15a9d8cd941ac 100644
--- a/libraries/joomla/database/driver/pdo.php
+++ b/libraries/joomla/database/driver/pdo.php
@@ -90,8 +90,7 @@ public function __construct($options)
*/
public function __destruct()
{
- $this->freeResult();
- unset($this->connection);
+ $this->disconnect();
}
/**
@@ -307,6 +306,11 @@ public function connect()
*/
public function disconnect()
{
+ foreach ($this->disconnectHandlers as $h)
+ {
+ call_user_func_array($h, array( &$this));
+ }
+
$this->freeResult();
unset($this->connection);
}
@@ -374,6 +378,10 @@ public function execute()
// Increment the query counter.
$this->count++;
+ // Reset the error values.
+ $this->errorNum = 0;
+ $this->errorMsg = '';
+
// If debugging is enabled then let's log the query.
if ($this->debug)
{
@@ -381,11 +389,9 @@ public function execute()
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
- }
- // Reset the error values.
- $this->errorNum = 0;
- $this->errorMsg = '';
+ $this->timings[] = microtime(true);
+ }
// Execute the query.
$this->executed = false;
@@ -404,6 +410,12 @@ public function execute()
$this->executed = $this->prepared->execute();
}
+ if ($this->debug)
+ {
+ $this->timings[] = microtime(true);
+ $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ }
+
// If an error occurred handle it.
if (!$this->executed)
{
diff --git a/libraries/joomla/database/driver/postgresql.php b/libraries/joomla/database/driver/postgresql.php
index cee7acd4ac3bf..3729e64dd5c75 100644
--- a/libraries/joomla/database/driver/postgresql.php
+++ b/libraries/joomla/database/driver/postgresql.php
@@ -84,10 +84,7 @@ public function __construct( $options )
*/
public function __destruct()
{
- if (is_resource($this->connection))
- {
- pg_close($this->connection);
- }
+ $this->disconnect();
}
/**
@@ -136,6 +133,11 @@ public function disconnect()
// Close the connection.
if (is_resource($this->connection))
{
+ foreach ($this->disconnectHandlers as $h)
+ {
+ call_user_func_array($h, array( &$this));
+ }
+
pg_close($this->connection);
}
@@ -532,7 +534,7 @@ public function getVersion()
*
* @example with insertid() call:
* $query = $this->getQuery(true)
- * insert('jos_dbtest')
+ * ->insert('jos_dbtest')
* ->columns('title,start_date,description')
* ->values("'testTitle2nd','1971-01-01','testDescription2nd'");
* $this->setQuery($query);
@@ -628,6 +630,10 @@ public function execute()
// Increment the query counter.
$this->count++;
+ // Reset the error values.
+ $this->errorNum = 0;
+ $this->errorMsg = '';
+
// If debugging is enabled then let's log the query.
if ($this->debug)
{
@@ -635,15 +641,19 @@ public function execute()
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
- }
- // Reset the error values.
- $this->errorNum = 0;
- $this->errorMsg = '';
+ $this->timings[] = microtime(true);
+ }
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
$this->cursor = @pg_query($this->connection, $query);
+ if ($this->debug)
+ {
+ $this->timings[] = microtime(true);
+ $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ }
+
// If an error occurred handle it.
if (!$this->cursor)
{
diff --git a/libraries/joomla/database/driver/sqlsrv.php b/libraries/joomla/database/driver/sqlsrv.php
index 64ca5bd580d31..f1e4a407bbb67 100644
--- a/libraries/joomla/database/driver/sqlsrv.php
+++ b/libraries/joomla/database/driver/sqlsrv.php
@@ -92,10 +92,7 @@ public function __construct($options)
*/
public function __destruct()
{
- if (is_resource($this->connection))
- {
- sqlsrv_close($this->connection);
- }
+ $this->disconnect();
}
/**
@@ -155,6 +152,11 @@ public function disconnect()
// Close the connection.
if (is_resource($this->connection))
{
+ foreach ($this->disconnectHandlers as $h)
+ {
+ call_user_func_array($h, array( &$this));
+ }
+
sqlsrv_close($this->connection);
}
@@ -581,6 +583,10 @@ public function execute()
// Increment the query counter.
$this->count++;
+ // Reset the error values.
+ $this->errorNum = 0;
+ $this->errorMsg = '';
+
// If debugging is enabled then let's log the query.
if ($this->debug)
{
@@ -588,11 +594,9 @@ public function execute()
$this->log[] = $query;
JLog::add($query, JLog::DEBUG, 'databasequery');
- }
- // Reset the error values.
- $this->errorNum = 0;
- $this->errorMsg = '';
+ $this->timings[] = microtime(true);
+ }
// SQLSrv_num_rows requires a static or keyset cursor.
if (strncmp(ltrim(strtoupper($query)), 'SELECT', strlen('SELECT')) == 0)
@@ -607,6 +611,12 @@ public function execute()
// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
$this->cursor = @sqlsrv_query($this->connection, $query, array(), $array);
+ if ($this->debug)
+ {
+ $this->timings[] = microtime(true);
+ $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ }
+
// If an error occurred handle it.
if (!$this->cursor)
{
diff --git a/libraries/joomla/profiler/profiler.php b/libraries/joomla/profiler/profiler.php
index edd725dd718b6..c943272f8a335 100644
--- a/libraries/joomla/profiler/profiler.php
+++ b/libraries/joomla/profiler/profiler.php
@@ -37,6 +37,12 @@ class JProfiler
*/
protected $buffer = null;
+ /**
+ * @var array The profiling messages.
+ * @since 12.1
+ */
+ protected $marks = null;
+
/**
* @var float
* @since 12.1
@@ -64,8 +70,9 @@ class JProfiler
*/
public function __construct($prefix = '')
{
- $this->start = $this->getmicrotime();
+ $this->start = microtime(1);
$this->prefix = $prefix;
+ $this->marks = array();
$this->buffer = array();
}
@@ -103,21 +110,32 @@ public static function getInstance($prefix = '')
*/
public function mark($label)
{
- $current = self::getmicrotime() - $this->start;
+ $current = microtime(1) - $this->start;
$currentMem = memory_get_usage() / 1048576;
+
+ $m = (object) array(
+ 'prefix' => $this->prefix,
+ 'time' => ($current > $this->previousTime ? '+' : '-') . (($current - $this->previousTime) * 1000),
+ 'totalTime' => ($current * 1000),
+ 'memory' => ($currentMem > $this->previousMem ? '+' : '-') . ($currentMem - $this->previousMem),
+ 'totalMemory' => $currentMem,
+ 'label' => $label
+ );
+ $this->marks[] = $m;
+
$mark = sprintf(
- '%s %.3f seconds (+%.3f); %0.2f MB (%s%0.3f) - %s',
- $this->prefix,
- $current,
- $current - $this->previousTime,
- $currentMem,
- ($currentMem > $this->previousMem) ? '+' : '', $currentMem - $this->previousMem,
- $label
+ '%s %.3f seconds (%.3f); %0.2f MB (%0.3f) - %s',
+ $m->prefix,
+ $m->totalTime / 1000,
+ $m->time / 1000,
+ $m->totalMemory,
+ $m->memory,
+ $m->label
);
+ $this->buffer[] = $mark;
$this->previousTime = $current;
$this->previousMem = $currentMem;
- $this->buffer[] = $mark;
return $mark;
}
@@ -128,6 +146,7 @@ public function mark($label)
* @return float The current time
*
* @since 11.1
+ * @deprecated 12.3 (Platform) & 4.0 (CMS) - Use PHP's microtime(1)
*/
public static function getmicrotime()
{
@@ -154,6 +173,19 @@ public function getMemory()
* Get all profiler marks.
*
* Returns an array of all marks created since the Profiler object
+ * was instantiated. Marks are objects as per {@link JProfiler::mark()}.
+ *
+ * @return array Array of profiler marks
+ */
+ public function getMarks()
+ {
+ return $this->marks;
+ }
+
+ /**
+ * Get all profiler mark buffers.
+ *
+ * Returns an array of all mark buffers created since the Profiler object
* was instantiated. Marks are strings as per {@link JProfiler::mark()}.
*
* @return array Array of profiler marks
diff --git a/media/cms/css/debug.css b/media/cms/css/debug.css
index dfbf4e0b4411b..627b99627fb7c 100644
--- a/media/cms/css/debug.css
+++ b/media/cms/css/debug.css
@@ -12,11 +12,10 @@ div#system-debug {
background-color: #fff;
color: #000;
border: 1px dashed silver;
- padding: 5px;
- text-align: left;
+ padding: 10px;
}
-#system-debug div.dbgHeader {
+#system-debug div.dbg-header {
background-color: #ddd;
border: 1px solid #eee;
font-size: 16px;
@@ -35,14 +34,8 @@ div#system-debug {
margin: 0px;
}
-#system-debug a:hover,
-#system-debug a:focus,
-#system-debug a:active,
-#system-debug a:link,
-#system-debug a:visited {
- background-color: #ddd;
- color: #000;
- text-decoration:none;
+#system-debug .dbg-error a h3 {
+ background-color: red;
}
#system-debug a:hover h3,
@@ -51,24 +44,24 @@ div#system-debug {
color: #ddd;
font-size: 14px;
cursor: pointer;
- text-decoration:none;
+ text-decoration: none;
}
-#system-debug div.dbgContainer {
+#system-debug div.dbg-container {
padding: 10px;
}
-#system-debug span.dbgCommand {
+#system-debug span.dbg-command {
color: blue;
font-weight: bold;
}
-#system-debug span.dbgTable {
+#system-debug span.dbg-table {
color: green;
font-weight: bold;
}
-#system-debug b.dbgOperator {
+#system-debug b.dbg-operator {
color: red;
font-weight: bold;
}
@@ -84,13 +77,13 @@ div#system-debug {
#system-debug h4 {
font-size: 14px;
- font-weight:bold;
+ font-weight: bold;
margin: 5px 0 0 0;
}
#system-debug h5 {
font-size: 13px;
- font-weight:bold;
+ font-weight: bold;
margin: 5px 0 0 0;
}
@@ -126,125 +119,67 @@ div#system-debug {
font-size: 13px;
}
-
-/* Common CSS for system debug */
-
-#system-debug {
- background-color: #fff;
- color: #000;
- border: 1px dashed silver;
- padding: 10px;
-}
-
-#system-debug div.dbgHeader {
- background-color: #ddd;
- border: 1px solid #eee;
- font-size: 16px;
-}
-
-#system-debug h3 {
- margin: 0;
-}
-
-#system-debug a h3 {
- background-color: #ddd;
- color: #000;
- font-size: 14px;
- padding: 5px;
- text-decoration: none;
- margin: 0px;
-}
-
-#system-debug .dbgerror a h3 {
+#system-debug div.dbg-header.dbg-error {
background-color: red;
}
-
-#system-debug a:hover,
-#system-debug a:focus,
-#system-debug a:active,
-#system-debug a:link,
-#system-debug a:visited {
- background-color: #ddd;
- color: #000;
- text-decoration:none;
-}
-
-#system-debug a:hover h3,
-#system-debug a:focus h3 {
- background-color: #4d4d4d;
- color: #ddd;
- font-size: 14px;
- cursor: pointer;
- text-decoration:none;
-}
-
-#system-debug div.dbgContainer {
- padding: 10px;
-}
-
-#system-debug span.dbgCommand {
- color: blue;
- font-weight: bold;
-}
-
-#system-debug span.dbgTable {
- color: green;
- font-weight: bold;
-}
-
-#system-debug b.dbgOperator {
+#system-debug .dbg-warning {
color: red;
font-weight: bold;
+ background-color: #ffffcc !important;
}
-#system-debug h1 {
- background-color: #2c2c2c;
- color: #fff;
- padding: 10px;
- margin: 0;
- font-size: 16px;
- line-height: 1em;
+#system-debug .accordion {
+ margin-bottom: 0;
}
-
-#system-debug h4 {
- font-size: 14px;
- font-weight:bold;
+#system-debug .dbg-noprofile {
+ text-decoration: line-through;
}
-#system-debug h5 {
- font-size: 13px;
- font-weight:bold;
- margin-top: 5px;
+/* dbg-bars */
+#system-debug .alert,
+#system-debug .dbg-bars {
+ margin-bottom: 10px;
}
-
-div#system-debug {
- margin: 5px;
+#system-debug .dbg-bar-spacer {
+ float: left;
+ height: 100%;
}
-
-#system-debug ol {
- margin-left: 25px;
- margin-right: 25px;
+/* dbg-bars-query */
+#system-debug .dbg-bars-query .dbg-bar {
+ opacity: 0.3;
+ height: 12px;
+ margin-top: 3px;
}
-
-#system-debug ul {
- list-style: none;
+#system-debug .dbg-bars-query:hover .dbg-bar {
+ opacity: 0.6;
+ height: 18px;
+ margin-top: 0;
}
-
-#system-debug li {
- font-size: 13px;
- margin-bottom: 10px;
+#system-debug .dbg-bars-query .dbg-bar:hover,
+#system-debug .dbg-bars-query .dbg-bar-active,
+#system-debug .dbg-bars-query:hover .dbg-bar-active {
+ opacity: 1;
+ height: 18px;
+ margin-top: 0;
}
-#system-debug code {
- font-size: 13px;
- text-align: left;
- direction: ltr;
+/* dbg-query-table */
+#system-debug table.dbg-query-table {
+ margin: 0px 0px 6px;
}
-
-#system-debug p {
- font-size: 13px;
+#system-debug table.dbg-query-table th,
+#system-debug table.dbg-query-table td {
+ padding: 3px 8px;
}
-#system-debug div.dbgHeader.dbgerror {
- background-color: red;
+#system-debug .dbg-profile-list .label {
+ display: inline-block;
+ min-width: 60px;
+ text-align: right;
}
+
+#system-debug .dbg-query-memory,
+#system-debug .dbg-query-rowsnumber
+{
+ margin-left: 50px;
+}
\ No newline at end of file
diff --git a/plugins/system/debug/debug.php b/plugins/system/debug/debug.php
index 1c22fd55a86bf..7873088edec98 100644
--- a/plugins/system/debug/debug.php
+++ b/plugins/system/debug/debug.php
@@ -36,6 +36,30 @@ class PlgSystemDebug extends JPlugin
*/
private $logEntries = array();
+ /**
+ * Holds SHOW PROFILES of queries
+ *
+ * @var array
+ * @since CMS 3.1.2
+ */
+ private $sqlShowProfiles = array();
+
+ /**
+ * Holds all SHOW PROFILE FOR QUERY n, indexed by n-1
+ *
+ * @var array
+ * @since CMS 3.1.2
+ */
+ private $sqlShowProfileEach = array();
+
+ /**
+ * Holds all EXPLAIN EXTENDED for all queries
+ *
+ * @var array
+ * @since CMS 3.1.2
+ */
+ private $explains = array();
+
/**
* Constructor.
*
@@ -72,7 +96,7 @@ public function __construct(&$subject, $config)
foreach ($this->params->get('log_priorities', array()) as $p)
{
- $const = 'JLog::'.strtoupper($p);
+ $const = 'JLog::' . strtoupper($p);
if (!defined($const))
{
@@ -88,6 +112,10 @@ public function __construct(&$subject, $config)
JLog::addLogger(array('logger' => 'callback', 'callback' => array($this, 'logger')), $priority, $categories, $mode);
}
+
+ // Prepare disconnect-handler for SQL profiling:
+ $db = JFactory::getDbo();
+ $db->addDisconnectHandler(array($this, 'mysqlDisconnectHandler'));
}
/**
@@ -105,6 +133,13 @@ public function onAfterDispatch()
{
JHtml::_('stylesheet', 'cms/debug.css', array(), true);
}
+
+ // Only if debugging is enabled for SQL queries popovers
+ if (JDEBUG && $this->isAuthorisedDisplayDebug())
+ {
+ JHtml::_('bootstrap.tooltip');
+ JHtml::_('bootstrap.popover', '.hasPopover', array('placement' => 'top'));
+ }
}
/**
@@ -142,7 +177,8 @@ public function __destruct()
// No debug for Safari and Chrome redirection
if (strstr(strtolower($_SERVER['HTTP_USER_AGENT']), 'webkit') !== false
- && substr($contents, 0, 50) == '