diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 135bd52b3fe9..975c611a61c3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,7 +13,8 @@ body: whether still open or closed, related to your report**. If there is, your report will be closed promptly. - And if you are not using the [latest version](https://github.com/codeigniter4/CodeIgniter4/releases) of CodeIgniter, please update. + For example, if you get the error "*Undefined property: Config\\Exceptions::$sensitiveDataInTrace*", + you can search the GitHub repository with the keyword "[$sensitiveDataInTrace](https://github.com/codeigniter4/CodeIgniter4/search?q=%24sensitiveDataInTrace&type=issues)". --- @@ -35,6 +36,23 @@ body: id: codeigniter-version attributes: label: CodeIgniter4 Version + description: | + e.g. 4.1.5 + If you are not using the [latest version](https://github.com/codeigniter4/CodeIgniter4/releases), please + check to see if the problem occurs with the latest version. + validations: + required: true + + - type: dropdown + id: codeigniter-installation + attributes: + label: CodeIgniter4 Installation Method + multiple: false + options: + - Composer (using `codeigniter4/appstarter`) + - Composer (as dependency to an existing project) + - Manual (zip or tar.gz) + - Git validations: required: true @@ -69,6 +87,7 @@ body: id: database attributes: label: Database + description: e.g. MySQL 5.6, MariaDB 10.2, PostgreSQL 9.6 validations: required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 69bb11b44fe8..9bec3b2d3431 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ blank_issues_enabled: false contact_links: - name: CodeIgniter Forum - url: https://forum.codeigniter.com + url: https://forum.codeigniter.com/forum-30.html about: Please ask your support questions in the forums. Thanks! - name: CodeIgniter Slack channel diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 000000000000..de6e982d91a6 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + exclude: + authors: + - dependabot + categories: + - title: Breaking Changes + labels: + - 'breaking change' + - title: Fixed Bugs + labels: + - bug + - title: New Features + labels: + - 'new feature' + - title: Enhancements + labels: + - enhancement + - title: Refactoring + labels: + - refactor + - title: Others (Only for checking. Remove this category) + labels: + - "*" diff --git a/.github/scripts/deploy-framework b/.github/scripts/deploy-framework index c3f7e39fa1b7..9396ed88aa04 100644 --- a/.github/scripts/deploy-framework +++ b/.github/scripts/deploy-framework @@ -28,6 +28,8 @@ done # Copy repo-specific files cp -Rf ${SOURCE}/admin/framework/. ./ +# Copy tests files +cp -Rf ${SOURCE}/admin/starter/tests/. ./tests/ # Commit the changes git add . diff --git a/.github/workflows/deploy-framework.yml b/.github/workflows/deploy-framework.yml index 5a65f3bd1cfc..cdd23f3c7242 100644 --- a/.github/workflows/deploy-framework.yml +++ b/.github/workflows/deploy-framework.yml @@ -40,11 +40,11 @@ jobs: with: github-token: ${{secrets.ACCESS_TOKEN}} script: | - const release = await github.repos.getLatestRelease({ + const release = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }) - github.repos.createRelease({ + github.rest.repos.createRelease({ owner: context.repo.owner, repo: 'framework', tag_name: release.data.tag_name, @@ -85,11 +85,11 @@ jobs: with: github-token: ${{secrets.ACCESS_TOKEN}} script: | - const release = await github.repos.getLatestRelease({ + const release = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }) - github.repos.createRelease({ + github.rest.repos.createRelease({ owner: context.repo.owner, repo: 'appstarter', tag_name: release.data.tag_name, diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index 0e59e3bf4e3a..eceb97524605 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.4', '8.0'] + php-versions: ['8.0', '8.1'] steps: - name: Checkout uses: actions/checkout@v2 diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index aa7d584991a6..61133437d3e8 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -4,12 +4,7 @@ on: push: branches: - develop - - '4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' - - 'tests/**' - composer.json - spark - phpunit.xml.dist @@ -18,12 +13,7 @@ on: pull_request: branches: - develop - - '4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' - - 'tests/**' - composer.json - spark - phpunit.xml.dist @@ -31,22 +21,24 @@ on: - .github/workflows/test-phpunit.yml jobs: - tests: + name: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} runs-on: ubuntu-20.04 if: "!contains(github.event.head_commit.message, '[ci skip]')" - name: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] db-platforms: ['MySQLi', 'Postgre', 'SQLite3', 'SQLSRV'] mysql-versions: ['5.7'] include: - php-versions: '7.4' db-platforms: MySQLi mysql-versions: '8.0' + # @todo remove once 8.1 is stable enough + - php-versions: '8.1' + composer-flag: '--ignore-platform-req=php' services: mysql: @@ -57,6 +49,7 @@ jobs: ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + postgres: image: postgres env: @@ -66,6 +59,7 @@ jobs: ports: - 5432:5432 options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3 + mssql: image: mcr.microsoft.com/mssql/server:2019-CU10-ubuntu-20.04 env: @@ -75,11 +69,13 @@ jobs: ports: - 1433:1433 options: --health-cmd="/opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q 'SELECT @@VERSION'" --health-interval=10s --health-timeout=5s --health-retries=3 + redis: image: redis ports: - 6379:6379 options: --health-cmd "redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + memcached: image: memcached:1.6-alpine ports: @@ -105,6 +101,7 @@ jobs: - name: Install latest ImageMagick run: | + sudo apt-get update sudo apt-get install --reinstall libgs9-common fonts-noto-mono libgs9:amd64 libijs-0.35:amd64 fonts-urw-base35 ghostscript poppler-data libjbig2dec0:amd64 gsfonts libopenjp2-7:amd64 fonts-droid-fallback ttf-dejavu-core sudo apt-get install -y imagemagick sudo apt-get install --fix-broken @@ -122,13 +119,13 @@ jobs: - name: Install dependencies run: | - composer update --ansi --no-interaction - composer remove --ansi --dev --unused -W rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard + composer update --ansi --no-interaction ${{ matrix.composer-flag }} + composer remove --ansi --dev --unused -W ${{ matrix.composer-flag }} -- rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard env: COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} - - name: Profile slow tests in PHP 7.4 MySQLi for now - if: matrix.php-versions == '7.4' && matrix.db-platforms == 'MySQLi' + - name: Profile slow tests in PHP 8.0 + if: matrix.php-versions == '8.0' run: echo "TACHYCARDIA_MONITOR_GA=enabled" >> $GITHUB_ENV - name: Test with PHPUnit @@ -137,10 +134,10 @@ jobs: DB: ${{ matrix.db-platforms }} TERM: xterm-256color - - if: github.repository_owner == 'codeigniter4' && matrix.php-versions == '7.4' - name: Run Coveralls + - name: Run Coveralls + if: github.repository_owner == 'codeigniter4' && matrix.php-versions == '8.0' run: | - composer global require --ansi php-coveralls/php-coveralls:^2.4 + composer global require --ansi php-coveralls/php-coveralls:^2.4 symfony/console:^5 php-coveralls --coverage_clover=build/logs/clover.xml -v env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -151,6 +148,7 @@ jobs: if: github.repository_owner == 'codeigniter4' needs: [tests] runs-on: ubuntu-20.04 + steps: - name: Coveralls Finished uses: coverallsapp/github-action@master diff --git a/CHANGELOG.md b/CHANGELOG.md index 74513d243589..c2ea5e536da0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,183 @@ # Changelog +## [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) + +**Breaking Changes** + +* fix: Incorrect type `BaseBuilder::$tableName` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5378 +* fix: Validation cannot handle array item by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5405 + +**Fixed Bugs** + +* fix: FileLocator cannot find files in sub-namespaces of the same vendor by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5292 +* fix: add a workaround for upgraded users who do not update Config\Exceptions by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5314 +* Fix db escape negative integers by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5277 +* Fix: remove incorrect processing of CLI params by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5274 +* fix: table alias is prefixed when LIKE clause by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5361 +* fix: `dot_array_search()` unexpected array structure causes Type Error by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5372 +* fix: UploadedFile::move() may return incorrect value by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5302 +* fix: BaseModel::insert() may not pass all the values from Entity by @katie1348 in https://github.com/codeigniter4/CodeIgniter4/pull/4980 +* fix: `IncomingRequest::getJsonVar()` may cause TypeError by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5392 +* chore: fix example test code for appstarter and module by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5421 +* fix: Model::save() may call unneeded countAllResults() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5439 +* fix: errors when MariaDB/MySQL has `ANSI_QUOTES` enabled by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5425 +* fix: Security class sends cookies immediately by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5429 +* fix: `is_cli()` returns `true` when `$_SERVER['HTTP_USER_AGENT']` is missing by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5393 +* fix: `MySQLi\Connection::_foreignKeyData()` may return duplicated rows by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5416 +* fix: `number_to_currency()` error on PHP 8.1 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5454 +* fix: VENDORPATH definition by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5453 +* fix: Throttler does not show correct token time by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5470 +* fix: directory_mirror() throws an error if destination directory exists by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5493 +* fix: KINT visual error when activating CSP by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5501 + +**New Features** + +* feat: add filter to check invalid chars in user input by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5227 + +**Enhancements** + +* Add support for PHP 8.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4883 +* Toolbar - Make it possible to turn off var data collection by @najdanovicivan in https://github.com/codeigniter4/CodeIgniter4/pull/5295 +* feat: add CSRF token randomization by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5283 +* Display file:line and trace information to database queries in debug toolbar by @lonnieezell in https://github.com/codeigniter4/CodeIgniter4/pull/5334 +* feat: add SecureHeaders filter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5419 +* Feature: BaseBuilder instance as subquery. by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/5488 + +**Refactoring** + +* Do not inappropriately register bind when the value is a closure by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5247 +* refactor: replace $request->uri with $request->getUri() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5346 +* Determine if binds are simple or named by looking at the $binds array by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5138 +* Remove unneeded cast to array by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5379 +* Additional fix for deprecated `null` usage by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5388 +* refactor: dot_array_search() regex by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5443 +* refactor: Time::getDst() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5415 +* The View class. Optimizing duplicate code. by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/5455 +* refactor: fix `ThrottleTest::testFlooding` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5463 +* refactor: update deprecated method in DatetimeCast by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5474 +* Remove semicolons from SQL statements. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5513 + +**New Contributors** + +* @katie1348 made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/4980 + +## [v4.1.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.5) (2021-11-08) + +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.4...v4.1.5) + +**Fixed bugs:** + +* Fix entity name generation when bundled in model by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5055 +* Fix `Model::__call` throwing `BadMethodCallException` on empty results by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5139 +* Fixed an issue where the dropForeginKey method would execute an empty query when the dropConstraintStr property was empty. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5173 +* Update 'updated_at' when enabled in replace() by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4684 +* Fix query binding with two colons in query by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5117 +* Fixed the problem that _createTable does not take into account that it returns true. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5133 +* Fixed a problem with not run escape for identities in like when `insensitiveSearch` is true. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5170 +* Fixed an issue where an unnecessary prefix was given when the random number was a column. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5179 +* Always escape identifiers in the set(), setUpdateBatch(), and insertBatch() by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5132 +* Error when value is an object - validating api data by @daycry in https://github.com/codeigniter4/CodeIgniter4/pull/5142 +* Fix color not updated in several places of the precompiled CSS by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5155 +* Fix debugbar styles printing by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5100 +* Fix highlighting in database debug toolbar by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5129 +* Fix debug toolbar db connection count by @danielTiringer in https://github.com/codeigniter4/CodeIgniter4/pull/5172 +* Fix CSRF filter does not work when set it to only post by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5194 +* Add CSRF Protection for PUT/PATCH/DELETE by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5228 +* Fix GC issue when session lifetime is set to 0 by @lf-uraku-yuki in https://github.com/codeigniter4/CodeIgniter4/pull/4744 +* Fix wrong helper path resolution by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5246 +* Fix: remove CURLRequest headers sharing from $_SERVER by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5249 +* Fix Localization not working/being ignored for 404 page by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5267 +* fix: module filters are not discovered when using route filters by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5280 +* IncomingRequest - Trim trailing slash by @najdanovicivan in https://github.com/codeigniter4/CodeIgniter4/pull/4974 +* Previous Responses by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5034 +* (Paging) Ensure page validity by @puschie286 in https://github.com/codeigniter4/CodeIgniter4/pull/5125 +* Fix variable variable `$$id` in RedisHandler by @Terrorboy in https://github.com/codeigniter4/CodeIgniter4/pull/5062 +* Fixes and enhancements to Exceptions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5052 + +**Implemented enhancements:** + +* feat: `_` can be used as separators in environment variable names by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5156 +* Multiple filters for a route and classname filter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5128 +* Feature - Mark duplicate queries by @danielTiringer in https://github.com/codeigniter4/CodeIgniter4/pull/5185 +* [Debug] Add formatted query string to timeline. by @sfadschm in https://github.com/codeigniter4/CodeIgniter4/pull/5196 +* [Debug] Improve keyword highlighting and escaping of query strings. by @sfadschm in https://github.com/codeigniter4/CodeIgniter4/pull/5200 +* Add `dropKey` method to `Forge` by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5171 +* Reduce memory usage of insertBatch(), updateBatch() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5202 +* Add Session based CSRF Protection by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5201 +* feat: add valid_url_strict rule by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5268 + +**Merged pull requests:** + +* Merge branch '4.2' by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5060 +* Update to latest laminas-escaper 2.9.0 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5065 +* Remove unintended dead code in pre-commit by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5116 +* Adjust orange color in debug toolbar by @vlakoff in https://github.com/codeigniter4/CodeIgniter4/pull/5136 +* Extract method to get prefix for DB access function by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/5178 +* Improve `model()` auto-completion by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5186 +* Rename toolbar loader to be a regular JS file by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5224 +* [HTTP] Update Http Status Description based on latest iana.org by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5235 +* Remove CSRF properties by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5231 +* Remove static variables for PHP 8.1 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/5262 +* Replace usage of `FILTER_SANITIZE_STRING` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5263 +* Simplify logic of `number_to_roman` function by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5270 +* Fix compatibility of `PgSql\Result` on closing the result instance by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5279 +* Fix compatibility of Postgres result for PHP 8.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5278 + +**New Contributors** + +* @Terrorboy made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/5062 +* @vlakoff made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/5136 +* @Felipebros made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/5152 +* @daycry made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/5142 +* @danielTiringer made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/5172 + ## [v4.1.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.4) (2021-09-06) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.3...v4.1.4) + This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with the new [CodeIgniter Coding Standard](https://github.com/CodeIgniter/coding-standard) (based on PSR-12). -*Note: Full changelog forthcoming.* +**What's Changed** + +* Use php-cs-fixer as coding style tool by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4770 +* Remove unused local variables by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4783 +* Use static lambda if a binding to `$this` is not required. by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4784 +* Use/Fix `preg_quote()` delimiters by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4789 +* Don't override `$path` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4787 +* Don't override `$value` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4788 +* Add brackets to clarify intent and avoid unwanted side-effects by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4791 +* Remove removed `safe_mode` ini Option by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4795 +* It will fix undefined index cid error when sending emails with embedded images by @mmfarhan in https://github.com/codeigniter4/CodeIgniter4/pull/4798 +* Revert Model coalesce by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/4819 +* Master language constructs shall be used instead of aliases. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4847 +* [Commands] Remove unused $minPHPVersion property at Serve command by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4852 +* Update to latest laminas-escaper ^2.8 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4878 +* Remove 'memory_usage' from 'displayPerformanceMetrics()' comment by @Mauricevb in https://github.com/codeigniter4/CodeIgniter4/pull/4939 +* Remove useless code separator comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4946 +* Optimize Filters by @mostafakhudair in https://github.com/codeigniter4/CodeIgniter4/pull/4965 +* Fix properly the phpstan error in 0.12.93 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4970 +* Manual cleanup of docblocks and comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4964 +* Make Cookie compatible with ArrayAccess by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5004 +* Replace deprecated FILTER_SANITIZE_STRING by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5005 +* Make CookieStore compatible with IteratorAggregate::getIterator by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5010 +* Make the session handlers all compatible with SessionHandlerInterface by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5012 +* Make CITestStreamFilter compatible with php_user_filter by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5014 +* Make Time compatible with DateTime by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5022 +* Add `ReturnTypeWillChange` attribute to Entity by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5028 +* Replace unused Entity private method by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5029 +* Make File compatible with SplFileInfo by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5040 +* Update documentation code samples by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5039 +* PHP Copy-Paste Detector by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5031 +* Fix key casting in form_dropdown helper. by @sfadschm in https://github.com/codeigniter4/CodeIgniter4/pull/5035 +* Switch to official coding standard by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5038 + +**New Contributors** + +* @mmfarhan made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/4798 +* @Mauricevb made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/4939 ## [v4.1.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.3) (2021-06-06) diff --git a/LICENSE b/LICENSE index daac9e5bb4f5..31425034e8e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) Copyright (c) 2014-2019 British Columbia Institute of Technology -Copyright (c) 2019-2021 CodeIgniter Foundation +Copyright (c) 2019-2022 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 diff --git a/SECURITY.md b/SECURITY.md index 7879188492b5..87b894ee713c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -20,6 +20,7 @@ This person will coordinate the fix and release process, involving the following - Confirm the problem and determine the affected versions. - Audit code to find any potential similar problems. - Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible. +- Publish security advisories at https://github.com/codeigniter4/CodeIgniter4/security/advisories ## Comments on this Policy diff --git a/admin/RELEASE.md b/admin/RELEASE.md index 822bd1f5f154..eb4e621e1e40 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -1,20 +1,30 @@ # Release Process > Documentation guide based on the releases of `4.0.5` and `4.1.0` on January 31, 2021. -> Updated for `4.1.2` on May 17, 2021. +> +> Updated for `4.1.6` on December 24, 2021. +> > -MGatner +## Changelog + +When generating the changelog each Pull Request to be included must have one of the following [labels](https://github.com/codeigniter4/CodeIgniter4/labels): +- **bug** ... PRs that fix bugs +- **enhancement** ... PRs to improve existing functionalities +- **new feature** ... PRs for new features +- **refactor** ... PRs to refactor + +PRs with breaking changes must have the following additional label: +- **breaking change** ... PRs that may break existing functionalities + +To auto-generate, start drafting a new Release and use the "Auto-generate release notes" button. +Copy the resulting content into **CHANGELOG.md** and adjust the format to match the existing content. + ## Preparation * Work off direct clones of the repos so the release branches persist for a time * Clone both **codeigniter4/CodeIgniter4** and **codeigniter4/userguide** and resolve any necessary PRs * Vet the **admin/** folders for any removed hidden files (Action deploy scripts *do not remove these*) -* Generate a new **CHANGELOG.md** ahead of time using [GitHub Changelog Generator](https://github.com/github-changelog-generator/github-changelog-generator): -``` -github_changelog_generator --user codeigniter4 --project codeigniter4 --since-tag v4.0.4 --future-release v4.0.5 --token {your_github_token} -...or -github_changelog_generator --user codeigniter4 --project codeigniter4 --since-commit "2021-02-01 13:26:28" --future-release v4.0.5 --token {your_github_token} -``` ## CodeIgniter4 diff --git a/admin/module/tests/database/ExampleDatabaseTest.php b/admin/module/tests/database/ExampleDatabaseTest.php index 203b1261c7e0..f9edc4d235d8 100644 --- a/admin/module/tests/database/ExampleDatabaseTest.php +++ b/admin/module/tests/database/ExampleDatabaseTest.php @@ -1,18 +1,18 @@ session->set('logged_in', 123); - - $value = $this->session->get('logged_in'); + $session = Services::session(); - $this->assertSame(123, $value); + $session->set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); } } diff --git a/admin/starter/tests/database/ExampleDatabaseTest.php b/admin/starter/tests/database/ExampleDatabaseTest.php index 5d13836f9dc6..f9edc4d235d8 100644 --- a/admin/starter/tests/database/ExampleDatabaseTest.php +++ b/admin/starter/tests/database/ExampleDatabaseTest.php @@ -2,6 +2,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; +use Tests\Support\Database\Seeds\ExampleSeeder; use Tests\Support\Models\ExampleModel; /** @@ -11,6 +12,8 @@ final class ExampleDatabaseTest extends CIUnitTestCase { use DatabaseTestTrait; + protected $seed = ExampleSeeder::class; + public function testModelFindAll() { $model = new ExampleModel(); diff --git a/admin/starter/tests/session/ExampleSessionTest.php b/admin/starter/tests/session/ExampleSessionTest.php index 151036412146..98fe7afa0d77 100644 --- a/admin/starter/tests/session/ExampleSessionTest.php +++ b/admin/starter/tests/session/ExampleSessionTest.php @@ -1,6 +1,7 @@ session->set('logged_in', 123); - $this->assertSame(123, $this->session->get('logged_in')); + $session = Services::session(); + + $session->set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); } } diff --git a/app/Config/Filters.php b/app/Config/Filters.php index df90270a6480..14685207f71b 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -6,6 +6,8 @@ use CodeIgniter\Filters\CSRF; use CodeIgniter\Filters\DebugToolbar; use CodeIgniter\Filters\Honeypot; +use CodeIgniter\Filters\InvalidChars; +use CodeIgniter\Filters\SecureHeaders; class Filters extends BaseConfig { @@ -16,9 +18,11 @@ class Filters extends BaseConfig * @var array */ public $aliases = [ - 'csrf' => CSRF::class, - 'toolbar' => DebugToolbar::class, - 'honeypot' => Honeypot::class, + 'csrf' => CSRF::class, + 'toolbar' => DebugToolbar::class, + 'honeypot' => Honeypot::class, + 'invalidchars' => InvalidChars::class, + 'secureheaders' => SecureHeaders::class, ]; /** @@ -31,10 +35,12 @@ class Filters extends BaseConfig 'before' => [ // 'honeypot', // 'csrf', + // 'invalidchars', ], 'after' => [ 'toolbar', // 'honeypot', + // 'secureheaders', ], ]; diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 973fb3984901..786bc6a1e5c7 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -509,7 +509,7 @@ public static function guessExtensionFromType(string $type, ?string $proposedExt { $type = trim(strtolower($type), '. '); - $proposedExtension = trim(strtolower($proposedExtension)); + $proposedExtension = trim(strtolower($proposedExtension ?? '')); if ($proposedExtension !== '') { if (array_key_exists($proposedExtension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposedExtension]) ? [static::$mimes[$proposedExtension]] : static::$mimes[$proposedExtension], true)) { diff --git a/app/Config/Security.php b/app/Config/Security.php index 563cf2f3a86e..05083f8b1db1 100644 --- a/app/Config/Security.php +++ b/app/Config/Security.php @@ -17,6 +17,17 @@ class Security extends BaseConfig */ public $csrfProtection = 'cookie'; + /** + * -------------------------------------------------------------------------- + * CSRF Token Randomization + * -------------------------------------------------------------------------- + * + * Randomize the CSRF Token for added security. + * + * @var bool + */ + public $tokenRandomize = false; + /** * -------------------------------------------------------------------------- * CSRF Token Name diff --git a/app/Config/Toolbar.php b/app/Config/Toolbar.php index 16a37e83c2b8..7183e1336a28 100644 --- a/app/Config/Toolbar.php +++ b/app/Config/Toolbar.php @@ -44,6 +44,18 @@ class Toolbar extends BaseConfig Events::class, ]; + /** + * -------------------------------------------------------------------------- + * Collect Var Data + * -------------------------------------------------------------------------- + * + * If set to false var data from the views will not be colleted. Usefull to + * avoid high memory usage when there are lots of data passed to the view. + * + * @var bool + */ + public $collectVarData = true; + /** * -------------------------------------------------------------------------- * Max History diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 4477ee08ff8b..693afed491f5 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -195,7 +195,7 @@ Path - uri) ?> + getUri()) ?> HTTP Method diff --git a/composer.json b/composer.json index b7b3176e055f..6799259fdf62 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "kint-php/kint": "^3.3", + "kint-php/kint": "^4.0", "laminas/laminas-escaper": "^2.9", "psr/log": "^1.1" }, @@ -21,10 +21,10 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", - "phpstan/phpstan": "^0.12.91", + "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.60" + "rector/rector": "0.12.10" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" diff --git a/contributing/documentation.rst b/contributing/documentation.rst index 03164f183e6e..eba3eb99437e 100644 --- a/contributing/documentation.rst +++ b/contributing/documentation.rst @@ -15,22 +15,11 @@ It is created automatically by inserting the following: .. contents:: :local: - - .. raw:: html - -
+ :depth: 2 .. contents:: :local: -.. raw:: html - -
- -The
that is inserted as raw HTML is a event for the documentation's -JavaScript to dynamically add links to any function and method definitions -contained in the current page. - ************** Tools Required ************** @@ -92,3 +81,32 @@ create these with the following tab triggers:: SubSubSubSubSection (!) """"""""""""""""""""""" + +********** +References +********** + +References to a Section +======================= + +If you need to link to a specific section, the first you add the label before a header:: + + .. _curlrequest-request-options-headers: + + headers + ======= + +And then you can reference it like this:: + + See :ref:`CURLRequest Class ` for how to add. + + See :ref:`curlrequest-request-options-headers` for how to add. + +References to a Page +==================== + +You can reference a page like the following:: + + :doc:`Session <../libraries/sessions>` library + + :doc:`../libraries/sessions` library diff --git a/contributing/pull_request.md b/contributing/pull_request.md index e08a5c110558..e788b76fede3 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -214,17 +214,27 @@ The best way to contribute is to fork the CodeIgniter4 repository, and "clone" t 2. Go to the [CodeIgniter4 repository](https://github.com/codeigniter4/CodeIgniter4). 3. [Fork](https://help.github.com/en/articles/fork-a-repo) it (to your GitHub account). 4. [Clone](https://help.github.com/en/articles/cloning-a-repository) your CodeIgniter repository: `git@github.com:/CodeIgniter4.git` -5. Create a new [branch](https://help.github.com/en/articles/about-branches) in your project for each set of changes you want to make. -6. Fix existing bugs on the [Issue tracker](https://github.com/codeigniter4/CodeIgniter4/issues) after confirming that no one else is working on them. -7. [Commit](https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project) the changed files in your contribution branch. -8. Commit messages are expected to be descriptive of what you changed specifically. Commit messages like - "Fixes #1234" would be asked by the reviewer to be revised. + - `> git clone git@github.com:/CodeIgniter4.git` +5. Install Composer dependencies. + - `> cd CodeIgniter4/` + - `> composer update` +6. Create a new [branch](https://help.github.com/en/articles/about-branches) in your project for each set of changes you want to make. + - `> git checkout -b ` +7. Fix existing bugs on the [Issue tracker](https://github.com/codeigniter4/CodeIgniter4/issues) after confirming that no one else is working on them. +8. [Commit](https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project) the changed files in your contribution branch. + - `> git commit` + - Commit messages are expected to be descriptive of what you changed specifically. Commit messages like "Fixes #1234" would be asked by the reviewer to be revised. 9. If there are intermediate commits that are not meaningful to the overall PR, such as "Fixed error on style guide", "Fixed phpstan error", "Fixing mistake in code", and other related commits, it is advised to squash your commits so that we can have a clean commit history. 10. If you have touched PHP code, run static analysis. + - `> composer analyze` + - `> vendor/bin/rector process` 11. Run unit tests on the specific file you modified. If there are no existing tests yet, please create one. -12. Make sure the tests pass to have a higher chance of merging. -13. [Push](https://docs.github.com/en/github/using-git/pushing-commits-to-a-remote-repository) your contribution branch to your fork. -14. Send a [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork). + - `> vendor/bin/phpunit tests/system/path/to/file/you/modified` + - Make sure the tests pass to have a higher chance of merging. +12. [Push](https://docs.github.com/en/github/using-git/pushing-commits-to-a-remote-repository) your contribution branch to your fork. + - `> git push origin ` +13. Send a [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork). +14. Label your pull request with the appropriate label if you can. See [Contribution workflow](./workflow.md) for Git workflow details. diff --git a/contributing/workflow.md b/contributing/workflow.md index 670727a89653..b2309df9477a 100644 --- a/contributing/workflow.md +++ b/contributing/workflow.md @@ -185,7 +185,6 @@ Make sure that the PR title is helpful for the maintainers and other developers. Add any comments appropriate, for instance asking for review. - **Note:** > If you do not provide a title or description for your PR, the odds of it being summarily rejected rise astronomically. @@ -203,6 +202,19 @@ If your PR does not follow our contribution guidelines, or is incomplete, the codebase maintainers will comment on it, pointing out what needs fixing. +### Labeling PRs + +If you have the privilege of labeling PRs, you can help the maintainers. + +Label your PRs with the one of the following [labels](https://github.com/codeigniter4/CodeIgniter4/labels): +- **bug** ... PRs that fix bugs +- **enhancement** ... PRs to improve existing functionalities +- **new feature** ... PRs for new features +- **refactor** ... PRs to refactor + +And if your PRs have the breaking changes, label the following label: +- **breaking change** ... PRs that may break existing functionalities + ## Cleanup If your PR is accepted and merged into the shared repository, you can diff --git a/depfile.yaml b/depfile.yaml index 2c87969f4fc4..301f17076f82 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -172,6 +172,7 @@ ruleset: HTTP: - Cookie - Files + - Security - URI Images: - Files diff --git a/env b/env index 6e30e34b7ddb..c60b367265e7 100644 --- a/env +++ b/env @@ -111,6 +111,7 @@ #-------------------------------------------------------------------- # security.csrfProtection = 'cookie' +# security.tokenRandomize = false # security.tokenName = 'csrf_token_name' # security.headerName = 'X-CSRF-TOKEN' # security.cookieName = 'csrf_cookie_name' diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist new file mode 100644 index 000000000000..0a91bd7fc64f --- /dev/null +++ b/phpstan-baseline.neon.dist @@ -0,0 +1,1022 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$callback of function spl_autoload_register expects \\(callable\\(string\\)\\: void\\)\\|null, array\\{\\$this\\(CodeIgniter\\\\Autoloader\\\\Autoloader\\), 'loadClass'\\} given\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Parameter \\#1 \\$callback of function spl_autoload_register expects \\(callable\\(string\\)\\: void\\)\\|null, array\\{\\$this\\(CodeIgniter\\\\Autoloader\\\\Autoloader\\), 'loadClassmap'\\} given\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$classmap \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$files \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$psr4 \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Method CodeIgniter\\\\Validation\\\\ValidationInterface\\:\\:run\\(\\) invoked with 3 parameters, 0\\-2 required\\.$#" + count: 1 + path: system/BaseModel.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$backupHandler \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$handler \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$validHandlers \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Comparison operation \"\\>\" between int\\<1, max\\> and \\(array\\|float\\|int\\) results in an error\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$storePath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^Method MemcachePool\\:\\:decrement\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Method MemcachePool\\:\\:increment\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Variable \\$config in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Variable \\$data might not be defined\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$redis \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/PredisHandler.php + + - + message: "#^Property CodeIgniter\\\\Cache\\\\Handlers\\\\RedisHandler\\:\\:\\$redis \\(Redis\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/RedisHandler.php + + - + message: "#^Variable \\$config in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: system/Cache/Handlers/RedisHandler.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:getPost\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:getSegments\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:setLocale\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Dead catch \\- CodeIgniter\\\\Exceptions\\\\PageNotFoundException is never thrown in the try block\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Property Config\\\\App\\:\\:\\$appTimezone \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Property Config\\\\App\\:\\:\\$defaultLocale \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Binary operation \"\\+\" between array\\\\|false and non\\-empty\\-array\\ results in an error\\.$#" + count: 1 + path: system/Common.php + + - + message: "#^Variable \\$params on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Common.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:\\$db \\(CodeIgniter\\\\Database\\\\BaseConnection\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Database/BaseBuilder.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_disableForeignKeyChecks\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_enableForeignKeyChecks\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\QueryInterface\\:\\:getOriginalQuery\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Negated boolean expression is always true\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 3 + path: system/Database/BaseResult.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 2 + path: system/Database/BaseResult.php + + - + message: "#^While loop condition is always true\\.$#" + count: 2 + path: system/Database/BaseResult.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:\\$DBDriver\\.$#" + count: 2 + path: system/Database/Database.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:\\$connID\\.$#" + count: 2 + path: system/Database/Database.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\Migration\\:\\:\\$DBGroup \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/Migration.php + + - + message: "#^Property Config\\\\Migrations\\:\\:\\$enabled \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/MigrationRunner.php + + - + message: "#^Property Config\\\\Migrations\\:\\:\\$table \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/MigrationRunner.php + + - + message: "#^Cannot access property \\$affected_rows on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$errno on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$error on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$insert_id on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method autocommit\\(\\) on bool\\|object\\|resource\\.$#" + count: 3 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method begin_transaction\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method close\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method commit\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method more_results\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method next_result\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method query\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method real_escape_string\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method rollback\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method select_db\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method store_result\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$strictOn \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\MySQLi\\\\Connection\\:\\:\\$mysqli \\(mysqli\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$mysqli\\.$#" + count: 3 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method bind_param\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method execute\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method get_result\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot access property \\$field_count on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot access property \\$num_rows on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method data_seek\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_assoc\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_field\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_fields\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_object\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method field_seek\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#" + count: 1 + path: system/Database/Postgre/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/Postgre/PreparedQuery.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$schema\\.$#" + count: 2 + path: system/Database/SQLSRV/Builder.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$schema\\.$#" + count: 14 + path: system/Database/SQLSRV/Forge.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/SQLSRV/PreparedQuery.php + + - + message: "#^Cannot call method changes\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method close\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method escapeString\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method exec\\(\\) on bool\\|object\\|resource\\.$#" + count: 4 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastErrorCode\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastErrorMsg\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastInsertRowID\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method query\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method bindValue\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method execute\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method lastErrorCode\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method lastErrorMsg\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method prepare\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method columnName\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method columnType\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method fetchArray\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method numColumns\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method reset\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Property Config\\\\Database\\:\\:\\$filesPath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/Seeder.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Parameter \\#4 \\$replacement of function array_splice expects array\\|string, true given\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property CodeIgniter\\\\Debug\\\\Exceptions\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property Config\\\\Exceptions\\:\\:\\$sensitiveDataInTrace \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property Config\\\\Toolbar\\:\\:\\$collectVarData \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Variable \\$request on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Variable \\$response on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getPerformanceData\\(\\)\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Events.php + + - + message: "#^Property CodeIgniter\\\\Log\\\\Logger\\:\\:\\$logCache \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Logs.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getData\\(\\)\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Views.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getPerformanceData\\(\\)\\.$#" + count: 2 + path: system/Debug/Toolbar/Collectors/Views.php + + - + message: "#^Static property CodeIgniter\\\\Email\\\\Email\\:\\:\\$func_overload \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Email/Email.php + + - + message: "#^Property Config\\\\Encryption\\:\\:\\$digest \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/Encryption/Encryption.php + + - + message: "#^Property CodeIgniter\\\\Files\\\\File\\:\\:\\$size \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Files/File.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$filters \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$globals \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$methods \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Parameter \\#1 \\$seconds of function sleep expects int, float given\\.$#" + count: 1 + path: system/HTTP/CURLRequest.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Files\\\\UploadedFile\\:\\:\\$error \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Return type \\(bool\\) of method CodeIgniter\\\\HTTP\\\\Files\\\\UploadedFile\\:\\:move\\(\\) should be compatible with return type \\(CodeIgniter\\\\Files\\\\File\\) of method CodeIgniter\\\\Files\\\\File\\:\\:move\\(\\)$#" + count: 1 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\IncomingRequest\\:\\:\\$locale \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/IncomingRequest.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Message\\:\\:\\$protocolVersion \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Message.php + + - + message: "#^Variable \\$_GET on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/HTTP/RedirectResponse.php + + - + message: "#^Variable \\$_POST on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/HTTP/RedirectResponse.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$proxyIPs \\(array\\|string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Request.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$uri \\(CodeIgniter\\\\HTTP\\\\URI\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/HTTP/Request.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSameSite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 3 + path: system/HTTP/Response.php + + - + message: "#^Cannot unset offset 'path' on array\\{host\\: mixed\\}\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$fragment \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$host \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$path \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Right side of && is always true\\.$#" + count: 1 + path: system/Helpers/filesystem_helper.php + + - + message: "#^Offset 'checked' on array\\{type\\: 'checkbox', name\\: mixed, value\\: string\\} in isset\\(\\) does not exist\\.$#" + count: 1 + path: system/Helpers/form_helper.php + + - + message: "#^Binary operation \"\\+\" between 0 and string results in an error\\.$#" + count: 1 + path: system/Helpers/number_helper.php + + - + message: "#^Variable \\$mockService in empty\\(\\) always exists and is always falsy\\.$#" + count: 1 + path: system/Helpers/test_helper.php + + - + message: "#^Parameter \\#2 \\$times of function str_repeat expects int, float given\\.$#" + count: 1 + path: system/Helpers/text_helper.php + + - + message: "#^Variable \\$pool might not be defined\\.$#" + count: 2 + path: system/Helpers/text_helper.php + + - + message: "#^Variable \\$count might not be defined\\.$#" + count: 1 + path: system/Helpers/url_helper.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$image \\(CodeIgniter\\\\Images\\\\Image\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Images/Handlers/BaseHandler.php + + - + message: "#^Comparison operation \"\\>\\=\" between \\(array\\|float\\|int\\) and 0 results in an error\\.$#" + count: 2 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^PHPDoc type string\\|null of property CodeIgniter\\\\Images\\\\Handlers\\\\ImageMagickHandler\\:\\:\\$resource is not covariant with PHPDoc type resource\\|null of overridden property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$resource\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$height \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 4 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$width \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 4 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$gravity might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$xAxis might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$yAxis might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property Config\\\\Logger\\:\\:\\$dateFormat \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Log/Logger.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:asArray\\(\\)\\.$#" + count: 1 + path: system/Model.php + + - + message: "#^Property CodeIgniter\\\\RESTful\\\\ResourceController\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/RESTful/ResourceController.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getDefaultNamespace\\(\\)\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getFilterForRoute\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getFiltersForRoute\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getRoutesOptions\\(\\)\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:isFiltered\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:setHTTPVerb\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getRoutes\\(\\) invoked with 1 parameter, 0 required\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFCookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFExpire \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFHeaderName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFRegenerate \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFTokenName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$cookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$csrfProtection \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$expires \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$headerName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$regenerate \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$tokenName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$tokenRandomize \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Access to an undefined property Config\\\\App\\:\\:\\$sessionDBGroup\\.$#" + count: 1 + path: system/Session/Handlers/DatabaseHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/DatabaseHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/FileHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/MemcachedHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/RedisHandler.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and true will always evaluate to false\\.$#" + count: 1 + path: system/Session/Handlers/RedisHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Session\\:\\:\\$sessionExpiration \\(int\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieDomain \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookiePath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSameSite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSecure \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionCookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionExpiration \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionMatchIP \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionRegenerateDestroy \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionTimeToUpdate \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$domain \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$path \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$raw \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$samesite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$secure \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: system/Test/CIUnitTestCase.php + + - + message: "#^Access to an undefined property object\\:\\:\\$createdField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to an undefined property object\\:\\:\\$deletedField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to an undefined property object\\:\\:\\$updatedField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to protected property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$uri\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$bodyFormat \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$clean \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$session \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Cannot access property \\$insert_id on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Test/Mock/MockConnection.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\Mock\\\\MockResourcePresenter\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/Mock/MockResourcePresenter.php + + - + message: "#^Property CodeIgniter\\\\Throttle\\\\Throttler\\:\\:\\$testTime \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Throttle/Throttler.php + + - + message: "#^Property CodeIgniter\\\\Validation\\\\Validation\\:\\:\\$errors \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Validation/Validation.php + + - + message: "#^Variable \\$error on left side of \\?\\? always exists and is always null\\.$#" + count: 1 + path: system/Validation/Validation.php + + - + message: "#^Property CodeIgniter\\\\View\\\\Cell\\:\\:\\$cache \\(CodeIgniter\\\\Cache\\\\CacheInterface\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: system/View/Cell.php + + - + message: "#^Property Config\\\\View\\:\\:\\$plugins \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/View/Parser.php + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 73e3a7a3a545..741b147136b3 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,9 @@ services: tags: - phpstan.rules.rule +includes: + - phpstan-baseline.neon.dist + parameters: tmpDir: build/phpstan level: 5 @@ -18,7 +21,7 @@ parameters: treatPhpDocTypesAsCertain: false bootstrapFiles: - system/Test/bootstrap.php - excludes_analyse: + excludePaths: - app/Views/errors/cli/* - app/Views/errors/html/* - system/Commands/Generators/Views/* @@ -28,17 +31,6 @@ parameters: - system/Test/Filters/CITestStreamFilter.php - system/ThirdParty/* - system/Validation/Views/single.php - ignoreErrors: - - '#Access to an undefined property CodeIgniter\\Database\\BaseConnection::\$mysqli|\$schema#' - - '#Access to an undefined property CodeIgniter\\Database\\ConnectionInterface::(\$DBDriver|\$connID|\$likeEscapeStr|\$likeEscapeChar|\$escapeChar|\$protectIdentifiers|\$schema)#' - - '#Call to an undefined method CodeIgniter\\Database\\BaseConnection::_(disable|enable)ForeignKeyChecks\(\)#' - - '#Call to an undefined method CodeIgniter\\Router\\RouteCollectionInterface::(getDefaultNamespace|isFiltered|getFilterForRoute|getFiltersForRoute|getRoutesOptions)\(\)#' - - '#Cannot access property [\$a-z_]+ on ((bool\|)?object\|resource)#' - - '#Cannot call method [a-zA-Z_]+\(\) on ((bool\|)?object\|resource)#' - - '#Method CodeIgniter\\Router\\RouteCollectionInterface::getRoutes\(\) invoked with 1 parameter, 0 required#' - - '#Method CodeIgniter\\Validation\\ValidationInterface::run\(\) invoked with 3 parameters, 0-2 required#' - - '#Negated boolean expression is always (true|false)#' - - '#Return type \(bool\) of method CodeIgniter\\HTTP\\Files\\UploadedFile::move\(\) should be compatible with return type \(CodeIgniter\\Files\\File\) of method CodeIgniter\\Files\\File::move\(\)#' parallel: processTimeout: 300.0 scanDirectories: diff --git a/rector.php b/rector.php index 4a5fde83a45c..21f63c0eca1b 100644 --- a/rector.php +++ b/rector.php @@ -42,6 +42,8 @@ use Rector\Php71\Rector\FuncCall\CountOnNullRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; +use Rector\PHPUnit\Set\PHPUnitSetList; +use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -53,9 +55,12 @@ return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->import(SetList::DEAD_CODE); $containerConfigurator->import(LevelSetList::UP_TO_PHP_73); + $containerConfigurator->import(PHPUnitSetList::PHPUNIT_SPECIFIC_METHOD); + $containerConfigurator->import(PHPUnitSetList::PHPUNIT_80); $parameters = $containerConfigurator->parameters(); + $parameters->set(Option::PARALLEL, true); // paths to refactor; solid alternative to CLI arguments $parameters->set(Option::PATHS, [__DIR__ . '/app', __DIR__ . '/system', __DIR__ . '/tests', __DIR__ . '/utils/Rector']); @@ -68,6 +73,7 @@ $parameters->set(Option::SKIP, [ __DIR__ . '/app/Views', __DIR__ . '/system/Debug/Toolbar/Views/toolbar.tpl.php', + __DIR__ . '/system/Debug/Kint/RichRenderer.php', __DIR__ . '/system/ThirdParty', __DIR__ . '/tests/system/Config/fixtures', __DIR__ . '/tests/_support', @@ -141,4 +147,5 @@ $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); $services->set(SimplifyEmptyArrayCheckRector::class); + $services->set(NormalizeNamespaceByPSR4ComposerAutoloadRector::class); }; diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 3472756ad4dd..492fb09930f0 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -114,10 +114,10 @@ public function initialize(Autoload $config, Modules $modules) public function register() { // Prepend the PSR4 autoloader for maximum performance. - spl_autoload_register([$this, 'loadClass'], true, true); // @phpstan-ignore-line + spl_autoload_register([$this, 'loadClass'], true, true); // Now prepend another loader for the files in our class map. - spl_autoload_register([$this, 'loadClassmap'], true, true); // @phpstan-ignore-line + spl_autoload_register([$this, 'loadClassmap'], true, true); // Load our non-class files foreach ($this->files as $file) { diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 6fa8109bf992..b8bfdf6df217 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -55,6 +55,7 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' // Standardize slashes to handle nested directories. $file = strtr($file, '/', '\\'); + $file = ltrim($file, '\\'); $segments = explode('\\', $file); @@ -64,23 +65,20 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' } $paths = []; - $prefix = ''; $filename = ''; // Namespaces always comes with arrays of paths $namespaces = $this->autoloader->getNamespace(); - while (! empty($segments)) { - $prefix .= empty($prefix) ? array_shift($segments) : '\\' . array_shift($segments); + foreach (array_keys($namespaces) as $namespace) { + if (substr($file, 0, strlen($namespace)) === $namespace) { + // There may be sub-namespaces of the same vendor, + // so overwrite them with namespaces found later. + $paths = $namespaces[$namespace]; - if (empty($namespaces[$prefix])) { - continue; + $fileWithoutNamespace = substr($file, strlen($namespace)); + $filename = ltrim(str_replace('\\', '/', $fileWithoutNamespace), '/'); } - - $paths = $namespaces[$prefix]; - - $filename = implode('/', $segments); - break; } // if no namespaces matched then quit diff --git a/system/BaseModel.php b/system/BaseModel.php index 6b9ef3687817..971303664a8e 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1578,7 +1578,7 @@ protected function transformDataToArray($data, string $type): array // properties representing the collection elements, we need to grab // them as an array. if (is_object($data) && ! $data instanceof stdClass) { - $data = $this->objectToArray($data, true, true); + $data = $this->objectToArray($data, ($type === 'update'), true); } // If it's still a stdClass, go ahead and convert to diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index ea1e1ad85611..347a894f7578 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -865,10 +865,12 @@ public static function getOptionString(bool $useLongOpts = false, bool $trim = f $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { - $out .= '"' . $value . '" '; + $out .= "\"{$value}\" "; } elseif ($value !== null) { $out .= "{$value} "; } diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index a7df6971b4bc..2517c6a5df11 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -241,7 +241,6 @@ protected function getItem(string $filename) return false; } - // @phpstan-ignore-next-line if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) { // If the file is still there then try to remove it if (is_file($this->path . $filename)) { diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 93c8cc59e0b5..f240a5d08de2 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -146,7 +146,7 @@ public function get(string $key) } } - return is_array($data) ? $data[0] : $data; // @phpstan-ignore-line + return is_array($data) ? $data[0] : $data; } /** @@ -172,7 +172,6 @@ public function save(string $key, $value, int $ttl = 60) return $this->memcached->set($key, $value, 0, $ttl); } - // @phpstan-ignore-next-line return false; } @@ -205,7 +204,6 @@ public function increment(string $key, int $offset = 1) $key = static::validateKey($key, $this->prefix); - // @phpstan-ignore-next-line return $this->memcached->increment($key, $offset, $offset, 60); } @@ -221,7 +219,7 @@ public function decrement(string $key, int $offset = 1) $key = static::validateKey($key, $this->prefix); // FIXME: third parameter isn't other handler actions. - // @phpstan-ignore-next-line + return $this->memcached->decrement($key, $offset, $offset, 60); } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index a8ebeef1b5cf..bcce77f1f853 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -12,6 +12,7 @@ namespace CodeIgniter; use Closure; +use CodeIgniter\Debug\Kint\RichRenderer; use CodeIgniter\Debug\Timer; use CodeIgniter\Events\Events; use CodeIgniter\Exceptions\FrameworkException; @@ -33,7 +34,6 @@ use Exception; use Kint; use Kint\Renderer\CliRenderer; -use Kint\Renderer\RichRenderer; /** * This class is the core of the framework, and will analyse the @@ -45,7 +45,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.1.5'; + public const CI_VERSION = '4.1.6'; private const MIN_PHP_VERSION = '7.3'; @@ -249,7 +249,7 @@ protected function initializeKint() */ $config = config('Config\Kint'); - Kint::$max_depth = $config->maxDepth; + Kint::$depth_limit = $config->maxDepth; Kint::$display_called_from = $config->displayCalledFrom; Kint::$expanded = $config->expanded; @@ -257,11 +257,13 @@ protected function initializeKint() Kint::$plugins = $config->plugins; } + Kint::$renderers[Kint::MODE_RICH] = RichRenderer::class; + RichRenderer::$theme = $config->richTheme; RichRenderer::$folder = $config->richFolder; RichRenderer::$sort = $config->richSort; if (! empty($config->richObjectPlugins) && is_array($config->richObjectPlugins)) { - RichRenderer::$object_plugins = $config->richObjectPlugins; + RichRenderer::$value_plugins = $config->richObjectPlugins; } if (! empty($config->richTabPlugins) && is_array($config->richTabPlugins)) { RichRenderer::$tab_plugins = $config->richTabPlugins; @@ -537,7 +539,6 @@ protected function getRequestObject() return; } - // @phpstan-ignore-next-line if (is_cli() && ENVIRONMENT !== 'testing') { // @codeCoverageIgnoreStart $this->request = Services::clirequest($this->config); @@ -721,7 +722,7 @@ protected function tryToRouteIt(?RouteCollectionInterface $routes = null) // If a {locale} segment was matched in the final route, // then we need to set the correct locale on our Request. if ($this->router->hasLocale()) { - $this->request->setLocale($this->router->getLocale()); // @phpstan-ignore-line + $this->request->setLocale($this->router->getLocale()); } $this->benchmark->stop('routing'); @@ -816,7 +817,7 @@ protected function createController() protected function runController($class) { // If this is a console request then use the input segments as parameters - $params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params(); // @phpstan-ignore-line + $params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params(); if (method_exists($class, '_remap')) { $output = $class->_remap($this->method, ...$params); @@ -969,7 +970,7 @@ public function spoofRequestMethod() return; } - $method = $this->request->getPost('_method'); // @phpstan-ignore-line + $method = $this->request->getPost('_method'); if (empty($method)) { return; diff --git a/system/Common.php b/system/Common.php index 7c150a01c1d4..e132d982b7d4 100644 --- a/system/Common.php +++ b/system/Common.php @@ -380,7 +380,7 @@ function env(string $key, $default = null) * If $data is an array, then it loops over it, escaping each * 'value' of the key/value pairs. * - * Valid context values: html, js, css, url, attr, raw, null + * Valid context values: html, js, css, url, attr, raw * * @param array|string $data * @param string $encoding @@ -480,9 +480,9 @@ function force_https(int $duration = 31536000, ?RequestInterface $request = null $uri = URI::createURIString( 'https', $baseURL, - $request->uri->getPath(), // Absolute URIs should use a "/" for an empty path - $request->uri->getQuery(), - $request->uri->getFragment() + $request->getUri()->getPath(), // Absolute URIs should use a "/" for an empty path + $request->getUri()->getQuery(), + $request->getUri()->getFragment() ); // Set an HSTS header @@ -643,16 +643,13 @@ function helper($filenames) */ function is_cli(): bool { - if (defined('STDIN')) { + if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) { return true; } - if (! isset($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['argv']) && count($_SERVER['argv']) > 0) { - return true; - } - - // if source of request is from CLI, the `$_SERVER` array will not populate this key - return ! isset($_SERVER['REQUEST_METHOD']); + // PHP_SAPI could be 'cgi-fcgi', 'fpm-fcgi'. + // See https://github.com/codeigniter4/CodeIgniter4/pull/5393 + return ! isset($_SERVER['REMOTE_ADDR']) && ! isset($_SERVER['REQUEST_METHOD']); } } @@ -813,11 +810,6 @@ function old(string $key, $default = null, $escape = 'html') return $default; } - // If the result was serialized array or string, then unserialize it for use... - if (is_string($value) && (strpos($value, 'a:') === 0 || strpos($value, 's:') === 0)) { - $value = unserialize($value); - } - return $escape === false ? $value : esc($value, $escape); } } @@ -1156,7 +1148,6 @@ function class_uses_recursive($class) $results = []; - // @phpstan-ignore-next-line foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) { $results += trait_uses_recursive($class); } diff --git a/system/ComposerScripts.php b/system/ComposerScripts.php index 6972395b5444..ef4dfe1a801b 100644 --- a/system/ComposerScripts.php +++ b/system/ComposerScripts.php @@ -43,20 +43,23 @@ final class ComposerScripts */ private static $dependencies = [ 'kint-src' => [ - 'from' => __DIR__ . '/../vendor/kint-php/kint/src/', - 'to' => __DIR__ . '/ThirdParty/Kint/', + 'license' => __DIR__ . '/../vendor/kint-php/kint/LICENSE', + 'from' => __DIR__ . '/../vendor/kint-php/kint/src/', + 'to' => __DIR__ . '/ThirdParty/Kint/', ], 'kint-resources' => [ 'from' => __DIR__ . '/../vendor/kint-php/kint/resources/', 'to' => __DIR__ . '/ThirdParty/Kint/resources/', ], 'escaper' => [ - 'from' => __DIR__ . '/../vendor/laminas/laminas-escaper/src/', - 'to' => __DIR__ . '/ThirdParty/Escaper/', + 'license' => __DIR__ . '/../vendor/laminas/laminas-escaper/LICENSE.md', + 'from' => __DIR__ . '/../vendor/laminas/laminas-escaper/src/', + 'to' => __DIR__ . '/ThirdParty/Escaper/', ], 'psr-log' => [ - 'from' => __DIR__ . '/../vendor/psr/log/Psr/Log/', - 'to' => __DIR__ . '/ThirdParty/PSR/Log/', + 'license' => __DIR__ . '/../vendor/psr/log/LICENSE', + 'from' => __DIR__ . '/../vendor/psr/log/Psr/Log/', + 'to' => __DIR__ . '/ThirdParty/PSR/Log/', ], ]; @@ -70,6 +73,10 @@ public static function postUpdate() foreach (self::$dependencies as $dependency) { self::recursiveMirror($dependency['from'], $dependency['to']); + if (isset($dependency['license'])) { + $license = basename($dependency['license']); + copy($dependency['license'], $dependency['to'] . '/' . $license); + } } self::copyKintInitFiles(); diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index 87dc472d1fe5..af7dd2f0e437 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -158,6 +158,8 @@ public function remove(string $name, string $prefix = '') /** * Dispatches all cookies in store. + * + * @deprecated Response should dispatch cookies. */ public function dispatch(): void { @@ -232,6 +234,8 @@ protected function validateCookies(array $cookies): void * Extracted call to `setrawcookie()` in order to run unit tests on it. * * @codeCoverageIgnore + * + * @deprecated */ protected function setRawCookie(string $name, string $value, array $options): void { @@ -242,6 +246,8 @@ protected function setRawCookie(string $name, string $value, array $options): vo * Extracted call to `setcookie()` in order to run unit tests on it. * * @codeCoverageIgnore + * + * @deprecated */ protected function setCookie(string $name, string $value, array $options): void { diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 74b9dffad0e4..2a431accd2f5 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -158,6 +158,9 @@ class BaseBuilder * Tracked separately because $QBFrom gets escaped * and prefixed. * + * When $tableName to the constructor has multiple tables, + * the value is empty string. + * * @var string */ protected $tableName; @@ -261,7 +264,9 @@ class BaseBuilder /** * Constructor * - * @param array|string $tableName + * @param array|string $tableName tablename or tablenames with or without aliases + * + * Examples of $tableName: `mytable`, `jobs j`, `jobs j, users u`, `['jobs j','users u']` * * @throws DatabaseException */ @@ -276,7 +281,13 @@ public function __construct($tableName, ConnectionInterface &$db, ?array $option */ $this->db = $db; - $this->tableName = $tableName; + // If it contains `,`, it has multiple tables + if (is_string($tableName) && strpos($tableName, ',') === false) { + $this->tableName = $tableName; // @TODO remove alias if exists + } else { + $this->tableName = ''; + } + $this->from($tableName); if (! empty($options)) { @@ -672,34 +683,34 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type $op = trim(current($op)); - if (substr($k, -1 * strlen($op)) === $op) { - $k = rtrim(strrev(preg_replace(strrev('/' . $op . '/'), strrev(''), strrev($k), 1))); + if (substr($k, -strlen($op)) === $op) { + $k = rtrim(substr($k, 0, -strlen($op))); + $op = " {$op}"; + } else { + $op = ''; } - } - - $bind = $this->setBind($k, $v, $escape); - - if (empty($op)) { - $k .= ' ='; } else { - $k .= " {$op}"; + $op = ' ='; } - if ($v instanceof Closure) { - $builder = $this->cleanClone(); - $v = '(' . str_replace("\n", ' ', $v($builder)->getCompiledSelect()) . ')'; + if ($this->isSubquery($v)) { + $v = $this->buildSubquery($v, true); } else { - $v = " :{$bind}:"; + $bind = $this->setBind($k, $v, $escape); + $v = " :{$bind}:"; } } elseif (! $this->hasOperator($k) && $qbKey !== 'QBHaving') { // value appears not to have been set, assign the test to IS NULL - $k .= ' IS NULL'; + $op = ' IS NULL'; } elseif (preg_match('/\s*(!?=|<>|IS(?:\s+NOT)?)\s*$/i', $k, $match, PREG_OFFSET_CAPTURE)) { - $k = substr($k, 0, $match[0][1]) . ($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); + $k = substr($k, 0, $match[0][1]); + $op = $match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'; + } else { + $op = ''; } $this->{$qbKey}[] = [ - 'condition' => $prefix . $k . $v, + 'condition' => $prefix . $k . $op . $v, 'escape' => $escape, ]; } @@ -711,7 +722,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type * Generates a WHERE field IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -724,7 +735,7 @@ public function whereIn(?string $key = null, $values = null, ?bool $escape = nul * Generates a WHERE field IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -737,7 +748,7 @@ public function orWhereIn(?string $key = null, $values = null, ?bool $escape = n * Generates a WHERE field NOT IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -750,7 +761,7 @@ public function whereNotIn(?string $key = null, $values = null, ?bool $escape = * Generates a WHERE field NOT IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -763,7 +774,7 @@ public function orWhereNotIn(?string $key = null, $values = null, ?bool $escape * Generates a HAVING field IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -776,7 +787,7 @@ public function havingIn(?string $key = null, $values = null, ?bool $escape = nu * Generates a HAVING field IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -789,7 +800,7 @@ public function orHavingIn(?string $key = null, $values = null, ?bool $escape = * Generates a HAVING field NOT IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -802,7 +813,7 @@ public function havingNotIn(?string $key = null, $values = null, ?bool $escape = * Generates a HAVING field NOT IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -817,7 +828,7 @@ public function orHavingNotIn(?string $key = null, $values = null, ?bool $escape * @used-by whereNotIn() * @used-by orWhereNotIn() * - * @param array|Closure|null $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|null $values The values searched on, or anonymous function with subquery * * @throws InvalidArgumentException * @@ -833,7 +844,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal return $this; // @codeCoverageIgnore } - if ($values === null || (! is_array($values) && ! ($values instanceof Closure))) { + if ($values === null || (! is_array($values) && ! $this->isSubquery($values))) { if (CI_DEBUG) { throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } @@ -853,18 +864,19 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $not = ($not) ? ' NOT' : ''; - if ($values instanceof Closure) { - $builder = $this->cleanClone(); - $ok = str_replace("\n", ' ', $values($builder)->getCompiledSelect()); + if ($this->isSubquery($values)) { + $whereIn = $this->buildSubquery($values, true); + $escape = false; } else { $whereIn = array_values($values); - $ok = $this->setBind($ok, $whereIn, $escape); } + $ok = $this->setBind($ok, $whereIn, $escape); + $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ - 'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ({$ok})" : " IN :{$ok}:"), + 'condition' => "{$prefix}{$key}{$not} IN :{$ok}:", 'escape' => false, ]; @@ -2712,9 +2724,35 @@ protected function setBind(string $key, $value = null, bool $escape = true): str * Returns a clone of a Base Builder with reset query builder values. * * @return $this + * + * @deprecated */ protected function cleanClone() { return (clone $this)->from([], true)->resetQuery(); } + + /** + * @param mixed $value + */ + protected function isSubquery($value): bool + { + return $value instanceof BaseBuilder || $value instanceof Closure; + } + + /** + * @param BaseBuilder|Closure $builder + * @param bool $wrapped Wrap the subquery in brackets + */ + protected function buildSubquery($builder, bool $wrapped = false): string + { + if ($builder instanceof Closure) { + $instance = (clone $this)->from([], true)->resetQuery(); + $builder = $builder($instance); + } + + $subquery = strtr($builder->getCompiledSelect(), "\n", ' '); + + return $wrapped ? '(' . $subquery . ')' : $subquery; + } } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index ebb63b7f5827..5f678e5114d7 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -565,7 +565,7 @@ abstract protected function execute(string $sql); * * @param mixed ...$binds * - * @return BaseResult|bool|Query + * @return BaseResult|bool|Query BaseResult when “read” type query, bool when “write” type query, Query when prepared query * * @todo BC set $queryClass default as null in 4.1 */ @@ -835,7 +835,7 @@ abstract protected function _transCommit(): bool; abstract protected function _transRollback(): bool; /** - * Returns an instance of the query builder for this connection. + * Returns a non-shared new instance of the query builder for this connection. * * @param array|string $tableName * @@ -883,7 +883,6 @@ public function prepare(Closure $func, array $options = []) $this->pretend(false); if ($sql instanceof QueryInterface) { - // @phpstan-ignore-next-line $sql = $sql->getOriginalQuery(); } @@ -955,6 +954,8 @@ public function getConnectDuration(int $decimals = 6): string * the correct identifiers. * * @param array|string $item + * @param bool $prefixSingle Prefix an item with no segments? + * @param bool $fieldExists Supplied $item contains a field name? * * @return array|string */ @@ -1012,7 +1013,8 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // // NOTE: The ! empty() condition prevents this method // from breaking when QB isn't enabled. - if (! empty($this->aliasedTables) && in_array($parts[0], $this->aliasedTables, true)) { + $firstSegment = trim($parts[0], $this->escapeChar); + if (! empty($this->aliasedTables) && in_array($firstSegment, $this->aliasedTables, true)) { if ($protectIdentifiers === true) { foreach ($parts as $key => $val) { if (! in_array($val, $this->reservedIdentifiers, true)) { @@ -1200,10 +1202,6 @@ public function escape($str) return ($str === false) ? 0 : 1; } - if (is_numeric($str) && $str < 0) { - return "'{$str}'"; - } - return $str ?? 'NULL'; } diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index 49a970f5bf11..5d223c7fc08b 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -154,7 +154,6 @@ public function getCustomResultObject(string $className) $this->customResultObject[$className][] = $row; } - // @phpstan-ignore-next-line return $this->customResultObject[$className]; } @@ -233,7 +232,6 @@ public function getResultObject(): array $this->resultObject[] = $row; } - // @phpstan-ignore-next-line return $this->resultObject; } diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 5af2b54dbad7..7848ae75ecf0 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -200,7 +200,7 @@ public function repairTable(string $tableName) public function getCSVFromResult(ResultInterface $query, string $delim = ',', string $newline = "\n", string $enclosure = '"') { $out = ''; - // First generate the headings from the table column names + foreach ($query->getFieldNames() as $name) { $out .= $enclosure . str_replace($enclosure, $enclosure . $enclosure, $name) . $enclosure . $delim; } @@ -212,7 +212,7 @@ public function getCSVFromResult(ResultInterface $query, string $delim = ',', st $line = []; foreach ($row as $item) { - $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item) . $enclosure; + $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item ?? '') . $enclosure; } $out .= implode($delim, $line) . $newline; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 8e0b7e43c7f3..406f75b47030 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -135,7 +135,7 @@ class Forge * * @var false|string */ - protected $renameTableStr = 'ALTER TABLE %s RENAME TO %s;'; + protected $renameTableStr = 'ALTER TABLE %s RENAME TO %s'; /** * UNSIGNED support @@ -462,7 +462,7 @@ public function dropKey(string $table, string $keyName) public function dropForeignKey(string $table, string $foreignName) { $sql = sprintf( - $this->dropConstraintStr, + (string) $this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table), $this->db->escapeIdentifiers($this->db->DBPrefix . $foreignName) ); @@ -1042,14 +1042,14 @@ protected function _processIndexes(string $table) if (in_array($i, $this->uniqueKeys, true)) { $sqls[] = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) . ' ADD CONSTRAINT ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) - . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; + . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ')'; continue; } $sqls[] = 'CREATE INDEX ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) . ' ON ' . $this->db->escapeIdentifiers($table) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ')'; } return $sqls; diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 62881620c46b..5badaf1c4881 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -100,19 +100,19 @@ public function connect(bool $persistent = false) if ($this->strictOn) { $this->mysqli->options( MYSQLI_INIT_COMMAND, - 'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")' + "SET SESSION sql_mode = CONCAT(@@sql_mode, ',', 'STRICT_ALL_TABLES')" ); } else { $this->mysqli->options( MYSQLI_INIT_COMMAND, - 'SET SESSION sql_mode = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + "SET SESSION sql_mode = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @@sql_mode, - "STRICT_ALL_TABLES,", ""), - ",STRICT_ALL_TABLES", ""), - "STRICT_ALL_TABLES", ""), - "STRICT_TRANS_TABLES,", ""), - ",STRICT_TRANS_TABLES", ""), - "STRICT_TRANS_TABLES", "")' + 'STRICT_ALL_TABLES,', ''), + ',STRICT_ALL_TABLES', ''), + 'STRICT_ALL_TABLES', ''), + 'STRICT_TRANS_TABLES,', ''), + ',STRICT_TRANS_TABLES', ''), + 'STRICT_TRANS_TABLES', '')" ); } } @@ -485,8 +485,10 @@ protected function _foreignKeyData(string $table): array FROM information_schema.TABLE_CONSTRAINTS AS tc INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc ON tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME + AND tc.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA INNER JOIN information_schema.KEY_COLUMN_USAGE AS kcu ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME + AND tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA WHERE tc.CONSTRAINT_TYPE = ' . $this->escape('FOREIGN KEY') . ' AND tc.TABLE_SCHEMA = ' . $this->escape($this->database) . ' AND diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index a768e0ecf432..57b4c78fd749 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -117,7 +117,6 @@ public function getVersion(): string return $this->dataCache['version']; } - // @phpstan-ignore-next-line if (! $this->connID || ($pgVersion = pg_version($this->connID)) === false) { $this->initialize(); } @@ -433,8 +432,11 @@ protected function buildDSN() $this->DSN = "host={$this->hostname} "; } - if (! empty($this->port) && ctype_digit($this->port)) { - $this->DSN .= "port={$this->port} "; + // ctype_digit only accepts strings + $port = (string) $this->port; + + if ($port !== '' && ctype_digit($port)) { + $this->DSN .= "port={$port} "; } if ($this->username !== '') { diff --git a/system/Database/Query.php b/system/Database/Query.php index a4bb1b2b9de5..91b98c77d2ef 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -273,37 +273,25 @@ public function getOriginalQuery(): string */ protected function compileBinds() { - $sql = $this->finalQueryString; + $sql = $this->finalQueryString; + $binds = $this->binds; - $hasBinds = strpos($sql, $this->bindMarker) !== false; - $hasNamedBinds = ! $hasBinds - && preg_match('/:(?!=).+:/', $sql) === 1; - - if (empty($this->binds) - || empty($this->bindMarker) - || (! $hasNamedBinds && ! $hasBinds) - ) { + if (empty($binds)) { return; } - if (! is_array($this->binds)) { - $binds = [$this->binds]; - $bindCount = 1; - } else { - $binds = $this->binds; + if (is_int(array_key_first($binds))) { $bindCount = count($binds); - } + $ml = strlen($this->bindMarker); - // Reverse the binds so that duplicate named binds - // will be processed prior to the original binds. - if (! is_numeric(key(array_slice($binds, 0, 1)))) { + $this->finalQueryString = $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); + } else { + // Reverse the binds so that duplicate named binds + // will be processed prior to the original binds. $binds = array_reverse($binds); - } - - $ml = strlen($this->bindMarker); - $sql = $hasNamedBinds ? $this->matchNamedBinds($sql, $binds) : $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); - $this->finalQueryString = $sql; + $this->finalQueryString = $this->matchNamedBinds($sql, $binds); + } } /** diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 6ad8e5dc939f..6afc04c51578 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -27,7 +27,7 @@ class Result extends BaseResult */ public function getFieldCount(): int { - return $this->resultID->numColumns(); // @phpstan-ignore-line + return $this->resultID->numColumns(); } /** @@ -38,7 +38,7 @@ public function getFieldNames(): array $fieldNames = []; for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { - $fieldNames[] = $this->resultID->columnName($i); // @phpstan-ignore-line + $fieldNames[] = $this->resultID->columnName($i); } return $fieldNames; @@ -58,18 +58,18 @@ public function getFieldData(): array ]; $retVal = []; - $this->resultID->fetchArray(SQLITE3_NUM); // @phpstan-ignore-line + $this->resultID->fetchArray(SQLITE3_NUM); for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $retVal[$i] = new stdClass(); - $retVal[$i]->name = $this->resultID->columnName($i); // @phpstan-ignore-line - $type = $this->resultID->columnType($i); // @phpstan-ignore-line + $retVal[$i]->name = $this->resultID->columnName($i); + $type = $this->resultID->columnType($i); $retVal[$i]->type = $type; $retVal[$i]->type_name = $dataTypes[$type] ?? null; $retVal[$i]->max_length = null; $retVal[$i]->length = null; } - $this->resultID->reset(); // @phpstan-ignore-line + $this->resultID->reset(); return $retVal; } @@ -100,7 +100,7 @@ public function dataSeek(int $n = 0) throw new DatabaseException('SQLite3 doesn\'t support seeking to other offset.'); } - return $this->resultID->reset(); // @phpstan-ignore-line + return $this->resultID->reset(); } /** @@ -112,7 +112,7 @@ public function dataSeek(int $n = 0) */ protected function fetchAssoc() { - return $this->resultID->fetchArray(SQLITE3_ASSOC); // @phpstan-ignore-line + return $this->resultID->fetchArray(SQLITE3_ASSOC); } /** diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index b6127af2cd91..92d281965c7e 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -68,6 +68,8 @@ class Seeder * Faker Generator instance. * * @var Generator|null + * + * @deprecated */ private static $faker; @@ -98,6 +100,8 @@ public function __construct(Database $config, ?BaseConnection $db = null) /** * Gets the Faker Generator instance. + * + * @deprecated */ public static function faker(): ?Generator { diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 04556c5c4f20..d319c2f9746e 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -70,6 +70,11 @@ public function __construct(ExceptionsConfig $config, IncomingRequest $request, $this->config = $config; $this->request = $request; $this->response = $response; + + // workaround for upgraded users + if (! isset($this->config->sensitiveDataInTrace)) { + $this->config->sensitiveDataInTrace = []; + } } /** @@ -389,7 +394,7 @@ public static function highlightFile(string $file, int $lineNumber, int $lines = $start = max($lineNumber - (int) round($lines / 2), 0); // Get just the lines we need to display, while keeping line numbers... - $source = array_splice($source, $start, $lines, true); // @phpstan-ignore-line + $source = array_splice($source, $start, $lines, true); // Used to format the line number in the source $format = '% ' . strlen((string) ($start + $lines)) . 'd'; diff --git a/system/Debug/Kint/RichRenderer.php b/system/Debug/Kint/RichRenderer.php new file mode 100644 index 000000000000..756cac75e144 --- /dev/null +++ b/system/Debug/Kint/RichRenderer.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Debug\Kint; + +use Kint\Renderer\RichRenderer as KintRichRenderer; + +/** + * Overrides RichRenderer::preRender() for CSP + */ +class RichRenderer extends KintRichRenderer +{ + public function preRender() + { + $output = ''; + + if ($this->pre_render) { + foreach (self::$pre_render_sources as $type => $values) { + $contents = ''; + + foreach ($values as $v) { + $contents .= $v($this); + } + + if (! \strlen($contents)) { + continue; + } + + switch ($type) { + case 'script': + $output .= ''; + break; + + case 'style': + $output .= ''; + break; + + default: + $output .= $contents; + } + } + + // Don't pre-render on every dump + if (! $this->force_pre_render) { + self::$needs_pre_render = false; + } + } + + $output .= '
'; + + return $output; + } +} diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index b951e2ed9658..3502ae877caf 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -310,6 +310,10 @@ protected function structureTimelineData(array $elements): array */ protected function collectVarData(): array { + if (! ($this->config->collectVarData ?? true)) { + return []; + } + $data = []; foreach ($this->collectors as $collector) { diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index d8445b80364f..520ddc7c5dc6 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -89,6 +89,7 @@ public static function collect(Query $query) 'query' => $query, 'string' => $queryString, 'duplicate' => in_array($queryString, array_column(static::$queries, 'string', null), true), + 'trace' => debug_backtrace(), ]; } } @@ -133,11 +134,34 @@ 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 = []; + + 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']); + } + $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']); + + if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) { + continue; + } + $line = empty($line) ? $traceLine : $line; + } + return [ - 'hover' => $isDuplicate ? 'This query was called more than once.' : '', - 'class' => $isDuplicate ? 'duplicate' : '', - 'duration' => ((float) $query['query']->getDuration(5) * 1000) . ' ms', - 'sql' => $query['query']->debugToolbarDisplay(), + 'hover' => $isDuplicate ? 'This query was called more than once.' : '', + 'class' => $isDuplicate ? 'duplicate' : '', + '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'] ?? '', + 'qid' => md5($query['query'] . microtime()), ]; }, static::$queries); diff --git a/system/Debug/Toolbar/Collectors/Events.php b/system/Debug/Toolbar/Collectors/Events.php index b8c59f4566bb..a8a7e7aa4c35 100644 --- a/system/Debug/Toolbar/Collectors/Events.php +++ b/system/Debug/Toolbar/Collectors/Events.php @@ -74,7 +74,7 @@ protected function formatTimelineData(): array { $data = []; - $rows = $this->viewer->getPerformanceData(); // @phpstan-ignore-line + $rows = $this->viewer->getPerformanceData(); foreach ($rows as $info) { $data[] = [ diff --git a/system/Debug/Toolbar/Collectors/Views.php b/system/Debug/Toolbar/Collectors/Views.php index 75fea1d6cc6d..fae3385fffbc 100644 --- a/system/Debug/Toolbar/Collectors/Views.php +++ b/system/Debug/Toolbar/Collectors/Views.php @@ -89,7 +89,7 @@ protected function formatTimelineData(): array { $data = []; - $rows = $this->viewer->getPerformanceData(); // @phpstan-ignore-line + $rows = $this->viewer->getPerformanceData(); foreach ($rows as $info) { $data[] = [ @@ -122,7 +122,7 @@ protected function formatTimelineData(): array public function getVarData(): array { return [ - // @phpstan-ignore-next-line + 'View Data' => $this->viewer->getData(), ]; } @@ -132,7 +132,7 @@ public function getVarData(): array */ public function getBadgeValue(): int { - return count($this->viewer->getPerformanceData()); // @phpstan-ignore-line + return count($this->viewer->getPerformanceData()); } /** diff --git a/system/Debug/Toolbar/Views/_database.tpl b/system/Debug/Toolbar/Views/_database.tpl index a373b56b5256..a2f5bd9808f1 100644 --- a/system/Debug/Toolbar/Views/_database.tpl +++ b/system/Debug/Toolbar/Views/_database.tpl @@ -7,9 +7,18 @@ {queries} - + {duration} {! sql !} + {trace-file}:{trace-line} + + + + + {trace} + {file}:{line}
+ {/trace} + {/queries} diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index b5a223b55d70..ed4230be0988 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -344,6 +344,8 @@ .debug-view.show-view { border-color: #DD8615; } +#debug-bar tr[data-toggle] { + cursor: pointer; } .debug-view-path { background-color: #FDC894; @@ -407,7 +409,7 @@ #debug-bar .muted { color: #DFDFDF; } #debug-bar .muted td { - color: #434343; } + color: #797979; } #debug-bar .muted:hover td { color: #DFDFDF; } #debug-bar #toolbar-position, @@ -496,7 +498,7 @@ #toolbarContainer.dark #debug-bar .muted { color: #DFDFDF; } #toolbarContainer.dark #debug-bar .muted td { - color: #434343; } + color: #797979; } #toolbarContainer.dark #debug-bar .muted:hover td { color: #DFDFDF; } #toolbarContainer.dark #debug-bar #toolbar-position, @@ -587,9 +589,9 @@ -moz-box-shadow: 0 1px 4px #DFDFDF; -webkit-box-shadow: 0 1px 4px #DFDFDF; } #toolbarContainer.light #debug-bar .muted { - color: #434343; } + color: #797979; } #toolbarContainer.light #debug-bar .muted td { - color: #DFDFDF; } + color: #797979; } #toolbarContainer.light #debug-bar .muted:hover td { color: #434343; } #toolbarContainer.light #debug-bar #toolbar-position, diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 690535f2de0d..b6883d4b9f3b 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -58,6 +58,13 @@ var ciDebugBar = { { buttons[i].addEventListener('click', ciDebugBar.showTab, true); } + + // Hook up generic toggle via data attributes `data-toggle="foo"` + var links = document.querySelectorAll('[data-toggle]'); + for (var i = 0; i < links.length; i++) + { + links[i].addEventListener('click', ciDebugBar.toggleRows, true); + } }, showTab: function () { @@ -124,6 +131,21 @@ var ciDebugBar = { } }, + /** + * Toggle display of another object based on + * the data-toggle value of this object + * + * @param event + */ + toggleRows : function(event) { + if(event.target) + { + let row = event.target.closest('tr'); + let target = document.getElementById(row.getAttribute('data-toggle')); + target.style.display = target.style.display === 'none' ? 'table-row' : 'none'; + } + }, + /** * Toggle display of a data table * @@ -137,7 +159,7 @@ var ciDebugBar = { if (obj) { - obj.style.display = obj.style.display == 'none' ? 'block' : 'none'; + obj.style.display = obj.style.display === 'none' ? 'block' : 'none'; } }, @@ -155,7 +177,7 @@ var ciDebugBar = { if (par && obj) { - obj.style.display = obj.style.display == 'none' ? '' : 'none'; + obj.style.display = obj.style.display === 'none' ? '' : 'none'; par.classList.toggle('timeline-parent-open'); } }, diff --git a/system/Entity/Cast/DatetimeCast.php b/system/Entity/Cast/DatetimeCast.php index 4655b4e374e3..99f425a410be 100644 --- a/system/Entity/Cast/DatetimeCast.php +++ b/system/Entity/Cast/DatetimeCast.php @@ -32,7 +32,7 @@ public static function get($value, array $params = []) } if ($value instanceof DateTime) { - return Time::instance($value); + return Time::createFromInstance($value); } if (is_numeric($value)) { diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index faa1df358cb4..edeb8b0571c5 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -397,13 +397,10 @@ protected function processGlobals(?string $uri = null) return; } - $uri = strtolower(trim($uri, '/ ')); + $uri = strtolower(trim($uri ?? '', '/ ')); // Add any global filters, unless they are excluded for this URI - $sets = [ - 'before', - 'after', - ]; + $sets = ['before', 'after']; foreach ($sets as $set) { if (isset($this->config->globals[$set])) { diff --git a/system/Filters/InvalidChars.php b/system/Filters/InvalidChars.php new file mode 100644 index 000000000000..4b1d8f7f9b6b --- /dev/null +++ b/system/Filters/InvalidChars.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\ResponseInterface; +use CodeIgniter\Security\Exceptions\SecurityException; + +/** + * InvalidChars filter. + * + * Check if user input data ($_GET, $_POST, $_COOKIE, php://input) do not contain + * invalid characters: + * - invalid UTF-8 characters + * - control characters except line break and tab code + */ +class InvalidChars implements FilterInterface +{ + /** + * Data source + * + * @var string + */ + protected $source; + + /** + * Regular expressions for valid control codes + * + * @var string + */ + protected $controlCodeRegex = '/\A[\r\n\t[:^cntrl:]]*\z/u'; + + /** + * Check invalid characters. + * + * @param array|null $arguments + * + * @return void + */ + public function before(RequestInterface $request, $arguments = null) + { + if ($request->isCLI()) { + return; + } + + $data = [ + 'get' => $request->getGet(), + 'post' => $request->getPost(), + 'cookie' => $request->getCookie(), + 'rawInput' => $request->getRawInput(), + ]; + + foreach ($data as $source => $values) { + $this->source = $source; + $this->checkEncoding($values); + $this->checkControl($values); + } + } + + /** + * We don't have anything to do here. + * + * @param array|null $arguments + * + * @return void + */ + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + } + + /** + * Check the character encoding is valid UTF-8. + * + * @param array|string $value + * + * @return array|string + */ + protected function checkEncoding($value) + { + if (is_array($value)) { + array_map([$this, 'checkEncoding'], $value); + + return $value; + } + + if (mb_check_encoding($value, 'UTF-8')) { + return $value; + } + + throw SecurityException::forInvalidUTF8Chars($this->source, $value); + } + + /** + * Check for the presence of control characters except line breaks and tabs. + * + * @param array|string $value + * + * @return array|string + */ + protected function checkControl($value) + { + if (is_array($value)) { + array_map([$this, 'checkControl'], $value); + + return $value; + } + + if (preg_match($this->controlCodeRegex, $value) === 1) { + return $value; + } + + throw SecurityException::forInvalidControlChars($this->source, $value); + } +} diff --git a/system/Filters/SecureHeaders.php b/system/Filters/SecureHeaders.php new file mode 100644 index 000000000000..fd656af6a80f --- /dev/null +++ b/system/Filters/SecureHeaders.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\ResponseInterface; + +/** + * Add Common Security Headers + */ +class SecureHeaders implements FilterInterface +{ + /** + * @var array + */ + protected $headers = [ + // https://owasp.org/www-project-secure-headers/#x-frame-options + 'X-Frame-Options' => 'SAMEORIGIN', + + // https://owasp.org/www-project-secure-headers/#x-content-type-options + 'X-Content-Type-Options' => 'nosniff', + + // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/jj542450(v=vs.85)#the-noopen-directive + 'X-Download-Options' => 'noopen', + + // https://owasp.org/www-project-secure-headers/#x-permitted-cross-domain-policies + 'X-Permitted-Cross-Domain-Policies' => 'none', + + // https://owasp.org/www-project-secure-headers/#referrer-policy + 'Referrer-Policy' => 'same-origin', + + // https://owasp.org/www-project-secure-headers/#x-xss-protection + // If you do not need to support legacy browsers, it is recommended that you use + // Content-Security-Policy without allowing unsafe-inline scripts instead. + // 'X-XSS-Protection' => '1; mode=block', + ]; + + /** + * We don't have anything to do here. + * + * @param array|null $arguments + * + * @return void + */ + public function before(RequestInterface $request, $arguments = null) + { + } + + /** + * Add security headers. + * + * @param array|null $arguments + * + * @return void + */ + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + foreach ($this->headers as $header => $value) { + $response->setHeader($header, $value); + } + } +} diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index fcc2a51389d2..11bf598fd36c 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -139,11 +139,13 @@ public function getOptionString(bool $useLongOpts = false): string $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { $out .= '"' . $value . '" '; - } elseif ($value !== null) { + } else { $out .= "{$value} "; } } @@ -170,17 +172,17 @@ protected function parseCommand() if ($optionValue) { $optionValue = false; } else { - $this->segments[] = esc(strip_tags($arg)); + $this->segments[] = $arg; } continue; } - $arg = esc(strip_tags(ltrim($arg, '-'))); + $arg = ltrim($arg, '-'); $value = null; if (isset($args[$i + 1]) && mb_strpos($args[$i + 1], '-') !== 0) { - $value = esc(strip_tags($args[$i + 1])); + $value = $args[$i + 1]; $optionValue = true; } diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index fffe57258a54..e00ac44f97e0 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -358,7 +358,7 @@ public function send(string $method, string $url) // Do we need to delay this request? if ($this->delay > 0) { - sleep($this->delay); // @phpstan-ignore-line + sleep($this->delay); } $output = $this->sendRequest($curlOptions); @@ -424,7 +424,7 @@ protected function applyMethod(string $method, array $curlOptions): array $this->method = $method; $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - $size = strlen($this->body); + $size = strlen($this->body ?? ''); // Have content? if ($size > 0) { diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 6455a5106d8d..b9a672921b94 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -141,10 +141,16 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = $destination = $overwrite ? $targetPath . $name : $this->getDestination($targetPath . $name); try { - move_uploaded_file($this->path, $destination); + $this->hasMoved = move_uploaded_file($this->path, $destination); } catch (Exception $e) { $error = error_get_last(); - $message = isset($error['message']) ? strip_tags($error['message']) : ''; + $message = strip_tags($error['message'] ?? ''); + + throw HTTPException::forMoveFailed(basename($this->path), $targetPath, $message); + } + + if ($this->hasMoved === false) { + $message = 'move_uploaded_file() returned false'; throw HTTPException::forMoveFailed(basename($this->path), $targetPath, $message); } @@ -152,9 +158,8 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = @chmod($targetPath, 0777 & ~umask()); // Success, so store our new information - $this->path = $targetPath; - $this->name = basename($destination); - $this->hasMoved = true; + $this->path = $targetPath; + $this->name = basename($destination); return true; } diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 128d6ee1c432..071b18e97d00 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -64,6 +64,8 @@ class IncomingRequest extends Request * AFTER the script name. So, if hosted in a sub-folder this will * appear different than actual URL. If you need that use getPath(). * + * @TODO should be protected. Use getUri() instead. + * * @var URI */ public $uri; @@ -518,7 +520,7 @@ public function getVar($index = null, $filter = null, $flags = null) */ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) { - return json_decode($this->body, $assoc, $depth, $options); + return json_decode($this->body ?? '', $assoc, $depth, $options); } /** @@ -535,7 +537,11 @@ public function getJsonVar(string $index, bool $assoc = false, ?int $filter = nu { helper('array'); - $data = dot_array_search($index, $this->getJSON(true)); + $json = $this->getJSON(true); + if (! is_array($json)) { + return null; + } + $data = dot_array_search($index, $json); if ($data === null) { return null; @@ -563,7 +569,7 @@ public function getJsonVar(string $index, bool $assoc = false, ?int $filter = nu */ public function getRawInput() { - parse_str($this->body, $output); + parse_str($this->body ?? '', $output); return $output; } diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index c0bb005099ab..327cddcb0e7f 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -273,7 +273,6 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, $value = $this->globals[$method][$index] ?? null; } - // @phpstan-ignore-next-line if (is_array($value) && ( $filter !== FILTER_DEFAULT diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 2b1205a5d47a..278143fd3c3a 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -16,13 +16,14 @@ use CodeIgniter\Cookie\Exceptions\CookieException; use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\Pager\PagerInterface; +use CodeIgniter\Security\Exceptions\SecurityException; use Config\Services; use DateTime; use DateTimeZone; use InvalidArgumentException; /** - * Request Trait + * Response Trait * * Additional methods to make a PSR-7 Response class * compliant with the framework's own ResponseInterface. @@ -435,7 +436,7 @@ public function send() if ($this->CSPEnabled === true) { $this->CSP->finalize($this); } else { - $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body); + $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body ?? ''); } $this->sendHeaders(); @@ -446,7 +447,7 @@ public function send() } /** - * Sends the headers of this HTTP request to the browser. + * Sends the headers of this HTTP response to the browser. * * @return Response */ @@ -535,15 +536,15 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null * Accepts an arbitrary number of binds (up to 7) or an associative * array in the first parameter containing all the values. * - * @param array|string $name Cookie name or array containing binds - * @param string $value Cookie value - * @param string $expire Cookie expiration time in seconds - * @param string $domain Cookie domain (e.g.: '.yourdomain.com') - * @param string $path Cookie path (default: '/') - * @param string $prefix Cookie name prefix - * @param bool $secure Whether to only transfer cookies via SSL - * @param bool $httponly Whether only make the cookie accessible via HTTP (no javascript) - * @param string|null $samesite + * @param array|Cookie|string $name Cookie name / array containing binds / Cookie object + * @param string $value Cookie value + * @param string $expire Cookie expiration time in seconds + * @param string $domain Cookie domain (e.g.: '.yourdomain.com') + * @param string $path Cookie path (default: '/') + * @param string $prefix Cookie name prefix + * @param bool $secure Whether to only transfer cookies via SSL + * @param bool $httponly Whether only make the cookie accessible via HTTP (no javascript) + * @param string|null $samesite * * @return $this */ @@ -558,6 +559,12 @@ public function setCookie( $httponly = false, $samesite = null ) { + if ($name instanceof Cookie) { + $this->cookieStore = $this->cookieStore->put($name); + + return $this; + } + if (is_array($name)) { // always leave 'name' in last place, as the loop will break otherwise, due to $$item foreach (['samesite', 'value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name'] as $item) { @@ -689,7 +696,51 @@ protected function sendCookies() return; } - $this->cookieStore->dispatch(); + $this->dispatchCookies(); + } + + private function dispatchCookies(): void + { + /** @var IncomingRequest $request */ + $request = Services::request(); + + foreach ($this->cookieStore->display() as $cookie) { + if ($cookie->isSecure() && ! $request->isSecure()) { + throw SecurityException::forDisallowedAction(); + } + + $name = $cookie->getPrefixedName(); + $value = $cookie->getValue(); + $options = $cookie->getOptions(); + + if ($cookie->isRaw()) { + $this->doSetRawCookie($name, $value, $options); + } else { + $this->doSetCookie($name, $value, $options); + } + } + + $this->cookieStore->clear(); + } + + /** + * Extracted call to `setrawcookie()` in order to run unit tests on it. + * + * @codeCoverageIgnore + */ + private function doSetRawCookie(string $name, string $value, array $options): void + { + setrawcookie($name, $value, $options); + } + + /** + * Extracted call to `setcookie()` in order to run unit tests on it. + * + * @codeCoverageIgnore + */ + private function doSetCookie(string $name, string $value, array $options): void + { + setcookie($name, $value, $options); } /** diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index c7bdbb135354..f9e9d34c277d 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -625,7 +625,7 @@ public function setAuthority(string $str) if (empty($parts['host']) && $parts['path'] !== '') { $parts['host'] = $parts['path']; - unset($parts['path']); // @phpstan-ignore-line + unset($parts['path']); } $this->applyParts($parts); diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index a06d4bb96c6e..2f8a5f9c8366 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -20,7 +20,13 @@ */ function dot_array_search(string $index, array $array) { - $segments = preg_split('/(?isDir()) { - mkdir($target, 0755); + if (! is_dir($target)) { + mkdir($target, 0755); + } } elseif (! is_file($target) || ($overwrite && is_file($target))) { copy($origin, $target); } diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index b3d7c80c6006..a9a2a938c36f 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -77,7 +77,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) { // Strip any formatting & ensure numeric input try { - $num = 0 + str_replace(',', '', $num); // @phpstan-ignore-line + $num = 0 + str_replace(',', '', $num); } catch (ErrorException $ee) { return false; } @@ -112,11 +112,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) } if (! function_exists('number_to_currency')) { - /** - * @param string $locale - * @param int $fraction - */ - function number_to_currency(float $num, string $currency, ?string $locale = null, ?int $fraction = null): string + function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string { return format_number($num, 1, $locale, [ 'type' => NumberFormatter::CURRENCY, diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 5f0738421908..4e7e5d855302 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -564,7 +564,6 @@ function random_string(string $type = 'alnum', int $len = 8): string break; } - // @phpstan-ignore-next-line return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len); case 'md5': diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index 8d089083eddd..42bcdc473619 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -352,7 +352,7 @@ function safe_mailto(string $email, string $title = '', $attributes = ''): strin $temp[] = $ordinal; - if (count($temp) === $count) { // @phpstan-ignore-line + if (count($temp) === $count) { $number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64); $x[] = '|' . $number; $count = 1; diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 919a5a391534..01698444587d 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -75,25 +75,23 @@ class Time extends DateTime */ public function __construct(?string $time = null, $timezone = null, ?string $locale = null) { - // If no locale was provided, grab it from Locale (set by IncomingRequest for web requests) - $this->locale = ! empty($locale) ? $locale : Locale::getDefault(); + $this->locale = $locale ?: Locale::getDefault(); - // If a test instance has been provided, use it instead. - if ($time === null && static::$testNow instanceof self) { - if (empty($timezone)) { - $timezone = static::$testNow->getTimezone(); - } + $time = $time ?? ''; - $time = static::$testNow->toDateTimeString(); + // If a test instance has been provided, use it instead. + if ($time === '' && static::$testNow instanceof self) { + $timezone = $timezone ?: static::$testNow->getTimezone(); + $time = (string) static::$testNow->toDateTimeString(); } - $timezone = ! empty($timezone) ? $timezone : date_default_timezone_get(); + $timezone = $timezone ?: date_default_timezone_get(); $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); // If the time string was a relative string (i.e. 'next Tuesday') // then we need to adjust the time going in so that we have a current // timezone to work with. - if (! empty($time) && (is_string($time) && static::hasRelativeKeywords($time))) { + if ($time !== '' && static::hasRelativeKeywords($time)) { $instance = new DateTime('now', $this->timezone); $instance->modify($time); $time = $instance->format('Y-m-d H:i:s'); @@ -481,21 +479,7 @@ public function getQuarter(): string */ public function getDst(): bool { - // grab the transactions that would affect today - $start = strtotime('-1 year', $this->getTimestamp()); - $end = strtotime('+2 year', $start); - $transitions = $this->timezone->getTransitions($start, $end); - - $daylightSaving = false; - - foreach ($transitions as $transition) { - if ($transition['time'] > $this->format('U')) { - $daylightSaving = (bool) ($transition['isdst'] ?? $daylightSaving); - break; - } - } - - return $daylightSaving; + return $this->format('I') === '1'; // 1 if Daylight Saving Time, 0 otherwise. } /** diff --git a/system/Images/Handlers/GDHandler.php b/system/Images/Handlers/GDHandler.php index 02d61c40a007..ab8e0b7e3dd3 100644 --- a/system/Images/Handlers/GDHandler.php +++ b/system/Images/Handlers/GDHandler.php @@ -188,7 +188,7 @@ protected function process(string $action) imagesavealpha($dest, true); } - $copy($dest, $src, 0, 0, $this->xAxis, $this->yAxis, $this->width, $this->height, $origWidth, $origHeight); + $copy($dest, $src, 0, 0, (int) $this->xAxis, (int) $this->yAxis, $this->width, $this->height, $origWidth, $origHeight); imagedestroy($src); $this->resource = $dest; @@ -472,9 +472,9 @@ protected function textOverlay(string $text, array $options = [], bool $isShadow // Add the shadow to the source image if (! empty($options['fontPath'])) { // We have to add fontheight because imagettftext locates the bottom left corner, not top-left corner. - imagettftext($src, $options['fontSize'], 0, $xAxis, $yAxis + $options['fontheight'], $color, $options['fontPath'], $text); + imagettftext($src, $options['fontSize'], 0, (int) $xAxis, (int) ($yAxis + $options['fontheight']), $color, $options['fontPath'], $text); } else { - imagestring($src, $options['fontSize'], $xAxis, $yAxis, $text, $color); + imagestring($src, (int) $options['fontSize'], (int) $xAxis, (int) $yAxis, $text, $color); } $this->resource = $src; diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index 5ec6a23cc4f7..37bd168ead02 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -384,10 +384,10 @@ protected function _text(string $text, array $options = []) break; } - $xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis; // @phpstan-ignore-line - $yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis; // @phpstan-ignore-line + $xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis; + $yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis; - $cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}"; // @phpstan-ignore-line + $cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}"; } // Color diff --git a/system/Model.php b/system/Model.php index c73e5c716778..32fa82fcff64 100644 --- a/system/Model.php +++ b/system/Model.php @@ -158,7 +158,7 @@ protected function doFind(bool $singleton, $id = null) */ protected function doFindColumn(string $columnName) { - return $this->select($columnName)->asArray()->find(); // @phpstan-ignore-line + return $this->select($columnName)->asArray()->find(); } /** @@ -584,12 +584,17 @@ public function set($key, $value = '', ?bool $escape = null) */ protected function shouldUpdate($data): bool { - // When useAutoIncrement feature is disabled check + if (parent::shouldUpdate($data) === false) { + return false; + } + + if ($this->useAutoIncrement === true) { + return true; + } + + // When useAutoIncrement feature is disabled, check // in the database if given record already exists - return parent::shouldUpdate($data) - && $this->useAutoIncrement - ? true - : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; + return $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; } /** diff --git a/system/Router/Router.php b/system/Router/Router.php index 621c54a5e9dd..5c4b3f0255d7 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -124,7 +124,6 @@ public function __construct(RouteCollectionInterface $routes, ?Request $request $this->controller = $this->collection->getDefaultController(); $this->method = $this->collection->getDefaultMethod(); - // @phpstan-ignore-next-line $this->collection->setHTTPVerb($request->getMethod() ?? strtolower($_SERVER['REQUEST_METHOD'])); } diff --git a/system/Security/Exceptions/SecurityException.php b/system/Security/Exceptions/SecurityException.php index 254f3ec345f5..ed118d95d5dd 100644 --- a/system/Security/Exceptions/SecurityException.php +++ b/system/Security/Exceptions/SecurityException.php @@ -20,6 +20,22 @@ public static function forDisallowedAction() return new static(lang('Security.disallowedAction'), 403); } + public static function forInvalidUTF8Chars(string $source, string $string) + { + return new static( + 'Invalid UTF-8 characters in ' . $source . ': ' . $string, + 400 + ); + } + + public static function forInvalidControlChars(string $source, string $string) + { + return new static( + 'Invalid Control characters in ' . $source . ': ' . $string, + 400 + ); + } + /** * @deprecated Use `CookieException::forInvalidSameSite()` instead. * diff --git a/system/Security/Security.php b/system/Security/Security.php index d9a44c4c9e6a..008e94aeb612 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -13,12 +13,14 @@ use CodeIgniter\Cookie\Cookie; use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\Response; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Session; use Config\App; use Config\Cookie as CookieConfig; use Config\Security as SecurityConfig; use Config\Services; +use LogicException; /** * Class Security @@ -30,6 +32,7 @@ class Security implements SecurityInterface { public const CSRF_PROTECTION_COOKIE = 'cookie'; public const CSRF_PROTECTION_SESSION = 'session'; + protected const CSRF_HASH_BYTES = 16; /** * CSRF Protection Method @@ -40,6 +43,13 @@ class Security implements SecurityInterface */ protected $csrfProtection = self::CSRF_PROTECTION_COOKIE; + /** + * CSRF Token Randomization + * + * @var bool + */ + protected $tokenRandomize = false; + /** * CSRF Hash * @@ -167,6 +177,7 @@ public function __construct(App $config) $this->regenerate = $security->regenerate ?? $this->regenerate; $this->rawCookieName = $security->cookieName ?? $this->rawCookieName; $this->expires = $security->expires ?? $this->expires; + $this->tokenRandomize = $security->tokenRandomize ?? $this->tokenRandomize; } else { // `Config/Security.php` is absence $this->tokenName = $config->CSRFTokenName ?? $this->tokenName; @@ -270,14 +281,15 @@ public function verify(RequestInterface $request) return $this; } - $token = $this->getPostedToken($request); + $token = $this->tokenRandomize ? $this->derandomize($this->getPostedToken($request)) + : $this->getPostedToken($request); // Do the tokens match? if (! isset($token, $this->hash) || ! hash_equals($this->hash, $token)) { throw SecurityException::forDisallowedAction(); } - $json = json_decode($request->getBody()); + $json = json_decode($request->getBody() ?? ''); if (isset($_POST[$this->tokenName])) { // We kill this since we're done and we don't want to pollute the POST array. @@ -312,9 +324,10 @@ private function getPostedToken(RequestInterface $request): ?string if ($request->hasHeader($this->headerName) && ! empty($request->header($this->headerName)->getValue())) { $tokenName = $request->header($this->headerName)->getValue(); } else { - $json = json_decode($request->getBody()); + $body = (string) $request->getBody(); + $json = json_decode($body); - if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { + if ($body !== '' && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { $tokenName = $json->{$this->tokenName} ?? null; } else { $tokenName = null; @@ -329,7 +342,33 @@ private function getPostedToken(RequestInterface $request): ?string */ public function getHash(): ?string { - return $this->hash; + return $this->tokenRandomize ? $this->randomize($this->hash) : $this->hash; + } + + /** + * Randomize hash to avoid BREACH attacks. + */ + protected function randomize(string $hash): string + { + $keyBinary = random_bytes(static::CSRF_HASH_BYTES); + $hashBinary = hex2bin($hash); + + if ($hashBinary === false) { + throw new LogicException('$hash is invalid: ' . $hash); + } + + return bin2hex(($hashBinary ^ $keyBinary) . $keyBinary); + } + + /** + * Derandomize the token. + */ + protected function derandomize(string $token): string + { + $key = substr($token, -static::CSRF_HASH_BYTES * 2); + $value = substr($token, 0, static::CSRF_HASH_BYTES * 2); + + return bin2hex(hex2bin($value) ^ hex2bin($key)); } /** @@ -461,7 +500,7 @@ protected function generateHash(): string return $this->hash = $this->session->get($this->tokenName); } - $this->hash = bin2hex(random_bytes(16)); + $this->hash = bin2hex(random_bytes(static::CSRF_HASH_BYTES)); if ($this->isCSRFCookie()) { $this->saveHashInCookie(); @@ -490,13 +529,18 @@ private function saveHashInCookie(): void 'expires' => $this->expires === 0 ? 0 : time() + $this->expires, ] ); - $this->sendCookie($this->request); + + /** @var Response $response */ + $response = Services::response(); + $response->setCookie($this->cookie); } /** * CSRF Send Cookie * * @return false|Security + * + * @deprecated Set cookies to Response object instead. */ protected function sendCookie(RequestInterface $request) { @@ -515,6 +559,8 @@ protected function sendCookie(RequestInterface $request) * Extracted for this to be unit tested. * * @codeCoverageIgnore + * + * @deprecated Set cookies to Response object instead. */ protected function doSendCookie(): void { diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index f0164d2dfc3c..dfaa472029fd 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -69,7 +69,6 @@ public function __construct(AppConfig $config, string $ipAddress) throw SessionException::forMissingDatabaseTable(); } - // @phpstan-ignore-next-line $this->DBGroup = $config->sessionDBGroup ?? config(Database::class)->defaultGroup; $this->db = Database::connect($this->DBGroup); diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index ce6e7bde5180..93a601eade70 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -206,7 +206,6 @@ public function close(): bool try { $pingReply = $this->redis->ping(); - // @phpstan-ignore-next-line if (($pingReply === true) || ($pingReply === '+PONG')) { if (isset($this->lockKey)) { $this->redis->del($this->lockKey); diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 50a28e13d2da..e2c6eab609bb 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -231,7 +231,7 @@ protected function setUp(): void { parent::setUp(); - if (! $this->app) { // @phpstan-ignore-line + if (! $this->app) { $this->app = $this->createApplication(); } diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index 0fb013cb1820..d4369765f0ee 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -510,12 +510,12 @@ protected function createMock(?int $count = null) $fields = []; if (! empty($this->model->useTimestamps)) { - $fields[$this->model->createdField] = $datetime; // @phpstan-ignore-line - $fields[$this->model->updatedField] = $datetime; // @phpstan-ignore-line + $fields[$this->model->createdField] = $datetime; + $fields[$this->model->updatedField] = $datetime; } if (! empty($this->model->useSoftDeletes)) { - $fields[$this->model->deletedField] = null; // @phpstan-ignore-line + $fields[$this->model->deletedField] = null; } // Iterate over new entities and add the necessary fields diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index 87423271cd63..d1a75edb8f62 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -349,7 +349,7 @@ protected function populateGlobals(string $method, Request $request, ?array $par // otherwise set it from the URL. $get = ! empty($params) && $method === 'get' ? $params - : $this->getPrivateProperty($request->uri, 'query'); // @phpstan-ignore-line + : $this->getPrivateProperty($request->uri, 'query'); $request->setGlobal('get', $get); if ($method !== 'get') { diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index b44ff8c65491..afb93376b9a0 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -344,7 +344,7 @@ protected function populateGlobals(string $method, Request $request, ?array $par // otherwise set it from the URL. $get = ! empty($params) && $method === 'get' ? $params - : $this->getPrivateProperty($request->uri, 'query'); // @phpstan-ignore-line + : $this->getPrivateProperty($request->uri, 'query'); $request->setGlobal('get', $get); if ($method !== 'get') { diff --git a/system/Test/Mock/MockConnection.php b/system/Test/Mock/MockConnection.php index 78bd405babad..c9d03e7638d6 100644 --- a/system/Test/Mock/MockConnection.php +++ b/system/Test/Mock/MockConnection.php @@ -166,7 +166,7 @@ public function error(): array */ public function insertID(): int { - return $this->connID->insert_id; // @phpstan-ignore-line + return $this->connID->insert_id; } /** diff --git a/system/Test/Mock/MockSecurity.php b/system/Test/Mock/MockSecurity.php index e24221c17b47..a078154b7ff9 100644 --- a/system/Test/Mock/MockSecurity.php +++ b/system/Test/Mock/MockSecurity.php @@ -19,4 +19,12 @@ protected function doSendCookie(): void { $_COOKIE['csrf_cookie_name'] = $this->hash; } + + protected function randomize(string $hash): string + { + $keyBinary = hex2bin('005513c290126d34d41bf41c5265e0f1'); + $hashBinary = hex2bin($hash); + + return bin2hex(($hashBinary ^ $keyBinary) . $keyBinary); + } } diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index f6ddb2ad68d1..00a4341c6e2a 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -86,15 +86,6 @@ class_alias('Config\Services', 'CodeIgniter\Services'); // Now load Composer's if it's available if (is_file(COMPOSER_PATH)) { - /* - * The path to the vendor directory. - * - * We do not want to enforce this, so set the constant if Composer was used. - */ - if (! defined('VENDORPATH')) { - define('VENDORPATH', realpath(ROOTPATH . 'vendor') . DIRECTORY_SEPARATOR); - } - require_once COMPOSER_PATH; } diff --git a/system/ThirdParty/Escaper/LICENSE.md b/system/ThirdParty/Escaper/LICENSE.md new file mode 100644 index 000000000000..10b40f1423b5 --- /dev/null +++ b/system/ThirdParty/Escaper/LICENSE.md @@ -0,0 +1,26 @@ +Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of Laminas Foundation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/system/ThirdParty/Kint/CallFinder.php b/system/ThirdParty/Kint/CallFinder.php index e7192a815284..e77a6407f018 100644 --- a/system/ThirdParty/Kint/CallFinder.php +++ b/system/ThirdParty/Kint/CallFinder.php @@ -27,7 +27,7 @@ class CallFinder { - private static $ignore = array( + private static $ignore = [ T_CLOSE_TAG => true, T_COMMENT => true, T_DOC_COMMENT => true, @@ -35,7 +35,7 @@ class CallFinder T_OPEN_TAG => true, T_OPEN_TAG_WITH_ECHO => true, T_WHITESPACE => true, - ); + ]; /** * Things we need to do specially for operator tokens: @@ -43,17 +43,19 @@ class CallFinder * - Wrap the access path in parentheses if there * are any of these in the final short parameter. */ - private static $operator = array( + private static $operator = [ T_AND_EQUAL => true, T_BOOLEAN_AND => true, T_BOOLEAN_OR => true, T_ARRAY_CAST => true, T_BOOL_CAST => true, + T_CLASS => true, T_CLONE => true, T_CONCAT_EQUAL => true, T_DEC => true, T_DIV_EQUAL => true, T_DOUBLE_CAST => true, + T_FUNCTION => true, T_INC => true, T_INCLUDE => true, T_INCLUDE_ONCE => true, @@ -84,6 +86,9 @@ class CallFinder T_STRING_CAST => true, T_UNSET_CAST => true, T_XOR_EQUAL => true, + T_POW => true, + T_POW_EQUAL => true, + T_DOUBLE_ARROW => true, '!' => true, '%' => true, '&' => true, @@ -100,9 +105,9 @@ class CallFinder '^' => true, '|' => true, '~' => true, - ); + ]; - private static $strip = array( + private static $strip = [ '(' => true, ')' => true, '[' => true, @@ -112,39 +117,43 @@ class CallFinder T_OBJECT_OPERATOR => true, T_DOUBLE_COLON => true, T_NS_SEPARATOR => true, - ); + ]; + + private static $classcalls = [ + T_DOUBLE_COLON => true, + T_OBJECT_OPERATOR => true, + ]; + + private static $namespace = [ + T_STRING => true, + ]; public static function getFunctionCalls($source, $line, $function) { - static $up = array( + static $up = [ '(' => true, '[' => true, '{' => true, T_CURLY_OPEN => true, T_DOLLAR_OPEN_CURLY_BRACES => true, - ); - static $down = array( + ]; + static $down = [ ')' => true, ']' => true, '}' => true, - ); - static $modifiers = array( + ]; + static $modifiers = [ '!' => true, '@' => true, '~' => true, '+' => true, '-' => true, - ); - static $identifier = array( + ]; + static $identifier = [ T_DOUBLE_COLON => true, T_STRING => true, T_NS_SEPARATOR => true, - ); - - if (KINT_PHP56) { - self::$operator[T_POW] = true; - self::$operator[T_POW_EQUAL] = true; - } + ]; if (KINT_PHP70) { self::$operator[T_SPACESHIP] = true; @@ -154,11 +163,24 @@ public static function getFunctionCalls($source, $line, $function) self::$operator[T_COALESCE_EQUAL] = true; } + if (KINT_PHP80) { + $up[T_ATTRIBUTE] = true; + self::$operator[T_MATCH] = true; + self::$strip[T_NULLSAFE_OBJECT_OPERATOR] = true; + self::$classcalls[T_NULLSAFE_OBJECT_OPERATOR] = true; + self::$namespace[T_NAME_FULLY_QUALIFIED] = true; + self::$namespace[T_NAME_QUALIFIED] = true; + self::$namespace[T_NAME_RELATIVE] = true; + $identifier[T_NAME_FULLY_QUALIFIED] = true; + $identifier[T_NAME_QUALIFIED] = true; + $identifier[T_NAME_RELATIVE] = true; + } + $tokens = \token_get_all($source); $cursor = 1; - $function_calls = array(); - /** @var array Performance optimization preventing backwards loops */ - $prev_tokens = array(null, null, null); + $function_calls = []; + // Performance optimization preventing backwards loops + $prev_tokens = [null, null, null]; if (\is_array($function)) { $class = \explode('\\', $function[0]); @@ -188,10 +210,16 @@ public static function getFunctionCalls($source, $line, $function) continue; } - $prev_tokens = array($prev_tokens[1], $prev_tokens[2], $token); + $prev_tokens = [$prev_tokens[1], $prev_tokens[2], $token]; // Check if it's the right type to be the function we're looking for - if (T_STRING !== $token[0] || \strtolower($token[1]) !== $function) { + if (!isset(self::$namespace[$token[0]])) { + continue; + } + + $ns = \explode('\\', \strtolower($token[1])); + + if (\end($ns) !== $function) { continue; } @@ -203,7 +231,7 @@ public static function getFunctionCalls($source, $line, $function) // Check if it matches the signature if (null === $class) { - if ($prev_tokens[1] && \in_array($prev_tokens[1][0], array(T_DOUBLE_COLON, T_OBJECT_OPERATOR), true)) { + if ($prev_tokens[1] && isset(self::$classcalls[$prev_tokens[1][0]])) { continue; } } else { @@ -211,7 +239,15 @@ public static function getFunctionCalls($source, $line, $function) continue; } - if (!$prev_tokens[0] || T_STRING !== $prev_tokens[0][0] || \strtolower($prev_tokens[0][1]) !== $class) { + if (!$prev_tokens[0] || !isset(self::$namespace[$prev_tokens[0][0]])) { + continue; + } + + /** @var array{int, string, int} $prev_tokens[0] */ + // All self::$namespace tokens are T_ constants + $ns = \explode('\\', \strtolower($prev_tokens[0][1])); + + if (\end($ns) !== $class) { continue; } } @@ -222,8 +258,8 @@ public static function getFunctionCalls($source, $line, $function) $instring = false; // Whether we're in a string or not $realtokens = false; // Whether the current scope contains anything meaningful or not $paramrealtokens = false; // Whether the current parameter contains anything meaningful - $params = array(); // All our collected parameters - $shortparam = array(); // The short version of the parameter + $params = []; // All our collected parameters + $shortparam = []; // The short version of the parameter $param_start = $offset; // The distance to the start of the parameter // Loop through the following tokens until the function call ends @@ -276,11 +312,11 @@ public static function getFunctionCalls($source, $line, $function) $shortparam[] = '"'; } elseif (1 === $depth) { if (',' === $token[0]) { - $params[] = array( + $params[] = [ 'full' => \array_slice($tokens, $param_start, $offset - $param_start), 'short' => $shortparam, - ); - $shortparam = array(); + ]; + $shortparam = []; $paramrealtokens = false; $param_start = $offset + 1; } elseif (T_CONSTANT_ENCAPSED_STRING === $token[0] && \strlen($token[1]) > 2) { @@ -293,10 +329,10 @@ public static function getFunctionCalls($source, $line, $function) // Depth has dropped to 0 (So we've hit the closing paren) if ($depth <= 0) { if ($paramrealtokens) { - $params[] = array( + $params[] = [ 'full' => \array_slice($tokens, $param_start, $offset - $param_start), 'short' => $shortparam, - ); + ]; } break; @@ -322,11 +358,11 @@ public static function getFunctionCalls($source, $line, $function) } } - $param = array( + $param = [ 'name' => self::tokensToString($name), 'path' => self::tokensToString(self::tokensTrim($param['full'])), 'expression' => $expression, - ); + ]; } // Get the modifiers @@ -340,7 +376,7 @@ public static function getFunctionCalls($source, $line, $function) --$index; } - $mods = array(); + $mods = []; while (isset($tokens[$index])) { if (isset(self::$ignore[$tokens[$index][0]])) { @@ -357,10 +393,10 @@ public static function getFunctionCalls($source, $line, $function) break; } - $function_calls[] = array( + $function_calls[] = [ 'parameters' => $params, 'modifiers' => $mods, - ); + ]; } return $function_calls; @@ -436,10 +472,11 @@ private static function tokensTrim(array $tokens) private static function tokensFormatted(array $tokens) { $space = false; + $attribute = false; $tokens = self::tokensTrim($tokens); - $output = array(); + $output = []; $last = null; foreach ($tokens as $index => $token) { @@ -450,7 +487,10 @@ private static function tokensFormatted(array $tokens) $next = $tokens[self::realTokenIndex($tokens, $index)]; - if (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) { + /** @var array|string $last */ + if ($attribute && ']' === $last[0]) { + $attribute = false; + } elseif (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) { continue; } @@ -461,6 +501,10 @@ private static function tokensFormatted(array $tokens) $token = ' '; $space = true; } else { + if (KINT_PHP80 && $last && T_ATTRIBUTE == $last[0]) { + $attribute = true; + } + $space = false; $last = $token; } diff --git a/system/ThirdParty/Kint/Kint.php b/system/ThirdParty/Kint/Kint.php index e0ce96337753..f11ed498c45f 100644 --- a/system/ThirdParty/Kint/Kint.php +++ b/system/ThirdParty/Kint/Kint.php @@ -26,11 +26,11 @@ namespace Kint; use InvalidArgumentException; -use Kint\Object\BasicObject; use Kint\Parser\Parser; use Kint\Parser\Plugin; use Kint\Renderer\Renderer; use Kint\Renderer\TextRenderer; +use Kint\Zval\Value; class Kint { @@ -102,12 +102,12 @@ class Kint * * Defaults to [$_SERVER['DOCUMENT_ROOT'] => ''] */ - public static $app_root_dirs = array(); + public static $app_root_dirs = []; /** - * @var int max array/object levels to go deep, if zero no limits are applied + * @var int depth limit for array/object traversal. 0 for no limit */ - public static $max_depth = 6; + public static $depth_limit = 7; /** * @var bool expand all trees by default for rich view @@ -124,23 +124,24 @@ class Kint /** * @var array Kint aliases. Add debug functions in Kint wrappers here to fix modifiers and backtraces */ - public static $aliases = array( - array('Kint\\Kint', 'dump'), - array('Kint\\Kint', 'trace'), - array('Kint\\Kint', 'dumpArray'), - ); + public static $aliases = [ + ['Kint\\Kint', 'dump'], + ['Kint\\Kint', 'trace'], + ['Kint\\Kint', 'dumpArray'], + ]; /** * @var array Array of modes to renderer class names */ - public static $renderers = array( + public static $renderers = [ self::MODE_RICH => 'Kint\\Renderer\\RichRenderer', self::MODE_PLAIN => 'Kint\\Renderer\\PlainRenderer', self::MODE_TEXT => 'Kint\\Renderer\\TextRenderer', self::MODE_CLI => 'Kint\\Renderer\\CliRenderer', - ); + ]; - public static $plugins = array( + public static $plugins = [ + 'Kint\\Parser\\ArrayLimitPlugin', 'Kint\\Parser\\ArrayObjectPlugin', 'Kint\\Parser\\Base64Plugin', 'Kint\\Parser\\BlacklistPlugin', @@ -162,9 +163,9 @@ class Kint 'Kint\\Parser\\TimestampPlugin', 'Kint\\Parser\\TracePlugin', 'Kint\\Parser\\XmlPlugin', - ); + ]; - protected static $plugin_pool = array(); + protected static $plugin_pool = []; protected $parser; protected $renderer; @@ -199,24 +200,25 @@ public function setStatesFromStatics(array $statics) { $this->renderer->setStatics($statics); - $this->parser->setDepthLimit(isset($statics['max_depth']) ? $statics['max_depth'] : false); + $this->parser->setDepthLimit(isset($statics['depth_limit']) ? $statics['depth_limit'] : 0); $this->parser->clearPlugins(); if (!isset($statics['plugins'])) { return; } - $plugins = array(); + $plugins = []; foreach ($statics['plugins'] as $plugin) { if ($plugin instanceof Plugin) { $plugins[] = $plugin; - } elseif (\is_string($plugin) && \is_subclass_of($plugin, 'Kint\\Parser\\Plugin')) { - if (!isset(self::$plugin_pool[$plugin])) { + } elseif (\is_string($plugin) && \is_subclass_of($plugin, Plugin::class)) { + if (!isset(static::$plugin_pool[$plugin])) { + /** @psalm-suppress UnsafeInstantiation */ $p = new $plugin(); - self::$plugin_pool[$plugin] = $p; + static::$plugin_pool[$plugin] = $p; } - $plugins[] = self::$plugin_pool[$plugin]; + $plugins[] = static::$plugin_pool[$plugin]; } } @@ -232,7 +234,7 @@ public function setStatesFromCallInfo(array $info) $this->renderer->setCallInfo($info); if (isset($info['modifiers']) && \is_array($info['modifiers']) && \in_array('+', $info['modifiers'], true)) { - $this->parser->setDepthLimit(false); + $this->parser->setDepthLimit(0); } $this->parser->setCallerClass(isset($info['caller']['class']) ? $info['caller']['class'] : null); @@ -241,8 +243,8 @@ public function setStatesFromCallInfo(array $info) /** * Renders a list of vars including the pre and post renders. * - * @param array $vars Data to dump - * @param BasicObject[] $base Base objects + * @param array $vars Data to dump + * @param array $base Base Zval\Value objects * * @return string */ @@ -254,13 +256,13 @@ public function dumpAll(array $vars, array $base) $output = $this->renderer->preRender(); - if ($vars === array()) { + if ([] === $vars) { $output .= $this->renderer->renderNothing(); } foreach ($vars as $key => $arg) { - if (!$base[$key] instanceof BasicObject) { - throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be BasicObject instances'); + if (!$base[$key] instanceof Value) { + throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be Value instances'); } $output .= $this->dumpVar($arg, $base[$key]); } @@ -273,12 +275,12 @@ public function dumpAll(array $vars, array $base) /** * Dumps and renders a var. * - * @param mixed $var Data to dump - * @param BasicObject $base Base object + * @param mixed $var Data to dump + * @param Value $base Base object * * @return string */ - public function dumpVar(&$var, BasicObject $base) + public function dumpVar(&$var, Value $base) { return $this->renderer->render( $this->parser->parse($var, $base) @@ -292,21 +294,21 @@ public function dumpVar(&$var, BasicObject $base) */ public static function getStatics() { - return array( - 'aliases' => self::$aliases, - 'app_root_dirs' => self::$app_root_dirs, - 'cli_detection' => self::$cli_detection, - 'display_called_from' => self::$display_called_from, - 'enabled_mode' => self::$enabled_mode, - 'expanded' => self::$expanded, - 'file_link_format' => self::$file_link_format, - 'max_depth' => self::$max_depth, - 'mode_default' => self::$mode_default, - 'mode_default_cli' => self::$mode_default_cli, - 'plugins' => self::$plugins, - 'renderers' => self::$renderers, - 'return' => self::$return, - ); + return [ + 'aliases' => static::$aliases, + 'app_root_dirs' => static::$app_root_dirs, + 'cli_detection' => static::$cli_detection, + 'depth_limit' => static::$depth_limit, + 'display_called_from' => static::$display_called_from, + 'enabled_mode' => static::$enabled_mode, + 'expanded' => static::$expanded, + 'file_link_format' => static::$file_link_format, + 'mode_default' => static::$mode_default, + 'mode_default_cli' => static::$mode_default_cli, + 'plugins' => static::$plugins, + 'renderers' => static::$renderers, + 'return' => static::$return, + ]; } /** @@ -325,7 +327,7 @@ public static function createFromStatics(array $statics) if (isset($statics['enabled_mode'])) { $mode = $statics['enabled_mode']; - if (true === $statics['enabled_mode'] && isset($statics['mode_default'])) { + if (true === $mode && isset($statics['mode_default'])) { $mode = $statics['mode_default']; if (PHP_SAPI === 'cli' && !empty($statics['cli_detection']) && isset($statics['mode_default_cli'])) { @@ -334,7 +336,7 @@ public static function createFromStatics(array $statics) } } - if (!$mode) { + if (false === $mode) { return null; } @@ -345,7 +347,8 @@ public static function createFromStatics(array $statics) $renderer = new $statics['renderers'][$mode](); } - return new self(new Parser(), $renderer); + /** @psalm-suppress UnsafeInstantiation */ + return new static(new Parser(), $renderer); } /** @@ -354,11 +357,11 @@ public static function createFromStatics(array $statics) * @param array $params Parameters as returned from getCallInfo * @param int $argc Number of arguments the helper was called with * - * @return BasicObject[] Base objects for the arguments + * @return Value[] Base objects for the arguments */ public static function getBasesFromParamInfo(array $params, $argc) { - static $blacklist = array( + static $blacklist = [ 'null', 'true', 'false', @@ -372,10 +375,10 @@ public static function getBasesFromParamInfo(array $params, $argc) 'b"..."', "'...'", "b'...'", - ); + ]; $params = \array_values($params); - $bases = array(); + $bases = []; for ($i = 0; $i < $argc; ++$i) { if (isset($params[$i])) { @@ -402,7 +405,7 @@ public static function getBasesFromParamInfo(array $params, $argc) $access_path = '$'.$i; } - $bases[] = BasicObject::blank($name, $access_path); + $bases[] = Value::blank($name, $access_path); } return $bases; @@ -424,23 +427,21 @@ public static function getCallInfo(array $aliases, array $trace, $argc) $found = false; $callee = null; $caller = null; - $miniTrace = array(); + $miniTrace = []; foreach ($trace as $index => $frame) { if (Utils::traceFrameIsListed($frame, $aliases)) { $found = true; - $miniTrace = array(); + $miniTrace = []; } - if (!Utils::traceFrameIsListed($frame, array('spl_autoload_call'))) { + if (!Utils::traceFrameIsListed($frame, ['spl_autoload_call'])) { $miniTrace[] = $frame; } } if ($found) { $callee = \reset($miniTrace) ?: null; - - /** @var null|array Psalm bug workaround */ $caller = \next($miniTrace) ?: null; } @@ -455,15 +456,15 @@ public static function getCallInfo(array $aliases, array $trace, $argc) $miniTrace = \array_values($miniTrace); - $call = self::getSingleCall($callee ?: array(), $argc); + $call = static::getSingleCall($callee ?: [], $argc); - $ret = array( + $ret = [ 'params' => null, - 'modifiers' => array(), + 'modifiers' => [], 'callee' => $callee, 'caller' => $caller, 'trace' => $miniTrace, - ); + ]; if ($call) { $ret['params'] = $call['parameters']; @@ -482,23 +483,21 @@ public static function getCallInfo(array $aliases, array $trace, $argc) */ public static function trace() { - if (!self::$enabled_mode) { + if (false === static::$enabled_mode) { return 0; } - Utils::normalizeAliases(self::$aliases); - - $args = \func_get_args(); + Utils::normalizeAliases(static::$aliases); - $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); + $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \func_num_args()); - $statics = self::getStatics(); + $statics = static::getStatics(); if (\in_array('~', $call_info['modifiers'], true)) { - $statics['enabled_mode'] = self::MODE_TEXT; + $statics['enabled_mode'] = static::MODE_TEXT; } - $kintstance = self::createFromStatics($statics); + $kintstance = static::createFromStatics($statics); if (!$kintstance) { // Should never happen return 0; // @codeCoverageIgnore @@ -513,23 +512,25 @@ public static function trace() $kintstance->setStatesFromStatics($statics); $kintstance->setStatesFromCallInfo($call_info); - $trimmed_trace = array(); - $trace = \debug_backtrace(true); + $trimmed_trace = []; + $trace = \debug_backtrace(); foreach ($trace as $frame) { - if (Utils::traceFrameIsListed($frame, self::$aliases)) { - $trimmed_trace = array(); + if (Utils::traceFrameIsListed($frame, static::$aliases)) { + $trimmed_trace = []; } $trimmed_trace[] = $frame; } + \array_shift($trimmed_trace); + $output = $kintstance->dumpAll( - array($trimmed_trace), - array(BasicObject::blank('Kint\\Kint::trace()', 'debug_backtrace(true)')) + [$trimmed_trace], + [Value::blank('Kint\\Kint::trace()', 'debug_backtrace()')] ); - if (self::$return || \in_array('@', $call_info['modifiers'], true)) { + if (static::$return || \in_array('@', $call_info['modifiers'], true)) { return $output; } @@ -545,29 +546,29 @@ public static function trace() /** * Dumps some data. * - * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace(true)) + * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace()) * * @return int|string */ public static function dump() { - if (!self::$enabled_mode) { + if (false === static::$enabled_mode) { return 0; } - Utils::normalizeAliases(self::$aliases); + Utils::normalizeAliases(static::$aliases); $args = \func_get_args(); - $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); + $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); - $statics = self::getStatics(); + $statics = static::getStatics(); if (\in_array('~', $call_info['modifiers'], true)) { - $statics['enabled_mode'] = self::MODE_TEXT; + $statics['enabled_mode'] = static::MODE_TEXT; } - $kintstance = self::createFromStatics($statics); + $kintstance = static::createFromStatics($statics); if (!$kintstance) { // Should never happen return 0; // @codeCoverageIgnore @@ -582,40 +583,13 @@ public static function dump() $kintstance->setStatesFromStatics($statics); $kintstance->setStatesFromCallInfo($call_info); - // If the call is Kint::dump(1) then dump a backtrace instead - if ($args === array(1) && (!isset($call_info['params'][0]['name']) || '1' === $call_info['params'][0]['name'])) { - $args = \debug_backtrace(true); - $trace = array(); - - foreach ($args as $index => $frame) { - if (Utils::traceFrameIsListed($frame, self::$aliases)) { - $trace = array(); - } - - $trace[] = $frame; - } - - if (isset($call_info['callee']['function'])) { - $tracename = $call_info['callee']['function'].'(1)'; - if (isset($call_info['callee']['class'], $call_info['callee']['type'])) { - $tracename = $call_info['callee']['class'].$call_info['callee']['type'].$tracename; - } - } else { - $tracename = 'Kint\\Kint::dump(1)'; - } - - $tracebase = BasicObject::blank($tracename, 'debug_backtrace(true)'); - - $output = $kintstance->dumpAll(array($trace), array($tracebase)); - } else { - $bases = self::getBasesFromParamInfo( - isset($call_info['params']) ? $call_info['params'] : array(), - \count($args) - ); - $output = $kintstance->dumpAll($args, $bases); - } + $bases = static::getBasesFromParamInfo( + isset($call_info['params']) ? $call_info['params'] : [], + \count($args) + ); + $output = $kintstance->dumpAll($args, $bases); - if (self::$return || \in_array('@', $call_info['modifiers'], true)) { + if (static::$return || \in_array('@', $call_info['modifiers'], true)) { return $output; } @@ -643,7 +617,7 @@ public static function shortenPath($file) $longest_match = 0; $match = '/'; - foreach (self::$app_root_dirs as $path => $alias) { + foreach (static::$app_root_dirs as $path => $alias) { if (empty($path)) { continue; } @@ -657,7 +631,7 @@ public static function shortenPath($file) } if ($longest_match) { - $file = \array_merge(array($match), \array_slice($file, $longest_match)); + $file = \array_merge([$match], \array_slice($file, $longest_match)); return \implode('/', $file); } @@ -676,7 +650,7 @@ public static function shortenPath($file) public static function getIdeLink($file, $line) { - return \str_replace(array('%f', '%l'), array($file, $line), self::$file_link_format); + return \str_replace(['%f', '%l'], [$file, $line], static::$file_link_format); } /** @@ -696,7 +670,7 @@ protected static function getSingleCall(array $frame, $argc) if (empty($frame['class'])) { $callfunc = $frame['function']; } else { - $callfunc = array($frame['class'], $frame['function']); + $callfunc = [$frame['class'], $frame['function']]; } $calls = CallFinder::getFunctionCalls( @@ -711,32 +685,30 @@ protected static function getSingleCall(array $frame, $argc) $is_unpack = false; // Handle argument unpacking as a last resort - if (KINT_PHP56) { - foreach ($call['parameters'] as $i => &$param) { - if (0 === \strpos($param['name'], '...')) { - if ($i < $argc && $i === \count($call['parameters']) - 1) { - for ($j = 1; $j + $i < $argc; ++$j) { - $call['parameters'][] = array( - 'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']', - 'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']', - 'expression' => false, - ); - } - - $param['name'] = 'reset('.\substr($param['name'], 3).')'; - $param['path'] = 'reset('.\substr($param['path'], 3).')'; - $param['expression'] = false; - } else { - $call['parameters'] = \array_slice($call['parameters'], 0, $i); + foreach ($call['parameters'] as $i => &$param) { + if (0 === \strpos($param['name'], '...')) { + if ($i < $argc && $i === \count($call['parameters']) - 1) { + for ($j = 1; $j + $i < $argc; ++$j) { + $call['parameters'][] = [ + 'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']', + 'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']', + 'expression' => false, + ]; } - $is_unpack = true; - break; + $param['name'] = 'reset('.\substr($param['name'], 3).')'; + $param['path'] = 'reset('.\substr($param['path'], 3).')'; + $param['expression'] = false; + } else { + $call['parameters'] = \array_slice($call['parameters'], 0, $i); } - if ($i >= $argc) { - continue 2; - } + $is_unpack = true; + break; + } + + if ($i >= $argc) { + continue 2; } } diff --git a/system/ThirdParty/Kint/LICENSE b/system/ThirdParty/Kint/LICENSE new file mode 100644 index 000000000000..01718d4953c4 --- /dev/null +++ b/system/ThirdParty/Kint/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com) + +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. diff --git a/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php new file mode 100644 index 000000000000..4fa94c63c3b9 --- /dev/null +++ b/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php @@ -0,0 +1,142 @@ += self::$trigger) { + throw new InvalidArgumentException('ArrayLimitPlugin::$limit can not be lower than ArrayLimitPlugin::$trigger'); + } + + $depth = $this->parser->getDepthLimit(); + + if (!$depth) { + return; + } + + if ($o->depth >= $depth - 1) { + return; + } + + if (\count($var) < self::$trigger) { + return; + } + + if (self::$numeric_only && Utils::isAssoc($var)) { + return; + } + + $base = clone $o; + $base->depth = $depth - 1; + $obj = $this->parser->parse($var, $base); + + if (!$obj instanceof Value || 'array' != $obj->type) { + return; // @codeCoverageIgnore + } + + $obj->depth = $o->depth; + $i = 0; + + foreach ($obj->value->contents as $child) { + // We only bother setting the correct depth for the first child, + // any deeper children should be cancelled by the depth limit + $child->depth = $o->depth + 1; + $this->recalcDepthLimit($child); + } + + $var2 = \array_slice($var, 0, self::$limit, true); + $base = clone $o; + $slice = $this->parser->parse($var2, $base); + + \array_splice($obj->value->contents, 0, self::$limit, $slice->value->contents); + + $o = $obj; + + $this->parser->haltParse(); + } + + protected function recalcDepthLimit(Value $o) + { + $hintkey = \array_search('depth_limit', $o->hints, true); + if (false !== $hintkey) { + $o->hints[$hintkey] = 'array_limit'; + } + + $reps = $o->getRepresentations(); + if ($o->value) { + $reps[] = $o->value; + } + + foreach ($reps as $rep) { + if ($rep->contents instanceof Value) { + $this->recalcDepthLimit($rep->contents); + } elseif (\is_array($rep->contents)) { + foreach ($rep->contents as $child) { + if ($child instanceof Value) { + $this->recalcDepthLimit($child); + } + } + } + } + } +} diff --git a/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php b/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php index 286d255b16b9..f32b4fada23a 100644 --- a/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php +++ b/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php @@ -26,13 +26,13 @@ namespace Kint\Parser; use ArrayObject; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class ArrayObjectPlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_BEGIN; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof ArrayObject) { return; diff --git a/system/ThirdParty/Kint/Parser/Base64Plugin.php b/system/ThirdParty/Kint/Parser/Base64Plugin.php index 3d7d6bc29011..5208d7ddef4a 100644 --- a/system/ThirdParty/Kint/Parser/Base64Plugin.php +++ b/system/ThirdParty/Kint/Parser/Base64Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class Base64Plugin extends Plugin { @@ -46,7 +46,7 @@ class Base64Plugin extends Plugin public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -54,7 +54,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) < self::$min_length_hard || \strlen($var) % 4) { return; @@ -68,14 +68,13 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - /** @var false|string */ $data = \base64_decode($var, true); if (false === $data) { return; } - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = 'base64_decode('.$o->name.')'; diff --git a/system/ThirdParty/Kint/Parser/BinaryPlugin.php b/system/ThirdParty/Kint/Parser/BinaryPlugin.php index 327c297cd560..9a6b117ba50e 100644 --- a/system/ThirdParty/Kint/Parser/BinaryPlugin.php +++ b/system/ThirdParty/Kint/Parser/BinaryPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; +use Kint\Zval\Value; class BinaryPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,9 +40,9 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof BlobObject || !\in_array($o->encoding, array('ASCII', 'UTF-8'), true)) { + if (!$o instanceof BlobValue || !\in_array($o->encoding, ['ASCII', 'UTF-8'], true)) { $o->value->hints[] = 'binary'; } } diff --git a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php index b37e45ff6fbf..9c472d43e798 100644 --- a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; class BlacklistPlugin extends Plugin { @@ -35,32 +35,18 @@ class BlacklistPlugin extends Plugin * * @var array */ - public static $blacklist = array(); + public static $blacklist = []; /** * List of classes and interfaces to blacklist except when dumped directly. * * @var array */ - public static $shallow_blacklist = array(); - - /** - * Maximum size of arrays before blacklisting. - * - * @var int - */ - public static $array_limit = 10000; - - /** - * Maximum size of arrays before blacklisting except when dumped directly. - * - * @var int - */ - public static $shallow_array_limit = 1000; + public static $shallow_blacklist = ['Psr\\Container\\ContainerInterface']; public function getTypes() { - return array('object', 'array'); + return ['object']; } public function getTriggers() @@ -68,21 +54,11 @@ public function getTriggers() return Parser::TRIGGER_BEGIN; } - public function parse(&$var, BasicObject &$o, $trigger) - { - if (\is_object($var)) { - return $this->parseObject($var, $o); - } - if (\is_array($var)) { - return $this->parseArray($var, $o); - } - } - - protected function parseObject(&$var, BasicObject &$o) + public function parse(&$var, Value &$o, $trigger) { foreach (self::$blacklist as $class) { if ($var instanceof $class) { - return $this->blacklistObject($var, $o); + return $this->blacklistValue($var, $o); } } @@ -92,17 +68,17 @@ protected function parseObject(&$var, BasicObject &$o) foreach (self::$shallow_blacklist as $class) { if ($var instanceof $class) { - return $this->blacklistObject($var, $o); + return $this->blacklistValue($var, $o); } } } - protected function blacklistObject(&$var, BasicObject &$o) + protected function blacklistValue(&$var, Value &$o) { - $object = new InstanceObject(); + $object = new InstanceValue(); $object->transplant($o); $object->classname = \get_class($var); - $object->hash = \spl_object_hash($var); + $object->spl_object_hash = \spl_object_hash($var); $object->clearRepresentations(); $object->value = null; $object->size = null; @@ -112,32 +88,4 @@ protected function blacklistObject(&$var, BasicObject &$o) $this->parser->haltParse(); } - - protected function parseArray(array &$var, BasicObject &$o) - { - if (\count($var) > self::$array_limit) { - return $this->blacklistArray($var, $o); - } - - if ($o->depth <= 0) { - return; - } - - if (\count($var) > self::$shallow_array_limit) { - return $this->blacklistArray($var, $o); - } - } - - protected function blacklistArray(array &$var, BasicObject &$o) - { - $object = new BasicObject(); - $object->transplant($o); - $object->value = null; - $object->size = \count($var); - $object->hints[] = 'blacklist'; - - $o = $object; - - $this->parser->haltParse(); - } } diff --git a/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php b/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php index e4c23716186a..152e59d9c762 100644 --- a/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php +++ b/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php @@ -25,19 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\MethodObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\InstanceValue; +use Kint\Zval\MethodValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; class ClassMethodsPlugin extends Plugin { - private static $cache = array(); + private static $cache = []; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -45,21 +45,21 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $class = \get_class($var); // assuming class definition will not change inside one request if (!isset(self::$cache[$class])) { - $methods = array(); + $methods = []; $reflection = new ReflectionClass($class); foreach ($reflection->getMethods() as $method) { - $methods[] = new MethodObject($method); + $methods[] = new MethodValue($method); } - \usort($methods, array('Kint\\Parser\\ClassMethodsPlugin', 'sort')); + \usort($methods, ['Kint\\Parser\\ClassMethodsPlugin', 'sort']); self::$cache[$class] = $methods; } @@ -91,19 +91,19 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - private static function sort(MethodObject $a, MethodObject $b) + private static function sort(MethodValue $a, MethodValue $b) { $sort = ((int) $a->static) - ((int) $b->static); if ($sort) { return $sort; } - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - $sort = InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + $sort = InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); if ($sort) { return $sort; } diff --git a/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php b/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php index 0ba58ca24874..89601af2f9f7 100644 --- a/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php +++ b/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php @@ -25,19 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; use ReflectionProperty; class ClassStaticsPlugin extends Plugin { - private static $cache = array(); + private static $cache = []; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -45,7 +45,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $class = \get_class($var); $reflection = new ReflectionClass($class); @@ -53,14 +53,14 @@ public function parse(&$var, BasicObject &$o, $trigger) // Constants // TODO: PHP 7.1 allows private consts but reflection doesn't have a way to check them yet if (!isset(self::$cache[$class])) { - $consts = array(); + $consts = []; foreach ($reflection->getConstants() as $name => $val) { - $const = BasicObject::blank($name, '\\'.$class.'::'.$name); + $const = Value::blank($name, '\\'.$class.'::'.$name); $const->const = true; $const->depth = $o->depth + 1; $const->owner_class = $class; - $const->operator = BasicObject::OPERATOR_STATIC; + $const->operator = Value::OPERATOR_STATIC; $const = $this->parser->parse($val, $const); $consts[] = $const; @@ -73,18 +73,18 @@ public function parse(&$var, BasicObject &$o, $trigger) $statics->contents = self::$cache[$class]; foreach ($reflection->getProperties(ReflectionProperty::IS_STATIC) as $static) { - $prop = new BasicObject(); + $prop = new Value(); $prop->name = '$'.$static->getName(); $prop->depth = $o->depth + 1; $prop->static = true; - $prop->operator = BasicObject::OPERATOR_STATIC; + $prop->operator = Value::OPERATOR_STATIC; $prop->owner_class = $static->getDeclaringClass()->name; - $prop->access = BasicObject::ACCESS_PUBLIC; + $prop->access = Value::ACCESS_PUBLIC; if ($static->isProtected()) { - $prop->access = BasicObject::ACCESS_PROTECTED; + $prop->access = Value::ACCESS_PROTECTED; } elseif ($static->isPrivate()) { - $prop->access = BasicObject::ACCESS_PRIVATE; + $prop->access = Value::ACCESS_PRIVATE; } if ($this->parser->childHasPath($o, $prop)) { @@ -92,31 +92,37 @@ public function parse(&$var, BasicObject &$o, $trigger) } $static->setAccessible(true); - $static = $static->getValue(); - $statics->contents[] = $this->parser->parse($static, $prop); + + if (KINT_PHP74 && !$static->isInitialized()) { + $prop->type = 'uninitialized'; + $statics->contents[] = $prop; + } else { + $static = $static->getValue(); + $statics->contents[] = $this->parser->parse($static, $prop); + } } if (empty($statics->contents)) { return; } - \usort($statics->contents, array('Kint\\Parser\\ClassStaticsPlugin', 'sort')); + \usort($statics->contents, ['Kint\\Parser\\ClassStaticsPlugin', 'sort']); $o->addRepresentation($statics); } - private static function sort(BasicObject $a, BasicObject $b) + private static function sort(Value $a, Value $b) { $sort = ((int) $a->const) - ((int) $b->const); if ($sort) { return $sort; } - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - return InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + return InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); } } diff --git a/system/ThirdParty/Kint/Parser/ClosurePlugin.php b/system/ThirdParty/Kint/Parser/ClosurePlugin.php index 73e367b22b03..f4a68f5db737 100644 --- a/system/ThirdParty/Kint/Parser/ClosurePlugin.php +++ b/system/ThirdParty/Kint/Parser/ClosurePlugin.php @@ -26,17 +26,17 @@ namespace Kint\Parser; use Closure; -use Kint\Object\BasicObject; -use Kint\Object\ClosureObject; -use Kint\Object\ParameterObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\ClosureValue; +use Kint\Zval\ParameterValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionFunction; class ClosurePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -44,13 +44,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Closure) { return; } - $object = new ClosureObject(); + $object = new ClosureValue(); $object->transplant($o); $o = $object; $object->removeRepresentation('properties'); @@ -61,24 +61,24 @@ public function parse(&$var, BasicObject &$o, $trigger) $o->startline = $closure->getStartLine(); foreach ($closure->getParameters() as $param) { - $o->parameters[] = new ParameterObject($param); + $o->parameters[] = new ParameterValue($param); } $p = new Representation('Parameters'); $p->contents = &$o->parameters; $o->addRepresentation($p, 0); - $statics = array(); + $statics = []; - if (\method_exists($closure, 'getClosureThis') && $v = $closure->getClosureThis()) { - $statics = array('this' => $v); + if ($v = $closure->getClosureThis()) { + $statics = ['this' => $v]; } if (\count($statics = $statics + $closure->getStaticVariables())) { - $statics_parsed = array(); + $statics_parsed = []; foreach ($statics as $name => &$static) { - $obj = BasicObject::blank('$'.$name); + $obj = Value::blank('$'.$name); $obj->depth = $o->depth + 1; $statics_parsed[$name] = $this->parser->parse($static, $obj); if (null === $statics_parsed[$name]->value) { diff --git a/system/ThirdParty/Kint/Parser/ColorPlugin.php b/system/ThirdParty/Kint/Parser/ColorPlugin.php index 0d748f2c35f2..a00b338c4708 100644 --- a/system/ThirdParty/Kint/Parser/ColorPlugin.php +++ b/system/ThirdParty/Kint/Parser/ColorPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\ColorRepresentation; +use Kint\Zval\Representation\ColorRepresentation; +use Kint\Zval\Value; class ColorPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) > 32) { return; diff --git a/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php b/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php index ec08d311ffef..53329820f787 100644 --- a/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php +++ b/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php @@ -28,9 +28,10 @@ use DOMNamedNodeMap; use DOMNode; use DOMNodeList; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; /** * The DOMDocument parser plugin is particularly useful as it is both the only @@ -63,14 +64,14 @@ class DOMDocumentPlugin extends Plugin * * @var array */ - public static $blacklist = array( + public static $blacklist = [ 'parentNode' => 'DOMNode', 'firstChild' => 'DOMNode', 'lastChild' => 'DOMNode', 'previousSibling' => 'DOMNode', 'nextSibling' => 'DOMNode', 'ownerDocument' => 'DOMDocument', - ); + ]; /** * Show all properties and methods. @@ -81,7 +82,7 @@ class DOMDocumentPlugin extends Plugin public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -89,9 +90,9 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof InstanceObject) { + if (!$o instanceof InstanceValue) { return; } @@ -104,10 +105,10 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - protected function parseList(&$var, InstanceObject &$o, $trigger) + protected function parseList(&$var, InstanceValue &$o, $trigger) { // Recursion should never happen, should always be stopped at the parent - // DOMNode. Depth limit on the other hand we're going to skip since + // DOMNode. Depth limit on the other hand we're going to skip since // that would show an empty iterator and rather useless. Let the depth // limit hit the children (DOMNodeList only has DOMNode as children) if ($trigger & Parser::TRIGGER_RECURSION) { @@ -125,36 +126,42 @@ protected function parseList(&$var, InstanceObject &$o, $trigger) // Depth limit // Make empty iterator representation since we need it in DOMNode to point out depth limits if ($this->parser->getDepthLimit() && $o->depth + 1 >= $this->parser->getDepthLimit()) { - $b = new BasicObject(); + $b = new Value(); $b->name = $o->classname.' Iterator Contents'; $b->access_path = 'iterator_to_array('.$o->access_path.')'; $b->depth = $o->depth + 1; $b->hints[] = 'depth_limit'; $r = new Representation('Iterator'); - $r->contents = array($b); + $r->contents = [$b]; $o->replaceRepresentation($r, 0); return; } - $data = \iterator_to_array($var); - $r = new Representation('Iterator'); $o->replaceRepresentation($r, 0); - foreach ($data as $key => $item) { - $base_obj = new BasicObject(); + foreach ($var as $key => $item) { + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = $item->nodeName; if ($o->access_path) { if ($var instanceof DOMNamedNodeMap) { - $base_obj->access_path = $o->access_path.'->getNamedItem('.\var_export($key, true).')'; + // We can't use getNamedItem() for attributes without a + // namespace because it will pick the first matching + // attribute of *any* namespace. + // + // Contrary to the PHP docs, getNamedItemNS takes null + // as a namespace argument for an unnamespaced item. + $base_obj->access_path = $o->access_path.'->getNamedItemNS('; + $base_obj->access_path .= \var_export($item->namespaceURI, true); + $base_obj->access_path .= ', '; + $base_obj->access_path .= \var_export($item->name, true); + $base_obj->access_path .= ')'; } elseif ($var instanceof DOMNodeList) { $base_obj->access_path = $o->access_path.'->item('.\var_export($key, true).')'; - } else { - $base_obj->access_path = 'iterator_to_array('.$o->access_path.')'; } } @@ -162,19 +169,19 @@ protected function parseList(&$var, InstanceObject &$o, $trigger) } } - protected function parseNode(&$var, InstanceObject &$o) + protected function parseNode(&$var, InstanceValue &$o) { // Fill the properties // They can't be enumerated through reflection or casting, // so we have to trust the docs and try them one at a time - $known_properties = array( + $known_properties = [ 'nodeValue', 'childNodes', 'attributes', - ); + ]; if (self::$verbose) { - $known_properties = array( + $known_properties = [ 'nodeName', 'nodeValue', 'nodeType', @@ -191,11 +198,11 @@ protected function parseNode(&$var, InstanceObject &$o) 'localName', 'baseURI', 'textContent', - ); + ]; } - $childNodes = array(); - $attributes = array(); + $childNodes = null; + $attributes = null; $rep = $o->value; @@ -217,7 +224,9 @@ protected function parseNode(&$var, InstanceObject &$o) // Attributes and comments and text nodes don't // need children or attributes of their own - if (\in_array($o->classname, array('DOMAttr', 'DOMText', 'DOMComment'), true)) { + if (\in_array($o->classname, ['DOMAttr', 'DOMText', 'DOMComment'], true)) { + $o = self::textualNodeToString($o); + return; } @@ -225,7 +234,7 @@ protected function parseNode(&$var, InstanceObject &$o) if ($attributes) { $a = new Representation('Attributes'); foreach ($attributes->contents as $attribute) { - $a->contents[] = self::textualNodeToString($attribute); + $a->contents[] = $attribute; } $o->addRepresentation($a, 0); } @@ -235,21 +244,16 @@ protected function parseNode(&$var, InstanceObject &$o) $c = new Representation('Children'); if (1 === \count($childNodes->contents) && ($node = \reset($childNodes->contents)) && \in_array('depth_limit', $node->hints, true)) { - $n = new InstanceObject(); + $n = new InstanceValue(); $n->transplant($node); $n->name = 'childNodes'; $n->classname = 'DOMNodeList'; - $c->contents = array($n); + $c->contents = [$n]; } else { - foreach ($childNodes->contents as $index => $node) { - // Shortcircuit text nodes to plain strings - if ('DOMText' === $node->classname || 'DOMComment' === $node->classname) { - $node = self::textualNodeToString($node); - - // And remove them if they're empty - if (\ctype_space($node->value->contents) || '' === $node->value->contents) { - continue; - } + foreach ($childNodes->contents as $node) { + // Remove text nodes if theyre empty + if ($node instanceof BlobValue && '#text' === $node->name && (\ctype_space($node->value->contents) || '' === $node->value->contents)) { + continue; } $c->contents[] = $node; @@ -259,8 +263,8 @@ protected function parseNode(&$var, InstanceObject &$o) $o->addRepresentation($c, 0); } - if (isset($c) && \count($c->contents)) { - $o->size = \count($c->contents); + if ($childNodes) { + $o->size = \count($childNodes->contents); } if (!$o->size) { @@ -268,15 +272,15 @@ protected function parseNode(&$var, InstanceObject &$o) } } - protected function parseProperty(InstanceObject $o, $prop, &$var) + protected function parseProperty(InstanceValue $o, $prop, &$var) { // Duplicating (And slightly optimizing) the Parser::parseObject() code here - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->owner_class = $o->classname; $base_obj->name = $prop; - $base_obj->operator = BasicObject::OPERATOR_OBJECT; - $base_obj->access = BasicObject::ACCESS_PUBLIC; + $base_obj->operator = Value::OPERATOR_OBJECT; + $base_obj->access = Value::ACCESS_PUBLIC; if (null !== $o->access_path) { $base_obj->access_path = $o->access_path; @@ -291,14 +295,19 @@ protected function parseProperty(InstanceObject $o, $prop, &$var) if (!isset($var->{$prop})) { $base_obj->type = 'null'; } elseif (isset(self::$blacklist[$prop])) { - $b = new InstanceObject(); + $b = new InstanceValue(); $b->transplant($base_obj); $base_obj = $b; $base_obj->hints[] = 'blacklist'; $base_obj->classname = self::$blacklist[$prop]; } elseif ('attributes' === $prop) { - $base_obj = $this->parser->parseDeep($var->{$prop}, $base_obj); + // Attributes are strings. If we're too deep set the + // depth limit to enable parsing them, but no deeper. + if ($this->parser->getDepthLimit() && $this->parser->getDepthLimit() - 2 < $base_obj->depth) { + $base_obj->depth = $this->parser->getDepthLimit() - 2; + } + $base_obj = $this->parser->parse($var->{$prop}, $base_obj); } else { $base_obj = $this->parser->parse($var->{$prop}, $base_obj); } @@ -306,13 +315,13 @@ protected function parseProperty(InstanceObject $o, $prop, &$var) return $base_obj; } - protected static function textualNodeToString(InstanceObject $o) + protected static function textualNodeToString(InstanceValue $o) { if (empty($o->value) || empty($o->value->contents) || empty($o->classname)) { return; } - if (!\in_array($o->classname, array('DOMText', 'DOMAttr', 'DOMComment'), true)) { + if (!\in_array($o->classname, ['DOMText', 'DOMAttr', 'DOMComment'], true)) { return; } diff --git a/system/ThirdParty/Kint/Parser/DateTimePlugin.php b/system/ThirdParty/Kint/Parser/DateTimePlugin.php index f2cebb643cb9..1c546fd7d2a1 100644 --- a/system/ThirdParty/Kint/Parser/DateTimePlugin.php +++ b/system/ThirdParty/Kint/Parser/DateTimePlugin.php @@ -26,14 +26,14 @@ namespace Kint\Parser; use DateTime; -use Kint\Object\BasicObject; -use Kint\Object\DateTimeObject; +use Kint\Zval\DateTimeValue; +use Kint\Zval\Value; class DateTimePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -41,13 +41,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof DateTime) { return; } - $object = new DateTimeObject($var); + $object = new DateTimeValue($var); $object->transplant($o); $o = $object; diff --git a/system/ThirdParty/Kint/Parser/FsPathPlugin.php b/system/ThirdParty/Kint/Parser/FsPathPlugin.php index 3a8d1e0538c2..79ed3288ca9a 100644 --- a/system/ThirdParty/Kint/Parser/FsPathPlugin.php +++ b/system/ThirdParty/Kint/Parser/FsPathPlugin.php @@ -25,17 +25,17 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SplFileInfoRepresentation; +use Kint\Zval\Representation\SplFileInfoRepresentation; +use Kint\Zval\Value; use SplFileInfo; class FsPathPlugin extends Plugin { - public static $blacklist = array('/', '.'); + public static $blacklist = ['/', '.']; public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -43,7 +43,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) > 2048) { return; diff --git a/system/ThirdParty/Kint/Parser/IteratorPlugin.php b/system/ThirdParty/Kint/Parser/IteratorPlugin.php index 0487a381f5b9..8aa1c342f5ce 100644 --- a/system/ThirdParty/Kint/Parser/IteratorPlugin.php +++ b/system/ThirdParty/Kint/Parser/IteratorPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use Traversable; class IteratorPlugin extends Plugin @@ -40,17 +40,17 @@ class IteratorPlugin extends Plugin * * @var array */ - public static $blacklist = array( + public static $blacklist = [ 'DOMNamedNodeMap', 'DOMNodeList', 'mysqli_result', 'PDOStatement', 'SplFileObject', - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -58,7 +58,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Traversable) { return; @@ -66,14 +66,14 @@ public function parse(&$var, BasicObject &$o, $trigger) foreach (self::$blacklist as $class) { if ($var instanceof $class) { - $b = new BasicObject(); + $b = new Value(); $b->name = $class.' Iterator Contents'; $b->access_path = 'iterator_to_array('.$o->access_path.', true)'; $b->depth = $o->depth + 1; $b->hints[] = 'blacklist'; $r = new Representation('Iterator'); - $r->contents = array($b); + $r->contents = [$b]; $o->addRepresentation($r); @@ -81,14 +81,9 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - /** @var array|false */ $data = \iterator_to_array($var); - if (false === $data) { - return; - } - - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { @@ -101,7 +96,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $primary = $o->getRepresentations(); $primary = \reset($primary); - if ($primary && $primary === $o->value && $primary->contents === array()) { + if ($primary && $primary === $o->value && [] === $primary->contents) { $o->addRepresentation($r, 0); } else { $o->addRepresentation($r); diff --git a/system/ThirdParty/Kint/Parser/JsonPlugin.php b/system/ThirdParty/Kint/Parser/JsonPlugin.php index 84b251955383..a105b8fd6ff1 100644 --- a/system/ThirdParty/Kint/Parser/JsonPlugin.php +++ b/system/ThirdParty/Kint/Parser/JsonPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class JsonPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!isset($var[0]) || ('{' !== $var[0] && '[' !== $var[0])) { return; @@ -54,7 +54,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $json = (array) $json; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { diff --git a/system/ThirdParty/Kint/Parser/MicrotimePlugin.php b/system/ThirdParty/Kint/Parser/MicrotimePlugin.php index 5062b59ad224..782c11f84f85 100644 --- a/system/ThirdParty/Kint/Parser/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Parser/MicrotimePlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\MicrotimeRepresentation; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Value; class MicrotimePlugin extends Plugin { @@ -37,7 +37,7 @@ class MicrotimePlugin extends Plugin public function getTypes() { - return array('string', 'double'); + return ['string', 'double']; } public function getTriggers() @@ -45,7 +45,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (0 !== $o->depth) { return; @@ -79,7 +79,7 @@ public function parse(&$var, BasicObject &$o, $trigger) self::$start = $time; } - self::$last = array($sec, $usec); + self::$last = [$sec, $usec]; if (null !== $lap) { $total = $time - self::$start; diff --git a/system/ThirdParty/Kint/Parser/MysqliPlugin.php b/system/ThirdParty/Kint/Parser/MysqliPlugin.php index 265299bec6ee..4c95d790a772 100644 --- a/system/ThirdParty/Kint/Parser/MysqliPlugin.php +++ b/system/ThirdParty/Kint/Parser/MysqliPlugin.php @@ -25,8 +25,10 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; use Mysqli; +use ReflectionClass; +use Throwable; /** * Adds support for Mysqli object parsing. @@ -37,21 +39,21 @@ class MysqliPlugin extends Plugin { // These 'properties' are actually globals - protected $always_readable = array( + protected $always_readable = [ 'client_version' => true, 'connect_errno' => true, 'connect_error' => true, - ); + ]; // These are readable on empty mysqli objects, but not on failed connections - protected $empty_readable = array( + protected $empty_readable = [ 'client_info' => true, 'errno' => true, 'error' => true, - ); + ]; // These are only readable on connected mysqli objects - protected $connected_readable = array( + protected $connected_readable = [ 'affected_rows' => true, 'error_list' => true, 'field_count' => true, @@ -60,16 +62,15 @@ class MysqliPlugin extends Plugin 'insert_id' => true, 'server_info' => true, 'server_version' => true, - 'stat' => true, 'sqlstate' => true, 'protocol_version' => true, 'thread_id' => true, 'warning_count' => true, - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -77,19 +78,24 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Mysqli) { return; } - $connected = false; - $empty = false; + try { + $connected = \is_string(@$var->sqlstate); + } catch (Throwable $t) { + $connected = false; + } - if (\is_string(@$var->sqlstate)) { - $connected = true; - } elseif (\is_string(@$var->client_info)) { - $empty = true; + try { + $empty = !$connected && \is_string(@$var->client_info); + } catch (Throwable $t) { // @codeCoverageIgnore + // Only possible in PHP 8.0. Before 8.0 there's no exception, + // after 8.1 there are no failed connection objects + $empty = false; // @codeCoverageIgnore } foreach ($o->value->contents as $key => $obj) { @@ -98,8 +104,9 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } } elseif (isset($this->empty_readable[$obj->name])) { - if (!$connected && !$empty) { - continue; + // No failed connections after PHP 8.1 + if (!$connected && !$empty) { // @codeCoverageIgnore + continue; // @codeCoverageIgnore } } elseif (!isset($this->always_readable[$obj->name])) { continue; @@ -109,13 +116,17 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } + // @codeCoverageIgnoreStart + // All of this is irellevant after 8.1, + // we have separate logic for that below + $param = $var->{$obj->name}; if (null === $param) { continue; } - $base = BasicObject::blank($obj->name, $obj->access_path); + $base = Value::blank($obj->name, $obj->access_path); $base->depth = $obj->depth; $base->owner_class = $obj->owner_class; @@ -124,6 +135,55 @@ public function parse(&$var, BasicObject &$o, $trigger) $base->reference = $obj->reference; $o->value->contents[$key] = $this->parser->parse($param, $base); + + // @codeCoverageIgnoreEnd + } + + // PHP81 returns an empty array when casting a Mysqli instance + if (KINT_PHP81) { + $r = new ReflectionClass(Mysqli::class); + + $basepropvalues = []; + + foreach ($r->getProperties() as $prop) { + if ($prop->isStatic()) { + continue; // @codeCoverageIgnore + } + + $pname = $prop->getName(); + $param = null; + + if (isset($this->connected_readable[$pname])) { + if ($connected) { + $param = $var->{$pname}; + } + } else { + $param = $var->{$pname}; + } + + $child = new Value(); + $child->depth = $o->depth + 1; + $child->owner_class = Mysqli::class; + $child->operator = Value::OPERATOR_OBJECT; + $child->name = $pname; + + if ($prop->isPublic()) { + $child->access = Value::ACCESS_PUBLIC; + } elseif ($prop->isProtected()) { // @codeCoverageIgnore + $child->access = Value::ACCESS_PROTECTED; // @codeCoverageIgnore + } elseif ($prop->isPrivate()) { // @codeCoverageIgnore + $child->access = Value::ACCESS_PRIVATE; // @codeCoverageIgnore + } + + // We only do base Mysqli properties so we don't need to worry about complex names + if ($this->parser->childHasPath($o, $child)) { + $child->access_path .= $o->access_path.'->'.$child->name; + } + + $basepropvalues[] = $this->parser->parse($param, $child); + } + + $o->value->contents = \array_merge($basepropvalues, $o->value->contents); } } } diff --git a/system/ThirdParty/Kint/Parser/Parser.php b/system/ThirdParty/Kint/Parser/Parser.php index b7f81c62186f..d658b092479d 100644 --- a/system/ThirdParty/Kint/Parser/Parser.php +++ b/system/ThirdParty/Kint/Parser/Parser.php @@ -27,11 +27,11 @@ use DomainException; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; -use Kint\Object\ResourceObject; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\ResourceValue; +use Kint\Zval\Value; use ReflectionObject; use stdClass; @@ -58,25 +58,22 @@ class Parser const TRIGGER_COMPLETE = 14; protected $caller_class; - protected $depth_limit = false; + protected $depth_limit = 0; protected $marker; - protected $object_hashes = array(); + protected $object_hashes = []; protected $parse_break = false; - protected $plugins = array(); + protected $plugins = []; /** - * @param false|int $depth_limit Maximum depth to parse data + * @param int $depth_limit Maximum depth to parse data * @param null|string $caller Caller class name */ - public function __construct($depth_limit = false, $caller = null) + public function __construct($depth_limit = 0, $caller = null) { $this->marker = \uniqid("kint\0", true); + $this->depth_limit = $depth_limit; $this->caller_class = $caller; - - if ($depth_limit) { - $this->depth_limit = $depth_limit; - } } /** @@ -99,9 +96,9 @@ public function getCallerClass() /** * Set the depth limit. * - * @param false|int $depth_limit Maximum depth to parse data + * @param int $depth_limit Maximum depth to parse data */ - public function setDepthLimit($depth_limit = false) + public function setDepthLimit($depth_limit = 0) { $this->noRecurseCall(); @@ -113,37 +110,15 @@ public function getDepthLimit() return $this->depth_limit; } - /** - * Disables the depth limit and parses a variable. - * - * This should not be used unless you know what you're doing! - * - * @param mixed $var The input variable - * @param BasicObject $o The base object - * - * @return BasicObject - */ - public function parseDeep(&$var, BasicObject $o) - { - $depth_limit = $this->depth_limit; - $this->depth_limit = false; - - $out = $this->parse($var, $o); - - $this->depth_limit = $depth_limit; - - return $out; - } - /** * Parses a variable into a Kint object structure. * - * @param mixed $var The input variable - * @param BasicObject $o The base object + * @param mixed $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - public function parse(&$var, BasicObject $o) + public function parse(&$var, Value $o) { $o->type = \strtolower(\gettype($var)); @@ -165,8 +140,10 @@ public function parse(&$var, BasicObject $o) return $this->parseResource($var, $o); case 'string': return $this->parseString($var, $o); + case 'unknown type': + case 'resource (closed)': default: - return $this->parseUnknown($var, $o); + return $this->parseResourceClosed($var, $o); } } @@ -184,12 +161,12 @@ public function addPlugin(Plugin $p) foreach ($types as $type) { if (!isset($this->plugins[$type])) { - $this->plugins[$type] = array( - self::TRIGGER_BEGIN => array(), - self::TRIGGER_SUCCESS => array(), - self::TRIGGER_RECURSION => array(), - self::TRIGGER_DEPTH_LIMIT => array(), - ); + $this->plugins[$type] = [ + self::TRIGGER_BEGIN => [], + self::TRIGGER_SUCCESS => [], + self::TRIGGER_RECURSION => [], + self::TRIGGER_DEPTH_LIMIT => [], + ]; } foreach ($this->plugins[$type] as $trigger => &$pool) { @@ -204,7 +181,7 @@ public function addPlugin(Plugin $p) public function clearPlugins() { - $this->plugins = array(); + $this->plugins = []; } public function haltParse() @@ -212,18 +189,18 @@ public function haltParse() $this->parse_break = true; } - public function childHasPath(InstanceObject $parent, BasicObject $child) + public function childHasPath(InstanceValue $parent, Value $child) { if ('object' === $parent->type && (null !== $parent->access_path || $child->static || $child->const)) { - if (BasicObject::ACCESS_PUBLIC === $child->access) { + if (Value::ACCESS_PUBLIC === $child->access) { return true; } - if (BasicObject::ACCESS_PRIVATE === $child->access && $this->caller_class) { + if (Value::ACCESS_PRIVATE === $child->access && $this->caller_class) { if ($this->caller_class === $child->owner_class) { return true; } - } elseif (BasicObject::ACCESS_PROTECTED === $child->access && $this->caller_class) { + } elseif (Value::ACCESS_PROTECTED === $child->access && $this->caller_class) { if ($this->caller_class === $child->owner_class) { return true; } @@ -262,9 +239,9 @@ protected function noRecurseCall() { $bt = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS); - $caller_frame = array( + $caller_frame = [ 'function' => __FUNCTION__, - ); + ]; while (isset($bt[0]['object']) && $bt[0]['object'] === $this) { $caller_frame = \array_shift($bt); @@ -277,7 +254,7 @@ protected function noRecurseCall() } } - private function parseGeneric(&$var, BasicObject $o) + private function parseGeneric(&$var, Value $o) { $rep = new Representation('Contents'); $rep->contents = $var; @@ -291,19 +268,19 @@ private function parseGeneric(&$var, BasicObject $o) } /** - * Parses a string into a Kint BlobObject structure. + * Parses a string into a Kint BlobValue structure. * - * @param string $var The input variable - * @param BasicObject $o The base object + * @param string $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseString(&$var, BasicObject $o) + private function parseString(&$var, Value $o) { - $string = new BlobObject(); + $string = new BlobValue(); $string->transplant($o); - $string->encoding = BlobObject::detectEncoding($var); - $string->size = BlobObject::strlen($var, $string->encoding); + $string->encoding = BlobValue::detectEncoding($var); + $string->size = \strlen($var); $rep = new Representation('Contents'); $rep->contents = $var; @@ -320,14 +297,14 @@ private function parseString(&$var, BasicObject $o) /** * Parses an array into a Kint object structure. * - * @param array $var The input variable - * @param BasicObject $o The base object + * @param array $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseArray(array &$var, BasicObject $o) + private function parseArray(array &$var, Value $o) { - $array = new BasicObject(); + $array = new Value(); $array->transplant($o); $array->size = \count($var); @@ -379,11 +356,11 @@ private function parseArray(array &$var, BasicObject $o) continue; } - $child = new BasicObject(); + $child = new Value(); $child->name = $key; $child->depth = $array->depth + 1; - $child->access = BasicObject::ACCESS_NONE; - $child->operator = BasicObject::OPERATOR_ARRAY; + $child->access = Value::ACCESS_NONE; + $child->operator = Value::OPERATOR_ARRAY; if (null !== $array->access_path) { if (\is_string($key) && (string) (int) $key === $key) { @@ -411,22 +388,22 @@ private function parseArray(array &$var, BasicObject $o) } /** - * Parses an object into a Kint InstanceObject structure. + * Parses an object into a Kint InstanceValue structure. * - * @param object $var The input variable - * @param BasicObject $o The base object + * @param object $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseObject(&$var, BasicObject $o) + private function parseObject(&$var, Value $o) { $hash = \spl_object_hash($var); $values = (array) $var; - $object = new InstanceObject(); + $object = new InstanceValue(); $object->transplant($o); $object->classname = \get_class($var); - $object->hash = $hash; + $object->spl_object_hash = $hash; $object->size = \count($values); if (isset($this->object_hashes[$hash])) { @@ -457,6 +434,48 @@ private function parseObject(&$var, BasicObject $o) $rep = new Representation('Properties'); + if (KINT_PHP74) { + $rprops = $reflector->getProperties(); + + foreach ($rprops as $rprop) { + if ($rprop->isStatic()) { + continue; + } + + $rprop->setAccessible(true); + if ($rprop->isInitialized($var)) { + continue; + } + + $undefined = null; + + $child = new Value(); + $child->type = 'undefined'; + $child->depth = $object->depth + 1; + $child->owner_class = $rprop->getDeclaringClass()->getName(); + $child->operator = Value::OPERATOR_OBJECT; + $child->name = $rprop->getName(); + + if ($rprop->isPublic()) { + $child->access = Value::ACCESS_PUBLIC; + } elseif ($rprop->isProtected()) { + $child->access = Value::ACCESS_PROTECTED; + } elseif ($rprop->isPrivate()) { + $child->access = Value::ACCESS_PRIVATE; + } + + // Can't dynamically add undefined properties, so no need to use var_export + if ($this->childHasPath($object, $child)) { + $child->access_path .= $object->access_path.'->'.$child->name; + } + + if ($this->applyPlugins($undefined, $child, self::TRIGGER_BEGIN)) { + $this->applyPlugins($undefined, $child, self::TRIGGER_SUCCESS); + } + $rep->contents[] = $child; + } + } + $copy = \array_values($values); $refmarker = new stdClass(); $i = 0; @@ -470,20 +489,20 @@ private function parseObject(&$var, BasicObject $o) // public properties show in the form "$property_name"; // http://www.php.net/manual/en/language.types.array.php#language.types.array.casting - $child = new BasicObject(); + $child = new Value(); $child->depth = $object->depth + 1; $child->owner_class = $object->classname; - $child->operator = BasicObject::OPERATOR_OBJECT; - $child->access = BasicObject::ACCESS_PUBLIC; + $child->operator = Value::OPERATOR_OBJECT; + $child->access = Value::ACCESS_PUBLIC; $split_key = \explode("\0", $key, 3); if (3 === \count($split_key) && '' === $split_key[0]) { $child->name = $split_key[2]; if ('*' === $split_key[1]) { - $child->access = BasicObject::ACCESS_PROTECTED; + $child->access = Value::ACCESS_PROTECTED; } else { - $child->access = BasicObject::ACCESS_PRIVATE; + $child->access = Value::ACCESS_PRIVATE; $child->owner_class = $split_key[1]; } } elseif (KINT_PHP72) { @@ -524,16 +543,16 @@ private function parseObject(&$var, BasicObject $o) } /** - * Parses a resource into a Kint ResourceObject structure. + * Parses a resource into a Kint ResourceValue structure. * - * @param resource $var The input variable - * @param BasicObject $o The base object + * @param resource $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseResource(&$var, BasicObject $o) + private function parseResource(&$var, Value $o) { - $resource = new ResourceObject(); + $resource = new ResourceValue(); $resource->transplant($o); $resource->resource_type = \get_resource_type($var); @@ -543,16 +562,16 @@ private function parseResource(&$var, BasicObject $o) } /** - * Parses an unknown into a Kint object structure. + * Parses a closed resource into a Kint object structure. * - * @param mixed $var The input variable - * @param BasicObject $o The base object + * @param mixed $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseUnknown(&$var, BasicObject $o) + private function parseResourceClosed(&$var, Value $o) { - $o->type = 'unknown'; + $o->type = 'resource (closed)'; $this->applyPlugins($var, $o, self::TRIGGER_SUCCESS); return $o; @@ -561,20 +580,20 @@ private function parseUnknown(&$var, BasicObject $o) /** * Applies plugins for an object type. * - * @param mixed $var variable - * @param BasicObject $o Kint object parsed so far - * @param int $trigger The trigger to check for the plugins + * @param mixed $var variable + * @param Value $o Kint object parsed so far + * @param int $trigger The trigger to check for the plugins * * @return bool Continue parsing */ - private function applyPlugins(&$var, BasicObject &$o, $trigger) + private function applyPlugins(&$var, Value &$o, $trigger) { $break_stash = $this->parse_break; /** @var bool Psalm bug workaround */ $this->parse_break = false; - $plugins = array(); + $plugins = []; if (isset($this->plugins[$o->type][$trigger])) { $plugins = $this->plugins[$o->type][$trigger]; diff --git a/system/ThirdParty/Kint/Parser/Plugin.php b/system/ThirdParty/Kint/Parser/Plugin.php index 51d5f0b1440b..981d2aa56e1b 100644 --- a/system/ThirdParty/Kint/Parser/Plugin.php +++ b/system/ThirdParty/Kint/Parser/Plugin.php @@ -25,7 +25,7 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; abstract class Plugin { @@ -43,7 +43,7 @@ public function setParser(Parser $p) */ public function getTypes() { - return array(); + return []; } public function getTriggers() @@ -51,5 +51,5 @@ public function getTriggers() return Parser::TRIGGER_NONE; } - abstract public function parse(&$variable, BasicObject &$o, $trigger); + abstract public function parse(&$var, Value &$o, $trigger); } diff --git a/system/ThirdParty/Kint/Parser/ProxyPlugin.php b/system/ThirdParty/Kint/Parser/ProxyPlugin.php index 3376d3aa9016..116f3883dbdb 100644 --- a/system/ThirdParty/Kint/Parser/ProxyPlugin.php +++ b/system/ThirdParty/Kint/Parser/ProxyPlugin.php @@ -26,7 +26,7 @@ namespace Kint\Parser; use InvalidArgumentException; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class ProxyPlugin extends Plugin { @@ -59,8 +59,8 @@ public function getTriggers() return $this->triggers; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - return \call_user_func_array($this->callback, array(&$var, &$o, $trigger, $this->parser)); + return \call_user_func_array($this->callback, [&$var, &$o, $trigger, $this->parser]); } } diff --git a/system/ThirdParty/Kint/Parser/SerializePlugin.php b/system/ThirdParty/Kint/Parser/SerializePlugin.php index c5dadb88d9de..5924483fc50e 100644 --- a/system/ThirdParty/Kint/Parser/SerializePlugin.php +++ b/system/ThirdParty/Kint/Parser/SerializePlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class SerializePlugin extends Plugin { @@ -45,11 +45,11 @@ class SerializePlugin extends Plugin * @var bool */ public static $safe_mode = true; - public static $options = array(true); + public static $options = [true]; public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -57,7 +57,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $trimmed = \rtrim($var); @@ -65,7 +65,7 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - if (!self::$safe_mode || !\in_array($trimmed[0], array('C', 'O', 'a'), true)) { + if (!self::$safe_mode || !\in_array($trimmed[0], ['C', 'O', 'a'], true)) { // Second parameter only supported on PHP 7 if (KINT_PHP70) { // Suppress warnings on unserializeable variable @@ -79,15 +79,15 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = 'unserialize('.$o->name.')'; if ($o->access_path) { $base_obj->access_path = 'unserialize('.$o->access_path; - if (!KINT_PHP70 || self::$options === array(true)) { + if (!KINT_PHP70 || self::$options === [true]) { $base_obj->access_path .= ')'; - } elseif (self::$options === array(false)) { + } elseif (self::$options === [false]) { $base_obj->access_path .= ', false)'; } else { $base_obj->access_path .= ', Serialize::$options)'; diff --git a/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php b/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php index b90c863f8873..9e44e5388ec8 100644 --- a/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php +++ b/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php @@ -25,9 +25,10 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\BlobValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\SimpleXMLElementValue; +use Kint\Zval\Value; use SimpleXMLElement; class SimpleXMLElementPlugin extends Plugin @@ -41,7 +42,7 @@ class SimpleXMLElementPlugin extends Plugin public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -49,106 +50,168 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SimpleXMLElement) { return; } - $o->hints[] = 'simplexml_element'; - if (!self::$verbose) { $o->removeRepresentation('properties'); $o->removeRepresentation('iterator'); $o->removeRepresentation('methods'); } + // An invalid SimpleXMLElement can gum up the works with + // warnings if we call stuff children/attributes on it. + if (!$var) { + $o->size = null; + + return; + } + + $x = new SimpleXMLElementValue(); + $x->transplant($o); + + $namespaces = \array_merge([null], $var->getDocNamespaces()); + // Attributes $a = new Representation('Attributes'); - $base_obj = new BasicObject(); - $base_obj->depth = $o->depth; + $base_obj = new Value(); + $base_obj->depth = $x->depth; - if ($o->access_path) { - $base_obj->access_path = '(string) '.$o->access_path; + if ($x->access_path) { + $base_obj->access_path = '(string) '.$x->access_path; } - if ($attribs = $var->attributes()) { - $attribs = \iterator_to_array($attribs); - $attribs = \array_map('strval', $attribs); - } else { - $attribs = array(); + // Attributes are strings. If we're too deep set the + // depth limit to enable parsing them, but no deeper. + if ($this->parser->getDepthLimit() && $this->parser->getDepthLimit() - 2 < $base_obj->depth) { + $base_obj->depth = $this->parser->getDepthLimit() - 2; } - // XML attributes are by definition strings and don't have children, - // so up the depth limit in case we're just below the limit since - // there won't be any recursive stuff anyway. - $a->contents = $this->parser->parseDeep($attribs, $base_obj)->value->contents; + $attribs = []; - $o->addRepresentation($a, 0); + foreach ($namespaces as $nsAlias => $nsUrl) { + if ($nsAttribs = $var->attributes($nsUrl)) { + $cleanAttribs = []; + foreach ($nsAttribs as $name => $attrib) { + $cleanAttribs[(string) $name] = $attrib; + } - // Children - // We need to check children() separately from the values we already parsed because - // text contents won't show up in children() but they will show up in properties. - // - // Why do we still need to check for attributes if we already have an attributes() - // method? Hell if I know! - $children = $var->children(); - - if ($o->value) { - $c = new Representation('Children'); - - foreach ($o->value->contents as $value) { - if ('@attributes' === $value->name) { - continue; + if (null === $nsUrl) { + $obj = clone $base_obj; + if ($obj->access_path) { + $obj->access_path .= '->attributes()'; + } + + $a->contents = $this->parser->parse($cleanAttribs, $obj)->value->contents; + } else { + $obj = clone $base_obj; + if ($obj->access_path) { + $obj->access_path .= '->attributes('.\var_export($nsAlias, true).', true)'; + } + + $cleanAttribs = $this->parser->parse($cleanAttribs, $obj)->value->contents; + + foreach ($cleanAttribs as $attribute) { + $attribute->name = $nsAlias.':'.$attribute->name; + $a->contents[] = $attribute; + } } + } + } + + $x->addRepresentation($a, 0); - if (isset($children->{$value->name})) { - $i = 0; + // Children + $c = new Representation('Children'); + + foreach ($namespaces as $nsAlias => $nsUrl) { + // This is doubling items because of the root namespace + // and the implicit namespace on its children. + $thisNs = $var->getNamespaces(); + if (isset($thisNs['']) && $thisNs[''] === $nsUrl) { + continue; + } - while (isset($children->{$value->name}[$i])) { - $base_obj = new BasicObject(); - $base_obj->depth = $o->depth + 1; - $base_obj->name = $value->name; - if ($value->access_path) { - $base_obj->access_path = $value->access_path.'['.$i.']'; + if ($nsChildren = $var->children($nsUrl)) { + $nsap = []; + foreach ($nsChildren as $name => $child) { + $obj = new Value(); + $obj->depth = $x->depth + 1; + $obj->name = (string) $name; + if ($x->access_path) { + if (null === $nsUrl) { + $obj->access_path = $x->access_path.'->children()->'; + } else { + $obj->access_path = $x->access_path.'->children('.\var_export($nsAlias, true).', true)->'; } - $value = $this->parser->parse($children->{$value->name}[$i], $base_obj); + if (\preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]+$/', (string) $name)) { + $obj->access_path .= (string) $name; + } else { + $obj->access_path .= '{'.\var_export((string) $name, true).'}'; + } - if ($value->access_path && 'string' === $value->type) { - $value->access_path = '(string) '.$value->access_path; + if (isset($nsap[$obj->access_path])) { + ++$nsap[$obj->access_path]; + $obj->access_path .= '['.$nsap[$obj->access_path].']'; + } else { + $nsap[$obj->access_path] = 0; } + } - $c->contents[] = $value; + $value = $this->parser->parse($child, $obj); - ++$i; + if ($value->access_path && 'string' === $value->type) { + $value->access_path = '(string) '.$value->access_path; } + + $c->contents[] = $value; } } + } - $o->size = \count($c->contents); + $x->size = \count($c->contents); - if (!$o->size) { - $o->size = null; + if ($x->size) { + $x->addRepresentation($c, 0); + } else { + $x->size = null; + + if (\strlen((string) $var)) { + $base_obj = new BlobValue(); + $base_obj->depth = $x->depth + 1; + $base_obj->name = $x->name; + if ($x->access_path) { + $base_obj->access_path = '(string) '.$x->access_path; + } + + $value = (string) $var; + + $s = $this->parser->parse($value, $base_obj); + $srep = $s->getRepresentation('contents'); + $svalrep = $s->value && 'contents' == $s->value->getName() ? $s : null; - if (\strlen((string) $var)) { - $base_obj = new BlobObject(); - $base_obj->depth = $o->depth + 1; - $base_obj->name = $o->name; - if ($o->access_path) { - $base_obj->access_path = '(string) '.$o->access_path; + if ($srep || $svalrep) { + $x->setIsStringValue(true); + $x->value = $srep ?: $svalrep; + + if ($srep) { + $x->replaceRepresentation($x->value, 0); } + } - $value = (string) $var; + $reps = \array_reverse($s->getRepresentations()); - $c = new Representation('Contents'); - $c->implicit_label = true; - $c->contents = array($this->parser->parseDeep($value, $base_obj)); + foreach ($reps as $rep) { + $x->addRepresentation($rep, 0); } } - - $o->addRepresentation($c, 0); } + + $o = $x; } } diff --git a/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php b/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php index 8b72193bc369..ada3e1fb8e85 100644 --- a/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php +++ b/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SplFileInfoRepresentation; +use Kint\Zval\Representation\SplFileInfoRepresentation; +use Kint\Zval\Value; use SplFileInfo; use SplFileObject; @@ -34,7 +34,7 @@ class SplFileInfoPlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -42,7 +42,7 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SplFileInfo || $var instanceof SplFileObject) { return; diff --git a/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php b/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php index 03ff301d3477..359774d3bfff 100644 --- a/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php +++ b/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; use SplObjectStorage; class SplObjectStoragePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SplObjectStorage || !($r = $o->getRepresentation('iterator'))) { return; diff --git a/system/ThirdParty/Kint/Parser/StreamPlugin.php b/system/ThirdParty/Kint/Parser/StreamPlugin.php index 464a3fff12c5..76608d94a6a6 100644 --- a/system/ThirdParty/Kint/Parser/StreamPlugin.php +++ b/system/ThirdParty/Kint/Parser/StreamPlugin.php @@ -25,16 +25,16 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; -use Kint\Object\ResourceObject; -use Kint\Object\StreamObject; +use Kint\Zval\Representation\Representation; +use Kint\Zval\ResourceValue; +use Kint\Zval\StreamValue; +use Kint\Zval\Value; class StreamPlugin extends Plugin { public function getTypes() { - return array('resource'); + return ['resource']; } public function getTriggers() @@ -42,20 +42,23 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof ResourceObject || 'stream' !== $o->resource_type) { + if (!$o instanceof ResourceValue || 'stream' !== $o->resource_type) { return; } - if (!$meta = \stream_get_meta_data($var)) { + // Doublecheck that the resource is open before we get the metadata + if (!\is_resource($var)) { return; } + $meta = \stream_get_meta_data($var); + $rep = new Representation('Stream'); $rep->implicit_label = true; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { @@ -71,7 +74,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $o->addRepresentation($rep, 0); $o->value = $rep; - $stream = new StreamObject($meta); + $stream = new StreamValue($meta); $stream->transplant($o); $o = $stream; } diff --git a/system/ThirdParty/Kint/Parser/TablePlugin.php b/system/ThirdParty/Kint/Parser/TablePlugin.php index 510c4ff0ef86..c6ca6e248d68 100644 --- a/system/ThirdParty/Kint/Parser/TablePlugin.php +++ b/system/ThirdParty/Kint/Parser/TablePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class TablePlugin extends Plugin { public function getTypes() { - return array('array'); + return ['array']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (empty($o->value->contents)) { return; diff --git a/system/ThirdParty/Kint/Parser/ThrowablePlugin.php b/system/ThirdParty/Kint/Parser/ThrowablePlugin.php index 8490d1d41a1a..ea343e96ee78 100644 --- a/system/ThirdParty/Kint/Parser/ThrowablePlugin.php +++ b/system/ThirdParty/Kint/Parser/ThrowablePlugin.php @@ -26,16 +26,16 @@ namespace Kint\Parser; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SourceRepresentation; -use Kint\Object\ThrowableObject; +use Kint\Zval\Representation\SourceRepresentation; +use Kint\Zval\ThrowableValue; +use Kint\Zval\Value; use Throwable; class ThrowablePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -43,13 +43,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Exception && (!KINT_PHP70 || !$var instanceof Throwable)) { return; } - $throw = new ThrowableObject($var); + $throw = new ThrowableValue($var); $throw->transplant($o); $r = new SourceRepresentation($var->getFile(), $var->getLine()); $r->showfilename = true; diff --git a/system/ThirdParty/Kint/Parser/TimestampPlugin.php b/system/ThirdParty/Kint/Parser/TimestampPlugin.php index 72958d6465c0..fa8d743dea89 100644 --- a/system/ThirdParty/Kint/Parser/TimestampPlugin.php +++ b/system/ThirdParty/Kint/Parser/TimestampPlugin.php @@ -25,20 +25,20 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class TimestampPlugin extends Plugin { - public static $blacklist = array( + public static $blacklist = [ 2147483648, 2147483647, 1073741824, 1073741823, - ); + ]; public function getTypes() { - return array('string', 'integer'); + return ['string', 'integer']; } public function getTriggers() @@ -46,7 +46,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\is_string($var) && !\ctype_digit($var)) { return; @@ -56,7 +56,7 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - $len = \strlen($var); + $len = \strlen((string) $var); // Guess for anything between March 1973 and November 2286 if (9 === $len || 10 === $len) { diff --git a/system/ThirdParty/Kint/Parser/ToStringPlugin.php b/system/ThirdParty/Kint/Parser/ToStringPlugin.php index 8b7a65fe60f5..d13cb29cc93b 100644 --- a/system/ThirdParty/Kint/Parser/ToStringPlugin.php +++ b/system/ThirdParty/Kint/Parser/ToStringPlugin.php @@ -25,20 +25,20 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; class ToStringPlugin extends Plugin { - public static $blacklist = array( + public static $blacklist = [ 'SimpleXMLElement', 'SplFileObject', - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -46,7 +46,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $reflection = new ReflectionClass($var); if (!$reflection->hasMethod('__toString')) { diff --git a/system/ThirdParty/Kint/Parser/TracePlugin.php b/system/ThirdParty/Kint/Parser/TracePlugin.php index 3554993dd2e1..ccdcadec59a8 100644 --- a/system/ThirdParty/Kint/Parser/TracePlugin.php +++ b/system/ThirdParty/Kint/Parser/TracePlugin.php @@ -25,18 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\TraceFrameObject; -use Kint\Object\TraceObject; use Kint\Utils; +use Kint\Zval\TraceFrameValue; +use Kint\Zval\TraceValue; +use Kint\Zval\Value; class TracePlugin extends Plugin { - public static $blacklist = array('spl_autoload_call'); + public static $blacklist = ['spl_autoload_call']; + public static $path_blacklist = []; public function getTypes() { - return array('array'); + return ['array']; } public function getTriggers() @@ -44,27 +45,29 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$o->value) { return; } + /** @var array[] $trace Psalm workaround */ $trace = $this->parser->getCleanArray($var); if (\count($trace) !== \count($o->value->contents) || !Utils::isTrace($trace)) { return; } - $traceobj = new TraceObject(); + $traceobj = new TraceValue(); $traceobj->transplant($o); $rep = $traceobj->value; $old_trace = $rep->contents; Utils::normalizeAliases(self::$blacklist); + $path_blacklist = self::normalizePaths(self::$path_blacklist); - $rep->contents = array(); + $rep->contents = []; foreach ($old_trace as $frame) { $index = $frame->name; @@ -78,7 +81,16 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } - $rep->contents[$index] = new TraceFrameObject($frame, $trace[$index]); + if (isset($trace[$index]['file'])) { + $realfile = \realpath($trace[$index]['file']); + foreach ($path_blacklist as $path) { + if (0 === \strpos($realfile, $path)) { + continue 2; + } + } + } + + $rep->contents[$index] = new TraceFrameValue($frame, $trace[$index]); } \ksort($rep->contents); @@ -89,4 +101,20 @@ public function parse(&$var, BasicObject &$o, $trigger) $traceobj->size = \count($rep->contents); $o = $traceobj; } + + protected static function normalizePaths(array $paths) + { + $normalized = []; + + foreach ($paths as $path) { + $realpath = \realpath($path); + if (\is_dir($realpath)) { + $realpath .= DIRECTORY_SEPARATOR; + } + + $normalized[] = $realpath; + } + + return $normalized; + } } diff --git a/system/ThirdParty/Kint/Parser/XmlPlugin.php b/system/ThirdParty/Kint/Parser/XmlPlugin.php index 0947e9a6cb14..a4fa2b0c21c8 100644 --- a/system/ThirdParty/Kint/Parser/XmlPlugin.php +++ b/system/ThirdParty/Kint/Parser/XmlPlugin.php @@ -27,8 +27,8 @@ use DOMDocument; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class XmlPlugin extends Plugin { @@ -45,7 +45,7 @@ class XmlPlugin extends Plugin public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -53,7 +53,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if ('access_path); + $xml = \call_user_func([\get_class($this), 'xmlTo'.self::$parse_method], $var, $o->access_path); if (empty($xml)) { return; @@ -71,7 +71,7 @@ public function parse(&$var, BasicObject &$o, $trigger) list($xml, $access_path, $name) = $xml; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = $name; $base_obj->access_path = $access_path; @@ -96,7 +96,7 @@ protected static function xmlToSimpleXML($var, $parent_path) return; } - if (!$xml) { + if (false === $xml) { return; } @@ -108,7 +108,7 @@ protected static function xmlToSimpleXML($var, $parent_path) $name = $xml->getName(); - return array($xml, $access_path, $name); + return [$xml, $access_path, $name]; } /** @@ -135,16 +135,23 @@ protected static function xmlToDOMDocument($var, $parent_path) $xml = new DOMDocument(); $xml->loadXML($var); - $xml = $xml->firstChild; + + if ($xml->childNodes->count() > 1) { + $xml = $xml->childNodes; + $access_path = 'childNodes'; + } else { + $xml = $xml->firstChild; + $access_path = 'firstChild'; + } if (null === $parent_path) { $access_path = null; } else { - $access_path = '@\\DOMDocument::loadXML('.$parent_path.')->firstChild'; + $access_path = '(function($s){$x = new \\DomDocument(); $x->loadXML($s); return $x;})('.$parent_path.')->'.$access_path; } - $name = $xml->nodeName; + $name = isset($xml->nodeName) ? $xml->nodeName : null; - return array($xml, $access_path, $name); + return [$xml, $access_path, $name]; } } diff --git a/system/ThirdParty/Kint/Renderer/CliRenderer.php b/system/ThirdParty/Kint/Renderer/CliRenderer.php index 0d0846a411c3..f86671ff1cf3 100644 --- a/system/ThirdParty/Kint/Renderer/CliRenderer.php +++ b/system/ThirdParty/Kint/Renderer/CliRenderer.php @@ -25,7 +25,9 @@ namespace Kint\Renderer; -use Kint\Object\BasicObject; +use Exception; +use Kint\Zval\Value; +use Throwable; class CliRenderer extends TextRenderer { @@ -73,7 +75,13 @@ public function __construct() if (!self::$terminal_width) { if (!KINT_WIN && self::$detect_width) { - self::$terminal_width = \exec('tput cols'); + try { + self::$terminal_width = \exec('tput cols'); + } catch (Exception $e) { + self::$terminal_width = self::$default_width; + } catch (Throwable $t) { + self::$terminal_width = self::$default_width; + } } if (self::$terminal_width < self::$min_terminal_width) { @@ -113,7 +121,7 @@ public function colorTitle($string) return "\x1b[36m".\str_replace("\n", "\x1b[0m\n\x1b[36m", $string)."\x1b[0m"; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { if ($this->windows_output) { return $this->utf8ToWindows(parent::renderTitle($o)); @@ -144,8 +152,8 @@ public function escape($string, $encoding = false) protected function utf8ToWindows($string) { return \str_replace( - array('┌', '═', '┐', '│', '└', '─', '┘'), - array("\xda", "\xdc", "\xbf", "\xb3", "\xc0", "\xc4", "\xd9"), + ['┌', '═', '┐', '│', '└', '─', '┘'], + ["\xda", "\xdc", "\xbf", "\xb3", "\xc0", "\xc4", "\xd9"], $string ); } diff --git a/system/ThirdParty/Kint/Renderer/PlainRenderer.php b/system/ThirdParty/Kint/Renderer/PlainRenderer.php index 493a7743bed4..4b8102a4750f 100644 --- a/system/ThirdParty/Kint/Renderer/PlainRenderer.php +++ b/system/ThirdParty/Kint/Renderer/PlainRenderer.php @@ -26,21 +26,21 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; +use Kint\Zval\Value; class PlainRenderer extends TextRenderer { - public static $pre_render_sources = array( - 'script' => array( - array('Kint\\Renderer\\PlainRenderer', 'renderJs'), - array('Kint\\Renderer\\Text\\MicrotimePlugin', 'renderJs'), - ), - 'style' => array( - array('Kint\\Renderer\\PlainRenderer', 'renderCss'), - ), - 'raw' => array(), - ); + public static $pre_render_sources = [ + 'script' => [ + ['Kint\\Renderer\\PlainRenderer', 'renderJs'], + ['Kint\\Renderer\\Text\\MicrotimePlugin', 'renderJs'], + ], + 'style' => [ + ['Kint\\Renderer\\PlainRenderer', 'renderCss'], + ], + 'raw' => [], + ]; /** * Path to the CSS file to load by default. @@ -118,7 +118,7 @@ public function colorTitle($string) return ''.$string.''; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { if (self::$disable_utf8) { return $this->utf8ToHtmlentity(parent::renderTitle($o)); @@ -193,7 +193,7 @@ public function ideLink($file, $line) public function escape($string, $encoding = false) { if (false === $encoding) { - $encoding = BlobObject::detectEncoding($string); + $encoding = BlobValue::detectEncoding($string); } $original_encoding = $encoding; @@ -206,7 +206,7 @@ public function escape($string, $encoding = false) // this call converts all non-ASCII characters into numeirc htmlentities if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) { - $string = \mb_encode_numericentity($string, array(0x80, 0xffff, 0, 0xffff), $encoding); + $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding); } return $string; @@ -215,8 +215,8 @@ public function escape($string, $encoding = false) protected function utf8ToHtmlentity($string) { return \str_replace( - array('┌', '═', '┐', '│', '└', '─', '┘'), - array('┌', '═', '┐', '│', '└', '─', '┘'), + ['┌', '═', '┐', '│', '└', '─', '┘'], + ['┌', '═', '┐', '│', '└', '─', '┘'], $string ); } diff --git a/system/ThirdParty/Kint/Renderer/Renderer.php b/system/ThirdParty/Kint/Renderer/Renderer.php index cf8b0a781179..0ed7ce0895b5 100644 --- a/system/ThirdParty/Kint/Renderer/Renderer.php +++ b/system/ThirdParty/Kint/Renderer/Renderer.php @@ -25,8 +25,8 @@ namespace Kint\Renderer; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; abstract class Renderer { @@ -34,11 +34,11 @@ abstract class Renderer const SORT_VISIBILITY = 1; const SORT_FULL = 2; - protected $call_info = array(); - protected $statics = array(); + protected $call_info = []; + protected $statics = []; protected $show_trace = true; - abstract public function render(BasicObject $o); + abstract public function render(Value $o); abstract public function renderNothing(); @@ -49,7 +49,7 @@ public function setCallInfo(array $info) } if (!isset($info['modifiers']) || !\is_array($info['modifiers'])) { - $info['modifiers'] = array(); + $info['modifiers'] = []; } if (!isset($info['callee'])) { @@ -61,16 +61,16 @@ public function setCallInfo(array $info) } if (!isset($info['trace']) || !\is_array($info['trace'])) { - $info['trace'] = array(); + $info['trace'] = []; } - $this->call_info = array( + $this->call_info = [ 'params' => $info['params'], 'modifiers' => $info['modifiers'], 'callee' => $info['callee'], 'caller' => $info['caller'], 'trace' => $info['trace'], - ); + ]; } public function getCallInfo() @@ -109,7 +109,7 @@ public function getShowTrace() */ public function matchPlugins(array $plugins, array $hints) { - $out = array(); + $out = []; foreach ($hints as $key) { if (isset($plugins[$key])) { @@ -135,40 +135,40 @@ public function postRender() return ''; } - public static function sortPropertiesFull(BasicObject $a, BasicObject $b) + public static function sortPropertiesFull(Value $a, Value $b) { - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - $sort = BasicObject::sortByName($a, $b); + $sort = Value::sortByName($a, $b); if ($sort) { return $sort; } - return InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + return InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); } /** - * Sorts an array of BasicObject. + * Sorts an array of Value. * - * @param BasicObject[] $contents Object properties to sort - * @param int $sort + * @param Value[] $contents Object properties to sort + * @param int $sort * - * @return BasicObject[] + * @return Value[] */ public static function sortProperties(array $contents, $sort) { switch ($sort) { case self::SORT_VISIBILITY: - /** @var array Containers to quickly stable sort by type */ - $containers = array( - BasicObject::ACCESS_PUBLIC => array(), - BasicObject::ACCESS_PROTECTED => array(), - BasicObject::ACCESS_PRIVATE => array(), - BasicObject::ACCESS_NONE => array(), - ); + // Containers to quickly stable sort by type + $containers = [ + Value::ACCESS_PUBLIC => [], + Value::ACCESS_PROTECTED => [], + Value::ACCESS_PRIVATE => [], + Value::ACCESS_NONE => [], + ]; foreach ($contents as $item) { $containers[$item->access][] = $item; @@ -176,7 +176,7 @@ public static function sortProperties(array $contents, $sort) return \call_user_func_array('array_merge', $containers); case self::SORT_FULL: - \usort($contents, array('Kint\\Renderer\\Renderer', 'sortPropertiesFull')); + \usort($contents, ['Kint\\Renderer\\Renderer', 'sortPropertiesFull']); // no break default: return $contents; diff --git a/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php new file mode 100644 index 000000000000..e6ebe569b85e --- /dev/null +++ b/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php @@ -0,0 +1,36 @@ +'.$this->renderLockedHeader($o, 'Array Limit').''; + } +} diff --git a/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php index 5b4d613fdce6..b12690a49969 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php @@ -25,7 +25,7 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; class BinaryPlugin extends Plugin implements TabPluginInterface { @@ -36,12 +36,17 @@ public function renderTab(Representation $r) { $out = '
';
 
-        $chunks = \str_split($r->contents, self::$line_length);
+        /** @var string[] Psalm bug workaround */
+        $lines = \str_split($r->contents, self::$line_length);
 
-        foreach ($chunks as $index => $chunk) {
+        foreach ($lines as $index => $line) {
             $out .= \sprintf('%08X', $index * self::$line_length).":\t";
-            $out .= \implode(' ', \str_split(\str_pad(\bin2hex($chunk), 2 * self::$line_length, ' '), self::$chunk_length));
-            $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $chunk)."\n";
+
+            /** @var string[] Psalm bug workaround */
+            $chunks = \str_split(\str_pad(\bin2hex($line), 2 * self::$line_length, ' '), self::$chunk_length);
+
+            $out .= \implode(' ', $chunks);
+            $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $line)."\n";
         }
 
         $out .= '
