First Local Commit - After Clean up.

Signed-off-by: Rick Hays <rhays@haysgang.com>
This commit is contained in:
2019-12-02 14:54:38 -06:00
commit 10412ab7f6
486 changed files with 123242 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
/**
* Base Toolbar collector
*/
class BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = false;
/**
* Whether this collector needs to display
* a label or not.
*
* @var boolean
*/
protected $hasLabel = false;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var boolean
*/
protected $hasVarData = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = '';
//--------------------------------------------------------------------
/**
* Gets the Collector's title.
*
* @param boolean $safe
* @return string
*/
public function getTitle(bool $safe = false): string
{
if ($safe)
{
return str_replace(' ', '-', strtolower($this->title));
}
return $this->title;
}
//--------------------------------------------------------------------
/**
* Returns any information that should be shown next to the title.
*
* @return string
*/
public function getTitleDetails(): string
{
return '';
}
//--------------------------------------------------------------------
/**
* Does this collector need it's own tab?
*
* @return boolean
*/
public function hasTabContent(): bool
{
return (bool) $this->hasTabContent;
}
//--------------------------------------------------------------------
/**
* Does this collector have a label?
*
* @return boolean
*/
public function hasLabel(): bool
{
return (bool) $this->hasLabel;
}
//--------------------------------------------------------------------
/**
* Does this collector have information for the timeline?
*
* @return boolean
*/
public function hasTimelineData(): bool
{
return (bool) $this->hasTimeline;
}
//--------------------------------------------------------------------
/**
* Grabs the data for the timeline, properly formatted,
* or returns an empty array.
*
* @return array
*/
public function timelineData(): array
{
if (! $this->hasTimeline)
{
return [];
}
return $this->formatTimelineData();
}
//--------------------------------------------------------------------
/**
* Does this Collector have data that should be shown in the
* 'Vars' tab?
*
* @return boolean
*/
public function hasVarData(): bool
{
return (bool) $this->hasVarData;
}
//--------------------------------------------------------------------
/**
* Gets a collection of data that should be shown in the 'Vars' tab.
* The format is an array of sections, each with their own array
* of key/value pairs:
*
* $data = [
* 'section 1' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* 'section 2' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* ];
*
* @return null
*/
public function getVarData()
{
return null;
}
//--------------------------------------------------------------------
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*
* Timeline data should be formatted into arrays that look like:
*
* [
* 'name' => 'Database::Query',
* 'component' => 'Database',
* 'start' => 10 // milliseconds
* 'duration' => 15 // milliseconds
* ]
*
* @return array
*/
protected function formatTimelineData(): array
{
return [];
}
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array|string
*/
public function display()
{
return [];
}
//--------------------------------------------------------------------
/**
* Clean Path
*
* This makes nicer looking paths for the error output.
*
* @param string $file
*
* @return string
*/
public function cleanPath(string $file): string
{
if (strpos($file, APPPATH) === 0)
{
$file = 'APPPATH/' . substr($file, strlen(APPPATH));
}
elseif (strpos($file, SYSTEMPATH) === 0)
{
$file = 'SYSTEMPATH/' . substr($file, strlen(SYSTEMPATH));
}
elseif (strpos($file, FCPATH) === 0)
{
$file = 'FCPATH/' . substr($file, strlen(FCPATH));
}
return $file;
}
/**
* Gets the "badge" value for the button.
*
* @return null
*/
public function getBadgeValue()
{
return null;
}
/**
* Does this collector have any data collected?
*
* If not, then the toolbar button won't get shown.
*
* @return boolean
*/
public function isEmpty(): bool
{
return false;
}
/**
* Returns the HTML to display the icon. Should either
* be SVG, or a base-64 encoded.
*
* Recommended dimensions are 24px x 24px
*
* @return string
*/
public function icon(): string
{
return '';
}
/**
* Return settings as an array.
*
* @return array
*/
public function getAsArray(): array
{
return [
'title' => $this->getTitle(),
'titleSafe' => $this->getTitle(true),
'titleDetails' => $this->getTitleDetails(),
'display' => $this->display(),
'badgeValue' => $this->getBadgeValue(),
'isEmpty' => $this->isEmpty(),
'hasTabContent' => $this->hasTabContent(),
'hasLabel' => $this->hasLabel(),
'icon' => $this->icon(),
'hasTimelineData' => $this->hasTimelineData(),
'timelineData' => $this->timelineData(),
];
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\App;
use Config\Services;
use CodeIgniter\CodeIgniter;
/**
* Debug toolbar configuration
*/
class Config
{
/**
* Return toolbar config values as an array.
*
* @return array
*/
public static function display(): array
{
$config = config(App::class);
return [
'ciVersion' => CodeIgniter::CI_VERSION,
'phpVersion' => phpversion(),
'phpSAPI' => php_sapi_name(),
'environment' => ENVIRONMENT,
'baseURL' => $config->baseURL,
'timezone' => app_timezone(),
'locale' => Services::request()->getLocale(),
'cspEnabled' => $config->CSPEnabled,
];
}
}

View File

@@ -0,0 +1,276 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Database\Query;
/**
* Collector for the Database tab of the Debug Toolbar.
*/
class Database extends BaseCollector
{
/**
* Whether this collector has timeline data.
*
* @var boolean
*/
protected $hasTimeline = true;
/**
* Whether this collector should display its own tab.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* Whether this collector has data for the Vars tab.
*
* @var boolean
*/
protected $hasVarData = false;
/**
* The name used to reference this collector in the toolbar.
*
* @var string
*/
protected $title = 'Database';
/**
* Array of database connections.
*
* @var array
*/
protected $connections;
/**
* The query instances that have been collected
* through the DBQuery Event.
*
* @var array
*/
protected static $queries = [];
//--------------------------------------------------------------------
/**
* Constructor
*/
public function __construct()
{
$this->connections = \Config\Database::getConnections();
}
//--------------------------------------------------------------------
/**
* The static method used during Events to collect
* data.
*
* @param \CodeIgniter\Database\Query $query
*
* @internal param $ array \CodeIgniter\Database\Query
*/
public static function collect(Query $query)
{
$config = config('Toolbar');
// Provide default in case it's not set
$max = $config->maxQueries ?: 100;
if (count(static::$queries) < $max)
{
static::$queries[] = $query;
}
}
//--------------------------------------------------------------------
/**
* Returns timeline data formatted for the toolbar.
*
* @return array The formatted data or an empty array.
*/
protected function formatTimelineData(): array
{
$data = [];
foreach ($this->connections as $alias => $connection)
{
// Connection Time
$data[] = [
'name' => 'Connecting to Database: "' . $alias . '"',
'component' => 'Database',
'start' => $connection->getConnectStart(),
'duration' => $connection->getConnectDuration(),
];
}
foreach (static::$queries as $query)
{
$data[] = [
'name' => 'Query',
'component' => 'Database',
'start' => $query->getStartTime(true),
'duration' => $query->getDuration(),
];
}
return $data;
}
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
*/
public function display(): array
{
// Key words we want bolded
$highlight = [
'SELECT',
'DISTINCT',
'FROM',
'WHERE',
'AND',
'LEFT&nbsp;JOIN',
'ORDER&nbsp;BY',
'GROUP&nbsp;BY',
'LIMIT',
'INSERT',
'INTO',
'VALUES',
'UPDATE',
'OR&nbsp;',
'HAVING',
'OFFSET',
'NOT&nbsp;IN',
'IN',
'LIKE',
'NOT&nbsp;LIKE',
'COUNT',
'MAX',
'MIN',
'ON',
'AS',
'AVG',
'SUM',
'(',
')',
];
$data = [
'queries' => [],
];
foreach (static::$queries as $query)
{
$sql = $query->getQuery();
foreach ($highlight as $term)
{
$sql = str_replace($term, "<strong>{$term}</strong>", $sql);
}
$data['queries'][] = [
'duration' => ($query->getDuration(5) * 1000) . ' ms',
'sql' => $sql,
];
}
return $data;
}
//--------------------------------------------------------------------
/**
* Gets the "badge" value for the button.
*
* @return integer
*/
public function getBadgeValue(): int
{
return count(static::$queries);
}
//--------------------------------------------------------------------
/**
* Information to be displayed next to the title.
*
* @return string The number of queries (in parentheses) or an empty string.
*/
public function getTitleDetails(): string
{
return '(' . count(static::$queries) . ' Queries across ' . ($countConnection = count($this->connections)) . ' Connection' .
($countConnection > 1 ? 's' : '') . ')';
}
//--------------------------------------------------------------------
/**
* Does this collector have any data collected?
*
* @return boolean
*/
public function isEmpty(): bool
{
return empty(static::$queries);
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADMSURBVEhLY6A3YExLSwsA4nIycQDIDIhRWEBqamo/UNF/SjDQjF6ocZgAKPkRiFeEhoYyQ4WIBiA9QAuWAPEHqBAmgLqgHcolGQD1V4DMgHIxwbCxYD+QBqcKINseKo6eWrBioPrtQBq/BcgY5ht0cUIYbBg2AJKkRxCNWkDQgtFUNJwtABr+F6igE8olGQD114HMgHIxAVDyAhA/AlpSA8RYUwoeXAPVex5qHCbIyMgwBCkAuQJIY00huDBUz/mUlBQDqHGjgBjAwAAACexpph6oHSQAAAAASUVORK5CYII=';
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Config\Services;
use CodeIgniter\View\RendererInterface;
/**
* Views collector
*/
class Events extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var boolean
*/
protected $hasVarData = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Events';
/**
* Instance of the Renderer service
*
* @var RendererInterface
*/
protected $viewer;
//--------------------------------------------------------------------
/**
* Constructor.
*/
public function __construct()
{
$this->viewer = Services::renderer(null, true);
}
//--------------------------------------------------------------------
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*
* @return array
*/
protected function formatTimelineData(): array
{
$data = [];
$rows = $this->viewer->getPerformanceData();
foreach ($rows as $name => $info)
{
$data[] = [
'name' => 'View: ' . $info['view'],
'component' => 'Views',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
*/
public function display(): array
{
$data = [
'events' => [],
];
foreach (\CodeIgniter\Events\Events::getPerformanceLogs() as $row)
{
$key = $row['event'];
if (! array_key_exists($key, $data['events']))
{
$data['events'][$key] = [
'event' => $key,
'duration' => number_format(($row['end'] - $row['start']) * 1000, 2),
'count' => 1,
];
continue;
}
$data['events'][$key]['duration'] += number_format(($row['end'] - $row['start']) * 1000, 2);
$data['events'][$key]['count']++;
}
return $data;
}
//--------------------------------------------------------------------
/**
* Gets the "badge" value for the button.
*
* @return integer
*/
public function getBadgeValue(): int
{
return count(\CodeIgniter\Events\Events::getPerformanceLogs());
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEASURBVEhL7ZXNDcIwDIVTsRBH1uDQDdquUA6IM1xgCA6MwJUN2hk6AQzAz0vl0ETUxC5VT3zSU5w81/mRMGZysixbFEVR0jSKNt8geQU9aRpFmp/keX6AbjZ5oB74vsaN5lSzA4tLSjpBFxsjeSuRy4d2mDdQTWU7YLbXTNN05mKyovj5KL6B7q3hoy3KwdZxBlT+Ipz+jPHrBqOIynZgcZonoukb/0ckiTHqNvDXtXEAaygRbaB9FvUTjRUHsIYS0QaSp+Dw6wT4hiTmYHOcYZsdLQ2CbXa4ftuuYR4x9vYZgdb4vsFYUdmABMYeukK9/SUme3KMFQ77+Yfzh8eYF8+orDuDWU5LAAAAAElFTkSuQmCC';
}
}

View File

@@ -0,0 +1,151 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
/**
* Files collector
*/
class Files extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Files';
//--------------------------------------------------------------------
/**
* Returns any information that should be shown next to the title.
*
* @return string
*/
public function getTitleDetails(): string
{
return '( ' . (int) count(get_included_files()) . ' )';
}
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
*/
public function display(): array
{
$rawFiles = get_included_files();
$coreFiles = [];
$userFiles = [];
foreach ($rawFiles as $file)
{
$path = $this->cleanPath($file);
if (strpos($path, 'SYSTEMPATH') !== false)
{
$coreFiles[] = [
'name' => basename($file),
'path' => $path,
];
}
else
{
$userFiles[] = [
'name' => basename($file),
'path' => $path,
];
}
}
sort($userFiles);
sort($coreFiles);
return [
'coreFiles' => $coreFiles,
'userFiles' => $userFiles,
];
}
//--------------------------------------------------------------------
/**
* Displays the number of included files as a badge in the tab button.
*
* @return integer
*/
public function getBadgeValue(): int
{
return count(get_included_files());
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGBSURBVEhL7ZQ9S8NQGIVTBQUncfMfCO4uLgoKbuKQOWg+OkXERRE1IAXrIHbVDrqIDuLiJgj+gro7S3dnpfq88b1FMTE3VZx64HBzzvvZWxKnj15QCcPwCD5HUfSWR+JtzgmtsUcQBEva5IIm9SwSu+95CAWbUuy67qBa32ByZEDpIaZYZSZMjjQuPcQUq8yEyYEb8FSerYeQVGbAFzJkX1PyQWLhgCz0BxTCekC1Wp0hsa6yokzhed4oje6Iz6rlJEkyIKfUEFtITVtQdAibn5rMyaYsMS+a5wTv8qeXMhcU16QZbKgl3hbs+L4/pnpdc87MElZgq10p5DxGdq8I7xrvUWUKvG3NbSK7ubngYzdJwSsF7TiOh9VOgfcEz1UayNe3JUPM1RWC5GXYgTfc75B4NBmXJnAtTfpABX0iPvEd9ezALwkplCFXcr9styiNOKc1RRZpaPM9tcqBwlWzGY1qPL9wjqRBgF5BH6j8HWh2S7MHlX8PrmbK+k/8PzjOOzx1D3i1pKTTAAAAAElFTkSuQmCC';
}
}

View File

@@ -0,0 +1,183 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
/**
* History collector
*/
class History extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* Whether this collector needs to display
* a label or not.
*
* @var boolean
*/
protected $hasLabel = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'History';
/**
* @var array History files
*/
protected $files = [];
//--------------------------------------------------------------------
/**
* Specify time limit & file count for debug history.
*
* @param integer $current Current history time
* @param integer $limit Max history files
*/
public function setFiles(int $current, int $limit = 20)
{
$filenames = glob(WRITEPATH . 'debugbar/debugbar_*.json');
$files = [];
$counter = 0;
foreach (array_reverse($filenames) as $filename)
{
$counter++;
// Oldest files will be deleted
if ($limit >= 0 && $counter > $limit)
{
unlink($filename);
continue;
}
// Get the contents of this specific history request
$contents = file_get_contents($filename);
$contents = @json_decode($contents);
if (json_last_error() === JSON_ERROR_NONE)
{
preg_match_all('/\d+/', $filename, $time);
$time = (int)end($time[0]);
// Debugbar files shown in History Collector
$files[] = [
'time' => $time,
'datetime' => date('Y-m-d H:i:s', $time),
'active' => $time === $current,
'status' => $contents->vars->response->statusCode,
'method' => $contents->method,
'url' => $contents->url,
'isAJAX' => $contents->isAJAX ? 'Yes' : 'No',
'contentType' => $contents->vars->response->contentType,
];
}
}
$this->files = $files;
}
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
*/
public function display(): array
{
return ['files' => $this->files];
}
//--------------------------------------------------------------------
/**
* Displays the number of included files as a badge in the tab button.
*
* @return integer
*/
public function getBadgeValue(): int
{
return count($this->files);
}
/**
* Return true if there are no history files.
*
* @return boolean
*/
public function isEmpty(): bool
{
return empty($this->files);
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJySURBVEhL3ZU7aJNhGIVTpV6i4qCIgkIHxcXLErS4FBwUFNwiCKGhuTYJGaIgnRoo4qRu6iCiiIuIXXTTIkIpuqoFwaGgonUQlC5KafU5ycmNP0lTdPLA4fu+8573/a4/f6hXpFKpwUwmc9fDfweKbk+n07fgEv33TLSbtt/hvwNFT1PsG/zdTE0Gp+GFfD6/2fbVIxqNrqPIRbjg4t/hY8aztcngfDabHXbKyiiXy2vcrcPH8oDCry2FKDrA+Ar6L01E/ypyXzXaARjDGGcoeNxSDZXE0dHRA5VRE5LJ5CFy5jzJuOX2wHRHRnjbklZ6isQ3tIctBaAd4vlK3jLtkOVWqABBXd47jGHLmjTmSScttQV5J+SjfcUweFQEbsjAas5aqoCLXutJl7vtQsAzpRowYqkBinyCC8Vicb2lOih8zoldd0F8RD7qTFiqAnGrAy8stUAvi/hbqDM+YzkAFrLPdR5ZqoLXsd+Bh5YCIH7JniVdquUWxOPxDfboHhrI5XJ7HHhiqQXox+APe/Qk64+gGYVCYZs8cMpSFQj9JOoFzVqqo7k4HIvFYpscCoAjOmLffUsNUGRaQUwDlmofUa34ecsdgXdcXo4wbakBgiUFafXJV8A4DJ/2UrxUKm3E95H8RbjLcgOJRGILhnmCP+FBy5XvwN2uIPcy1AJvWgqC4xm2aU4Xb3lF4I+Tpyf8hRe5w3J7YLymSeA8Z3nSclv4WLRyFdfOjzrUFX0klJUEtZtntCNc+F69cz/FiDzEPtjzmcUMOr83kDQEX6pAJxJfpL3OX22n01YN7SZCoQnaSdoZ+Jz+PZihH3wt/xlCoT9M6nEtmRSPCQAAAABJRU5ErkJggg==';
}
}

View File

@@ -0,0 +1,139 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Config\Services;
/**
* Loags collector
*/
class Logs extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Logs';
/**
* Our collected data.
*
* @var array
*/
protected $data;
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
*/
public function display(): array
{
return [
'logs' => $this->collectLogs(),
];
}
//--------------------------------------------------------------------
/**
* Does this collector actually have any data to display?
*
* @return boolean
*/
public function isEmpty(): bool
{
$this->collectLogs();
return empty($this->data);
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACYSURBVEhLYxgFJIHU1FSjtLS0i0D8AYj7gEKMEBkqAaAFF4D4ERCvAFrwH4gDoFIMKSkpFkB+OTEYqgUTACXfA/GqjIwMQyD9H2hRHlQKJFcBEiMGQ7VgAqCBvUgK32dmZspCpagGGNPT0/1BLqeF4bQHQJePpiIwhmrBBEADR1MRfgB0+WgqAmOoFkwANHA0FY0CUgEDAwCQ0PUpNB3kqwAAAABJRU5ErkJggg==';
}
//--------------------------------------------------------------------
/**
* Ensures the data has been collected.
*/
protected function collectLogs()
{
if (! is_null($this->data))
{
return $this->data;
}
return $this->data = Services::logger(true)->logCache ?? [];
}
//--------------------------------------------------------------------
}

View File

@@ -0,0 +1,181 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Config\Services;
/**
* Routes collector
*/
class Routes extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Routes';
//--------------------------------------------------------------------
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array
* @throws \ReflectionException
*/
public function display(): array
{
$rawRoutes = Services::routes(true);
$router = Services::router(null, null, true);
/*
* Matched Route
*/
$route = $router->getMatchedRoute();
// Get our parameters
// Closure routes
if (is_callable($router->controllerName()))
{
$method = new \ReflectionFunction($router->controllerName());
}
else
{
try
{
$method = new \ReflectionMethod($router->controllerName(), $router->methodName());
}
catch (\ReflectionException $e)
{
// If we're here, the method doesn't exist
// and is likely calculated in _remap.
$method = new \ReflectionMethod($router->controllerName(), '_remap');
}
}
$rawParams = $method->getParameters();
$params = [];
foreach ($rawParams as $key => $param)
{
$params[] = [
'name' => $param->getName(),
'value' => $router->params()[$key] ??
'&lt;empty&gt;&nbsp| default: ' . var_export($param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, true),
];
}
$matchedRoute = [
[
'directory' => $router->directory(),
'controller' => $router->controllerName(),
'method' => $router->methodName(),
'paramCount' => count($router->params()),
'truePCount' => count($params),
'params' => $params ?? [],
],
];
/*
* Defined Routes
*/
$rawRoutes = $rawRoutes->getRoutes();
$routes = [];
foreach ($rawRoutes as $from => $to)
{
$routes[] = [
'from' => $from,
'to' => $to,
];
}
return [
'matchedRoute' => $matchedRoute,
'routes' => $routes,
];
}
//--------------------------------------------------------------------
/**
* Returns a count of all the routes in the system.
*
* @return integer
*/
public function getBadgeValue(): int
{
$rawRoutes = Services::routes(true);
return count($rawRoutes->getRoutes());
}
//--------------------------------------------------------------------
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFDSURBVEhL7ZRNSsNQFIUjVXSiOFEcuQIHDpzpxC0IGYeE/BEInbWlCHEDLsSiuANdhKDjgm6ggtSJ+l25ldrmmTwIgtgDh/t37r1J+16cX0dRFMtpmu5pWAkrvYjjOB7AETzStBFW+inxu3KUJMmhludQpoflS1zXban4LYqiO224h6VLTHr8Z+z8EpIHFF9gG78nDVmW7UgTHKjsCyY98QP+pcq+g8Ku2s8G8X3f3/I8b038WZTp+bO38zxfFd+I6YY6sNUvFlSDk9CRhiAI1jX1I9Cfw7GG1UB8LAuwbU0ZwQnbRDeEN5qqBxZMLtE1ti9LtbREnMIuOXnyIf5rGIb7Wq8HmlZgwYBH7ORTcKH5E4mpjeGt9fBZcHE2GCQ3Vt7oTNPNg+FXLHnSsHkw/FR+Gg2bB8Ptzrst/v6C/wrH+QB+duli6MYJdQAAAABJRU5ErkJggg==';
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Config\Services;
/**
* Timers collector
*/
class Timers extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = true;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Timers';
//--------------------------------------------------------------------
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*
* @return array
*/
protected function formatTimelineData(): array
{
$data = [];
$benchmark = Services::timer(true);
$rows = $benchmark->getTimers(6);
foreach ($rows as $name => $info)
{
if ($name === 'total_execution')
{
continue;
}
$data[] = [
'name' => ucwords(str_replace('_', ' ', $name)),
'component' => 'Timer',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
}

View File

@@ -0,0 +1,192 @@
<?php
/**
* CodeIgniter
*
* An open source application development framework for PHP
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2014-2019 British Columbia Institute of Technology
* Copyright (c) 2019 CodeIgniter Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @package CodeIgniter
* @author CodeIgniter Dev Team
* @copyright 2019 CodeIgniter Foundation
* @license https://opensource.org/licenses/MIT MIT License
* @link https://codeigniter.com
* @since Version 4.0.0
* @filesource
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Config\Services;
use CodeIgniter\View\RendererInterface;
/**
* Views collector
*/
class Views extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var boolean
*/
protected $hasTimeline = true;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var boolean
*/
protected $hasTabContent = false;
/**
* Whether this collector needs to display
* a label or not.
*
* @var boolean
*/
protected $hasLabel = true;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var boolean
*/
protected $hasVarData = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Views';
/**
* Instance of the Renderer service
*
* @var RendererInterface
*/
protected $viewer;
/**
* Views counter
*
* @var array
*/
protected $views = [];
//--------------------------------------------------------------------
/**
* Constructor.
*/
public function __construct()
{
$this->viewer = Services::renderer();
}
//--------------------------------------------------------------------
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*
* @return array
*/
protected function formatTimelineData(): array
{
$data = [];
$rows = $this->viewer->getPerformanceData();
foreach ($rows as $name => $info)
{
$data[] = [
'name' => 'View: ' . $info['view'],
'component' => 'Views',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
//--------------------------------------------------------------------
/**
* Gets a collection of data that should be shown in the 'Vars' tab.
* The format is an array of sections, each with their own array
* of key/value pairs:
*
* $data = [
* 'section 1' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* 'section 2' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* ];
*
* @return array
*/
public function getVarData(): array
{
return [
'View Data' => $this->viewer->getData(),
];
}
//--------------------------------------------------------------------
/**
* Returns a count of all views.
*
* @return integer
*/
public function getBadgeValue(): int
{
return count($this->viewer->getPerformanceData());
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*
* @return string
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADeSURBVEhL7ZSxDcIwEEWNYA0YgGmgyAaJLTcUaaBzQQEVjMEabBQxAdw53zTHiThEovGTfnE/9rsoRUxhKLOmaa6Uh7X2+UvguLCzVxN1XW9x4EYHzik033Hp3X0LO+DaQG8MDQcuq6qao4qkHuMgQggLvkPLjqh00ZgFDBacMJYFkuwFlH1mshdkZ5JPJERA9JpI6xNCBESvibQ+IURA9JpI6xNCBESvibQ+IURA9DTsuHTOrVFFxixgB/eUFlU8uKJ0eDBFOu/9EvoeKnlJS2/08Tc8NOwQ8sIfMeYFjqKDjdU2sp4AAAAASUVORK5CYII=';
}
}

View File

@@ -0,0 +1,48 @@
<p class="debug-bar-alignRight">
<a href="https://codeigniter4.github.io/CodeIgniter4/index.html" target="_blank" >Read the CodeIgniter docs...</a>
</p>
<table>
<tbody>
<tr>
<td>CodeIgniter Version:</td>
<td>{ ciVersion }</td>
</tr>
<tr>
<td>PHP Version:</td>
<td>{ phpVersion }</td>
</tr>
<tr>
<td>PHP SAPI:</td>
<td>{ phpSAPI }</td>
</tr>
<tr>
<td>Environment:</td>
<td>{ environment }</td>
</tr>
<tr>
<td>Base URL:</td>
<td>
{ if $baseURL == '' }
<div class="warning">
The $baseURL should always be set manually to prevent possible URL personification from external parties.
</div>
{ else }
{ baseURL }
{ endif }
</td>
</tr>
<tr>
<td>TimeZone:</td>
<td>{ timezone }</td>
</tr>
<tr>
<td>Locale:</td>
<td>{ locale }</td>
</tr>
<tr>
<td>Content Security Policy Enabled:</td>
<td>{ if $cspEnabled } Yes { else } No { endif }</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,16 @@
<table>
<thead>
<tr>
<th class="debug-bar-width6r">Time</th>
<th>Query String</th>
</tr>
</thead>
<tbody>
{queries}
<tr>
<td class="narrow">{duration}</td>
<td>{! sql !}</td>
</tr>
{/queries}
</tbody>
</table>

View File

@@ -0,0 +1,18 @@
<table>
<thead>
<tr>
<th class="debug-bar-width6r">Time</th>
<th>Event Name</th>
<th>Times Called</th>
</tr>
</thead>
<tbody>
{events}
<tr>
<td class="narrow">{ duration } ms</td>
<td>{event}</td>
<td>{count}</td>
</tr>
{/events}
</tbody>
</table>

View File

@@ -0,0 +1,16 @@
<table>
<tbody>
{userFiles}
<tr>
<td>{name}</td>
<td>{path}</td>
</tr>
{/userFiles}
{coreFiles}
<tr class="muted">
<td class="debug-bar-width20e">{name}</td>
<td>{path}</td>
</tr>
{/coreFiles}
</tbody>
</table>

View File

@@ -0,0 +1,28 @@
<table>
<thead>
<tr>
<th>Action</th>
<th>Datetime</th>
<th>Status</th>
<th>Method</th>
<th>URL</th>
<th>Content-Type</th>
<th>Is AJAX?</th>
</tr>
</thead>
<tbody>
{files}
<tr data-active="{active}">
<td class="debug-bar-width70p">
<button class="ci-history-load" data-time="{time}">Load</button>
</td>
<td class="debug-bar-width140p">{datetime}</td>
<td>{status}</td>
<td>{method}</td>
<td>{url}</td>
<td>{contentType}</td>
<td>{isAJAX}</td>
</tr>
{/files}
</tbody>
</table>

View File

@@ -0,0 +1,20 @@
{ if $logs == [] }
<p>Nothing was logged. If you were expecting logged items, ensure that LoggerConfig file has the correct threshold set.</p>
{ else }
<table>
<thead>
<tr>
<th>Severity</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{logs}
<tr>
<td>{level}</td>
<td>{msg}</td>
</tr>
{/logs}
</tbody>
</table>
{ endif }

View File

@@ -0,0 +1,44 @@
<h3>Matched Route</h3>
<table>
<tbody>
{matchedRoute}
<tr>
<td>Directory:</td>
<td>{directory}</td>
</tr>
<tr>
<td>Controller:</td>
<td>{controller}</td>
</tr>
<tr>
<td>Method:</td>
<td>{method}</td>
</tr>
<tr>
<td>Params:</td>
<td>{paramCount} / {truePCount}</td>
</tr>
{params}
<tr class="route-params-item">
<td>{name}</td>
<td>{value}</td>
</tr>
{/params}
{/matchedRoute}
</tbody>
</table>
<h3>Defined Routes</h3>
<table>
<tbody>
{routes}
<tr>
<td>{from}</td>
<td>{to}</td>
</tr>
{/routes}
</tbody>
</table>

View File

@@ -0,0 +1,403 @@
#debug-icon {
position: fixed;
bottom: 0;
right: 0;
width: 36px;
height: 36px;
background: #fff;
border: 1px solid #ddd;
margin: 0px;
z-index: 10000;
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
clear: both;
text-align: center;
}
#debug-icon a svg {
margin: 4px;
max-width: 26px;
max-height: 26px;
}
#debug-bar a:active, #debug-bar a:link, #debug-bar a:visited {
color: #dd4814;
}
#debug-bar {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 36px;
background: #fff;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 36px;
z-index: 10000;
}
#debug-bar h1,
#debug-bar h2,
#debug-bar h3 {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #666;
line-height: 1.5;
}
#debug-bar p {
font-size: 12px;
margin: 0 0 10px 20px;
padding: 0;
}
#debug-bar a {
text-decoration: none;
}
#debug-bar a:hover {
text-decoration: underline;
text-decoration-color: #4e4a4a;
}
#debug-bar .muted,
#debug-bar .muted td {
color: #bbb;
}
#debug-bar .toolbar {
display: block;
background: inherit;
overflow: hidden;
overflow-y: auto;
white-space: nowrap;
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
padding: 0 12px 0 12px; /* give room for OS X scrollbar */
z-index: 10000;
}
#debug-bar #toolbar-position > a {
padding: 0 6px;
}
#debug-icon.fixed-top,
#debug-bar.fixed-top {
top: 0;
bottom: auto;
}
#debug-icon.fixed-top,
#debug-bar.fixed-top .toolbar {
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
#debug-bar h1 {
font-size: 16px;
line-height: 36px;
font-weight: 500;
margin: 0 16px 0 0;
padding: 0;
text-align: left;
display: inline-block;
position: absolute;
right: 30px;
top: 0;
bottom: 0;
}
#debug-bar-link {
padding: 6px;
position: absolute;
display: inline-block;
top: 0;
bottom: 0;
right: 10px;
font-size: 16px;
line-height: 36px;
width: 24px;
}
#debug-bar h2 {
font-size: 16px;
font-weight: 500;
margin: 0;
padding: 0;
}
#debug-bar h2 span {
font-size: 13px;
}
#debug-bar h3 {
text-transform: uppercase;
font-size: 11px;
font-weight: 200;
margin-left: 10pt;
}
#debug-bar span.ci-label {
display: inline-block;
font-size: 14px;
line-height: 36px;
vertical-align: baseline;
}
#debug-bar span.ci-label img {
display: inline-block;
margin: 6px 3px 6px 0;
float: left;
clear: left;
}
#debug-bar span.ci-label .badge {
display: inline-block;
padding: 3px 6px;
font-size: 75%;
font-weight: 500;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 10rem;
background-color: #5bc0de;
margin-left: 0.5em;
}
#debug-bar span.ci-label .badge.active {
background-color: red;
}
#debug-bar button {
border: 1px solid #ddd;
background-color: #fff;
cursor: pointer;
border-radius: 4px;
color: #333;
}
#debug-bar button:hover {
background-color: #eaeaea;
}
#debug-bar tr[data-active="1"] {
background-color: #dff0d8;
}
#debug-bar tr[data-active="1"]:hover {
background-color: #a7d499;
}
#debug-bar tr.current {
background-color: #FDC894;
}
#debug-bar tr.current:hover {
background-color: #DD4814;
}
#debug-bar table strong {
font-weight: 500;
color: rgba(0, 0, 0, 0.3);
}
#debug-bar .ci-label {
text-shadow: none;
}
#debug-bar .ci-label:hover {
background-color: #eaeaea;
cursor: pointer;
}
#debug-bar .ci-label a {
display: block;
padding: 0 10px;
color: inherit;
text-decoration: none;
letter-spacing: normal;
}
#debug-bar .ci-label.active {
background-color: #eaeaea;
border-color: #bbb;
}
#debug-bar .tab {
display: none;
background: inherit;
padding: 1em 2em;
border: solid #ddd;
border-width: 1px 0;
position: fixed;
bottom: 35px;
left: 0;
right: 0;
z-index: 9999;
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
overflow-y: auto;
max-height: 62%;
}
#debug-bar.fixed-top .tab {
top: 36px;
bottom: auto;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
#debug-bar table {
margin: 0 0 10px 20px;
font-size: 0.9rem;
border-collapse: collapse;
width: 100%;
}
#debug-bar td,
#debug-bar th {
display: table-cell;
text-align: left;
}
#debug-bar tr {
border: none;
}
#debug-bar td {
border: none;
padding: 0 10px 0 5px;
margin: 0;
}
#debug-bar th {
padding-bottom: 0.7em;
}
#debug-bar tr td:first-child {
max-width: 20%;
}
#debug-bar tr td:first-child.narrow {
width: 7em;
}
#debug-bar tr:hover {
background-color: #f3f3f3;
}
#debug-bar table.timeline {
width: 100%;
margin-left: 0;
}
#debug-bar table.timeline th {
font-size: 0.7em;
font-weight: 200;
text-align: left;
padding-bottom: 1em;
}
#debug-bar table.timeline td,
#debug-bar table.timeline th {
border-left: 1px solid #ddd;
padding: 0 1em;
position: relative;
}
#debug-bar table.timeline tr td:first-child,
#debug-bar table.timeline tr th:first-child {
border-left: 0;
padding-left: 0;
}
#debug-bar table.timeline td {
padding: 5px;
}
#debug-bar table.timeline .timer {
position: absolute;
display: inline-block;
padding: 5px;
top: 40%;
border-radius: 4px;
background-color: #999;
}
#debug-bar .route-params,
#debug-bar .route-params-item {
vertical-align: top;
}
#debug-bar .route-params-item td:first-child {
padding-left: 1em;
text-align: right;
font-style: italic;
}
.debug-view.show-view {
border: 1px solid #dd4814;
margin: 4px;
}
.debug-view-path {
background-color: #fdc894;
color: #000;
padding: 2px;
font-family: monospace;
font-size: 11px;
min-height: 16px;
text-align: left;
}
.show-view .debug-view-path {
display: block !important;
}
@media screen and (max-width: 748px) {
.hide-sm {
display: none !important;
}
}
/**
simple styles to replace inline styles
*/
.debug-bar-width30 {
width: 30%;
}
.debug-bar-width10 {
width: 10%;
}
.debug-bar-width70p {
width: 70px;
}
.debug-bar-width140p {
width: 140px;
}
.debug-bar-width20e {
width: 20em;
}
.debug-bar-width6r {
width: 6rem;
}
.debug-bar-ndisplay {
display: none;
}
.debug-bar-alignRight {
text-align: right;
}
.debug-bar-alignLeft {
text-align: left;
}
.debug-bar-noverflow {
overflow: hidden;
}

