diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ea5e536da0..23c77082242e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,28 @@ # Changelog +## [v4.1.7](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.7) (2022-01-09) + +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.6...v4.1.7) + +**Breaking Changes** + +* fix: replace deprecated FILTER_SANITIZE_STRING by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5555 + +**Fixed Bugs** + +* fix: BaseConnection::getConnectDuration() number_format(): Passing null to parameter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5536 +* Fix: Debug toolbar selectors by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/5544 +* Fix: Toolbar. ciDebugBar.showTab() context. by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/5554 +* Refactor Database Collector display by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5553 + ## [v4.1.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.6) (2022-01-03) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.5...v4.1.6) +**SECURITY** + +* *Deserialization of Untrusted Data* found in the ``old()`` function was fixed. See the [Security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-w6jr-wj64-mc9x) for more information. + **Breaking Changes** * fix: Incorrect type `BaseBuilder::$tableName` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5378 diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index bcce77f1f853..ed4e500466f6 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 5f678e5114d7..53e5dad1b351 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 520ddc7c5dc6..26cb02ddfeb0 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 a2f5bd9808f1..1bd9b8a88405 100644 --- a/system/Debug/Toolbar/Views/_database.tpl +++ b/system/Debug/Toolbar/Views/_database.tpl @@ -10,13 +10,14 @@