'; diff --git a/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php index fcfedc1a00be..ed7f4ec96495 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class BlacklistPlugin extends Plugin implements ObjectPluginInterface +class BlacklistPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
'.$this->renderLockedHeader($o, 'Blacklisted').'
'; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php index 5834017ba550..b28b56a07ad1 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php @@ -25,30 +25,30 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\ClosureObject; -use Kint\Object\MethodObject; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\ClosureValue; +use Kint\Zval\MethodValue; +use Kint\Zval\Value; -class CallablePlugin extends Plugin implements ObjectPluginInterface +class CallablePlugin extends Plugin implements ValuePluginInterface { - protected static $method_cache = array(); + protected static $method_cache = []; - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { - if ($o instanceof MethodObject) { + if ($o instanceof MethodValue) { return $this->renderMethod($o); } - if ($o instanceof ClosureObject) { + if ($o instanceof ClosureValue) { return $this->renderClosure($o); } return $this->renderCallable($o); } - protected function renderClosure(ClosureObject $o) + protected function renderClosure(ClosureValue $o) { $children = $this->renderer->renderChildren($o); @@ -63,8 +63,8 @@ protected function renderClosure(ClosureObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } @@ -72,7 +72,7 @@ protected function renderClosure(ClosureObject $o) return '
'.$this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header).$children.'
'; } - protected function renderCallable(BasicObject $o) + protected function renderCallable(Value $o) { $children = $this->renderer->renderChildren($o); @@ -87,8 +87,8 @@ protected function renderCallable(BasicObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } @@ -96,7 +96,7 @@ protected function renderCallable(BasicObject $o) return '
'.$this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header).$children.'
'; } - protected function renderMethod(MethodObject $o) + protected function renderMethod(MethodValue $o) { if (!empty(self::$method_cache[$o->owner_class][$o->name])) { $children = self::$method_cache[$o->owner_class][$o->name]['children']; @@ -154,17 +154,17 @@ protected function renderMethod(MethodObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } if (\strlen($o->owner_class) && \strlen($o->name)) { - self::$method_cache[$o->owner_class][$o->name] = array( + self::$method_cache[$o->owner_class][$o->name] = [ 'header' => $header, 'children' => $children, - ); + ]; } $header = $this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header); diff --git a/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php index 79a9926cab7f..44813e3ef89f 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php @@ -26,16 +26,16 @@ namespace Kint\Renderer\Rich; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\ClosureObject; +use Kint\Zval\ClosureValue; +use Kint\Zval\Value; -class ClosurePlugin extends Plugin implements ObjectPluginInterface +class ClosurePlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $children = $this->renderer->renderChildren($o); - if (!($o instanceof ClosureObject)) { + if (!($o instanceof ClosureValue)) { $header = $this->renderer->renderHeader($o); } else { $header = ''; diff --git a/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php index 241a8154f430..ebd02cb59e24 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php @@ -25,13 +25,13 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\Representation\ColorRepresentation; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\ColorRepresentation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; -class ColorPlugin extends Plugin implements TabPluginInterface, ObjectPluginInterface +class ColorPlugin extends Plugin implements TabPluginInterface, ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $r = $o->getRepresentation('color'); @@ -92,7 +92,7 @@ public function renderTab(Representation $r) } if (!\strlen($out)) { - return false; + return; } return '
'.$out.'
'; diff --git a/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php index cd92b417985c..69808c7c3e1d 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class DepthLimitPlugin extends Plugin implements ObjectPluginInterface +class DepthLimitPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
'.$this->renderLockedHeader($o, 'Depth Limit').'
'; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php index 19c530951c4d..cb53a74fb182 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php @@ -26,25 +26,25 @@ namespace Kint\Renderer\Rich; use Kint\Kint; -use Kint\Object\Representation\DocstringRepresentation; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\DocstringRepresentation; +use Kint\Zval\Representation\Representation; class DocstringPlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof DocstringRepresentation)) { - return false; + return; } - $docstring = array(); + $docstring = []; foreach (\explode("\n", $r->contents) as $line) { $docstring[] = \trim($line); } $docstring = \implode("\n", $docstring); - $location = array(); + $location = []; if ($r->class) { $location[] = 'Inherited from '.$this->renderer->escape($r->class); diff --git a/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php index a56bb23ef53a..3d06b529252b 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php @@ -25,16 +25,16 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\MicrotimeRepresentation; -use Kint\Object\Representation\Representation; use Kint\Utils; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Representation\Representation; class MicrotimePlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof MicrotimeRepresentation)) { - return false; + return; } $out = $r->getDateTime()->format('Y-m-d H:i:s.u'); diff --git a/system/ThirdParty/Kint/Renderer/Rich/Plugin.php b/system/ThirdParty/Kint/Renderer/Rich/Plugin.php index 06710bcc45c2..58e22cb276f4 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/Plugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; use Kint\Renderer\RichRenderer; +use Kint\Zval\Value; abstract class Plugin implements PluginInterface { @@ -40,10 +40,9 @@ public function __construct(RichRenderer $r) /** * Renders a locked header. * - * @param BasicObject $o - * @param string $content + * @param string $content */ - public function renderLockedHeader(BasicObject $o, $content) + public function renderLockedHeader(Value $o, $content) { $header = '
'; diff --git a/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php index 618d2176d917..baad2ecb57b8 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class RecursionPlugin extends Plugin implements ObjectPluginInterface +class RecursionPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
'.$this->renderLockedHeader($o, 'Recursion').'
'; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php index 6c18931ee7af..718cd67aace3 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php @@ -25,13 +25,13 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\Value; -class SimpleXMLElementPlugin extends Plugin implements ObjectPluginInterface +class SimpleXMLElementPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $children = $this->renderer->renderChildren($o); @@ -63,15 +63,11 @@ public function renderObject(BasicObject $o) $header .= '('.$this->renderer->escape($s).') '; } - if (null === $s && $c = $o->getRepresentation('contents')) { - $c = \reset($c->contents); - - if ($c && null !== ($s = $c->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; - } - $header .= $this->renderer->escape($s); + if (null !== ($s = $o->getValueShort())) { + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } + $header .= $this->renderer->escape($s); } $header = $this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header); diff --git a/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php index 5443dbfd9a8e..4be024b627b2 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php @@ -25,15 +25,15 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; -use Kint\Object\Representation\SourceRepresentation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Representation\SourceRepresentation; class SourcePlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof SourceRepresentation) || empty($r->source)) { - return false; + return; } $source = $r->source; diff --git a/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php b/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php index 7cdbde72d2ad..779e13acd3a9 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php @@ -25,9 +25,12 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; interface TabPluginInterface extends PluginInterface { - public function renderTab(Representation $o); + /** + * @return null|string + */ + public function renderTab(Representation $r); } diff --git a/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php index cc3ee0f05da7..ac345a167f9d 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php @@ -25,9 +25,9 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BlobObject; -use Kint\Object\Representation\Representation; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\Representation\Representation; class TablePlugin extends Plugin implements TabPluginInterface { @@ -89,8 +89,8 @@ public function renderTab(Representation $r) case 'string': if ($field->encoding) { $val = $field->value->contents; - if (RichRenderer::$strlen_max && self::$respect_str_length && BlobObject::strlen($val) > RichRenderer::$strlen_max) { - $val = \substr($val, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max && self::$respect_str_length) { + $val = Utils::truncateString($val, RichRenderer::$strlen_max); } $out .= $this->renderer->escape($val); diff --git a/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php index 6e3a2f8c5c83..f0c58e67a3cc 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php @@ -27,7 +27,7 @@ use DateTime; use DateTimeZone; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; class TimestampPlugin extends Plugin implements TabPluginInterface { diff --git a/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php index 6ca19bb67157..ea7048bcdd09 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\TraceFrameObject; +use Kint\Zval\TraceFrameValue; +use Kint\Zval\Value; -class TraceFramePlugin extends Plugin implements ObjectPluginInterface +class TraceFramePlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { - if (!$o instanceof TraceFrameObject) { + if (!$o instanceof TraceFrameValue) { return; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php b/system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php similarity index 88% rename from system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php rename to system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php index f46aa2946ea3..8f750eda6bad 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php @@ -25,9 +25,12 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -interface ObjectPluginInterface extends PluginInterface +interface ValuePluginInterface extends PluginInterface { - public function renderObject(BasicObject $o); + /** + * @return null|string + */ + public function renderValue(Value $o); } diff --git a/system/ThirdParty/Kint/Renderer/RichRenderer.php b/system/ThirdParty/Kint/Renderer/RichRenderer.php index dcd39eec8c53..94b7f98ab71f 100644 --- a/system/ThirdParty/Kint/Renderer/RichRenderer.php +++ b/system/ThirdParty/Kint/Renderer/RichRenderer.php @@ -26,18 +26,19 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; use Kint\Utils; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class RichRenderer extends Renderer { /** - * RichRenderer object plugins should implement Kint\Renderer\Rich\ObjectPluginInterface. + * RichRenderer value plugins should implement Kint\Renderer\Rich\ValuePluginInterface. */ - public static $object_plugins = array( + public static $value_plugins = [ + 'array_limit' => 'Kint\\Renderer\\Rich\\ArrayLimitPlugin', 'blacklist' => 'Kint\\Renderer\\Rich\\BlacklistPlugin', 'callable' => 'Kint\\Renderer\\Rich\\CallablePlugin', 'closure' => 'Kint\\Renderer\\Rich\\ClosurePlugin', @@ -46,12 +47,12 @@ class RichRenderer extends Renderer 'recursion' => 'Kint\\Renderer\\Rich\\RecursionPlugin', 'simplexml_element' => 'Kint\\Renderer\\Rich\\SimpleXMLElementPlugin', 'trace_frame' => 'Kint\\Renderer\\Rich\\TraceFramePlugin', - ); + ]; /** * RichRenderer tab plugins should implement Kint\Renderer\Rich\TabPluginInterface. */ - public static $tab_plugins = array( + public static $tab_plugins = [ 'binary' => 'Kint\\Renderer\\Rich\\BinaryPlugin', 'color' => 'Kint\\Renderer\\Rich\\ColorPlugin', 'docstring' => 'Kint\\Renderer\\Rich\\DocstringPlugin', @@ -59,18 +60,18 @@ class RichRenderer extends Renderer 'source' => 'Kint\\Renderer\\Rich\\SourcePlugin', 'table' => 'Kint\\Renderer\\Rich\\TablePlugin', 'timestamp' => 'Kint\\Renderer\\Rich\\TimestampPlugin', - ); - - public static $pre_render_sources = array( - 'script' => array( - array('Kint\\Renderer\\RichRenderer', 'renderJs'), - array('Kint\\Renderer\\Rich\\MicrotimePlugin', 'renderJs'), - ), - 'style' => array( - array('Kint\\Renderer\\RichRenderer', 'renderCss'), - ), - 'raw' => array(), - ); + ]; + + public static $pre_render_sources = [ + 'script' => [ + ['Kint\\Renderer\\RichRenderer', 'renderJs'], + ['Kint\\Renderer\\Rich\\MicrotimePlugin', 'renderJs'], + ], + 'style' => [ + ['Kint\\Renderer\\RichRenderer', 'renderCss'], + ], + 'raw' => [], + ]; /** * Whether or not to render access paths. @@ -118,7 +119,7 @@ class RichRenderer extends Renderer * * @var bool */ - public static $folder = true; + public static $folder = false; /** * Sort mode for object properties. @@ -132,7 +133,7 @@ class RichRenderer extends Renderer public static $always_pre_render = false; - protected $plugin_objs = array(); + protected $plugin_objs = []; protected $expand = false; protected $force_pre_render = false; protected $pre_render; @@ -193,7 +194,6 @@ public function setForcePreRender() public function setPreRender($pre_render) { - $this->setForcePreRender(); // TODO: Remove line in next major version $this->pre_render = $pre_render; } @@ -212,10 +212,11 @@ public function getUseFolder() return $this->use_folder; } - public function render(BasicObject $o) + public function render(Value $o) { - if ($plugin = $this->getPlugin(self::$object_plugins, $o->hints)) { - if (\strlen($output = $plugin->renderObject($o))) { + if ($plugin = $this->getPlugin(self::$value_plugins, $o->hints)) { + $output = $plugin->renderValue($o); + if (null !== $output && \strlen($output)) { return $output; } } @@ -231,7 +232,7 @@ public function renderNothing() return '
No argument
'; } - public function renderHeaderWrapper(BasicObject $o, $has_children, $contents) + public function renderHeaderWrapper(Value $o, $has_children, $contents) { $out = ''; } - public function renderHeader(BasicObject $o) + public function renderHeader(Value $o) { $output = ''; @@ -319,10 +320,10 @@ public function renderHeader(BasicObject $o) return \trim($output); } - public function renderChildren(BasicObject $o) + public function renderChildren(Value $o) { - $contents = array(); - $tabs = array(); + $contents = []; + $tabs = []; foreach ($o->getRepresentations() as $rep) { $result = $this->renderTab($o, $rep); @@ -353,10 +354,16 @@ public function renderChildren(BasicObject $o) $output .= $this->escape($tab->getLabel()).''; } - $output .= '
    '; + $output .= '
    '; - foreach ($contents as $tab) { - $output .= '
  • '.$tab.'
  • '; + foreach ($contents as $i => $tab) { + if (0 === $i) { + $output .= '
  • '; + } else { + $output .= '
  • '; + } + + $output .= $tab.'
  • '; } $output .= '