View File

@@ -0,0 +1,551 @@
/*
* Functionality for the CodeIgniter Debug Toolbar.
*/
var ciDebugBar = {
toolbar : null,
icon : null,
//--------------------------------------------------------------------
init : function () {
this.toolbar = document.getElementById('debug-bar');
this.icon = document.getElementById('debug-icon');
ciDebugBar.createListeners();
ciDebugBar.setToolbarState();
ciDebugBar.setToolbarPosition();
ciDebugBar.toggleViewsHints();
document.getElementById('debug-bar-link').addEventListener('click', ciDebugBar.toggleToolbar, true);
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') + '"]');
ciDebugBar.addClass(btn.parentNode.parentNode, 'current');
historyLoad = document.getElementsByClassName('ci-history-load');
for (var i = 0; i < historyLoad.length; i++)
{
historyLoad[i].addEventListener('click', function () {
loadDoc(this.getAttribute('data-time'));
}, true);
}
// Display the active Tab on page load
var tab = ciDebugBar.readCookie('debug-bar-tab');
if (document.getElementById(tab))
{
var el = document.getElementById(tab);
el.style.display = 'block';
ciDebugBar.addClass(el, 'active');
tab = document.querySelector('[data-tab=' + tab + ']');
if (tab)
{
ciDebugBar.addClass(tab.parentNode, 'active');
}
}
},
//--------------------------------------------------------------------
createListeners : function () {
var buttons = [].slice.call(document.querySelectorAll('#debug-bar .ci-label a'));
for (var i = 0; i < buttons.length; i++)
{
buttons[i].addEventListener('click', ciDebugBar.showTab, true);
}
},
//--------------------------------------------------------------------
showTab: function () {
// Get the target tab, if any
var tab = document.getElementById(this.getAttribute('data-tab'));
// If the label have not a tab stops here
if (! tab)
{
return;
}
// Remove debug-bar-tab cookie
ciDebugBar.createCookie('debug-bar-tab', '', -1);
// Check our current state.
var state = tab.style.display;
// Hide all tabs
var tabs = document.querySelectorAll('#debug-bar .tab');
for (var i = 0; i < tabs.length; i++)
{
tabs[i].style.display = 'none';
}
// Mark all labels as inactive
var labels = document.querySelectorAll('#debug-bar .ci-label');
for (var i = 0; i < labels.length; i++)
{
ciDebugBar.removeClass(labels[i], 'active');
}
// Show/hide the selected tab
if (state != 'block')
{
tab.style.display = 'block';
ciDebugBar.addClass(this.parentNode, 'active');
// Create debug-bar-tab cookie to persistent state
ciDebugBar.createCookie('debug-bar-tab', this.getAttribute('data-tab'), 365);
}
},
//--------------------------------------------------------------------
addClass : function (el, className) {
if (el.classList)
{
el.classList.add(className);
}
else
{
el.className += ' ' + className;
}
},
//--------------------------------------------------------------------
removeClass : function (el, className) {
if (el.classList)
{
el.classList.remove(className);
}
else
{
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
},
//--------------------------------------------------------------------
/**
* Toggle display of a data table
*
* @param obj
*/
toggleDataTable : function (obj) {
if (typeof obj == 'string')
{
obj = document.getElementById(obj + '_table');
}
if (obj)
{
obj.style.display = obj.style.display == 'none' ? 'block' : 'none';
}
},
//--------------------------------------------------------------------
/**
* Toggle tool bar from full to icon and icon to full
*/
toggleToolbar : function () {
var open = ciDebugBar.toolbar.style.display != 'none';
ciDebugBar.icon.style.display = open == true ? 'inline-block' : 'none';
ciDebugBar.toolbar.style.display = open == false ? 'inline-block' : 'none';
// Remember it for other page loads on this site
ciDebugBar.createCookie('debug-bar-state', '', -1);
ciDebugBar.createCookie('debug-bar-state', open == true ? 'minimized' : 'open' , 365);
},
//--------------------------------------------------------------------
/**
* Sets the initial state of the toolbar (open or minimized) when
* the page is first loaded to allow it to remember the state between refreshes.
*/
setToolbarState: function () {
var open = ciDebugBar.readCookie('debug-bar-state');
ciDebugBar.icon.style.display = open != 'open' ? 'inline-block' : 'none';
ciDebugBar.toolbar.style.display = open == 'open' ? 'inline-block' : 'none';
},
//--------------------------------------------------------------------
toggleViewsHints: function () {
// Avoid toggle hints on history requests that are not the initial
if (localStorage.getItem('debugbar-time') != localStorage.getItem('debugbar-time-new'))
{
var a = document.querySelector('a[data-tab="ci-views"]');
a.href = '#';
return;
}
var nodeList = []; // [ Element, NewElement( 1 )/OldElement( 0 ) ]
var sortedComments = [];
var comments = [];
var getComments = function () {
var nodes = [];
var result = [];
var xpathResults = document.evaluate( "//comment()[starts-with(., ' DEBUG-VIEW')]", document, null, XPathResult.ANY_TYPE, null);
var nextNode = xpathResults.iterateNext();
while ( nextNode )
{
nodes.push( nextNode );
nextNode = xpathResults.iterateNext();
}
// sort comment by opening and closing tags
for (var i = 0; i < nodes.length; ++i)
{
// get file path + name to use as key
var path = nodes[i].nodeValue.substring( 18, nodes[i].nodeValue.length - 1 );
if ( nodes[i].nodeValue[12] === 'S' ) // simple check for start comment
{
// create new entry
result[path] = [ nodes[i], null ];
}
else if (result[path])
{
// add to existing entry
result[path][1] = nodes[i];
}
}
return result;
};
// find node that has TargetNode as parentNode
var getParentNode = function ( node, targetNode ) {
if ( node.parentNode === null )
{
return null;
}
if ( node.parentNode !== targetNode )
{
return getParentNode( node.parentNode, targetNode );
}
return node;
};
// define invalid & outer ( also invalid ) elements
const INVALID_ELEMENTS = [ 'NOSCRIPT', 'SCRIPT', 'STYLE' ];
const OUTER_ELEMENTS = [ 'HTML', 'BODY', 'HEAD' ];
var getValidElementInner = function ( node, reverse ) {
// handle invalid tags
if ( OUTER_ELEMENTS.indexOf( node.nodeName ) !== -1 )
{
for (var i = 0; i < document.body.children.length; ++i)
{
var index = reverse ? document.body.children.length - ( i + 1 ) : i;
var element = document.body.children[index];
// skip invalid tags
if ( INVALID_ELEMENTS.indexOf( element.nodeName ) !== -1 )
{
continue;
}
return [ element, reverse ];
}
return null;
}
// get to next valid element
while ( node !== null && INVALID_ELEMENTS.indexOf( node.nodeName ) !== -1 )
{
node = reverse ? node.previousElementSibling : node.nextElementSibling;
}
// return non array if we couldnt find something
if ( node === null )
{
return null;
}
return [ node, reverse ];
};
// get next valid element ( to be safe to add divs )
// @return [ element, skip element ] or null if we couldnt find a valid place
var getValidElement = function ( nodeElement ) {
if (nodeElement)
{
if ( nodeElement.nextElementSibling !== null )
{
return getValidElementInner( nodeElement.nextElementSibling, false )
|| getValidElementInner( nodeElement.previousElementSibling, true );
}
if ( nodeElement.previousElementSibling !== null )
{
return getValidElementInner( nodeElement.previousElementSibling, true );
}
}
// something went wrong! -> element is not in DOM
return null;
};
function showHints()
{
// Had AJAX? Reset view blocks
sortedComments = getComments();
for (var key in sortedComments)
{
var startElement = getValidElement( sortedComments[key][0] );
var endElement = getValidElement( sortedComments[key][1] );
// skip if we couldnt get a valid element
if ( startElement === null || endElement === null )
{
continue;
}
// find element which has same parent as startelement
var jointParent = getParentNode( endElement[0], startElement[0].parentNode );
if ( jointParent === null )
{
// find element which has same parent as endelement
jointParent = getParentNode( startElement[0], endElement[0].parentNode );
if ( jointParent === null )
{
// both tries failed
continue;
}
else
{
startElement[0] = jointParent;
}
}
else
{
endElement[0] = jointParent;
}
var debugDiv = document.createElement( 'div' ); // holder
var debugPath = document.createElement( 'div' ); // path
var childArray = startElement[0].parentNode.childNodes; // target child array
var parent = startElement[0].parentNode;
var start, end;
// setup container
debugDiv.classList.add( 'debug-view' );
debugDiv.classList.add( 'show-view' );
debugPath.classList.add( 'debug-view-path' );
debugPath.innerText = key;
debugDiv.appendChild( debugPath );
// calc distance between them
// start
for (var i = 0; i < childArray.length; ++i)
{
// check for comment ( start & end ) -> if its before valid start element
if ( childArray[i] === sortedComments[key][1] ||
childArray[i] === sortedComments[key][0] ||
childArray[i] === startElement[0] )
{
start = i;
if ( childArray[i] === sortedComments[key][0] )
{
start++; // increase to skip the start comment
}
break;
}
}
// adjust if we want to skip the start element
if ( startElement[1] )
{
start++;
}
// end
for (var i = start; i < childArray.length; ++i)
{
if ( childArray[i] === endElement[0] )
{
end = i;
// dont break to check for end comment after end valid element
}
else if ( childArray[i] === sortedComments[key][1] )
{
// if we found the end comment, we can break
end = i;
break;
}
}
// move elements
var number = end - start;
if ( endElement[1] )
{
number++;
}
for (var i = 0; i < number; ++i)
{
if ( INVALID_ELEMENTS.indexOf( childArray[start] ) !== -1 )
{
// skip invalid childs that can cause problems if moved
start++;
continue;
}
debugDiv.appendChild( childArray[start] );
}
// add container to DOM
nodeList.push( parent.insertBefore( debugDiv, childArray[start] ) );
}
ciDebugBar.createCookie('debug-view', 'show', 365);
ciDebugBar.addClass(btn, 'active');
}
function hideHints()
{
for (var i = 0; i < nodeList.length; ++i)
{
var index;
// find index
for (var j = 0; j < nodeList[i].parentNode.childNodes.length; ++j)
{
if ( nodeList[i].parentNode.childNodes[j] === nodeList[i] )
{
index = j;
break;
}
}
// move child back
while ( nodeList[i].childNodes.length !== 1 )
{
nodeList[i].parentNode.insertBefore( nodeList[i].childNodes[1], nodeList[i].parentNode.childNodes[index].nextSibling );
index++;
}
nodeList[i].parentNode.removeChild( nodeList[i] );
}
nodeList.length = 0;
ciDebugBar.createCookie('debug-view', '', -1);
ciDebugBar.removeClass(btn, 'active');
}
var btn = document.querySelector('[data-tab=ci-views]');
// If the Views Collector is inactive stops here
if (! btn)
{
return;
}
btn.parentNode.onclick = function () {
if (ciDebugBar.readCookie('debug-view'))
{
hideHints();
}
else
{
showHints();
}
};
// Determine Hints state on page load
if (ciDebugBar.readCookie('debug-view'))
{
showHints();
}
},
//--------------------------------------------------------------------
setToolbarPosition: function () {
var btnPosition = document.getElementById('toolbar-position');
if (ciDebugBar.readCookie('debug-bar-position') === 'top')
{
ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top');
ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top');
}
btnPosition.addEventListener('click', function () {
var position = ciDebugBar.readCookie('debug-bar-position');
ciDebugBar.createCookie('debug-bar-position', '', -1);
if (!position || position === 'bottom')
{
ciDebugBar.createCookie('debug-bar-position', 'top', 365);
ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top');
ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top');
}
else
{
ciDebugBar.createCookie('debug-bar-position', 'bottom', 365);
ciDebugBar.removeClass(ciDebugBar.icon, 'fixed-top');
ciDebugBar.removeClass(ciDebugBar.toolbar, 'fixed-top');
}
}, true);
},
//--------------------------------------------------------------------
/**
* Helper to create a cookie.
*
* @param name
* @param value
* @param days
*/
createCookie : function (name,value,days) {
if (days)
{
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toGMTString();
}
else
{
var expires = "";
}
document.cookie = name + "=" + value + expires + "; path=/";
},
//--------------------------------------------------------------------
readCookie : function (name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++)
{
var c = ca[i];
while (c.charAt(0) == ' ')
{
c = c.substring(1,c.length);
}
if (c.indexOf(nameEQ) == 0)
{
return c.substring(nameEQ.length,c.length);
}
}
return null;
}
};

