diff --git a/composer.json b/composer.json
index 25ac1f07..6c02a4b7 100644
--- a/composer.json
+++ b/composer.json
@@ -10,7 +10,7 @@
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
- "kint-php/kint": "^4.0",
+ "kint-php/kint": "^3.3",
"laminas/laminas-escaper": "^2.9",
"psr/log": "^1.1"
},
diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php
index bcce77f1..ed4e5004 100644
--- a/system/CodeIgniter.php
+++ b/system/CodeIgniter.php
@@ -45,7 +45,7 @@ class CodeIgniter
/**
* The current version of CodeIgniter Framework
*/
- public const CI_VERSION = '4.1.6';
+ public const CI_VERSION = '4.1.7';
private const MIN_PHP_VERSION = '7.3';
diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php
index 5f678e51..53e5dad1 100644
--- a/system/Database/BaseConnection.php
+++ b/system/Database/BaseConnection.php
@@ -258,14 +258,14 @@ abstract class BaseConnection implements ConnectionInterface
*
* @var float
*/
- protected $connectTime;
+ protected $connectTime = 0.0;
/**
* How long it took to establish connection.
*
* @var float
*/
- protected $connectDuration;
+ protected $connectDuration = 0.0;
/**
* If true, no queries will actually be
diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php
index 520ddc7c..26cb02dd 100644
--- a/system/Debug/Toolbar/Collectors/Database.php
+++ b/system/Debug/Toolbar/Collectors/Database.php
@@ -85,11 +85,19 @@ public static function collect(Query $query)
if (count(static::$queries) < $max) {
$queryString = $query->getQuery();
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+
+ if (! is_cli()) {
+ // when called in the browser, the first two trace arrays
+ // are from the DB event trigger, which are unneeded
+ $backtrace = array_slice($backtrace, 2);
+ }
+
static::$queries[] = [
'query' => $query,
'string' => $queryString,
'duplicate' => in_array($queryString, array_column(static::$queries, 'string', null), true),
- 'trace' => debug_backtrace(),
+ 'trace' => $backtrace,
];
}
}
@@ -134,23 +142,39 @@ public function display(): array
$data['queries'] = array_map(static function (array $query) {
$isDuplicate = $query['duplicate'] === true;
- // Find the first line that doesn't include `system` in the backtrace
- $line = [];
+ $firstNonSystemLine = '';
+
+ foreach ($query['trace'] as $index => &$line) {
+ // simplify file and line
+ if (isset($line['file'])) {
+ $line['file'] = clean_path($line['file']) . ':' . $line['line'];
+ unset($line['line']);
+ } else {
+ $line['file'] = '[internal function]';
+ }
+
+ // find the first trace line that does not originate from `system/`
+ if ($firstNonSystemLine === '' && strpos($line['file'], 'SYSTEMPATH') === false) {
+ $firstNonSystemLine = $line['file'];
+ }
- foreach ($query['trace'] as &$traceLine) {
- // Clean up the file paths
- $traceLine['file'] = str_ireplace(APPPATH, 'APPPATH/', $traceLine['file']);
- $traceLine['file'] = str_ireplace(SYSTEMPATH, 'SYSTEMPATH/', $traceLine['file']);
- if (defined('VENDORPATH')) {
- // VENDORPATH is not defined unless `vendor/autoload.php` exists
- $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']);
+ // simplify function call
+ if (isset($line['class'])) {
+ $line['function'] = $line['class'] . $line['type'] . $line['function'];
+ unset($line['class'], $line['type']);
}
- $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']);
- if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) {
- continue;
+ if (strrpos($line['function'], '{closure}') === false) {
+ $line['function'] .= '()';
}
- $line = empty($line) ? $traceLine : $line;
+
+ $line['function'] = str_repeat(chr(0xC2) . chr(0xA0), 8) . $line['function'];
+
+ // add index numbering padded with nonbreaking space
+ $indexPadded = str_pad(sprintf('%d', $index + 1), 3, ' ', STR_PAD_LEFT);
+ $indexPadded = preg_replace('/\s/', chr(0xC2) . chr(0xA0), $indexPadded);
+
+ $line['index'] = $indexPadded . str_repeat(chr(0xC2) . chr(0xA0), 4);
}
return [
@@ -159,8 +183,7 @@ public function display(): array
'duration' => ((float) $query['query']->getDuration(5) * 1000) . ' ms',
'sql' => $query['query']->debugToolbarDisplay(),
'trace' => $query['trace'],
- 'trace-file' => str_replace(ROOTPATH, '/', $line['file'] ?? ''),
- 'trace-line' => $line['line'] ?? '',
+ 'trace-file' => $firstNonSystemLine,
'qid' => md5($query['query'] . microtime()),
];
}, static::$queries);
diff --git a/system/Debug/Toolbar/Views/_database.tpl b/system/Debug/Toolbar/Views/_database.tpl
index a2f5bd98..1bd9b8a8 100644
--- a/system/Debug/Toolbar/Views/_database.tpl
+++ b/system/Debug/Toolbar/Views/_database.tpl
@@ -10,13 +10,14 @@
{duration} |
{! sql !} |
- {trace-file}:{trace-line} |
+ {trace-file} |
|
{trace}
- {file}:{line}
+ {index}{file}
+ {function}
{/trace}
|
diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js
index b6883d4b..3bd05d5e 100644
--- a/system/Debug/Toolbar/Views/toolbar.js
+++ b/system/Debug/Toolbar/Views/toolbar.js
@@ -24,10 +24,10 @@ var ciDebugBar = {
document.getElementById('debug-icon-link').addEventListener('click', ciDebugBar.toggleToolbar, true);
// Allows to highlight the row of the current history request
- var btn = document.querySelector('button[data-time="' + localStorage.getItem('debugbar-time') + '"]');
+ var btn = this.toolbar.querySelector('button[data-time="' + localStorage.getItem('debugbar-time') + '"]');
ciDebugBar.addClass(btn.parentNode.parentNode, 'current');
- historyLoad = document.getElementsByClassName('ci-history-load');
+ historyLoad = this.toolbar.getElementsByClassName('ci-history-load');
for (var i = 0; i < historyLoad.length; i++)
{
@@ -52,7 +52,7 @@ var ciDebugBar = {
},
createListeners : function () {
- var buttons = [].slice.call(document.querySelectorAll('#debug-bar .ci-label a'));
+ var buttons = [].slice.call(this.toolbar.querySelectorAll('.ci-label a'));
for (var i = 0; i < buttons.length; i++)
{
@@ -60,7 +60,7 @@ var ciDebugBar = {
}
// Hook up generic toggle via data attributes `data-toggle="foo"`
- var links = document.querySelectorAll('[data-toggle]');
+ var links = this.toolbar.querySelectorAll('[data-toggle]');
for (var i = 0; i < links.length; i++)
{
links[i].addEventListener('click', ciDebugBar.toggleRows, true);
@@ -502,7 +502,7 @@ var ciDebugBar = {
},
setToolbarPosition: function () {
- var btnPosition = document.getElementById('toolbar-position');
+ var btnPosition = this.toolbar.querySelector('#toolbar-position');
if (ciDebugBar.readCookie('debug-bar-position') === 'top')
{
@@ -531,7 +531,7 @@ var ciDebugBar = {
},
setToolbarTheme: function () {
- var btnTheme = document.getElementById('toolbar-theme');
+ var btnTheme = this.toolbar.querySelector('#toolbar-theme');
var isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;
var isLightMode = window.matchMedia("(prefers-color-scheme: light)").matches;
@@ -627,7 +627,7 @@ var ciDebugBar = {
routerLink: function () {
var row, _location;
- var rowGet = document.querySelectorAll('#debug-bar td[data-debugbar-route="GET"]');
+ var rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"]');
var patt = /\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)/;
for (var i = 0; i < rowGet.length; i++)
@@ -653,7 +653,7 @@ var ciDebugBar = {
}
}
- rowGet = document.querySelectorAll('#debug-bar td[data-debugbar-route="GET"] form');
+ rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"] form');
for (var i = 0; i < rowGet.length; i++)
{
row = rowGet[i];
diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php
index e47a8635..51a746c5 100755
--- a/system/Helpers/cookie_helper.php
+++ b/system/Helpers/cookie_helper.php
@@ -65,7 +65,7 @@ function get_cookie($index, bool $xssClean = false)
{
$prefix = isset($_COOKIE[$index]) ? '' : config(App::class)->cookiePrefix;
$request = Services::request();
- $filter = $xssClean ? FILTER_SANITIZE_STRING : FILTER_DEFAULT;
+ $filter = $xssClean ? FILTER_SANITIZE_FULL_SPECIAL_CHARS : FILTER_DEFAULT;
return $request->getCookie($prefix . $index, $filter);
}
diff --git a/system/ThirdParty/Kint/Renderer/CliRenderer.php b/system/ThirdParty/Kint/Renderer/CliRenderer.php
index f86671ff..12b18d03 100644
--- a/system/ThirdParty/Kint/Renderer/CliRenderer.php
+++ b/system/ThirdParty/Kint/Renderer/CliRenderer.php
@@ -59,6 +59,15 @@ class CliRenderer extends TextRenderer
*/
public static $min_terminal_width = 40;
+ /**
+ * Which stream to check for VT100 support on windows.
+ *
+ * null uses STDOUT if it's defined
+ *
+ * @var null|resource
+ */
+ public static $windows_stream = null;
+
protected static $terminal_width = null;
protected $windows_output = false;
@@ -69,8 +78,22 @@ public function __construct()
{
parent::__construct();
- if (!self::$force_utf8) {
- $this->windows_output = KINT_WIN;
+ if (!self::$force_utf8 && KINT_WIN) {
+ if (!KINT_PHP72) {
+ $this->windows_output = true;
+ } else {
+ $stream = self::$windows_stream;
+
+ if (!$stream && \defined('STDOUT')) {
+ $stream = STDOUT;
+ }
+
+ if (!$stream) {
+ $this->windows_output = true;
+ } else {
+ $this->windows_output = !\sapi_windows_vt100_support($stream);
+ }
+ }
}
if (!self::$terminal_width) {
@@ -153,7 +176,7 @@ protected function utf8ToWindows($string)
{
return \str_replace(
['┌', '═', '┐', '│', '└', '─', '┘'],
- ["\xda", "\xdc", "\xbf", "\xb3", "\xc0", "\xc4", "\xd9"],
+ [' ', '=', ' ', '|', ' ', '-', ' '],
$string
);
}
diff --git a/system/ThirdParty/Kint/Renderer/RichRenderer.php b/system/ThirdParty/Kint/Renderer/RichRenderer.php
index 94b7f98a..46a8827d 100644
--- a/system/ThirdParty/Kint/Renderer/RichRenderer.php
+++ b/system/ThirdParty/Kint/Renderer/RichRenderer.php
@@ -133,6 +133,9 @@ class RichRenderer extends Renderer
public static $always_pre_render = false;
+ public static $js_nonce = null;
+ public static $css_nonce = null;
+
protected $plugin_objs = [];
protected $expand = false;
protected $force_pre_render = false;
@@ -389,10 +392,18 @@ public function preRender()
switch ($type) {
case 'script':
- $output .= '';
+ $output .= '