'; @@ -441,7 +448,7 @@ public function postRender() !empty($this->call_info['callee']['class']) || !\in_array( $this->call_info['callee']['function'], - array('include', 'include_once', 'require', 'require_once'), + ['include', 'include_once', 'require', 'require_once'], true ) ) @@ -465,7 +472,7 @@ public function postRender() $output .= '
  • '.$this->ideLink($step['file'], $step['line']); // closing tag not required if (isset($step['function']) - && !\in_array($step['function'], array('include', 'include_once', 'require', 'require_once'), true) + && !\in_array($step['function'], ['include', 'include_once', 'require', 'require_once'], true) ) { $output .= ' ['; if (isset($step['class'])) { @@ -488,7 +495,7 @@ public function postRender() public function escape($string, $encoding = false) { if (false === $encoding) { - $encoding = BlobObject::detectEncoding($string); + $encoding = BlobValue::detectEncoding($string); } $original_encoding = $encoding; @@ -501,7 +508,7 @@ public function escape($string, $encoding = false) // this call converts all non-ASCII characters into numeirc htmlentities if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) { - $string = \mb_encode_numericentity($string, array(0x80, 0xffff, 0, 0xffff), $encoding); + $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding); } return $string; @@ -525,10 +532,11 @@ public function ideLink($file, $line) return ''.$path.''; } - protected function renderTab(BasicObject $o, Representation $rep) + protected function renderTab(Value $o, Representation $rep) { if ($plugin = $this->getPlugin(self::$tab_plugins, $rep->hints)) { - if (\strlen($output = $plugin->renderTab($rep))) { + $output = $plugin->renderTab($rep); + if (null !== $output && \strlen($output)) { return $output; } } @@ -536,7 +544,7 @@ protected function renderTab(BasicObject $o, Representation $rep) if (\is_array($rep->contents)) { $output = ''; - if ($o instanceof InstanceObject && 'properties' === $rep->getName()) { + if ($o instanceof InstanceValue && 'properties' === $rep->getName()) { foreach (self::sortProperties($rep->contents, self::$sort) as $obj) { $output .= $this->render($obj); } @@ -559,7 +567,7 @@ protected function renderTab(BasicObject $o, Representation $rep) } else { if (\preg_match('/(:?[\\r\\n\\t\\f\\v]| {2})/', $rep->contents)) { $show_contents = true; - } elseif (self::$strlen_max && BlobObject::strlen($o->getValueShort()) > self::$strlen_max) { + } elseif (self::$strlen_max && null !== $o->getValueShort() && BlobValue::strlen($o->getValueShort()) > self::$strlen_max) { $show_contents = true; } @@ -573,9 +581,11 @@ protected function renderTab(BasicObject $o, Representation $rep) } } - if ($rep->contents instanceof BasicObject) { + if ($rep->contents instanceof Value) { return $this->render($rep->contents); } + + return ''; } protected function getPlugin(array $plugins, array $hints) @@ -607,6 +617,6 @@ protected static function renderCss() protected static function renderFolder() { - return '
    Kint
    '; + return '
    Kint
    '; } } diff --git a/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php new file mode 100644 index 000000000000..12c16f397b1b --- /dev/null +++ b/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php @@ -0,0 +1,44 @@ +depth) { + $out .= $this->renderer->colorTitle($this->renderer->renderTitle($o)).PHP_EOL; + } + + $out .= $this->renderer->renderHeader($o).' '.$this->renderer->colorValue('ARRAY LIMIT').PHP_EOL; + + return $out; + } +} diff --git a/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php b/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php index 127d32a197f9..441368b10720 100644 --- a/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class BlacklistPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php index 310b87e417b0..cea6cdf89a50 100644 --- a/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class DepthLimitPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php b/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php index 9128032c4ae0..ce63a5447d87 100644 --- a/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php @@ -25,12 +25,12 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; -use Kint\Object\Representation\MicrotimeRepresentation; use Kint\Renderer\PlainRenderer; use Kint\Renderer\Rich\MicrotimePlugin as RichPlugin; use Kint\Renderer\TextRenderer; use Kint\Utils; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Value; class MicrotimePlugin extends Plugin { @@ -45,12 +45,12 @@ public function __construct(TextRenderer $r) } } - public function render(BasicObject $o) + public function render(Value $o) { $r = $o->getRepresentation('microtime'); if (!$r instanceof MicrotimeRepresentation) { - return false; + return; } $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/Plugin.php b/system/ThirdParty/Kint/Renderer/Text/Plugin.php index 9de25c1a1147..61a1820f48c8 100644 --- a/system/ThirdParty/Kint/Renderer/Text/Plugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; use Kint\Renderer\TextRenderer; +use Kint\Zval\Value; abstract class Plugin { @@ -37,5 +37,8 @@ public function __construct(TextRenderer $r) $this->renderer = $r; } - abstract public function render(BasicObject $o); + /** + * @return null|string + */ + abstract public function render(Value $o); } diff --git a/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php b/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php index 72c2257ca8fc..21956b6ec221 100644 --- a/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class RecursionPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php b/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php index 5833840cdf8f..b25f113e040b 100644 --- a/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php @@ -25,12 +25,12 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; -use Kint\Object\MethodObject; +use Kint\Zval\MethodValue; +use Kint\Zval\Value; class TracePlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; @@ -66,7 +66,7 @@ public function render(BasicObject $o) if (\is_string($frame->trace['function'])) { $framedesc .= $this->renderer->escape($frame->trace['function']).'(...)'; - } elseif ($frame->trace['function'] instanceof MethodObject) { + } elseif ($frame->trace['function'] instanceof MethodValue) { $framedesc .= $this->renderer->escape($frame->trace['function']->getName()); $framedesc .= '('.$this->renderer->escape($frame->trace['function']->getParams()).')'; } diff --git a/system/ThirdParty/Kint/Renderer/TextRenderer.php b/system/ThirdParty/Kint/Renderer/TextRenderer.php index 43b6c40d63b8..0cfba527c78b 100644 --- a/system/ThirdParty/Kint/Renderer/TextRenderer.php +++ b/system/ThirdParty/Kint/Renderer/TextRenderer.php @@ -26,33 +26,36 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; use Kint\Utils; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; class TextRenderer extends Renderer { /** * TextRenderer plugins should be instances of Kint\Renderer\Text\Plugin. */ - public static $plugins = array( + public static $plugins = [ + 'array_limit' => 'Kint\\Renderer\\Text\\ArrayLimitPlugin', 'blacklist' => 'Kint\\Renderer\\Text\\BlacklistPlugin', 'depth_limit' => 'Kint\\Renderer\\Text\\DepthLimitPlugin', 'microtime' => 'Kint\\Renderer\\Text\\MicrotimePlugin', 'recursion' => 'Kint\\Renderer\\Text\\RecursionPlugin', 'trace' => 'Kint\\Renderer\\Text\\TracePlugin', - ); + ]; /** * Parser plugins must be instanceof one of these or * it will be removed for performance reasons. */ - public static $parser_plugin_whitelist = array( + public static $parser_plugin_whitelist = [ + 'Kint\\Parser\\ArrayLimitPlugin', + 'Kint\\Parser\\ArrayObjectPlugin', 'Kint\\Parser\\BlacklistPlugin', 'Kint\\Parser\\MicrotimePlugin', 'Kint\\Parser\\StreamPlugin', 'Kint\\Parser\\TracePlugin', - ); + ]; /** * The maximum length of a string before it is truncated. @@ -94,7 +97,7 @@ class TextRenderer extends Renderer public $header_width = 80; public $indent_width = 4; - protected $plugin_objs = array(); + protected $plugin_objs = []; public function __construct() { @@ -102,10 +105,11 @@ public function __construct() $this->indent_width = self::$default_indent; } - public function render(BasicObject $o) + public function render(Value $o) { if ($plugin = $this->getPlugin(self::$plugins, $o->hints)) { - if (\strlen($output = $plugin->render($o))) { + $output = $plugin->render($o); + if (null !== $output && \strlen($output)) { return $output; } } @@ -149,7 +153,7 @@ public function boxText($text, $width) return $out; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { $name = (string) $o->getName(); @@ -160,9 +164,9 @@ public function renderTitle(BasicObject $o) return Utils::truncateString($name, $this->header_width); } - public function renderHeader(BasicObject $o) + public function renderHeader(Value $o) { - $output = array(); + $output = []; if ($o->depth) { if (null !== ($s = $o->getModifiers())) { @@ -200,7 +204,7 @@ public function renderHeader(BasicObject $o) return \str_repeat(' ', $o->depth * $this->indent_width).\implode(' ', $output); } - public function renderChildren(BasicObject $o) + public function renderChildren(Value $o) { if ('array' === $o->type) { $output = ' ['; @@ -213,7 +217,7 @@ public function renderChildren(BasicObject $o) $children = ''; if ($o->value && \is_array($o->value->contents)) { - if ($o instanceof InstanceObject && 'properties' === $o->value->getName()) { + if ($o instanceof InstanceValue && 'properties' === $o->value->getName()) { foreach (self::sortProperties($o->value->contents, self::$sort) as $obj) { $children .= $this->render($obj); } @@ -274,7 +278,7 @@ public function postRender() public function filterParserPlugins(array $plugins) { - $return = array(); + $return = []; foreach ($plugins as $index => $plugin) { foreach (self::$parser_plugin_whitelist as $whitelist) { @@ -313,7 +317,7 @@ protected function calledFrom() !empty($this->call_info['callee']['class']) || !\in_array( $this->call_info['callee']['function'], - array('include', 'include_once', 'require', 'require_once'), + ['include', 'include_once', 'require', 'require_once'], true ) ) diff --git a/system/ThirdParty/Kint/Utils.php b/system/ThirdParty/Kint/Utils.php index 27a24913fdb1..5143731c75c4 100644 --- a/system/ThirdParty/Kint/Utils.php +++ b/system/ThirdParty/Kint/Utils.php @@ -25,8 +25,7 @@ namespace Kint; -use InvalidArgumentException; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; use ReflectionNamedType; use ReflectionType; @@ -51,15 +50,36 @@ private function __construct() */ public static function getHumanReadableBytes($value) { - static $unit = array('B', 'KB', 'MB', 'GB', 'TB'); + static $unit = ['B', 'KB', 'MB', 'GB', 'TB']; + + $negative = $value < 0; + $value = \abs($value); + + if ($value < 1024) { + $i = 0; + $value = \floor($value); + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 40) { + $i = 1; + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 30) { + $i = 2; + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 20) { + $i = 3; + } else { + $i = 4; + } - $i = \floor(\log($value, 1024)); - $i = \min($i, 4); // Only go up to TB + if ($i) { + $value = $value / \pow(1024, $i); + } + + if ($negative) { + $value *= -1; + } - return array( - 'value' => (float) ($value / \pow(1024, $i)), + return [ + 'value' => \round($value, 1), 'unit' => $unit[$i], - ); + ]; } public static function isSequential(array $array) @@ -67,9 +87,14 @@ public static function isSequential(array $array) return \array_keys($array) === \range(0, \count($array) - 1); } + public static function isAssoc(array $array) + { + return (bool) \count(\array_filter(\array_keys($array), 'is_string')); + } + public static function composerGetExtras($key = 'kint') { - $extras = array(); + $extras = []; if (0 === \strpos(KINT_DIR, 'phar://')) { // Only run inside phar file, so skip for code coverage @@ -131,7 +156,7 @@ public static function isTrace(array $trace) return false; } - static $bt_structure = array( + static $bt_structure = [ 'function' => 'string', 'line' => 'integer', 'file' => 'string', @@ -139,7 +164,7 @@ public static function isTrace(array $trace) 'object' => 'object', 'type' => 'string', 'args' => 'array', - ); + ]; $file_found = false; @@ -169,7 +194,7 @@ public static function isTrace(array $trace) public static function traceFrameIsListed(array $frame, array $matches) { if (isset($frame['class'])) { - $called = array(\strtolower($frame['class']), \strtolower($frame['function'])); + $called = [\strtolower($frame['class']), \strtolower($frame['function'])]; } else { $called = \strtolower($frame['function']); } @@ -189,10 +214,10 @@ public static function normalizeAliases(array &$aliases) \preg_match('/^'.$name_regex.'$/', $alias[1]) && \preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias[0]) ) { - $alias = array( + $alias = [ \strtolower(\ltrim($alias[0], '\\')), \strtolower($alias[1]), - ); + ]; } else { unset($aliases[$index]); continue; @@ -216,14 +241,15 @@ public static function normalizeAliases(array &$aliases) public static function truncateString($input, $length = PHP_INT_MAX, $end = '...', $encoding = false) { $length = (int) $length; - $endlength = BlobObject::strlen($end); + $endlength = BlobValue::strlen($end); if ($endlength >= $length) { - throw new InvalidArgumentException('Can\'t truncate a string to '.$length.' characters if ending with string '.$endlength.' characters long'); + $endlength = 0; + $end = ''; } - if (BlobObject::strlen($input, $encoding) > $length) { - return BlobObject::substr($input, 0, $length - $endlength, $encoding).$end; + if (BlobValue::strlen($input, $encoding) > $length) { + return BlobValue::substr($input, 0, $length - $endlength, $encoding).$end; } return $input; @@ -232,7 +258,12 @@ public static function truncateString($input, $length = PHP_INT_MAX, $end = '... public static function getTypeString(ReflectionType $type) { if ($type instanceof ReflectionNamedType) { - return $type->getName(); + $name = $type->getName(); + if ($type->allowsNull() && false === \strpos($name, '|')) { + $name = '?'.$name; + } + + return $name; } return (string) $type; // @codeCoverageIgnore diff --git a/system/ThirdParty/Kint/Object/BlobObject.php b/system/ThirdParty/Kint/Zval/BlobValue.php similarity index 95% rename from system/ThirdParty/Kint/Object/BlobObject.php rename to system/ThirdParty/Kint/Zval/BlobValue.php index 66d508ff70db..c5ac53acb096 100644 --- a/system/ThirdParty/Kint/Object/BlobObject.php +++ b/system/ThirdParty/Kint/Zval/BlobValue.php @@ -23,9 +23,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class BlobObject extends BasicObject +class BlobValue extends Value { /** * @var array Character encodings to detect @@ -51,10 +51,10 @@ class BlobObject extends BasicObject * * This depends on the mbstring extension */ - public static $char_encodings = array( + public static $char_encodings = [ 'ASCII', 'UTF-8', - ); + ]; /** * @var array Legacy character encodings to detect @@ -74,11 +74,11 @@ class BlobObject extends BasicObject * * This depends on the iconv extension */ - public static $legacy_encodings = array(); + public static $legacy_encodings = []; public $type = 'string'; public $encoding = false; - public $hints = array('string'); + public $hints = ['string']; public function getType() { @@ -100,7 +100,7 @@ public function getValueShort() } } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); diff --git a/system/ThirdParty/Kint/Object/ClosureObject.php b/system/ThirdParty/Kint/Zval/ClosureValue.php similarity index 91% rename from system/ThirdParty/Kint/Object/ClosureObject.php rename to system/ThirdParty/Kint/Zval/ClosureValue.php index 344eceb21e77..95dd3fea9e39 100644 --- a/system/ThirdParty/Kint/Object/ClosureObject.php +++ b/system/ThirdParty/Kint/Zval/ClosureValue.php @@ -23,12 +23,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class ClosureObject extends InstanceObject +class ClosureValue extends InstanceValue { - public $parameters = array(); - public $hints = array('object', 'callable', 'closure'); + public $parameters = []; + public $hints = ['object', 'callable', 'closure']; private $paramcache; @@ -49,7 +49,7 @@ public function getParams() return $this->paramcache; } - $out = array(); + $out = []; foreach ($this->parameters as $p) { $type = $p->getType(); diff --git a/system/ThirdParty/Kint/Object/DateTimeObject.php b/system/ThirdParty/Kint/Zval/DateTimeValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/DateTimeObject.php rename to system/ThirdParty/Kint/Zval/DateTimeValue.php index f8b1b3fd164f..1a8084ec3b9f 100644 --- a/system/ThirdParty/Kint/Object/DateTimeObject.php +++ b/system/ThirdParty/Kint/Zval/DateTimeValue.php @@ -23,15 +23,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use DateTime; -class DateTimeObject extends InstanceObject +class DateTimeValue extends InstanceValue { public $dt; - public $hints = array('object', 'datetime'); + public $hints = ['object', 'datetime']; public function __construct(DateTime $dt) { diff --git a/system/ThirdParty/Kint/Object/InstanceObject.php b/system/ThirdParty/Kint/Zval/InstanceValue.php similarity index 88% rename from system/ThirdParty/Kint/Object/InstanceObject.php rename to system/ThirdParty/Kint/Zval/InstanceValue.php index 943b33d8eabb..1c26600ca47e 100644 --- a/system/ThirdParty/Kint/Object/InstanceObject.php +++ b/system/ThirdParty/Kint/Zval/InstanceValue.php @@ -23,29 +23,29 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class InstanceObject extends BasicObject +class InstanceValue extends Value { public $type = 'object'; public $classname; - public $hash; + public $spl_object_hash; public $filename; public $startline; - public $hints = array('object'); + public $hints = ['object']; public function getType() { return $this->classname; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); if ($old instanceof self) { $this->classname = $old->classname; - $this->hash = $old->hash; + $this->spl_object_hash = $old->spl_object_hash; $this->filename = $old->filename; $this->startline = $old->startline; } @@ -56,7 +56,7 @@ public static function sortByHierarchy($a, $b) if (\is_string($a) && \is_string($b)) { $aclass = $a; $bclass = $b; - } elseif (!($a instanceof BasicObject) || !($b instanceof BasicObject)) { + } elseif (!($a instanceof Value) || !($b instanceof Value)) { return 0; } elseif ($a instanceof self && $b instanceof self) { $aclass = $a->classname; diff --git a/system/ThirdParty/Kint/Object/MethodObject.php b/system/ThirdParty/Kint/Zval/MethodValue.php similarity index 90% rename from system/ThirdParty/Kint/Object/MethodObject.php rename to system/ThirdParty/Kint/Zval/MethodValue.php index 78d49de22264..5d59a50765f2 100644 --- a/system/ThirdParty/Kint/Object/MethodObject.php +++ b/system/ThirdParty/Kint/Zval/MethodValue.php @@ -23,27 +23,27 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\DocstringRepresentation; use Kint\Utils; +use Kint\Zval\Representation\DocstringRepresentation; use ReflectionFunctionAbstract; use ReflectionMethod; -class MethodObject extends BasicObject +class MethodValue extends Value { public $type = 'method'; public $filename; public $startline; public $endline; - public $parameters = array(); + public $parameters = []; public $abstract; public $final; public $internal; public $docstring; public $returntype; public $return_reference = false; - public $hints = array('callable', 'method'); + public $hints = ['callable', 'method']; public $showparams = true; private $paramcache; @@ -61,7 +61,7 @@ public function __construct(ReflectionFunctionAbstract $method) $this->return_reference = $method->returnsReference(); foreach ($method->getParameters() as $param) { - $this->parameters[] = new ParameterObject($param); + $this->parameters[] = new ParameterValue($param); } if (KINT_PHP70) { @@ -73,15 +73,15 @@ public function __construct(ReflectionFunctionAbstract $method) if ($method instanceof ReflectionMethod) { $this->static = $method->isStatic(); - $this->operator = $this->static ? BasicObject::OPERATOR_STATIC : BasicObject::OPERATOR_OBJECT; + $this->operator = $this->static ? Value::OPERATOR_STATIC : Value::OPERATOR_OBJECT; $this->abstract = $method->isAbstract(); $this->final = $method->isFinal(); $this->owner_class = $method->getDeclaringClass()->name; - $this->access = BasicObject::ACCESS_PUBLIC; + $this->access = Value::ACCESS_PUBLIC; if ($method->isProtected()) { - $this->access = BasicObject::ACCESS_PROTECTED; + $this->access = Value::ACCESS_PROTECTED; } elseif ($method->isPrivate()) { - $this->access = BasicObject::ACCESS_PRIVATE; + $this->access = Value::ACCESS_PRIVATE; } } @@ -100,9 +100,9 @@ public function __construct(ReflectionFunctionAbstract $method) $this->value = $docstring; } - public function setAccessPathFrom(InstanceObject $parent) + public function setAccessPathFrom(InstanceValue $parent) { - static $magic = array( + static $magic = [ '__call' => true, '__callstatic' => true, '__clone' => true, @@ -118,7 +118,7 @@ public function setAccessPathFrom(InstanceObject $parent) '__tostring' => true, '__unset' => true, '__wakeup' => true, - ); + ]; $name = \strtolower($this->name); @@ -172,12 +172,12 @@ public function getValueShort() public function getModifiers() { - $mods = array( + $mods = [ $this->abstract ? 'abstract' : null, $this->final ? 'final' : null, $this->getAccess(), $this->static ? 'static' : null, - ); + ]; $out = ''; @@ -209,7 +209,7 @@ public function getParams() return $this->paramcache; } - $out = array(); + $out = []; foreach ($this->parameters as $p) { $type = $p->getType(); diff --git a/system/ThirdParty/Kint/Object/ParameterObject.php b/system/ThirdParty/Kint/Zval/ParameterValue.php similarity index 95% rename from system/ThirdParty/Kint/Object/ParameterObject.php rename to system/ThirdParty/Kint/Zval/ParameterValue.php index 4bed551f548b..29bcbe72bb2b 100644 --- a/system/ThirdParty/Kint/Object/ParameterObject.php +++ b/system/ThirdParty/Kint/Zval/ParameterValue.php @@ -23,18 +23,18 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Kint\Utils; use ReflectionException; use ReflectionParameter; -class ParameterObject extends BasicObject +class ParameterValue extends Value { public $type_hint; public $default; public $position; - public $hints = array('parameter'); + public $hints = ['parameter']; public function __construct(ReflectionParameter $param) { @@ -64,7 +64,6 @@ public function __construct(ReflectionParameter $param) $this->position = $param->getPosition(); if ($param->isDefaultValueAvailable()) { - /** @var mixed Psalm bug workaround */ $default = $param->getDefaultValue(); switch (\gettype($default)) { case 'NULL': diff --git a/system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php index d6a072f50891..533ccb35d940 100644 --- a/system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php @@ -23,7 +23,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use InvalidArgumentException; @@ -39,7 +39,7 @@ class ColorRepresentation extends Representation const COLOR_HEX_4 = 8; const COLOR_HEX_8 = 9; - public static $color_map = array( + public static $color_map = [ 'aliceblue' => 'f0f8ff', 'antiquewhite' => 'faebd7', 'aqua' => '00ffff', @@ -191,7 +191,7 @@ class ColorRepresentation extends Representation 'whitesmoke' => 'f5f5f5', 'yellow' => 'ffff00', 'yellowgreen' => '9acd32', - ); + ]; public $r = 0; public $g = 0; @@ -199,7 +199,7 @@ class ColorRepresentation extends Representation public $a = 1.0; public $variant; public $implicit_label = true; - public $hints = array('color'); + public $hints = ['color']; public function __construct($value) { @@ -254,7 +254,7 @@ public function getColor($variant = null) return \sprintf('hsla(%d, %d%%, %d%%, %s)', $val[0], $val[1], $val[2], \round($this->a, 4)); case self::COLOR_HEX_4: - if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11 && 0 === ($this->a * 255) % 0x11) { + if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11 && 0 === ((int) ($this->a * 255)) % 0x11) { return \sprintf( '#%1X%1X%1X%1X', \round($this->r / 0x11), @@ -413,21 +413,19 @@ protected function setValuesFromFunction($value) if (3 === $i) { $color = $color / 100; - } elseif (\in_array($variant, array(self::COLOR_RGB, self::COLOR_RGBA), true)) { + } elseif (\in_array($variant, [self::COLOR_RGB, self::COLOR_RGBA], true)) { $color = \round($color / 100 * 0xFF); } } $color = (float) $color; - if (0 === $i && \in_array($variant, array(self::COLOR_HSL, self::COLOR_HSLA), true)) { - $color = ($color % 360 + 360) % 360; + if (0 === $i && \in_array($variant, [self::COLOR_HSL, self::COLOR_HSLA], true)) { + $color = \fmod(\fmod($color, 360) + 360, 360); } } - /** @var float[] Psalm bug workaround */ - $params = \array_map('floatval', $params); - + /** @var non-empty-array $params Psalm bug workaround */ switch ($variant) { case self::COLOR_RGBA: case self::COLOR_RGB: @@ -486,11 +484,11 @@ public static function hslToRgb($h, $s, $l) $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l * $s; $m1 = $l * 2 - $m2; - return array( + return [ (int) \round(self::hueToRgb($m1, $m2, $h + 1 / 3) * 0xFF), (int) \round(self::hueToRgb($m1, $m2, $h) * 0xFF), (int) \round(self::hueToRgb($m1, $m2, $h - 1 / 3) * 0xFF), - ); + ]; } /** @@ -541,17 +539,16 @@ public static function rgbToHsl($red, $green, $blue) } } - return array( - (float) ($H * 360 % 360), + return [ + \fmod($H * 360, 360), (float) ($S * 100), (float) ($L * 100), - ); + ]; } /** * Helper function for hslToRgb. Even blacker magic. * - * * @param float $m1 * @param float $m2 * @param float $hue diff --git a/system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php similarity index 97% rename from system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php index 488d8d6e0748..8acdcc1e8583 100644 --- a/system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php @@ -23,14 +23,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class DocstringRepresentation extends Representation { public $file; public $line; public $class; - public $hints = array('docstring'); + public $hints = ['docstring']; public function __construct($docstring, $file, $line, $class = null) { diff --git a/system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php index b9f4dacb314b..aedc2edffb6e 100644 --- a/system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php @@ -23,7 +23,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use DateTime; @@ -40,7 +40,7 @@ class MicrotimeRepresentation extends Representation public $mem_real = 0; public $mem_peak = 0; public $mem_peak_real = 0; - public $hints = array('microtime'); + public $hints = ['microtime']; public function __construct($seconds, $microseconds, $group, $lap = null, $total = null, $i = 0) { diff --git a/system/ThirdParty/Kint/Object/Representation/Representation.php b/system/ThirdParty/Kint/Zval/Representation/Representation.php similarity index 95% rename from system/ThirdParty/Kint/Object/Representation/Representation.php rename to system/ThirdParty/Kint/Zval/Representation/Representation.php index 0c911a4eaa98..2d649d077c13 100644 --- a/system/ThirdParty/Kint/Object/Representation/Representation.php +++ b/system/ThirdParty/Kint/Zval/Representation/Representation.php @@ -23,14 +23,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class Representation { public $label; public $implicit_label = false; - public $hints = array(); - public $contents = array(); + public $hints = []; + public $contents = []; protected $name; diff --git a/system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php index c2cf1204f1a9..65077d6218c6 100644 --- a/system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php @@ -23,12 +23,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class SourceRepresentation extends Representation { - public $hints = array('source'); - public $source = array(); + public $hints = ['source']; + public $source = []; public $filename; public $line = 0; public $showfilename = false; diff --git a/system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php similarity index 95% rename from system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php index 3df50e6a1284..6208451b41ed 100644 --- a/system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php @@ -23,29 +23,29 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use Kint\Utils; use SplFileInfo; class SplFileInfoRepresentation extends Representation { - public $perms; + public $perms = null; public $flags; public $path; - public $realpath; - public $linktarget; + public $realpath = null; + public $linktarget = null; public $size; public $is_dir = false; public $is_file = false; public $is_link = false; - public $owner; - public $group; + public $owner = null; + public $group = null; public $ctime; public $mtime; public $typename = 'Unknown file'; public $typeflag = '-'; - public $hints = array('fspath'); + public $hints = ['fspath']; public function __construct(SplFileInfo $fileInfo) { @@ -109,7 +109,7 @@ public function __construct(SplFileInfo $fileInfo) break; } - $this->flags = array($this->typeflag); + $this->flags = [$this->typeflag]; // User $this->flags[] = (($this->perms & 0400) ? 'r' : '-'); diff --git a/system/ThirdParty/Kint/Object/ResourceObject.php b/system/ThirdParty/Kint/Zval/ResourceValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/ResourceObject.php rename to system/ThirdParty/Kint/Zval/ResourceValue.php index a43f85d900ee..ef1c5541e476 100644 --- a/system/ThirdParty/Kint/Object/ResourceObject.php +++ b/system/ThirdParty/Kint/Zval/ResourceValue.php @@ -23,9 +23,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class ResourceObject extends BasicObject +class ResourceValue extends Value { public $resource_type; @@ -38,7 +38,7 @@ public function getType() return 'resource'; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); diff --git a/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php b/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php new file mode 100644 index 000000000000..b385bc6daa2e --- /dev/null +++ b/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php @@ -0,0 +1,48 @@ +is_string_value = $is_string_value; + } + + public function getValueShort() + { + if ($this->is_string_value && ($rep = $this->value) && 'contents' === $rep->getName() && 'string' === \gettype($rep->contents)) { + return '"'.$rep->contents.'"'; + } + } +} diff --git a/system/ThirdParty/Kint/Object/StreamObject.php b/system/ThirdParty/Kint/Zval/StreamValue.php similarity index 96% rename from system/ThirdParty/Kint/Object/StreamObject.php rename to system/ThirdParty/Kint/Zval/StreamValue.php index 358f2743e94f..af909c84f39a 100644 --- a/system/ThirdParty/Kint/Object/StreamObject.php +++ b/system/ThirdParty/Kint/Zval/StreamValue.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Kint\Kint; -class StreamObject extends ResourceObject +class StreamValue extends ResourceValue { public $stream_meta; diff --git a/system/ThirdParty/Kint/Object/ThrowableObject.php b/system/ThirdParty/Kint/Zval/ThrowableValue.php similarity index 88% rename from system/ThirdParty/Kint/Object/ThrowableObject.php rename to system/ThirdParty/Kint/Zval/ThrowableValue.php index 2a86d57538df..26676481c26d 100644 --- a/system/ThirdParty/Kint/Object/ThrowableObject.php +++ b/system/ThirdParty/Kint/Zval/ThrowableValue.php @@ -23,21 +23,21 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Exception; use InvalidArgumentException; use Throwable; -class ThrowableObject extends InstanceObject +class ThrowableValue extends InstanceValue { public $message; - public $hints = array('object', 'throwable'); + public $hints = ['object', 'throwable']; public function __construct($throw) { if (!$throw instanceof Exception && (!KINT_PHP70 || !$throw instanceof Throwable)) { - throw new InvalidArgumentException('ThrowableObject must be constructed with a Throwable'); + throw new InvalidArgumentException('ThrowableValue must be constructed with a Throwable'); } parent::__construct(); diff --git a/system/ThirdParty/Kint/Object/TraceFrameObject.php b/system/ThirdParty/Kint/Zval/TraceFrameValue.php similarity index 81% rename from system/ThirdParty/Kint/Object/TraceFrameObject.php rename to system/ThirdParty/Kint/Zval/TraceFrameValue.php index 4259aeeec1aa..62f7829192d2 100644 --- a/system/ThirdParty/Kint/Object/TraceFrameObject.php +++ b/system/ThirdParty/Kint/Zval/TraceFrameValue.php @@ -23,52 +23,57 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\Representation; -use Kint\Object\Representation\SourceRepresentation; +use InvalidArgumentException; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Representation\SourceRepresentation; use ReflectionFunction; use ReflectionMethod; -class TraceFrameObject extends BasicObject +class TraceFrameValue extends Value { public $trace; - public $hints = array('trace_frame'); + public $hints = ['trace_frame']; - public function __construct(BasicObject $base, array $raw_frame) + public function __construct(Value $base, array $raw_frame) { parent::__construct(); $this->transplant($base); - $this->trace = array( - 'function' => isset($raw_frame['function']) ? $raw_frame['function'] : null, + if (!isset($this->value)) { + throw new InvalidArgumentException('Tried to create TraceFrameValue from Value with no value representation'); + } + + $this->trace = [ + 'function' => $raw_frame['function'], 'line' => isset($raw_frame['line']) ? $raw_frame['line'] : null, 'file' => isset($raw_frame['file']) ? $raw_frame['file'] : null, 'class' => isset($raw_frame['class']) ? $raw_frame['class'] : null, 'type' => isset($raw_frame['type']) ? $raw_frame['type'] : null, 'object' => null, 'args' => null, - ); + ]; if ($this->trace['class'] && \method_exists($this->trace['class'], $this->trace['function'])) { $func = new ReflectionMethod($this->trace['class'], $this->trace['function']); - $this->trace['function'] = new MethodObject($func); + $this->trace['function'] = new MethodValue($func); } elseif (!$this->trace['class'] && \function_exists($this->trace['function'])) { $func = new ReflectionFunction($this->trace['function']); - $this->trace['function'] = new MethodObject($func); + $this->trace['function'] = new MethodValue($func); } foreach ($this->value->contents as $frame_prop) { if ('object' === $frame_prop->name) { $this->trace['object'] = $frame_prop; $this->trace['object']->name = null; - $this->trace['object']->operator = BasicObject::OPERATOR_NONE; + $this->trace['object']->operator = Value::OPERATOR_NONE; } if ('args' === $frame_prop->name) { $this->trace['args'] = $frame_prop->value->contents; - if ($this->trace['function'] instanceof MethodObject) { + if ($this->trace['function'] instanceof MethodValue) { foreach (\array_values($this->trace['function']->parameters) as $param) { if (isset($this->trace['args'][$param->position])) { $this->trace['args'][$param->position]->name = $param->getName(); diff --git a/system/ThirdParty/Kint/Object/TraceObject.php b/system/ThirdParty/Kint/Zval/TraceValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/TraceObject.php rename to system/ThirdParty/Kint/Zval/TraceValue.php index a780b082bf9c..4d0edc42219a 100644 --- a/system/ThirdParty/Kint/Object/TraceObject.php +++ b/system/ThirdParty/Kint/Zval/TraceValue.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class TraceObject extends BasicObject +class TraceValue extends Value { - public $hints = array('trace'); + public $hints = ['trace']; public function getType() { diff --git a/system/ThirdParty/Kint/Object/BasicObject.php b/system/ThirdParty/Kint/Zval/Value.php similarity index 91% rename from system/ThirdParty/Kint/Object/BasicObject.php rename to system/ThirdParty/Kint/Zval/Value.php index d69347eb8dfc..747efb5f718f 100644 --- a/system/ThirdParty/Kint/Object/BasicObject.php +++ b/system/ThirdParty/Kint/Zval/Value.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; -class BasicObject +class Value { const ACCESS_NONE = null; const ACCESS_PUBLIC = 1; @@ -51,9 +51,9 @@ class BasicObject public $depth = 0; public $size; public $value; - public $hints = array(); + public $hints = []; - protected $representations = array(); + protected $representations = []; public function __construct() { @@ -70,7 +70,7 @@ public function addRepresentation(Representation $rep, $pos = null) } else { $this->representations = \array_merge( \array_slice($this->representations, 0, $pos), - array($rep->getName() => $rep), + [$rep->getName() => $rep], \array_slice($this->representations, $pos) ); } @@ -111,7 +111,7 @@ public function getRepresentations() public function clearRepresentations() { - $this->representations = array(); + $this->representations = []; } public function getType() @@ -131,7 +131,7 @@ public function getModifiers() $out .= ' static'; } - if (\strlen($out)) { + if (null !== $out && \strlen($out)) { return \ltrim($out); } } @@ -188,7 +188,7 @@ public function getAccessPath() return $this->access_path; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { $this->name = $old->name; $this->size = $old->size; @@ -212,7 +212,7 @@ public function transplant(BasicObject $old) * @param null|string $name * @param null|string $access_path * - * @return \Kint\Object\BasicObject + * @return \Kint\Zval\Value */ public static function blank($name = null, $access_path = null) { @@ -223,19 +223,19 @@ public static function blank($name = null, $access_path = null) return $o; } - public static function sortByAccess(BasicObject $a, BasicObject $b) + public static function sortByAccess(Value $a, Value $b) { - static $sorts = array( + static $sorts = [ self::ACCESS_PUBLIC => 1, self::ACCESS_PROTECTED => 2, self::ACCESS_PRIVATE => 3, self::ACCESS_NONE => 4, - ); + ]; return $sorts[$a->access] - $sorts[$b->access]; } - public static function sortByName(BasicObject $a, BasicObject $b) + public static function sortByName(Value $a, Value $b) { $ret = \strnatcasecmp($a->name, $b->name); diff --git a/system/ThirdParty/Kint/init.php b/system/ThirdParty/Kint/init.php index 952e041400ff..2e7c62b4b1c9 100644 --- a/system/ThirdParty/Kint/init.php +++ b/system/ThirdParty/Kint/init.php @@ -30,31 +30,33 @@ return; } -if (\version_compare(PHP_VERSION, '5.3') < 0) { - throw new Exception('Kint 3.0 requires PHP 5.3 or higher'); +if (\version_compare(PHP_VERSION, '5.6') < 0) { + throw new Exception('Kint 4.0 requires PHP 5.6 or higher'); } \define('KINT_DIR', __DIR__); \define('KINT_WIN', DIRECTORY_SEPARATOR !== '/'); -\define('KINT_PHP56', (\version_compare(PHP_VERSION, '5.6') >= 0)); \define('KINT_PHP70', (\version_compare(PHP_VERSION, '7.0') >= 0)); +\define('KINT_PHP71', (\version_compare(PHP_VERSION, '7.1') >= 0)); \define('KINT_PHP72', (\version_compare(PHP_VERSION, '7.2') >= 0)); \define('KINT_PHP73', (\version_compare(PHP_VERSION, '7.3') >= 0)); \define('KINT_PHP74', (\version_compare(PHP_VERSION, '7.4') >= 0)); +\define('KINT_PHP80', (\version_compare(PHP_VERSION, '8.0') >= 0)); +\define('KINT_PHP81', (\version_compare(PHP_VERSION, '8.1') >= 0)); // Dynamic default settings Kint::$file_link_format = \ini_get('xdebug.file_link_format'); if (isset($_SERVER['DOCUMENT_ROOT'])) { - Kint::$app_root_dirs = array( + Kint::$app_root_dirs = [ $_SERVER['DOCUMENT_ROOT'] => '', \realpath($_SERVER['DOCUMENT_ROOT']) => '', - ); + ]; } Utils::composerSkipFlags(); if ((!\defined('KINT_SKIP_FACADE') || !KINT_SKIP_FACADE) && !\class_exists('Kint')) { - \class_alias('Kint\\Kint', 'Kint'); + \class_alias(Kint::class, 'Kint'); } if (!\defined('KINT_SKIP_HELPERS') || !KINT_SKIP_HELPERS) { diff --git a/system/ThirdParty/Kint/init_helpers.php b/system/ThirdParty/Kint/init_helpers.php index b961d67f1af5..3dca84c35f08 100644 --- a/system/ThirdParty/Kint/init_helpers.php +++ b/system/ThirdParty/Kint/init_helpers.php @@ -24,6 +24,7 @@ */ use Kint\Kint; +use Kint\Renderer\CliRenderer; if (!\function_exists('d')) { /** @@ -35,7 +36,7 @@ function d() { $args = \func_get_args(); - return \call_user_func_array(array('Kint', 'dump'), $args); + return \call_user_func_array(['Kint', 'dump'], $args); } Kint::$aliases[] = 'd'; @@ -59,23 +60,28 @@ function d() */ function s() { - if (!Kint::$enabled_mode) { + if (false === Kint::$enabled_mode) { return 0; } - $stash = Kint::$enabled_mode; + $kstash = Kint::$enabled_mode; + $cstash = CliRenderer::$cli_colors; if (Kint::MODE_TEXT !== Kint::$enabled_mode) { Kint::$enabled_mode = Kint::MODE_PLAIN; + if (PHP_SAPI === 'cli' && true === Kint::$cli_detection) { Kint::$enabled_mode = Kint::$mode_default_cli; } } + CliRenderer::$cli_colors = false; + $args = \func_get_args(); - $out = \call_user_func_array(array('Kint', 'dump'), $args); + $out = \call_user_func_array(['Kint', 'dump'], $args); - Kint::$enabled_mode = $stash; + Kint::$enabled_mode = $kstash; + CliRenderer::$cli_colors = $cstash; return $out; } diff --git a/system/ThirdParty/Kint/resources/compiled/aante-light.css b/system/ThirdParty/Kint/resources/compiled/aante-light.css index 2de17accf9a9..dc7a40a73489 100644 --- a/system/ThirdParty/Kint/resources/compiled/aante-light.css +++ b/system/ThirdParty/Kint/resources/compiled/aante-light.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:none}.kint-rich.kint-folder.kint-show{display:block}.kint-rich.kint-folder dd.kint-folder{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} diff --git a/system/ThirdParty/Kint/resources/compiled/microtime.js b/system/ThirdParty/Kint/resources/compiled/microtime.js index 20e3445b2b05..c9b8f00a58d7 100644 --- a/system/ThirdParty/Kint/resources/compiled/microtime.js +++ b/system/ThirdParty/Kint/resources/compiled/microtime.js @@ -1 +1 @@ -void 0===window.kintMicrotimeInitialized&&(window.kintMicrotimeInitialized=1,window.addEventListener("load",function(){"use strict";var c={},i=Array.prototype.slice.call(document.querySelectorAll("[data-kint-microtime-group]"),0);i.forEach(function(i){if(i.querySelector(".kint-microtime-lap")){var t=i.getAttribute("data-kint-microtime-group"),e=parseFloat(i.querySelector(".kint-microtime-lap").innerHTML),r=parseFloat(i.querySelector(".kint-microtime-avg").innerHTML);void 0===c[t]&&(c[t]={}),(void 0===c[t].min||c[t].min>e)&&(c[t].min=e),(void 0===c[t].max||c[t].maxe)&&(a[i].min=e),(void 0===a[i].max||a[i].maxdl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#0092db;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #5cb730}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#e0eaef;border:1px solid #b6cedb;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#0092db}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} diff --git a/system/ThirdParty/Kint/resources/compiled/rich.js b/system/ThirdParty/Kint/resources/compiled/rich.js index 18fb072ead95..5648cda6de9e 100644 --- a/system/ThirdParty/Kint/resources/compiled/rich.js +++ b/system/ThirdParty/Kint/resources/compiled/rich.js @@ -1 +1 @@ -void 0===window.kintRich&&(window.kintRich=function(){"use strict";var n={selectText:function(e){var t=window.getSelection(),a=document.createRange();a.selectNodeContents(e),t.removeAllRanges(),t.addRange(a)},each:function(e,t){Array.prototype.slice.call(document.querySelectorAll(e),0).forEach(t)},hasClass:function(e,t){return!!e.classList&&(void 0===t&&(t="kint-show"),e.classList.contains(t))},addClass:function(e,t){void 0===t&&(t="kint-show"),e.classList.add(t)},removeClass:function(e,t){return void 0===t&&(t="kint-show"),e.classList.remove(t),e},toggle:function(e,t){var a=n.getChildren(e);a&&(void 0===t&&(t=n.hasClass(e)),t?n.removeClass(e):n.addClass(e),1===a.childNodes.length&&(a=a.childNodes[0].childNodes[0])&&n.hasClass(a,"kint-parent")&&n.toggle(a,t))},toggleChildren:function(e,t){var a=n.getChildren(e);if(a){var r=a.getElementsByClassName("kint-parent"),o=r.length;for(void 0===t&&(t=!n.hasClass(e));o--;)n.toggle(r[o],t)}},toggleAll:function(e){for(var t=document.getElementsByClassName("kint-parent"),a=t.length,r=!n.hasClass(e.parentNode);a--;)n.toggle(t[a],r)},switchTab:function(e){var t,a=e.previousSibling,r=0;for(n.removeClass(e.parentNode.getElementsByClassName("kint-active-tab")[0],"kint-active-tab"),n.addClass(e,"kint-active-tab");a;)1===a.nodeType&&r++,a=a.previousSibling;t=e.parentNode.nextSibling.childNodes;for(var o=0;o"},openInNewWindow:function(e){var t=window.open();t&&(t.document.open(),t.document.write(n.mktag("html")+n.mktag("head")+n.mktag("title")+"Kint ("+(new Date).toISOString()+")"+n.mktag("/title")+n.mktag('meta charset="utf-8"')+document.getElementsByClassName("kint-rich-script")[0].outerHTML+document.getElementsByClassName("kint-rich-style")[0].outerHTML+n.mktag("/head")+n.mktag("body")+'
    '+e.parentNode.outerHTML+"
    "+n.mktag("/body")),t.document.close())},sortTable:function(e,a){var t=e.tBodies[0];[].slice.call(e.tBodies[0].rows).sort(function(e,t){if(e=e.cells[a].textContent.trim().toLocaleLowerCase(),t=t.cells[a].textContent.trim().toLocaleLowerCase(),isNaN(e)||isNaN(t)){if(isNaN(e)&&!isNaN(t))return 1;if(isNaN(t)&&!isNaN(e))return-1}else e=parseFloat(e),t=parseFloat(t);return eli:not(.kint-active-tab)",function(e){0===e.offsetWidth&&0===e.offsetHeight||n.keyboardNav.targets.push(e)})},sync:function(e){var t=document.querySelector(".kint-focused");if(t&&n.removeClass(t,"kint-focused"),n.keyboardNav.active){var a=n.keyboardNav.targets[n.keyboardNav.target];n.addClass(a,"kint-focused"),e||n.keyboardNav.scroll(a)}},scroll:function(e){var t=function(e){return e.offsetTop+(e.offsetParent?t(e.offsetParent):0)},a=t(e);if(n.folder){var r=n.folder.querySelector("dd.kint-folder");r.scrollTo(0,a-r.clientHeight/2)}else window.scrollTo(0,a-window.innerHeight/2)},moveCursor:function(e){for(n.keyboardNav.target+=e;n.keyboardNav.target<0;)n.keyboardNav.target+=n.keyboardNav.targets.length;for(;n.keyboardNav.target>=n.keyboardNav.targets.length;)n.keyboardNav.target-=n.keyboardNav.targets.length;n.keyboardNav.sync()},setCursor:function(e){n.keyboardNav.fetchTargets();for(var t=0;t"},openInNewWindow:function(e){var t=window.open();t&&(t.document.open(),t.document.write(i.mktag("html")+i.mktag("head")+i.mktag("title")+"Kint ("+(new Date).toISOString()+")"+i.mktag("/title")+i.mktag('meta charset="utf-8"')+document.getElementsByClassName("kint-rich-script")[0].outerHTML+document.getElementsByClassName("kint-rich-style")[0].outerHTML+i.mktag("/head")+i.mktag("body")+'
    '+e.parentNode.outerHTML+"
    "+i.mktag("/body")),t.document.close())},sortTable:function(e,a){var t=e.tBodies[0];[].slice.call(e.tBodies[0].rows).sort(function(e,t){if(e=e.cells[a].textContent.trim().toLocaleLowerCase(),t=t.cells[a].textContent.trim().toLocaleLowerCase(),isNaN(e)||isNaN(t)){if(isNaN(e)&&!isNaN(t))return 1;if(isNaN(t)&&!isNaN(e))return-1}else e=parseFloat(e),t=parseFloat(t);return eli:not(.kint-active-tab)",function(e){i.isFolderOpen()&&!i.folder.contains(e)||0===e.offsetWidth&&0===e.offsetHeight||i.keyboardNav.targets.push(e)}),e&&-1!==i.keyboardNav.targets.indexOf(e)&&(i.keyboardNav.target=i.keyboardNav.targets.indexOf(e))},sync:function(e){var t=document.querySelector(".kint-focused");t&&i.removeClass(t,"kint-focused"),i.keyboardNav.active&&(t=i.keyboardNav.targets[i.keyboardNav.target],i.addClass(t,"kint-focused"),e||i.keyboardNav.scroll(t))},scroll:function(e){var t,a;e!==i.folder.querySelector("dt > nav")&&(a=(t=function(e){return e.offsetTop+(e.offsetParent?t(e.offsetParent):0)})(e),i.isFolderOpen()?(e=i.folder.querySelector("dd.kint-foldout")).scrollTo(0,a-e.clientHeight/2):window.scrollTo(0,a-window.innerHeight/2))},moveCursor:function(e){for(i.keyboardNav.target+=e;i.keyboardNav.target<0;)i.keyboardNav.target+=i.keyboardNav.targets.length;for(;i.keyboardNav.target>=i.keyboardNav.targets.length;)i.keyboardNav.target-=i.keyboardNav.targets.length;i.keyboardNav.sync()},setCursor:function(e){if(i.isFolderOpen()&&!i.folder.contains(e))return!1;i.keyboardNav.fetchTargets();for(var t=0;tdl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}body{background:#073642;color:#fff}.kint-rich{box-shadow:0 0 5px 3px #073642}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:#073642}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#839496}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#839496;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#002b36;border:1px solid #586e75;color:#839496;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}body{background:#073642;color:#fff}.kint-rich{box-shadow:0 0 5px 3px #073642}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} diff --git a/system/ThirdParty/Kint/resources/compiled/solarized.css b/system/ThirdParty/Kint/resources/compiled/solarized.css index db5da0d2d3b7..fa04f2de8f4d 100644 --- a/system/ThirdParty/Kint/resources/compiled/solarized.css +++ b/system/ThirdParty/Kint/resources/compiled/solarized.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:none}.kint-rich.kint-folder.kint-show{display:block}.kint-rich.kint-folder dd.kint-folder{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} diff --git a/system/ThirdParty/PSR/Log/LICENSE b/system/ThirdParty/PSR/Log/LICENSE new file mode 100644 index 000000000000..474c952b4b50 --- /dev/null +++ b/system/ThirdParty/PSR/Log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +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. diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index 0bdf8a95522d..89c32981a841 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -79,10 +79,9 @@ public function getTokenTime(): int * * Example: * - * if (! $throttler->check($request->ipAddress(), 60, MINUTE)) - * { + * if (! $throttler->check($request->ipAddress(), 60, MINUTE)) { * die('You submitted over 60 requests within a minute.'); - * } + * } * * @param string $key The name to use as the "bucket" name. * @param int $capacity The number of requests the "bucket" can hold @@ -95,12 +94,20 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): { $tokenName = $this->prefix . $key; + // Number of tokens to add back per second + $rate = $capacity / $seconds; + // Number of seconds to get one token + $refresh = 1 / $rate; + // Check to see if the bucket has even been created yet. if (($tokens = $this->cache->get($tokenName)) === null) { // If it hasn't been created, then we'll set it to the maximum // capacity - 1, and save it to the cache. - $this->cache->save($tokenName, $capacity - $cost, $seconds); - $this->cache->save($tokenName . 'Time', time(), $seconds); + $tokens = $capacity - $cost; + $this->cache->save($tokenName, $tokens, $seconds); + $this->cache->save($tokenName . 'Time', $this->time(), $seconds); + + $this->tokenTime = 0; return true; } @@ -110,15 +117,6 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): $throttleTime = $this->cache->get($tokenName . 'Time'); $elapsed = $this->time() - $throttleTime; - // Number of tokens to add back per second - $rate = $capacity / $seconds; - - // How many seconds till a new token is available. - // We must have a minimum wait of 1 second for a new token. - // Primarily stored to allow devs to report back to users. - $newTokenAvailable = (1 / $rate) - $elapsed; - $this->tokenTime = max(1, $newTokenAvailable); - // Add tokens based up on number per second that // should be refilled, then checked against capacity // to be sure the bucket didn't overflow. @@ -128,12 +126,21 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): // If $tokens >= 1, then we are safe to perform the action, but // we need to decrement the number of available tokens. if ($tokens >= 1) { - $this->cache->save($tokenName, $tokens - $cost, $seconds); - $this->cache->save($tokenName . 'Time', time(), $seconds); + $tokens = $tokens - $cost; + $this->cache->save($tokenName, $tokens, $seconds); + $this->cache->save($tokenName . 'Time', $this->time(), $seconds); + + $this->tokenTime = 0; return true; } + // How many seconds till a new token is available. + // We must have a minimum wait of 1 second for a new token. + // Primarily stored to allow devs to report back to users. + $newTokenAvailable = (int) ($refresh - $elapsed - $refresh * $tokens); + $this->tokenTime = max(1, $newTokenAvailable); + return false; } @@ -164,6 +171,8 @@ public function setTestTime(int $time) /** * Return the test time, defaulting to current. + * + * @TODO should be private */ public function time(): int { diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index 2167e28cba79..4d02f221365d 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -23,7 +23,7 @@ class FormatRules */ public function alpha(?string $str = null): bool { - return ctype_alpha($str); + return ctype_alpha($str ?? ''); } /** @@ -45,11 +45,16 @@ public function alpha_space(?string $value = null): bool /** * Alphanumeric with underscores and dashes + * + * @see https://regex101.com/r/XfVY3d/1 */ public function alpha_dash(?string $str = null): bool { - // @see https://regex101.com/r/XfVY3d/1 - return (bool) preg_match('/\A[a-z0-9_-]+\z/i', $str); + if ($str === null) { + return false; + } + + return preg_match('/\A[a-z0-9_-]+\z/i', $str) === 1; } /** @@ -59,14 +64,19 @@ public function alpha_dash(?string $str = null): bool * _ underscore, + plus, = equals, | vertical bar, : colon, . period * ~ ! # $ % & * - _ + = | : . * - * @param string $str + * @param string|null $str * * @return bool + * + * @see https://regex101.com/r/6N8dDY/1 */ public function alpha_numeric_punct($str) { - // @see https://regex101.com/r/6N8dDY/1 - return (bool) preg_match('/\A[A-Z0-9 ~!#$%\&\*\-_+=|:.]+\z/i', $str); + if ($str === null) { + return false; + } + + return preg_match('/\A[A-Z0-9 ~!#$%\&\*\-_+=|:.]+\z/i', $str) === 1; } /** @@ -74,7 +84,7 @@ public function alpha_numeric_punct($str) */ public function alpha_numeric(?string $str = null): bool { - return ctype_alnum($str); + return ctype_alnum($str ?? ''); } /** @@ -83,7 +93,7 @@ public function alpha_numeric(?string $str = null): bool public function alpha_numeric_space(?string $str = null): bool { // @see https://regex101.com/r/0AZDME/1 - return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str); + return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str ?? ''); } /** @@ -105,7 +115,7 @@ public function string($str = null): bool public function decimal(?string $str = null): bool { // @see https://regex101.com/r/HULifl/2/ - return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str); + return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str ?? ''); } /** @@ -113,7 +123,7 @@ public function decimal(?string $str = null): bool */ public function hex(?string $str = null): bool { - return ctype_xdigit($str); + return ctype_xdigit($str ?? ''); } /** @@ -121,7 +131,7 @@ public function hex(?string $str = null): bool */ public function integer(?string $str = null): bool { - return (bool) preg_match('/\A[\-+]?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d+\z/', $str ?? ''); } /** @@ -129,7 +139,7 @@ public function integer(?string $str = null): bool */ public function is_natural(?string $str = null): bool { - return ctype_digit($str); + return ctype_digit($str ?? ''); } /** @@ -137,7 +147,7 @@ public function is_natural(?string $str = null): bool */ public function is_natural_no_zero(?string $str = null): bool { - return $str !== '0' && ctype_digit($str); + return $str !== '0' && ctype_digit($str ?? ''); } /** @@ -146,7 +156,7 @@ public function is_natural_no_zero(?string $str = null): bool public function numeric(?string $str = null): bool { // @see https://regex101.com/r/bb9wtr/2 - return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str ?? ''); } /** @@ -158,7 +168,7 @@ public function regex_match(?string $str, string $pattern): bool $pattern = "/{$pattern}/"; } - return (bool) preg_match($pattern, $str); + return (bool) preg_match($pattern, $str ?? ''); } /** @@ -171,7 +181,7 @@ public function regex_match(?string $str, string $pattern): bool */ public function timezone(?string $str = null): bool { - return in_array($str, timezone_identifiers_list(), true); + return in_array($str ?? '', timezone_identifiers_list(), true); } /** @@ -184,6 +194,10 @@ public function timezone(?string $str = null): bool */ public function valid_base64(?string $str = null): bool { + if ($str === null) { + return false; + } + return base64_encode(base64_decode($str, true)) === $str; } @@ -194,7 +208,7 @@ public function valid_base64(?string $str = null): bool */ public function valid_json(?string $str = null): bool { - json_decode($str); + json_decode($str ?? ''); return json_last_error() === JSON_ERROR_NONE; } @@ -207,7 +221,7 @@ public function valid_json(?string $str = null): bool public function valid_email(?string $str = null): bool { // @see https://regex101.com/r/wlJG1t/1/ - if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str, $matches)) { + if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str ?? '', $matches)) { $str = $matches[1] . '@' . idn_to_ascii($matches[2], 0, INTL_IDNA_VARIANT_UTS46); } @@ -224,8 +238,9 @@ public function valid_email(?string $str = null): bool */ public function valid_emails(?string $str = null): bool { - foreach (explode(',', $str) as $email) { + foreach (explode(',', $str ?? '') as $email) { $email = trim($email); + if ($email === '') { return false; } @@ -241,8 +256,7 @@ public function valid_emails(?string $str = null): bool /** * Validate an IP address (human readable format or binary string - inet_pton) * - * @param string $ip IP Address - * @param string $which IP protocol: 'ipv4' or 'ipv6' + * @param string|null $which IP protocol: 'ipv4' or 'ipv6' */ public function valid_ip(?string $ip = null, ?string $which = null): bool { @@ -250,7 +264,7 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool return false; } - switch (strtolower($which)) { + switch (strtolower($which ?? '')) { case 'ipv4': $which = FILTER_FLAG_IPV4; break; @@ -260,11 +274,11 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool break; default: - $which = null; - break; + $which = 0; } - return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which) || (! ctype_print($ip) && (bool) filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which)); + return filter_var($ip, FILTER_VALIDATE_IP, $which) !== false + || (! ctype_print($ip) && filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which) !== false); } /** @@ -272,8 +286,6 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool * * Warning: this rule will pass basic strings like * "banana"; use valid_url_strict for a stricter rule. - * - * @param string $str */ public function valid_url(?string $str = null): bool { @@ -305,7 +317,7 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu return false; } - $scheme = strtolower(parse_url($str, PHP_URL_SCHEME)); + $scheme = strtolower(parse_url($str, PHP_URL_SCHEME) ?? ''); // absent scheme gives null $validSchemes = explode( ',', strtolower($validSchemes ?? 'http,https') @@ -317,18 +329,16 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu /** * Checks for a valid date and matches a given date format - * - * @param string $str - * @param string $format */ public function valid_date(?string $str = null, ?string $format = null): bool { if (empty($format)) { - return (bool) strtotime($str); + return strtotime($str) !== false; } - $date = DateTime::createFromFormat($format, $str); + $date = DateTime::createFromFormat($format, $str); + $errors = DateTime::getLastErrors(); - return (bool) $date && DateTime::getLastErrors()['warning_count'] === 0 && DateTime::getLastErrors()['error_count'] === 0; + return $date !== false && $errors !== false && $errors['warning_count'] === 0 && $errors['error_count'] === 0; } } diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 20f558e52be2..aba9ff117df6 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -22,8 +22,7 @@ class Rules /** * The value does not match another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function differs(?string $str, string $field, array $data): bool { @@ -36,8 +35,6 @@ public function differs(?string $str, string $field, array $data): bool /** * Equals the static value provided. - * - * @param string $str */ public function equals(?string $str, string $val): bool { @@ -47,15 +44,13 @@ public function equals(?string $str, string $val): bool /** * Returns true if $str is $val characters long. * $val = "5" (one) | "5,8,12" (multiple values) - * - * @param string $str */ public function exact_length(?string $str, string $val): bool { $val = explode(',', $val); foreach ($val as $tmp) { - if (is_numeric($tmp) && (int) $tmp === mb_strlen($str)) { + if (is_numeric($tmp) && (int) $tmp === mb_strlen($str ?? '')) { return true; } } @@ -65,8 +60,6 @@ public function exact_length(?string $str, string $val): bool /** * Greater than - * - * @param string $str */ public function greater_than(?string $str, string $min): bool { @@ -75,8 +68,6 @@ public function greater_than(?string $str, string $min): bool /** * Equal to or Greater than - * - * @param string $str */ public function greater_than_equal_to(?string $str, string $min): bool { @@ -91,8 +82,6 @@ public function greater_than_equal_to(?string $str, string $min): bool * Example: * is_not_unique[table.field,where_field,where_value] * is_not_unique[menu.id,active,1] - * - * @param string $str */ public function is_not_unique(?string $str, string $field, array $data): bool { @@ -102,9 +91,8 @@ public function is_not_unique(?string $str, string $field, array $data): bool // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -118,8 +106,6 @@ public function is_not_unique(?string $str, string $field, array $data): bool /** * Value should be within an array of values - * - * @param string $value */ public function in_list(?string $value, string $list): bool { @@ -136,20 +122,15 @@ public function in_list(?string $value, string $list): bool * Example: * is_unique[table.field,ignore_field,ignore_value] * is_unique[users.email,id,5] - * - * @param string $str */ public function is_unique(?string $str, string $field, array $data): bool { - // Grab any data for exclusion of a single row. [$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null); - // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -163,8 +144,6 @@ public function is_unique(?string $str, string $field, array $data): bool /** * Less than - * - * @param string $str */ public function less_than(?string $str, string $max): bool { @@ -173,8 +152,6 @@ public function less_than(?string $str, string $max): bool /** * Equal to or Less than - * - * @param string $str */ public function less_than_equal_to(?string $str, string $max): bool { @@ -184,8 +161,7 @@ public function less_than_equal_to(?string $str, string $max): bool /** * Matches the value of another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function matches(?string $str, string $field, array $data): bool { @@ -198,22 +174,18 @@ public function matches(?string $str, string $field, array $data): bool /** * Returns true if $str is $val or fewer characters in length. - * - * @param string $str */ public function max_length(?string $str, string $val): bool { - return is_numeric($val) && $val >= mb_strlen($str); + return is_numeric($val) && $val >= mb_strlen($str ?? ''); } /** * Returns true if $str is at least $val length. - * - * @param string $str */ public function min_length(?string $str, string $val): bool { - return is_numeric($val) && $val <= mb_strlen($str); + return is_numeric($val) && $val <= mb_strlen($str ?? ''); } /** @@ -237,19 +209,23 @@ public function not_in_list(?string $value, string $list): bool } /** - * Required - * - * @param mixed $str Value - * - * @return bool True if valid, false if not + * @param mixed $str */ public function required($str = null): bool { + if ($str === null) { + return false; + } + if (is_object($str)) { return true; } - return is_array($str) ? ! empty($str) : (trim($str) !== ''); + if (is_array($str)) { + return $str !== []; + } + + return trim((string) $str) !== ''; } /** @@ -270,11 +246,10 @@ public function required_with($str = null, ?string $fields = null, array $data = throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { @@ -311,11 +286,10 @@ public function required_without($str = null, ?string $fields = null, array $dat throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 8bd14817e79d..39af6703f8df 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -139,16 +139,22 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup } $values = dot_array_search($field, $data); - $values = is_array($values) ? $values : [$values]; if ($values === []) { // We'll process the values right away if an empty array $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data); + + continue; } - foreach ($values as $value) { - // Otherwise, we'll let the loop do the job - $this->processRules($field, $setup['label'] ?? $field, $value, $rules, $data); + if (strpos($field, '*') !== false && is_array($values)) { + // Process multiple fields + foreach ($values as $value) { + $this->processRules($field, $setup['label'] ?? $field, $value, $rules, $data); + } + } else { + // Process single field + $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data); } } @@ -194,11 +200,15 @@ protected function processRules(string $field, ?string $label, $value, $rules = // that can be used later $ifExistField = str_replace('\.\*', '\.(?:[^\.]+)', preg_quote($field, '/')); - $dataIsExisting = array_reduce(array_keys($flattenedData), static function ($carry, $item) use ($ifExistField) { - $pattern = sprintf('/%s/u', $ifExistField); + $dataIsExisting = array_reduce( + array_keys($flattenedData), + static function ($carry, $item) use ($ifExistField) { + $pattern = sprintf('/%s/u', $ifExistField); - return $carry || preg_match($pattern, $item) === 1; - }, false); + return $carry || preg_match($pattern, $item) === 1; + }, + false + ); } else { $dataIsExisting = array_key_exists($ifExistField, $flattenedData); } @@ -215,7 +225,10 @@ protected function processRules(string $field, ?string $label, $value, $rules = } if (in_array('permit_empty', $rules, true)) { - if (! in_array('required', $rules, true) && (is_array($value) ? empty($value) : (trim($value) === ''))) { + if ( + ! in_array('required', $rules, true) + && (is_array($value) ? $value === [] : trim((string) $value) === '') + ) { $passed = true; foreach ($rules as $rule) { @@ -261,7 +274,7 @@ protected function processRules(string $field, ?string $label, $value, $rules = // Placeholder for custom errors from the rules. $error = null; - // If it's a callable, call and and get out of here. + // If it's a callable, call and get out of here. if ($isCallable) { $passed = $param === false ? $rule($value) : $rule($value, $param, $data); } else { @@ -274,7 +287,9 @@ protected function processRules(string $field, ?string $label, $value, $rules = } $found = true; - $passed = $param === false ? $set->{$rule}($value, $error) : $set->{$rule}($value, $param, $data, $error); + $passed = $param === false + ? $set->{$rule}($value, $error) + : $set->{$rule}($value, $param, $data, $error); break; } @@ -295,7 +310,15 @@ protected function processRules(string $field, ?string $label, $value, $rules = $value = json_encode($value); } - $this->errors[$field] = $error ?? $this->getErrorMessage($rule, $field, $label, $param, $value); + $param = ($param === false) ? '' : $param; + + $this->errors[$field] = $error ?? $this->getErrorMessage( + $rule, + $field, + $label, + $param, + (string) $value + ); return false; } @@ -570,13 +593,13 @@ protected function fillPlaceholders(array $rules, array $data): array continue; } - $row = strtr($row, $replacements); + $row = strtr($row ?? '', $replacements); } continue; } - $rule = strtr($rule, $replacements); + $rule = strtr($rule ?? '', $replacements); } } @@ -594,10 +617,6 @@ public function hasError(string $field): bool /** * Returns the error(s) for a specified $field (or empty string if not * set). - * - * @param string $field Field. - * - * @return string Error(s). */ public function getError(?string $field = null): string { @@ -617,9 +636,7 @@ public function getError(?string $field = null): string * 'field2' => 'error message', * ] * - * @return array - * - * Excluded from code coverage because that it always run as cli + * @return array * * @codeCoverageIgnore */ @@ -648,11 +665,12 @@ public function setError(string $field, string $error): ValidationInterface /** * Attempts to find the appropriate error message * - * @param string $param - * @param string $value The value that caused the validation to fail. + * @param string|null $value The value that caused the validation to fail. */ protected function getErrorMessage(string $rule, string $field, ?string $label = null, ?string $param = null, ?string $value = null): string { + $param = $param ?? ''; + // Check if custom message has been defined by user if (isset($this->customErrors[$field][$rule])) { $message = lang($this->customErrors[$field][$rule]); @@ -664,9 +682,13 @@ protected function getErrorMessage(string $rule, string $field, ?string $label = } $message = str_replace('{field}', empty($label) ? $field : lang($label), $message); - $message = str_replace('{param}', empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), $message); + $message = str_replace( + '{param}', + empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), + $message + ); - return str_replace('{value}', $value, $message); + return str_replace('{value}', $value ?? '', $message); } /** diff --git a/system/View/Table.php b/system/View/Table.php index d57a7092de00..539fd193c2a3 100644 --- a/system/View/Table.php +++ b/system/View/Table.php @@ -179,9 +179,8 @@ public function makeColumns($array = [], $columnLimit = 0) } $new[] = $temp; - } while (count($array) > 0); + } while ($array !== []); - // @phpstan-ignore-next-line return $new; } diff --git a/system/View/View.php b/system/View/View.php index 6005b5f40582..e65416e5cf48 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -199,11 +199,7 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n } // Make our view data available to the view. - $this->tempData = $this->tempData ?? $this->data; - - if ($saveData) { - $this->data = $this->tempData; - } + $this->prepareTemplateData($saveData); // Save current vars $renderVars = $this->renderVars; @@ -275,13 +271,9 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n */ public function renderString(string $view, ?array $options = null, ?bool $saveData = null): string { - $start = microtime(true); - $saveData = $saveData ?? $this->saveData; - $this->tempData = $this->tempData ?? $this->data; - - if ($saveData) { - $this->data = $this->tempData; - } + $start = microtime(true); + $saveData = $saveData ?? $this->saveData; + $this->prepareTemplateData($saveData); $output = (function (string $view): string { extract($this->tempData); @@ -454,4 +446,13 @@ protected function logPerformance(float $start, float $end, string $view) ]; } } + + protected function prepareTemplateData(bool $saveData): void + { + $this->tempData = $this->tempData ?? $this->data; + + if ($saveData) { + $this->data = $this->tempData; + } + } } diff --git a/system/bootstrap.php b/system/bootstrap.php index 17226d099974..4549fbc2c939 100644 --- a/system/bootstrap.php +++ b/system/bootstrap.php @@ -117,7 +117,7 @@ class_alias('Config\Services', 'CodeIgniter\Services'); * We do not want to enforce this, so set the constant if Composer was used. */ if (! defined('VENDORPATH')) { - define('VENDORPATH', realpath(ROOTPATH . 'vendor') . DIRECTORY_SEPARATOR); + define('VENDORPATH', dirname(COMPOSER_PATH) . DIRECTORY_SEPARATOR); } require_once COMPOSER_PATH; diff --git a/tests/_support/Entity/User.php b/tests/_support/Entity/User.php new file mode 100644 index 000000000000..dc8a3954341d --- /dev/null +++ b/tests/_support/Entity/User.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Entity; + +use CodeIgniter\Entity\Entity; + +class User extends Entity +{ + protected $attributes = [ + 'country' => 'India', + ]; +} diff --git a/tests/_support/Models/UserObjModel.php b/tests/_support/Models/UserObjModel.php new file mode 100644 index 000000000000..ea461ec64fb3 --- /dev/null +++ b/tests/_support/Models/UserObjModel.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Models; + +use CodeIgniter\Model; + +class UserObjModel extends Model +{ + protected $table = 'user'; + protected $allowedFields = [ + 'name', + 'email', + 'country', + 'deleted_at', + ]; + protected $returnType = \Tests\Support\Entity\User::class; + protected $useSoftDeletes = true; + protected $dateFormat = 'datetime'; +} diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 958be5434689..abff4ce0c1a9 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\API; +use CodeIgniter\Format\FormatterInterface; use CodeIgniter\Format\JSONFormatter; use CodeIgniter\Format\XMLFormatter; use CodeIgniter\HTTP\URI; @@ -30,7 +31,7 @@ final class ResponseTraitTest extends CIUnitTestCase protected $response; /** - * @var Response formatter + * @var FormatterInterface|null */ protected $formatter; @@ -488,7 +489,7 @@ public function testXMLFormatter() $this->formatter = new XMLFormatter(); $controller = $this->makeController(); - $this->assertSame('CodeIgniter\Format\XMLFormatter', get_class($this->formatter)); + $this->assertInstanceOf('CodeIgniter\Format\XMLFormatter', $this->formatter); $controller->respondCreated(['id' => 3], 'A Custom Reason'); $expected = <<<'EOH' diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index c85e4c215ba2..3a40ed24345b 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -39,8 +39,11 @@ protected function setUp(): void TESTPATH, SYSTEMPATH, ], - 'Errors' => APPPATH . 'Views/errors', - 'System' => SUPPORTPATH . 'Autoloader/system', + 'Errors' => APPPATH . 'Views/errors', + 'System' => SUPPORTPATH . 'Autoloader/system', + 'CodeIgniter\\Devkit' => [ + TESTPATH . '_support/', + ], ]); $this->locator = new FileLocator($autoloader); @@ -125,6 +128,15 @@ public function testLocateFileCanFindNestedNamespacedView() $this->assertSame($expected, $this->locator->locateFile($file, 'html')); } + public function testLocateFileCanFindNamespacedViewWhenVendorHasTwoNamespaces() + { + $file = '\CodeIgniter\Devkit\View\Views/simple'; + + $expected = ROOTPATH . 'tests/_support/View/Views/simple.php'; + + $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); + } + public function testLocateFileNotFoundExistingNamespace() { $file = '\App\Views/unexistence-file.php'; diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index a5b3dd1e9783..087c28c12072 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -67,7 +67,7 @@ public function testHeader() $console = new Console($this->app); $console->showHeader(); $result = CITestStreamFilter::$buffer; - $this->assertTrue(strpos($result, sprintf('CodeIgniter v%s Command Line Tool', CodeIgniter::CI_VERSION)) > 0); + $this->assertGreaterThan(0, strpos($result, sprintf('CodeIgniter v%s Command Line Tool', CodeIgniter::CI_VERSION))); } public function testNoHeader() diff --git a/tests/system/Cache/Handlers/MemcachedHandlerTest.php b/tests/system/Cache/Handlers/MemcachedHandlerTest.php index 38005d87ed5b..08a28f376fe7 100644 --- a/tests/system/Cache/Handlers/MemcachedHandlerTest.php +++ b/tests/system/Cache/Handlers/MemcachedHandlerTest.php @@ -37,6 +37,10 @@ protected function setUp(): void { parent::setUp(); + if (! extension_loaded('memcached')) { + $this->markTestSkipped('Memcached extension not loaded.'); + } + $this->config = new Cache(); $this->handler = new MemcachedHandler($this->config); diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index 4eb8f8b08560..205e708fc99a 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -36,6 +36,10 @@ protected function setUp(): void { parent::setUp(); + if (! extension_loaded('redis')) { + $this->markTestSkipped('redis extension not loaded.'); + } + $this->config = new Cache(); $this->handler = new RedisHandler($this->config); diff --git a/tests/system/Commands/BaseCommandTest.php b/tests/system/Commands/BaseCommandTest.php index 7295c05e4d0c..5f9764208042 100644 --- a/tests/system/Commands/BaseCommandTest.php +++ b/tests/system/Commands/BaseCommandTest.php @@ -35,14 +35,14 @@ public function testMagicIssetTrue() { $command = new AppInfo($this->logger, service('commands')); - $this->assertTrue(isset($command->group)); + $this->assertObjectHasAttribute('group', $command); } public function testMagicIssetFalse() { $command = new AppInfo($this->logger, service('commands')); - $this->assertFalse(isset($command->foobar)); + $this->assertObjectNotHasAttribute('foobar', $command); } public function testMagicGet() diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index ba4c1e7a4e07..3916a1ab785f 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -29,6 +29,7 @@ use Config\Logger; use Config\Modules; use InvalidArgumentException; +use Kint; use stdClass; use Tests\Support\Models\JobModel; @@ -41,10 +42,10 @@ final class CommonFunctionsTest extends CIUnitTestCase { protected function setUp(): void { - parent::setUp(); - $renderer = Services::renderer(); - $renderer->resetData(); unset($_ENV['foo'], $_SERVER['foo']); + Services::reset(); + + parent::setUp(); } public function testStringifyAttributes() @@ -300,7 +301,7 @@ public function testOldInput() $_GET = ['foo' => 'bar']; $_POST = [ 'bar' => 'baz', - 'zibble' => serialize('fritz'), + 'zibble' => 'fritz', ]; $response = new RedirectResponse(new App()); @@ -308,7 +309,40 @@ public function testOldInput() $this->assertSame('bar', old('foo')); // regular parameter $this->assertSame('doo', old('yabba dabba', 'doo')); // non-existing parameter - $this->assertSame('fritz', old('zibble')); // serialized parameter + $this->assertSame('fritz', old('zibble')); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testOldInputSerializeData() + { + $this->injectSessionMock(); + // setup from RedirectResponseTest... + $_SERVER['REQUEST_METHOD'] = 'GET'; + + $this->config = new App(); + $this->config->baseURL = 'http://example.com/'; + + $this->routes = new RouteCollection(Services::locator(), new Modules()); + Services::injectMock('routes', $this->routes); + + $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + Services::injectMock('request', $this->request); + + // setup & ask for a redirect... + $_SESSION = []; + $_GET = []; + $_POST = [ + 'zibble' => serialize('fritz'), + ]; + + $response = new RedirectResponse(new App()); + $response->withInput(); + + // serialized parameters are only HTML-escaped. + $this->assertSame('s:5:"fritz";', old('zibble')); } /** @@ -482,4 +516,37 @@ public function testIsCli() $this->assertIsBool(is_cli()); $this->assertTrue(is_cli()); } + + public function testDWithCSP() + { + /** @var App $config */ + $config = config(App::class); + $CSPEnabled = $config->CSPEnabled; + $cliDetection = Kint::$cli_detection; + + $config->CSPEnabled = true; + Kint::$cli_detection = false; + + $this->expectOutputRegex('/