View File

@@ -0,0 +1,306 @@
<?php
/**
* @var \CodeIgniter\Debug\Toolbar $this
* @var int $totalTime
* @var int $totalMemory
* @var string $url
* @var string $method
* @var bool $isAJAX
* @var int $startTime
* @var int $totalTime
* @var int $totalMemory
* @var float $segmentDuration
* @var int $segmentCount
* @var string $CI_VERSION
* @var array $collectors
* @var array $vars
* @var array $styles
* @var \CodeIgniter\View\Parser $parser
*/
?>
<style type="text/css">
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . '/toolbar.css')) ?>
</style>
<script id="toolbar_js" type="text/javascript">
<?= file_get_contents(__DIR__ . '/toolbar.js') ?>
</script>
<div id="debug-icon" class="debug-bar-ndisplay">
<a id="debug-icon-link" href="javascript:void(0)">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="155.000000px" height="200.000000px" viewBox="0 0 155.000000 200.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)" fill="#dd4814" stroke="none">
<path d="M737 1963 c22 -79 -7 -185 -78 -290 -18 -26 -107 -122 -197 -213
-239 -240 -336 -371 -403 -544 -79 -206 -78 -408 5 -582 64 -134 212 -264 361
-314 l60 -20 -30 22 c-210 152 -229 387 -48 588 25 27 48 50 51 50 4 0 7 -27
7 -61 0 -57 2 -62 37 -95 30 -27 46 -34 78 -34 56 0 99 24 116 65 29 69 16
120 -50 205 -105 134 -117 233 -43 347 l31 48 7 -47 c13 -82 58 -129 250 -258
209 -141 306 -261 328 -405 11 -72 -1 -161 -31 -218 -27 -53 -112 -143 -165
-174 -24 -14 -43 -26 -43 -28 0 -2 24 4 53 14 241 83 427 271 482 486 19 76
19 202 -1 285 -35 152 -146 305 -299 412 l-70 49 -6 -33 c-8 -48 -26 -76 -59
-93 -45 -23 -103 -19 -138 10 -67 57 -78 146 -37 305 30 116 32 206 5 291 -27
89 -104 206 -162 247 -17 13 -18 12 -11 -15z"/>
</g>
</svg>
</a>
</div>
<div id="debug-bar">
<div class="toolbar">
<span id="toolbar-position"><a href="javascript: void(0)">&#8597;</a></span>
<span class="ci-label">
<a href="javascript: void(0)" data-tab="ci-timeline">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAD7SURBVEhLY6ArSEtLK09NTbWHcvGC9PR0BaDaQiAdUl9fzwQVxg+AFvwHamqHcnGCpKQkeaDa9yD1UD09UCn8AKaBWJySkmIApFehi0ONwwRQBceBLurAh4FqFoHUAtkrgPgREN+ByYEw1DhMANVEMIhAYQ5U1wtU/wmILwLZRlAp/IBYC8gGw88CaFj3A/FnIL4ETDXGUCnyANSC/UC6HIpnQMXAqQXIvo0khxNDjcMEQEmU9AzDuNI7Lgw1DhOAJIEuhQcRKMcC+e+QNHdDpcgD6BaAANSSQqBcENFlDi6AzQKqgkFlwWhxjVI8o2OgmkFaXI8CTMDAAAAxd1O4FzLMaAAAAABJRU5ErkJggg==">
<span class="hide-sm"><?= $totalTime ?> ms &nbsp; <?= $totalMemory ?> MB</span>
</a>
</span>
<?php foreach ($collectors as $c) : ?>
<?php if (! $c['isEmpty'] && ($c['hasTabContent'] || $c['hasLabel'])) : ?>
<span class="ci-label">
<a href="javascript: void(0)" data-tab="ci-<?= $c['titleSafe'] ?>">
<img src="<?= $c['icon'] ?>">
<span class="hide-sm">
<?= $c['title'] ?>
<?php if (! is_null($c['badgeValue'])) : ?>
<span class="badge"><?= $c['badgeValue'] ?></span>
<?php endif ?>
</span>
</a>
</span>
<?php endif ?>
<?php endforeach ?>
<span class="ci-label">
<a href="javascript: void(0)" data-tab="ci-vars">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACLSURBVEhLYxgFJIHU1NSraWlp/6H4T0pKSjRUijoAyXAwBlrYDpViAFpmARQrJwZDtWACoCROC4D8CnR5XBiqBRMADfyNprgRKkUdAApzoCUdUNwE5MtApYYIALp6NBWBMVQLJgAaOJqK8AOgq+mSio6DggjEBtLUT0UwQ5HZIADkj6aiUTAggIEBANAEDa/lkCRlAAAAAElFTkSuQmCC">
<span class="hide-sm">Vars</span>
</a>
</span>
<h1>
<span class="ci-label">
<a href="javascript: void(0)" data-tab="ci-config">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="18.60px" height="24.0px" viewBox="0 0 18.60 28.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,28.000000) scale(0.010000,-0.010000)" fill="#dd4814" stroke="none">
<path d="M737 1963 c22 -79 -7 -185 -78 -290 -18 -26 -107 -122 -197 -213
-239 -240 -336 -371 -403 -544 -79 -206 -78 -408 5 -582 64 -134 212 -264 361
-314 l60 -20 -30 22 c-210 152 -229 387 -48 588 25 27 48 50 51 50 4 0 7 -27
7 -61 0 -57 2 -62 37 -95 30 -27 46 -34 78 -34 56 0 99 24 116 65 29 69 16
120 -50 205 -105 134 -117 233 -43 347 l31 48 7 -47 c13 -82 58 -129 250 -258
209 -141 306 -261 328 -405 11 -72 -1 -161 -31 -218 -27 -53 -112 -143 -165
-174 -24 -14 -43 -26 -43 -28 0 -2 24 4 53 14 241 83 427 271 482 486 19 76
19 202 -1 285 -35 152 -146 305 -299 412 l-70 49 -6 -33 c-8 -48 -26 -76 -59
-93 -45 -23 -103 -19 -138 10 -67 57 -78 146 -37 305 30 116 32 206 5 291 -27
89 -104 206 -162 247 -17 13 -18 12 -11 -15z"/>
</g>
</svg>
<?= $CI_VERSION ?>
</a>
</span>
</h1>
<!-- Open/Close Toggle -->
<a id="debug-bar-link" href="javascript:void(0)" title="Open/Close">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEPSURBVEhL7ZVLDoJAEEThRuoGDwSEG+jCuFU34s3AK3APP1VDDSGMqI1xx0s6M/2rnlHEaMZElmWrPM+vsDvsYbQ7+us0TReSC2EBrEHxCevRYuppYLXkQpC8sVCuGfTvqSE3hFdFwUGuGfRvqSE35NUAfKZrbQNQm2jrMA+gOK+M+FmhDsRL5voHMA8gFGecq0JOXLWlQg7E7AMIxZnjOiZOEJ82gFCcedUE4gS56QP8yf8ywItz7e+RituKlkkDBoIOH4Nd4HZD4NsGYJ/Abn1xEVOcuZ8f0zc/tHiYmzTAwscBvDIK/veyQ9K/rnewjdF26q0kF1IUxZIFPAVW98x/a+qp8L2M/+HMhETRE6S8TxpZ7KGXAAAAAElFTkSuQmCC">
</a>
</div>
<!-- Timeline -->
<div id="ci-timeline" class="tab">
<table class="timeline">
<thead>
<tr>
<th class="debug-bar-width30">NAME</th>
<th class="debug-bar-width10">COMPONENT</th>
<th class="debug-bar-width10">DURATION</th>
<?php for ($i = 0; $i < $segmentCount; $i++) : ?>
<th><?= $i * $segmentDuration ?> ms</th>
<?php endfor ?>
</tr>
</thead>
<tbody>
<?= $this->renderTimeline($collectors, $startTime, $segmentCount, $segmentDuration,
$styles) ?>
</tbody>
</table>
</div>
<!-- Collector-provided Tabs -->
<?php foreach ($collectors as $c) : ?>
<?php if (! $c['isEmpty']) : ?>
<?php if ($c['hasTabContent']) : ?>
<div id="ci-<?= $c['titleSafe'] ?>" class="tab">
<h2><?= $c['title'] ?> <span><?= $c['titleDetails'] ?></span></h2>
<?= is_string($c['display']) ? $c['display'] : $parser->setData($c['display'])->render("_{$c['titleSafe']}.tpl") ?>
</div>
<?php endif ?>
<?php endif ?>
<?php endforeach ?>
<!-- In & Out -->
<div id="ci-vars" class="tab">
<!-- VarData from Collectors -->
<?php if (isset($vars['varData'])) : ?>
<?php foreach ($vars['varData'] as $heading => $items) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('<?= strtolower(str_replace(' ',
'-', $heading)) ?>'); return false;">
<h2><?= $heading ?></h2>
</a>
<?php if (is_array($items)) : ?>
<table id="<?= strtolower(str_replace(' ', '-', $heading . '_table')) ?>">
<tbody>
<?php foreach ($items as $key => $value) : ?>
<tr>
<td><?= $key ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php else: ?>
<p class="muted">No data to display.</p>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>
<!-- Session -->
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('session'); return false;">
<h2>Session User Data</h2>
</a>
<?php if (isset($vars['session'])) : ?>
<?php if (! empty($vars['session'])) : ?>
<table id="session_table">
<tbody>
<?php foreach ($vars['session'] as $key => $value) : ?>
<tr>
<td><?= $key ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php else : ?>
<p class="muted">No data to display.</p>
<?php endif ?>
<?php else : ?>
<p class="muted">Session doesn't seem to be active.</p>
<?php endif ?>
<h2>Request <span>( <?= $vars['request'] ?> )</span></h2>
<?php if (isset($vars['get']) && $get = $vars['get']) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('get'); return false;">
<h3>$_GET</h3>
</a>
<table id="get_table">
<tbody>
<?php foreach ($get as $name => $value) : ?>
<tr>
<td><?= $name ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
<?php if (isset($vars['post']) && $post = $vars['post']) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('post'); return false;">
<h3>$_POST</h3>
</a>
<table id="post_table">
<tbody>
<?php foreach ($post as $name => $value) : ?>
<tr>
<td><?= $name ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
<?php if (isset($vars['headers']) && $headers = $vars['headers']) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('request_headers'); return false;">
<h3>Headers</h3>
</a>
<table id="request_headers_table">
<tbody>
<?php foreach ($headers as $header => $value) : ?>
<tr>
<td><?= $header ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
<?php if (isset($vars['cookies']) && $cookies = $vars['cookies']) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('cookie'); return false;">
<h3>Cookies</h3>
</a>
<table id="cookie_table">
<tbody>
<?php foreach ($cookies as $name => $value) : ?>
<tr>
<td><?= $name ?></td>
<td><?= is_array($value) ? print_r($value, true) : $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
<h2>Response
<span>( <?= $vars['response']['statusCode'] . ' - ' . $vars['response']['reason'] ?> )</span>
</h2>
<?php if (isset($vars['headers']) && $headers = $vars['headers']) : ?>
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('response_headers'); return false;">
<h3>Headers</h3>
</a>
<table id="response_headers_table">
<tbody>
<?php foreach ($headers as $header => $value) : ?>
<tr>
<td><?= $header ?></td>
<td><?= $value ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php endif ?>
</div>
<!-- Config Values -->
<div id="ci-config" class="tab">
<h2>System Configuration</h2>
<?= $parser->setData($config)->render('_config.tpl') ?>
</div>
</div>
<style type="text/css">
<?php foreach($styles as $name => $style) : ?>
.<?= $name ?> {
<?= $style ?>
}
<?php endforeach ?>
</style>

View File

@@ -0,0 +1,88 @@
<?php if (ENVIRONMENT !== 'testing') : ?>
document.addEventListener('DOMContentLoaded', loadDoc, false);
function loadDoc(time) {
if (isNaN(time)) {
time = document.getElementById("debugbar_loader").getAttribute("data-time");
localStorage.setItem('debugbar-time', time);
}
localStorage.setItem('debugbar-time-new', time);
var url = "<?= rtrim(site_url(), '/') ?>";
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
var toolbar = document.getElementById("toolbarContainer");
if (!toolbar) {
toolbar = document.createElement('div');
toolbar.setAttribute('id', 'toolbarContainer');
document.body.appendChild(toolbar);
}
// copy for easier manipulation
let responseText = this.responseText;
// get csp blocked parts
// the style block is the first and starts at 0
{
let PosBeg = responseText.indexOf( '>', responseText.indexOf( '<style' ) ) + 1;
let PosEnd = responseText.indexOf( '</style>', PosBeg );
document.getElementById( 'debugbar_dynamic_style' ).innerHTML = responseText.substr( PosBeg, PosEnd - PosBeg );
responseText = responseText.substr( PosEnd + 8 );
}
// the script block starts right after style blocks ended
{
let PosBeg = responseText.indexOf( '>', responseText.indexOf( '<script' ) ) + 1;
let PosEnd = responseText.indexOf( '</script>' );
document.getElementById( 'debugbar_dynamic_script' ).innerHTML = responseText.substr( PosBeg, PosEnd - PosBeg );
responseText = responseText.substr( PosEnd + 9 );
}
// check for last style block
{
let PosBeg = responseText.indexOf( '>', responseText.lastIndexOf( '<style' ) ) + 1;
let PosEnd = responseText.indexOf( '</style>', PosBeg );
document.getElementById( 'debugbar_dynamic_style' ).innerHTML += responseText.substr( PosBeg, PosEnd - PosBeg );
responseText = responseText.substr( 0, PosBeg + 8 );
}
toolbar.innerHTML = responseText;
if (typeof ciDebugBar === 'object') {
ciDebugBar.init();
}
} else if (this.readyState === 4 && this.status === 404) {
console.log('CodeIgniter DebugBar: File "WRITEPATH/debugbar/debugbar_' + time + '" not found.');
}
};
xhttp.open("GET", url + "/?debugbar_time=" + time, true);
xhttp.send();
}
// Track all AJAX requests
if (window.ActiveXObject) {
var oldXHR = new ActiveXObject('Microsoft.XMLHTTP');
} else {
var oldXHR = window.XMLHttpRequest;
}
function newXHR() {
var realXHR = new oldXHR();
realXHR.addEventListener("readystatechange", function() {
// Only success responses and URLs that do not contains "debugbar_time" are tracked
if (realXHR.readyState === 4 && realXHR.status.toString()[0] === '2' && realXHR.responseURL.indexOf('debugbar_time') === -1) {
var debugbarTime = realXHR.getResponseHeader('Debugbar-Time');
if (debugbarTime) {
var h2 = document.querySelector('#ci-history > h2');
h2.innerHTML = 'History <small>You have new debug data.</small> <button onclick="loadDoc(' + debugbarTime + ')">Update</button>';
var badge = document.querySelector('a[data-tab="ci-history"] > span > .badge');
badge.className += ' active';
}
}
}, false);
return realXHR;
}
window.XMLHttpRequest = newXHR;
<?php endif; ?>