🍲dfcv🏰dd⋉(● ∸ ●)⋊@% PNG %k25u25%fgd5n! PNG %k25u25%fgd5n!PKk]]AVfflaravel-debugbar/CHANGELOG.mdnuW+A# Changelog ## v3.15.4 - 2025-04-16 ### What's Changed * Remove html `` tag from route on clockwork by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1777 * Fix default for capturing dd/dump by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1783 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.15.3...v3.15.4 ## v3.15.3 - 2025-04-08 ### What's Changed * Add condition for implemented query grammar by @rikwillems in https://github.com/barryvdh/laravel-debugbar/pull/1757 * Collect dumps on message collector by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1759 * Fix `capture_dumps` option on laravel `dd();` by @parallels999 in https://github.com/barryvdh/laravel-debugbar/pull/1762 * Preserve laravel error handler by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1760 * Fix `Trying to access array offset on false on LogsCollector.php` by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1763 * Update css theme for views widget by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1768 * Fix laravel-debugbar.css on query widget by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1765 * Use htmlvardumper if available on CacheCollector by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1766 * Update QueryCollector.php fix issue #1775 by @Mathias-DS in https://github.com/barryvdh/laravel-debugbar/pull/1776 * Better grouping the events count by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1774 ### New Contributors * @rikwillems made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1757 * @Mathias-DS made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1776 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.15.2...v3.15.3 ## v3.15.2 - 2025-02-25 ### What's Changed * Fix empty tabs on clockwork by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1750 * fix: Ignore info query statements in Clockwork converter by @boserup in https://github.com/barryvdh/laravel-debugbar/pull/1749 * Check if request controller is string by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1751 ### New Contributors * @boserup made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1749 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.15.1...v3.15.2 ## v3.15.1 - 2025-02-24 ### What's Changed * Hide more empty tabs by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1742 * Always show application by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1745 * Add conflict with old debugbar by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1746 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.15.0...v3.15.1 ## v3.15.0 - 2025-02-21 ### What's Changed * Add middleware to web to save session by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1710 * Check web middleware by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1712 * Add special `dev` to composer keywords by @jnoordsij in https://github.com/barryvdh/laravel-debugbar/pull/1713 * Removed extra sentence by @cheack in https://github.com/barryvdh/laravel-debugbar/pull/1714 * Hide empty tabs by default by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1711 * Combine route info with Request by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1720 * fix: The log is not processed correctly when it consists of multiple lines. by @uniho in https://github.com/barryvdh/laravel-debugbar/pull/1721 * [WIP] Use php-debugbar dark theme, move to variables by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1717 * Remove openhandler overrides by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1723 * Drop Lumen And Laravel 9 by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1725 * Use tooltip for Laravel collector by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1724 * Add more data to timeline by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1726 * Laravel version preview as repo branch name by @angeljqv in https://github.com/barryvdh/laravel-debugbar/pull/1727 * Laravel 12 support by @jonnott in https://github.com/barryvdh/laravel-debugbar/pull/1730 * Preview action_name on request tooltip by @angeljqv in https://github.com/barryvdh/laravel-debugbar/pull/1728 * Map tooltips by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1732 * Add back L9 by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1734 * Fix tooltip url by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1735 * Show request status as badge by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1736 * Fix request badge by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1737 * Use Laravel ULID for key by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1738 * defer datasets by config option by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1739 * Reorder request tab by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1740 * Defer config by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1741 ### New Contributors * @cheack made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1714 * @angeljqv made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1727 * @jonnott made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1730 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.14.10...v3.15.0 ## v3.14.10 - 2024-12-23 ### What's Changed * Fix Debugbar spelling inconsistencies by @ralphjsmit in https://github.com/barryvdh/laravel-debugbar/pull/1626 * Fix Visual Explain confirm message by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1709 ### New Contributors * @ralphjsmit made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1626 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.14.9...v3.14.10 ## v3.14.9 - 2024-11-25 ### What's Changed * Fix custom prototype array by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1706 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.14.8...v3.14.9 ## v3.14.8 - 2024-11-25 ### What's Changed * Add fix + failing test for custom array prototype by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1705 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.14.7...v3.14.8 ## v3.14.7 - 2024-11-14 ### What's Changed * Make better use of query tab space by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1694 * Do not open query details on text selecting by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1693 * Add (initial) support for PHP 8.4 by @jnoordsij in https://github.com/barryvdh/laravel-debugbar/pull/1631 * More warnings by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1696 * Fix sql-duplicate highlight by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1699 * ci: Use GitHub Actions V4 by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1700 * Fix "Uncaught TypeError: is not iterable" by @erikn69 in https://github.com/barryvdh/laravel-debugbar/pull/1701 * Fix Exception when QueryCollector softLimit exceeded by @johnkary in https://github.com/barryvdh/laravel-debugbar/pull/1702 * Test soft/hard limit queries by @barryvdh in https://github.com/barryvdh/laravel-debugbar/pull/1703 ### New Contributors * @johnkary made their first contribution in https://github.com/barryvdh/laravel-debugbar/pull/1702 **Full Changelog**: https://github.com/barryvdh/laravel-debugbar/compare/v3.14.6...v3.14.7 PKk]Z*vddlaravel-debugbar/composer.jsonnuW+A{ "name": "barryvdh/laravel-debugbar", "description": "PHP Debugbar integration for Laravel", "keywords": [ "laravel", "debugbar", "profiler", "debug", "webprofiler", "dev" ], "license": "MIT", "authors": [ { "name": "Barry vd. Heuvel", "email": "barryvdh@gmail.com" } ], "require": { "php": "^8.1", "php-debugbar/php-debugbar": "~2.2.0", "illuminate/routing": "^9|^10|^11|^12", "illuminate/session": "^9|^10|^11|^12", "illuminate/support": "^9|^10|^11|^12", "symfony/finder": "^6|^7" }, "require-dev": { "mockery/mockery": "^1.3.3", "orchestra/testbench-dusk": "^7|^8|^9|^10", "phpunit/phpunit": "^9.5.10|^10|^11", "squizlabs/php_codesniffer": "^3.5" }, "autoload": { "psr-4": { "Barryvdh\\Debugbar\\": "src/" }, "files": [ "src/helpers.php" ] }, "autoload-dev": { "psr-4": { "Barryvdh\\Debugbar\\Tests\\": "tests" } }, "minimum-stability": "dev", "prefer-stable": true, "extra": { "branch-alias": { "dev-master": "3.16-dev" }, "laravel": { "providers": [ "Barryvdh\\Debugbar\\ServiceProvider" ], "aliases": { "Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar" } } }, "scripts": { "check-style": "phpcs", "fix-style": "phpcbf", "test": "phpunit" } } PKk]{dFF$laravel-debugbar/config/debugbar.phpnuW+A env('DEBUGBAR_ENABLED', null), 'hide_empty_tabs' => env('DEBUGBAR_HIDE_EMPTY_TABS', true), // Hide tabs until they have content 'except' => [ 'telescope*', 'horizon*', ], /* |-------------------------------------------------------------------------- | Storage settings |-------------------------------------------------------------------------- | | Debugbar stores data for session/ajax requests. | You can disable this, so the debugbar stores data in headers/session, | but this can cause problems with large data collectors. | By default, file storage (in the storage folder) is used. Redis and PDO | can also be used. For PDO, run the package migrations first. | | Warning: Enabling storage.open will allow everyone to access previous | request, do not enable open storage in publicly available environments! | Specify a callback if you want to limit based on IP or authentication. | Leaving it to null will allow localhost only. */ 'storage' => [ 'enabled' => env('DEBUGBAR_STORAGE_ENABLED', true), 'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback. 'driver' => env('DEBUGBAR_STORAGE_DRIVER', 'file'), // redis, file, pdo, socket, custom 'path' => env('DEBUGBAR_STORAGE_PATH', storage_path('debugbar')), // For file driver 'connection' => env('DEBUGBAR_STORAGE_CONNECTION', null), // Leave null for default connection (Redis/PDO) 'provider' => env('DEBUGBAR_STORAGE_PROVIDER', ''), // Instance of StorageInterface for custom driver 'hostname' => env('DEBUGBAR_STORAGE_HOSTNAME', '127.0.0.1'), // Hostname to use with the "socket" driver 'port' => env('DEBUGBAR_STORAGE_PORT', 2304), // Port to use with the "socket" driver ], /* |-------------------------------------------------------------------------- | Editor |-------------------------------------------------------------------------- | | Choose your preferred editor to use when clicking file name. | | Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote", | "vscode-insiders-remote", "vscodium", "textmate", "emacs", | "sublime", "atom", "nova", "macvim", "idea", "netbeans", | "xdebug", "espresso" | */ 'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'), /* |-------------------------------------------------------------------------- | Remote Path Mapping |-------------------------------------------------------------------------- | | If you are using a remote dev server, like Laravel Homestead, Docker, or | even a remote VPS, it will be necessary to specify your path mapping. | | Leaving one, or both of these, empty or null will not trigger the remote | URL changes and Debugbar will treat your editor links as local files. | | "remote_sites_path" is an absolute base path for your sites or projects | in Homestead, Vagrant, Docker, or another remote development server. | | Example value: "/home/vagrant/Code" | | "local_sites_path" is an absolute base path for your sites or projects | on your local computer where your IDE or code editor is running on. | | Example values: "/Users//Code", "C:\Users\\Documents\Code" | */ 'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'), 'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')), /* |-------------------------------------------------------------------------- | Vendors |-------------------------------------------------------------------------- | | Vendor files are included by default, but can be set to false. | This can also be set to 'js' or 'css', to only include javascript or css vendor files. | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files) | and for js: jquery and highlight.js | So if you want syntax highlighting, set it to true. | jQuery is set to not conflict with existing jQuery scripts. | */ 'include_vendors' => env('DEBUGBAR_INCLUDE_VENDORS', true), /* |-------------------------------------------------------------------------- | Capture Ajax Requests |-------------------------------------------------------------------------- | | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors), | you can use this option to disable sending the data through the headers. | | Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools. | | Note for your request to be identified as ajax requests they must either send the header | X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header. | | By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar. | Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading. | | You can defer loading the dataset, so it will be loaded with ajax after the request is done. (Experimental) */ 'capture_ajax' => env('DEBUGBAR_CAPTURE_AJAX', true), 'add_ajax_timing' => env('DEBUGBAR_ADD_AJAX_TIMING', false), 'ajax_handler_auto_show' => env('DEBUGBAR_AJAX_HANDLER_AUTO_SHOW', true), 'ajax_handler_enable_tab' => env('DEBUGBAR_AJAX_HANDLER_ENABLE_TAB', true), 'defer_datasets' => env('DEBUGBAR_DEFER_DATASETS', false), /* |-------------------------------------------------------------------------- | Custom Error Handler for Deprecated warnings |-------------------------------------------------------------------------- | | When enabled, the Debugbar shows deprecated warnings for Symfony components | in the Messages tab. | */ 'error_handler' => env('DEBUGBAR_ERROR_HANDLER', false), /* |-------------------------------------------------------------------------- | Clockwork integration |-------------------------------------------------------------------------- | | The Debugbar can emulate the Clockwork headers, so you can use the Chrome | Extension, without the server-side code. It uses Debugbar collectors instead. | */ 'clockwork' => env('DEBUGBAR_CLOCKWORK', false), /* |-------------------------------------------------------------------------- | DataCollectors |-------------------------------------------------------------------------- | | Enable/disable DataCollectors | */ 'collectors' => [ 'phpinfo' => env('DEBUGBAR_COLLECTORS_PHPINFO', false), // Php version 'messages' => env('DEBUGBAR_COLLECTORS_MESSAGES', true), // Messages 'time' => env('DEBUGBAR_COLLECTORS_TIME', true), // Time Datalogger 'memory' => env('DEBUGBAR_COLLECTORS_MEMORY', true), // Memory usage 'exceptions' => env('DEBUGBAR_COLLECTORS_EXCEPTIONS', true), // Exception displayer 'log' => env('DEBUGBAR_COLLECTORS_LOG', true), // Logs from Monolog (merged in messages if enabled) 'db' => env('DEBUGBAR_COLLECTORS_DB', true), // Show database (PDO) queries and bindings 'views' => env('DEBUGBAR_COLLECTORS_VIEWS', true), // Views with their data 'route' => env('DEBUGBAR_COLLECTORS_ROUTE', false), // Current route information 'auth' => env('DEBUGBAR_COLLECTORS_AUTH', false), // Display Laravel authentication status 'gate' => env('DEBUGBAR_COLLECTORS_GATE', true), // Display Laravel Gate checks 'session' => env('DEBUGBAR_COLLECTORS_SESSION', false), // Display session data 'symfony_request' => env('DEBUGBAR_COLLECTORS_SYMFONY_REQUEST', true), // Only one can be enabled.. 'mail' => env('DEBUGBAR_COLLECTORS_MAIL', true), // Catch mail messages 'laravel' => env('DEBUGBAR_COLLECTORS_LARAVEL', true), // Laravel version and environment 'events' => env('DEBUGBAR_COLLECTORS_EVENTS', false), // All events fired 'default_request' => env('DEBUGBAR_COLLECTORS_DEFAULT_REQUEST', false), // Regular or special Symfony request logger 'logs' => env('DEBUGBAR_COLLECTORS_LOGS', false), // Add the latest log messages 'files' => env('DEBUGBAR_COLLECTORS_FILES', false), // Show the included files 'config' => env('DEBUGBAR_COLLECTORS_CONFIG', false), // Display config settings 'cache' => env('DEBUGBAR_COLLECTORS_CACHE', false), // Display cache events 'models' => env('DEBUGBAR_COLLECTORS_MODELS', true), // Display models 'livewire' => env('DEBUGBAR_COLLECTORS_LIVEWIRE', true), // Display Livewire (when available) 'jobs' => env('DEBUGBAR_COLLECTORS_JOBS', false), // Display dispatched jobs 'pennant' => env('DEBUGBAR_COLLECTORS_PENNANT', false), // Display Pennant feature flags ], /* |-------------------------------------------------------------------------- | Extra options |-------------------------------------------------------------------------- | | Configure some DataCollectors | */ 'options' => [ 'time' => [ 'memory_usage' => env('DEBUGBAR_OPTIONS_TIME_MEMORY_USAGE', false), // Calculated by subtracting memory start and end, it may be inaccurate ], 'messages' => [ 'trace' => env('DEBUGBAR_OPTIONS_MESSAGES_TRACE', true), // Trace the origin of the debug message 'capture_dumps' => env('DEBUGBAR_OPTIONS_MESSAGES_CAPTURE_DUMPS', false), // Capture laravel `dump();` as message ], 'memory' => [ 'reset_peak' => env('DEBUGBAR_OPTIONS_MEMORY_RESET_PEAK', false), // run memory_reset_peak_usage before collecting 'with_baseline' => env('DEBUGBAR_OPTIONS_MEMORY_WITH_BASELINE', false), // Set boot memory usage as memory peak baseline 'precision' => (int) env('DEBUGBAR_OPTIONS_MEMORY_PRECISION', 0), // Memory rounding precision ], 'auth' => [ 'show_name' => env('DEBUGBAR_OPTIONS_AUTH_SHOW_NAME', true), // Also show the users name/email in the debugbar 'show_guards' => env('DEBUGBAR_OPTIONS_AUTH_SHOW_GUARDS', true), // Show the guards that are used ], 'gate' => [ 'trace' => false, // Trace the origin of the Gate checks ], 'db' => [ 'with_params' => env('DEBUGBAR_OPTIONS_WITH_PARAMS', true), // Render SQL with the parameters substituted 'exclude_paths' => [ // Paths to exclude entirely from the collector //'vendor/laravel/framework/src/Illuminate/Session', // Exclude sessions queries ], 'backtrace' => env('DEBUGBAR_OPTIONS_DB_BACKTRACE', true), // Use a backtrace to find the origin of the query in your files. 'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults) 'timeline' => env('DEBUGBAR_OPTIONS_DB_TIMELINE', false), // Add the queries to the timeline 'duration_background' => env('DEBUGBAR_OPTIONS_DB_DURATION_BACKGROUND', true), // Show shaded background on each query relative to how long it took to execute. 'explain' => [ // Show EXPLAIN output on queries 'enabled' => env('DEBUGBAR_OPTIONS_DB_EXPLAIN_ENABLED', false), ], 'hints' => env('DEBUGBAR_OPTIONS_DB_HINTS', false), // Show hints for common mistakes 'show_copy' => env('DEBUGBAR_OPTIONS_DB_SHOW_COPY', true), // Show copy button next to the query, 'slow_threshold' => env('DEBUGBAR_OPTIONS_DB_SLOW_THRESHOLD', false), // Only track queries that last longer than this time in ms 'memory_usage' => env('DEBUGBAR_OPTIONS_DB_MEMORY_USAGE', false), // Show queries memory usage 'soft_limit' => (int) env('DEBUGBAR_OPTIONS_DB_SOFT_LIMIT', 100), // After the soft limit, no parameters/backtrace are captured 'hard_limit' => (int) env('DEBUGBAR_OPTIONS_DB_HARD_LIMIT', 500), // After the hard limit, queries are ignored ], 'mail' => [ 'timeline' => env('DEBUGBAR_OPTIONS_MAIL_TIMELINE', true), // Add mails to the timeline 'show_body' => env('DEBUGBAR_OPTIONS_MAIL_SHOW_BODY', true), ], 'views' => [ 'timeline' => env('DEBUGBAR_OPTIONS_VIEWS_TIMELINE', true), // Add the views to the timeline 'data' => env('DEBUGBAR_OPTIONS_VIEWS_DATA', false), // True for all data, 'keys' for only names, false for no parameters. 'group' => (int) env('DEBUGBAR_OPTIONS_VIEWS_GROUP', 50), // Group duplicate views. Pass value to auto-group, or true/false to force 'inertia_pages' => env('DEBUGBAR_OPTIONS_VIEWS_INERTIA_PAGES', 'js/Pages'), // Path for Inertia views 'exclude_paths' => [ // Add the paths which you don't want to appear in the views 'vendor/filament' // Exclude Filament components by default ], ], 'route' => [ 'label' => env('DEBUGBAR_OPTIONS_ROUTE_LABEL', true), // Show complete route on bar ], 'session' => [ 'hiddens' => [], // Hides sensitive values using array paths ], 'symfony_request' => [ 'label' => env('DEBUGBAR_OPTIONS_SYMFONY_REQUEST_LABEL', true), // Show route on bar 'hiddens' => [], // Hides sensitive values using array paths, example: request_request.password ], 'events' => [ 'data' => env('DEBUGBAR_OPTIONS_EVENTS_DATA', false), // Collect events data, listeners 'excluded' => [], // Example: ['eloquent.*', 'composing', Illuminate\Cache\Events\CacheHit::class] ], 'logs' => [ 'file' => env('DEBUGBAR_OPTIONS_LOGS_FILE', null), ], 'cache' => [ 'values' => env('DEBUGBAR_OPTIONS_CACHE_VALUES', true), // Collect cache values ], ], /* |-------------------------------------------------------------------------- | Inject Debugbar in Response |-------------------------------------------------------------------------- | | Usually, the debugbar is added just before , by listening to the | Response after the App is done. If you disable this, you have to add them | in your template yourself. See http://phpdebugbar.com/docs/rendering.html | */ 'inject' => env('DEBUGBAR_INJECT', true), /* |-------------------------------------------------------------------------- | Debugbar route prefix |-------------------------------------------------------------------------- | | Sometimes you want to set route prefix to be used by Debugbar to load | its resources from. Usually the need comes from misconfigured web server or | from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97 | */ 'route_prefix' => env('DEBUGBAR_ROUTE_PREFIX', '_debugbar'), /* |-------------------------------------------------------------------------- | Debugbar route middleware |-------------------------------------------------------------------------- | | Additional middleware to run on the Debugbar routes */ 'route_middleware' => [], /* |-------------------------------------------------------------------------- | Debugbar route domain |-------------------------------------------------------------------------- | | By default Debugbar route served from the same domain that request served. | To override default domain, specify it as a non-empty value. */ 'route_domain' => env('DEBUGBAR_ROUTE_DOMAIN', null), /* |-------------------------------------------------------------------------- | Debugbar theme |-------------------------------------------------------------------------- | | Switches between light and dark theme. If set to auto it will respect system preferences | Possible values: auto, light, dark */ 'theme' => env('DEBUGBAR_THEME', 'auto'), /* |-------------------------------------------------------------------------- | Backtrace stack limit |-------------------------------------------------------------------------- | | By default, the Debugbar limits the number of frames returned by the 'debug_backtrace()' function. | If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit. */ 'debug_backtrace_limit' => (int) env('DEBUGBAR_DEBUG_BACKTRACE_LIMIT', 50), ]; PKk]][laravel-debugbar/database/migrations/2014_12_01_120000_create_phpdebugbar_storage_table.phpnuW+Astring('id'); $table->longText('data'); $table->string('meta_utime'); $table->dateTime('meta_datetime'); $table->string('meta_uri'); $table->string('meta_ip'); $table->string('meta_method'); $table->primary('id'); $table->index('meta_utime'); $table->index('meta_datetime'); $table->index('meta_uri'); $table->index('meta_ip'); $table->index('meta_method'); }); } /** * Reverse the migrations. */ public function down() { Schema::drop('phpdebugbar'); } }; PKk]CR,,laravel-debugbar/LICENSEnuW+ACopyright (C) 2013-present Barry vd. Heuvel 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. PKk]laravel-debugbar/phpcs.xmlnuW+A config src tests src/Resources/* *.blade.php PKk]2vi$i$laravel-debugbar/readme.mdnuW+A## Debugbar for Laravel ![Unit Tests](https://github.com/barryvdh/laravel-debugbar/workflows/Unit%20Tests/badge.svg) [![Packagist License](https://img.shields.io/badge/Licence-MIT-blue)](http://choosealicense.com/licenses/mit/) [![Latest Stable Version](https://img.shields.io/packagist/v/barryvdh/laravel-debugbar?label=Stable)](https://packagist.org/packages/barryvdh/laravel-debugbar) [![Total Downloads](https://img.shields.io/packagist/dt/barryvdh/laravel-debugbar?label=Downloads)](https://packagist.org/packages/barryvdh/laravel-debugbar) [![Fruitcake](https://img.shields.io/badge/Powered%20By-Fruitcake-b2bc35.svg)](https://fruitcake.nl/) This is a package to integrate [PHP Debug Bar](https://github.com/php-debugbar/php-debugbar) with Laravel. It includes a ServiceProvider to register the debugbar and attach it to the output. You can publish assets and configure it through Laravel. It bootstraps some Collectors to work with Laravel and implements a couple custom DataCollectors, specific for Laravel. It is configured to display Redirects and Ajax/Livewire Requests. (Shown in a dropdown) Read [the documentation](http://phpdebugbar.com/docs/) for more configuration options. ![Debugbar Dark Mode screenshot](https://github.com/barryvdh/laravel-debugbar/assets/973269/6600837a-8b2d-4acb-ab0c-158c9ca5439c) > [!CAUTION] > Use the DebugBar only in development. Do not use Debugbar on publicly accessible websites, as it will leak information from stored requests (by design). > [!WARNING] > It can also slow the application down (because it has to gather and render data). So when experiencing slowness, try disabling some of the collectors. This package includes some custom collectors: - QueryCollector: Show all queries, including binding + timing - RouteCollector: Show information about the current Route. - ViewCollector: Show the currently loaded views. (Optionally: display the shared data) - EventsCollector: Show all events - LaravelCollector: Show the Laravel version and Environment. (disabled by default) - SymfonyRequestCollector: replaces the RequestCollector with more information about the request/response - LogsCollector: Show the latest log entries from the storage logs. (disabled by default) - FilesCollector: Show the files that are included/required by PHP. (disabled by default) - ConfigCollector: Display the values from the config files. (disabled by default) - CacheCollector: Display all cache events. (disabled by default) Bootstraps the following collectors for Laravel: - LogCollector: Show all Log messages - SymfonyMailCollector for Mail And the default collectors: - PhpInfoCollector - MessagesCollector - TimeDataCollector (With Booting and Application timing) - MemoryCollector - ExceptionsCollector It also provides a facade interface (`Debugbar`) for easy logging Messages, Exceptions and Time ## Installation Require this package with composer. It is recommended to only require the package for development. ```shell composer require barryvdh/laravel-debugbar --dev ``` Laravel uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider. The Debugbar will be enabled when `APP_DEBUG` is `true`. > If you use a catch-all/fallback route, make sure you load the Debugbar ServiceProvider before your own App ServiceProviders. ### Laravel without auto-discovery: If you don't use auto-discovery, add the ServiceProvider to the providers list. For Laravel 11 or newer, add the ServiceProvider in bootstrap/providers.php. For Laravel 10 or older, add the ServiceProvider in config/app.php. ```php Barryvdh\Debugbar\ServiceProvider::class, ``` If you want to use the facade to log messages, add this within the `register` method of `app/Providers/AppServiceProvider.php` class: ```php public function register(): void { $loader = \Illuminate\Foundation\AliasLoader::getInstance(); $loader->alias('Debugbar', \Barryvdh\Debugbar\Facades\Debugbar::class); } ``` The profiler is enabled by default, if you have APP_DEBUG=true. You can override that in the config (`debugbar.enabled`) or by setting `DEBUGBAR_ENABLED` in your `.env`. See more options in `config/debugbar.php` You can also set in your config if you want to include/exclude the vendor files also (FontAwesome, Highlight.js and jQuery). If you already use them in your site, set it to false. You can also only display the js or css vendors, by setting it to 'js' or 'css'. (Highlight.js requires both css + js, so set to `true` for syntax highlighting) #### Copy the package config to your local config with the publish command: ```shell php artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider" ``` ### Laravel with Octane: Make sure to add LaravelDebugbar to your flush list in `config/octane.php`. ```php 'flush' => [ \Barryvdh\Debugbar\LaravelDebugbar::class, ], ``` ### Lumen: For Lumen, register a different Provider in `bootstrap/app.php`: ```php if (env('APP_DEBUG')) { $app->register(Barryvdh\Debugbar\LumenServiceProvider::class); } ``` To change the configuration, copy the file to your config folder and enable it: ```php $app->configure('debugbar'); ``` ## Usage You can now add messages using the Facade (when added), using the PSR-3 levels (debug, info, notice, warning, error, critical, alert, emergency): ```php Debugbar::info($object); Debugbar::error('Error!'); Debugbar::warning('Watch out…'); Debugbar::addMessage('Another message', 'mylabel'); ``` And start/stop timing: ```php Debugbar::startMeasure('render','Time for rendering'); Debugbar::stopMeasure('render'); Debugbar::addMeasure('now', LARAVEL_START, microtime(true)); Debugbar::measure('My long operation', function() { // Do something… }); ``` Or log exceptions: ```php try { throw new Exception('foobar'); } catch (Exception $e) { Debugbar::addThrowable($e); } ``` There are also helper functions available for the most common calls: ```php // All arguments will be dumped as a debug message debug($var1, $someString, $intValue, $object); // `$collection->debug()` will return the collection and dump it as a debug message. Like `$collection->dump()` collect([$var1, $someString])->debug(); start_measure('render','Time for rendering'); stop_measure('render'); add_measure('now', LARAVEL_START, microtime(true)); measure('My long operation', function() { // Do something… }); ``` If you want you can add your own DataCollectors, through the Container or the Facade: ```php Debugbar::addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages')); //Or via the App container: $debugbar = App::make('debugbar'); $debugbar->addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages')); ``` By default, the Debugbar is injected just before ``. If you want to inject the Debugbar yourself, set the config option 'inject' to false and use the renderer yourself and follow http://phpdebugbar.com/docs/rendering.html ```php $renderer = Debugbar::getJavascriptRenderer(); ``` Note: Not using the auto-inject, will disable the Request information, because that is added After the response. You can add the default_request datacollector in the config as alternative. ## Enabling/Disabling on run time You can enable or disable the debugbar during run time. ```php \Debugbar::enable(); \Debugbar::disable(); ``` NB. Once enabled, the collectors are added (and could produce extra overhead), so if you want to use the debugbar in production, disable in the config and only enable when needed. ## Storage Debugbar remembers previous requests, which you can view using the Browse button on the right. This will only work if you enable `debugbar.storage.open` in the config. Make sure you only do this on local development, because otherwise other people will be able to view previous requests. In general, Debugbar should only be used locally or at least restricted by IP. It's possible to pass a callback, which will receive the Request object, so you can determine access to the OpenHandler storage. ## Twig Integration Laravel Debugbar comes with two Twig Extensions. These are tested with [rcrowe/TwigBridge](https://github.com/rcrowe/TwigBridge) 0.6.x Add the following extensions to your TwigBridge config/extensions.php (or register the extensions manually) ```php 'Barryvdh\Debugbar\Twig\Extension\Debug', 'Barryvdh\Debugbar\Twig\Extension\Dump', 'Barryvdh\Debugbar\Twig\Extension\Stopwatch', ``` The Dump extension will replace the [dump function](http://twig.sensiolabs.org/doc/functions/dump.html) to output variables using the DataFormatter. The Debug extension adds a `debug()` function which passes variables to the Message Collector, instead of showing it directly in the template. It dumps the arguments, or when empty; all context variables. ```twig {{ debug() }} {{ debug(user, categories) }} ``` The Stopwatch extension adds a [stopwatch tag](http://symfony.com/blog/new-in-symfony-2-4-a-stopwatch-tag-for-twig) similar to the one in Symfony/Silex Twigbridge. ```twig {% stopwatch "foo" %} …some things that gets timed {% endstopwatch %} ``` ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=barryvdh/laravel-debugbar&type=Date)](https://www.star-history.com/#barryvdh/laravel-debugbar&Date) PKk]gglaravel-debugbar/SECURITY.mdnuW+A# Security Policy ## Reporting a Vulnerability Please report security issues to `barryvdh@gmail.com` PKk]pwug-laravel-debugbar/src/Console/ClearCommand.phpnuW+Adebugbar = $debugbar; parent::__construct(); } public function handle() { $this->debugbar->boot(); if ($storage = $this->debugbar->getStorage()) { try { $storage->clear(); } catch (\InvalidArgumentException $e) { // hide InvalidArgumentException if storage location does not exist if (strpos($e->getMessage(), 'does not exist') === false) { throw $e; } } $this->info('Debugbar Storage cleared!'); } else { $this->error('No Debugbar Storage found..'); } } } PKk]CD4laravel-debugbar/src/Controllers/AssetController.phpnuW+Adebugbar->getJavascriptRenderer(); $content = $renderer->dumpAssetsToString('js'); $response = new Response( $content, 200, [ 'Content-Type' => 'text/javascript', ] ); return $this->cacheResponse($response); } /** * Return the stylesheets for the Debugbar * * @return \Symfony\Component\HttpFoundation\Response */ public function css() { $renderer = $this->debugbar->getJavascriptRenderer(); $content = $renderer->dumpAssetsToString('css'); $response = new Response( $content, 200, [ 'Content-Type' => 'text/css', ] ); return $this->cacheResponse($response); } /** * Cache the response 1 year (31536000 sec) */ protected function cacheResponse(Response $response) { $response->setSharedMaxAge(31536000); $response->setMaxAge(31536000); $response->setExpires(new \DateTime('+1 year')); return $response; } } PKk]#3laravel-debugbar/src/Controllers/BaseController.phpnuW+Adebugbar = $debugbar; if ($request->hasSession()) { $request->session()->reflash(); } $this->middleware(function ($request, $next) { if (class_exists(Telescope::class)) { Telescope::stopRecording(); } return $next($request); }); } } } else { class BaseController { protected $debugbar; public function __construct(Request $request, LaravelDebugbar $debugbar) { $this->debugbar = $debugbar; if ($request->hasSession()) { $request->session()->reflash(); } } } } PKk]Jm84laravel-debugbar/src/Controllers/CacheController.phpnuW+Atags($tags); } else { unset($tags); } $success = $cache->forget($key); return response()->json(compact('success')); } } PKk]z  :laravel-debugbar/src/Controllers/OpenHandlerController.phpnuW+Aip(), ['127.0.0.1', '::1'], true)) { return true; } return false; } public function handle(Request $request) { if ($request->input('op') === 'get' || $this->isStorageOpen($request)) { $openHandler = new OpenHandler($this->debugbar); $data = $openHandler->handle($request->input(), false, false); } else { $data = [ [ 'datetime' => date("Y-m-d H:i:s"), 'id' => null, 'ip' => $request->getClientIp(), 'method' => 'ERROR', 'uri' => '!! To enable public access to previous requests, set debugbar.storage.open to true in your config, or enable DEBUGBAR_OPEN_STORAGE if you did not publish the config. !!', 'utime' => microtime(true), ] ]; } return new Response( $data, 200, [ 'Content-Type' => 'application/json' ] ); } /** * Return Clockwork output * * @param $id * @return mixed * @throws \DebugBar\DebugBarException */ public function clockwork(Request $request, $id) { $request = [ 'op' => 'get', 'id' => $id, ]; $openHandler = new OpenHandler($this->debugbar); $data = $openHandler->handle($request, false, false); // Convert to Clockwork $converter = new Converter(); $output = $converter->convert(json_decode($data, true)); return response()->json($output); } } PKk]MAA6laravel-debugbar/src/Controllers/QueriesController.phpnuW+Ajson([ 'success' => false, 'message' => 'EXPLAIN is currently disabled in the Debugbar.', ], 400); } try { $explain = new Explain(); if ($request->json('mode') === 'visual') { return response()->json([ 'success' => true, 'data' => $explain->generateVisualExplain($request->json('connection'), $request->json('query'), $request->json('bindings'), $request->json('hash')), ]); } return response()->json([ 'success' => true, 'data' => $explain->generateRawExplain($request->json('connection'), $request->json('query'), $request->json('bindings'), $request->json('hash')), 'visual' => $explain->isVisualExplainSupported($request->json('connection')) ? [ 'confirm' => $explain->confirmVisualExplain($request->json('connection')), ] : null, ]); } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage(), ], 400); } } } PKk]f8laravel-debugbar/src/Controllers/TelescopeController.phpnuW+Afind($uuid); $result = $storage->get('request', (new EntryQueryOptions())->batchId($entry->batchId))->first(); return redirect(config('telescope.domain') . '/' . config('telescope.path') . '/requests/' . $result->id); } } PKk][SS5laravel-debugbar/src/DataCollector/CacheCollector.phpnuW+A ['hit', RetrievingKey::class], CacheMissed::class => ['missed', RetrievingKey::class], CacheFlushed::class => ['flushed', CacheFlushing::class], CacheFlushFailed::class => ['flush_failed', CacheFlushing::class], KeyWritten::class => ['written', WritingKey::class], KeyWriteFailed::class => ['write_failed', WritingKey::class], KeyForgotten::class => ['forgotten', ForgettingKey::class], KeyForgetFailed::class => ['forget_failed', ForgettingKey::class], ]; public function __construct($requestStartTime, $collectValues) { parent::__construct($requestStartTime); $this->collectValues = $collectValues; } public function onCacheEvent($event) { $class = get_class($event); $params = get_object_vars($event); $label = $this->classMap[$class][0]; if (isset($params['value'])) { if ($this->collectValues) { if ($this->isHtmlVarDumperUsed()) { $params['value'] = $this->getVarDumper()->renderVar($params['value']); } else { $params['value'] = htmlspecialchars($this->getDataFormatter()->formatVar($params['value'])); } } else { unset($params['value']); } } if (!empty($params['key'] ?? null) && in_array($label, ['hit', 'written'])) { $params['delete'] = route('debugbar.cache.delete', [ 'key' => urlencode($params['key']), 'tags' => !empty($params['tags']) ? json_encode($params['tags']) : '', ]); } $time = microtime(true); $startHashKey = $this->getEventHash($this->classMap[$class][1] ?? '', $params); $startTime = $this->eventStarts[$startHashKey] ?? $time; $this->addMeasure($label . "\t" . ($params['key'] ?? ''), $startTime, $time, $params); } public function onStartCacheEvent($event) { $startHashKey = $this->getEventHash(get_class($event), get_object_vars($event)); $this->eventStarts[$startHashKey] = microtime(true); } private function getEventHash(string $class, array $params): string { unset($params['value']); return $class . ':' . substr(hash('sha256', json_encode($params)), 0, 12); } public function subscribe(Dispatcher $dispatcher) { foreach (array_keys($this->classMap) as $eventClass) { $dispatcher->listen($eventClass, [$this, 'onCacheEvent']); } $startEvents = array_unique(array_filter(array_map( fn ($values) => $values[1] ?? null, array_values($this->classMap) ))); foreach ($startEvents as $eventClass) { $dispatcher->listen($eventClass, [$this, 'onStartCacheEvent']); } } public function collect() { $data = parent::collect(); $data['nb_measures'] = $data['count'] = count($data['measures']); return $data; } public function getName() { return 'cache'; } public function getWidgets() { return [ 'cache' => [ 'icon' => 'clipboard', 'widget' => 'PhpDebugBar.Widgets.LaravelCacheWidget', 'map' => 'cache', 'default' => '{}', ], 'cache:badge' => [ 'map' => 'cache.nb_measures', 'default' => 'null', ], ]; } } PKk]K^^5laravel-debugbar/src/DataCollector/EventCollector.phpnuW+AcollectValues = $collectValues; $this->excludedEvents = $excludedEvents; $this->setDataFormatter(new SimpleFormatter()); } public function onWildcardEvent($name = null, $data = []) { $currentTime = microtime(true); $eventClass = explode(':', $name)[0]; foreach ($this->excludedEvents as $excludedEvent) { if (Str::is($excludedEvent, $eventClass)) { return; } } if (! $this->collectValues) { $this->addMeasure($name, $currentTime, $currentTime, [], null, $eventClass); return; } $params = $this->prepareParams($data); // Find all listeners for the current event foreach ($this->events->getListeners($name) as $i => $listener) { // Check if it's an object + method name if (is_array($listener) && count($listener) > 1 && is_object($listener[0])) { list($class, $method) = $listener; // Skip this class itself if ($class instanceof static) { continue; } // Format the listener to readable format $listener = get_class($class) . '@' . $method; // Handle closures } elseif ($listener instanceof \Closure) { $reflector = new \ReflectionFunction($listener); // Skip our own listeners if ($reflector->getNamespaceName() == 'Barryvdh\Debugbar') { continue; } // Format the closure to a readable format $filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/'); $lines = $reflector->getStartLine() . '-' . $reflector->getEndLine(); $listener = $reflector->getName() . ' (' . $filename . ':' . $lines . ')'; } else { // Not sure if this is possible, but to prevent edge cases $listener = $this->getDataFormatter()->formatVar($listener); } $params['listeners.' . $i] = $listener; } $this->addMeasure($name, $currentTime, $currentTime, $params, null, $eventClass); } public function subscribe(Dispatcher $events) { $this->events = $events; $events->listen('*', [$this, 'onWildcardEvent']); } protected function prepareParams($params) { $data = []; foreach ($params as $key => $value) { if (is_object($value) && Str::is('Illuminate\*\Events\*', get_class($value))) { $value = $this->prepareParams(get_object_vars($value)); } $data[$key] = htmlentities($this->getDataFormatter()->formatVar($value), ENT_QUOTES, 'UTF-8', false); } return $data; } public function collect() { $data = parent::collect(); $data['nb_measures'] = $data['count'] = count($data['measures']); return $data; } public function getName() { return 'event'; } public function getWidgets() { return [ "events" => [ "icon" => "tasks", "widget" => "PhpDebugBar.Widgets.TimelineWidget", "map" => "event", "default" => "{}", ], 'events:badge' => [ 'map' => 'event.nb_measures', 'default' => 0, ], ]; } } PKk]k5laravel-debugbar/src/DataCollector/FilesCollector.phpnuW+Aapp = $app; $this->basePath = base_path(); } /** * {@inheritDoc} */ public function collect() { $files = $this->getIncludedFiles(); $compiled = $this->getCompiledFiles(); $included = []; $alreadyCompiled = []; foreach ($files as $file) { // Skip the files from Debugbar, they are only loaded for Debugging and confuse the output. // Of course some files are stil always loaded (ServiceProvider, Facade etc) if ( strpos($file, 'vendor/maximebf/debugbar/src') !== false || strpos( $file, 'vendor/barryvdh/laravel-debugbar/src' ) !== false ) { continue; } elseif (!in_array($file, $compiled)) { $included[] = [ 'message' => "'" . $this->stripBasePath($file) . "',", // Use PHP syntax so we can copy-paste to compile config file. 'is_string' => true, ]; } else { $alreadyCompiled[] = [ 'message' => "* '" . $this->stripBasePath($file) . "',", // Mark with *, so know they are compiled anyway. 'is_string' => true, ]; } } // First the included files, then those that are going to be compiled. $messages = array_merge($included, $alreadyCompiled); return [ 'messages' => $messages, 'count' => count($included), ]; } /** * Get the files included on load. * * @return array */ protected function getIncludedFiles() { return get_included_files(); } /** * Get the files that are going to be compiled, so they aren't as important. * * @return array */ protected function getCompiledFiles() { if ($this->app && class_exists('Illuminate\Foundation\Console\OptimizeCommand')) { $reflector = new \ReflectionClass('Illuminate\Foundation\Console\OptimizeCommand'); $path = dirname($reflector->getFileName()) . '/Optimize/config.php'; if (file_exists($path)) { $app = $this->app; $core = require $path; return array_merge($core, $app['config']['compile']); } } return []; } /** * Remove the basePath from the paths, so they are relative to the base * * @param $path * @return string */ protected function stripBasePath($path) { return ltrim(str_replace($this->basePath, '', $path), '/'); } /** * {@inheritDoc} */ public function getWidgets() { $name = $this->getName(); return [ "$name" => [ "icon" => "files-o", "widget" => "PhpDebugBar.Widgets.MessagesWidget", "map" => "$name.messages", "default" => "{}" ], "$name:badge" => [ "map" => "$name.count", "default" => "null" ] ]; } /** * {@inheritDoc} */ public function getName() { return 'files'; } } PKk] OO4laravel-debugbar/src/DataCollector/GateCollector.phpnuW+Arouter = $router; $this->setDataFormatter(new SimpleFormatter()); $gate->after(function ($user, $ability, $result, $arguments = []) { $this->addCheck($user, $ability, $result, $arguments); }); } /** * {@inheritDoc} */ protected function customizeMessageHtml($messageHtml, $message) { $pos = strpos((string) $messageHtml, 'array:5'); if ($pos !== false) { $name = $message['ability'] .' ' . $message['target'] ?? ''; $messageHtml = substr_replace($messageHtml, $name, $pos, 7); } return parent::customizeMessageHtml($messageHtml, $message); } public function addCheck($user, $ability, $result, $arguments = []) { $userKey = 'user'; $userId = null; if ($user) { $userKey = Str::snake(class_basename($user)); $userId = $user instanceof Authenticatable ? $user->getAuthIdentifier() : $user->getKey(); } $label = $result ? 'success' : 'error'; if ($result instanceof Response) { $label = $result->allowed() ? 'success' : 'error'; } $target = null; if (isset($arguments[0])) { if ($arguments[0] instanceof Model) { $model = $arguments[0]; if ($model->getKeyName() && isset($model[$model->getKeyName()])) { $target = get_class($model) . '(' . $model->getKeyName() . '=' . $model->getKey() . ')'; } else { $target = get_class($model); } } else if (is_string($arguments[0])) { $target = $arguments[0]; } } $this->addMessage([ 'ability' => $ability, 'target' => $target, 'result' => $result, $userKey => $userId, 'arguments' => $this->getDataFormatter()->formatVar($arguments), ], $label, false); } /** * @param array $stacktrace * * @return array */ protected function getStackTraceItem($stacktrace) { foreach ($stacktrace as $i => $trace) { if (!isset($trace['file'])) { continue; } if (str_ends_with($trace['file'], 'Illuminate/Routing/ControllerDispatcher.php')) { $trace = $this->findControllerFromDispatcher($trace); } elseif (str_starts_with($trace['file'], storage_path())) { $hash = pathinfo($trace['file'], PATHINFO_FILENAME); if ($file = $this->findViewFromHash($hash)) { $trace['file'] = $file; } } if ($this->fileIsInExcludedPath($trace['file'])) { continue; } return $trace; } return $stacktrace[0]; } /** * Find the route action file * * @param array $trace * @return array */ protected function findControllerFromDispatcher($trace) { /** @var \Closure|string|array $action */ $action = $this->router->current()->getAction('uses'); if (is_string($action)) { [$controller, $method] = explode('@', $action); $reflection = new \ReflectionMethod($controller, $method); $trace['file'] = $reflection->getFileName(); $trace['line'] = $reflection->getStartLine(); } elseif ($action instanceof \Closure) { $reflection = new \ReflectionFunction($action); $trace['file'] = $reflection->getFileName(); $trace['line'] = $reflection->getStartLine(); } return $trace; } /** * Find the template name from the hash. * * @param string $hash * @return null|array */ protected function findViewFromHash($hash) { $finder = app('view')->getFinder(); if (isset($this->reflection['viewfinderViews'])) { $property = $this->reflection['viewfinderViews']; } else { $reflection = new \ReflectionClass($finder); $property = $reflection->getProperty('views'); $property->setAccessible(true); $this->reflection['viewfinderViews'] = $property; } $xxh128Exists = in_array('xxh128', hash_algos()); foreach ($property->getValue($finder) as $name => $path) { if (($xxh128Exists && hash('xxh128', 'v2' . $path) == $hash) || sha1('v2' . $path) == $hash) { return $path; } } } } PKk]d+H4laravel-debugbar/src/DataCollector/JobsCollector.phpnuW+Alisten(\Illuminate\Queue\Events\JobQueued::class, function ($event) { $class = get_class($event->job); $this->jobs[$class] = ($this->jobs[$class] ?? 0) + 1; $this->count++; }); } public function collect() { ksort($this->jobs, SORT_NUMERIC); return ['data' => array_reverse($this->jobs), 'count' => $this->count]; } /** * {@inheritDoc} */ public function getName() { return 'jobs'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "jobs" => [ "icon" => "briefcase", "widget" => "PhpDebugBar.Widgets.HtmlVariableListWidget", "map" => "jobs.data", "default" => "{}" ], 'jobs:badge' => [ 'map' => 'jobs.count', 'default' => 0 ] ]; } } PKk](?܏7laravel-debugbar/src/DataCollector/LaravelCollector.phpnuW+A Str::of($this->laravel->version())->explode('.')->first() . '.x', 'tooltip' => [ 'Laravel Version' => $this->laravel->version(), 'PHP Version' => phpversion(), 'Environment' => $this->laravel->environment(), 'Debug Mode' => config('app.debug') ? 'Enabled' : 'Disabled', 'URL' => Str::of(config('app.url'))->replace(['http://', 'https://'], ''), 'Timezone' => config('app.timezone'), 'Locale' => config('app.locale'), ] ]; } /** * {@inheritDoc} */ public function getName() { return 'laravel'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "version" => [ "icon" => "laravel phpdebugbar-fab", "map" => "laravel.version", "default" => "" ], "version:tooltip" => [ "map" => "laravel.tooltip", "default" => "{}" ], ]; } } PKk]ҸJV 8laravel-debugbar/src/DataCollector/LivewireCollector.phpnuW+AgetData()['_instance']; // Create a unique name for each component $key = $component->getName() . ' #' . $component->id; $data = [ 'data' => $component->getPublicPropertiesDefinedBySubClass(), ]; if ($request->request->get('id') == $component->id) { $data['oldData'] = $request->request->get('data'); $data['actionQueue'] = $request->request->get('actionQueue'); } $data['name'] = $component->getName(); $data['view'] = $view->name(); $data['component'] = get_class($component); $data['id'] = $component->id; $this->data[$key] = $this->formatVar($data); }); Livewire::listen('render', function (Component $component) use ($request) { // Create an unique name for each compoent $key = $component->getName() . ' #' . $component->getId(); $data = [ 'data' => $component->all(), ]; if ($request->request->get('id') == $component->getId()) { $data['oldData'] = $request->request->get('data'); $data['actionQueue'] = $request->request->get('actionQueue'); } $data['name'] = $component->getName(); $data['component'] = get_class($component); $data['id'] = $component->getId(); $this->data[$key] = $this->formatVar($data); }); } public function collect() { return ['data' => $this->data, 'count' => count($this->data)]; } /** * {@inheritDoc} */ public function getName() { return 'livewire'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "livewire" => [ "icon" => "bolt", "widget" => "PhpDebugBar.Widgets.VariableListWidget", "map" => "livewire.data", "default" => "{}" ], 'livewire:badge' => [ 'map' => 'livewire.count', 'default' => 0 ] ]; } } PKk]||4laravel-debugbar/src/DataCollector/LogsCollector.phpnuW+AgetStorageLogs($path); } } /** * get logs apache in app/storage/logs * only 24 last of current day * * @param string $path * * @return array */ public function getStorageLogs($path) { if (!file_exists($path)) { return; } //Load the latest lines, guessing about 15x the number of log entries (for stack traces etc) $file = implode("", $this->tailFile($path, $this->lines)); $basename = basename($path); foreach ($this->getLogs($file) as $log) { $this->messages[] = [ 'message' => $log['header'] . $log['stack'], 'label' => $log['level'], 'time' => substr($log['header'], 1, 19), 'collector' => $basename, 'is_string' => false, ]; } } /** * By Ain Tohvri (ain) * http://tekkie.flashbit.net/php/tail-functionality-in-php * @param string $file * @param int $lines * @return array */ protected function tailFile($file, $lines) { $handle = fopen($file, "r"); $linecounter = $lines; $pos = -2; $beginning = false; $text = []; while ($linecounter > 0) { $t = " "; while ($t != "\n") { if (fseek($handle, $pos, SEEK_END) == -1) { $beginning = true; break; } $t = fgetc($handle); $pos--; } $linecounter--; if ($beginning) { rewind($handle); } $text[$lines - $linecounter - 1] = fgets($handle); if ($beginning) { break; } } fclose($handle); return array_reverse($text); } /** * Search a string for log entries * Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand * * @param $file * @return array */ public function getLogs($file) { $pattern = "/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\](?:(?!\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\])[\s\S])*/"; $log_levels = $this->getLevels(); // There has GOT to be a better way of doing this... preg_match_all($pattern, $file, $headings); $log_data = preg_split($pattern, $file) ?: []; $log = []; foreach ($headings as $h) { for ($i = 0, $j = count($h); $i < $j; $i++) { foreach ($log_levels as $ll) { if (strpos(strtolower($h[$i]), strtolower('.' . $ll))) { $log[] = ['level' => $ll, 'header' => $h[$i], 'stack' => $log_data[$i] ?? '']; } } } } return $log; } /** * @return array */ public function getMessages() { return array_reverse(parent::getMessages()); } /** * Get the log levels from psr/log. * Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand * * @access public * @return array */ public function getLevels() { $class = new ReflectionClass(new LogLevel()); return $class->getConstants(); } } PKk]bhZZ6laravel-debugbar/src/DataCollector/ModelsCollector.phpnuW+Alisten('eloquent.retrieved:*', function ($event, $models) { foreach (array_filter($models) as $model) { $class = get_class($model); $this->models[$class] = ($this->models[$class] ?? 0) + 1; $this->count++; } }); } public function collect() { ksort($this->models, SORT_NUMERIC); return ['data' => array_reverse($this->models), 'count' => $this->count]; } /** * {@inheritDoc} */ public function getName() { return 'models'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "models" => [ "icon" => "cubes", "widget" => "PhpDebugBar.Widgets.HtmlVariableListWidget", "map" => "models.data", "default" => "{}" ], 'models:badge' => [ 'map' => 'models.count', 'default' => 0 ] ]; } } PKk]wHH9laravel-debugbar/src/DataCollector/MultiAuthCollector.phpnuW+Aauth = $auth; $this->guards = $guards; } /** * Set to show the users name/email * @param bool $showName */ public function setShowName($showName) { $this->showName = (bool) $showName; } /** * Set to hide the guards tab, and show only name * @param bool $showGuardsData */ public function setShowGuardsData($showGuardsData) { $this->showGuardsData = (bool) $showGuardsData; } /** * @{inheritDoc} */ public function collect() { $data = [ 'guards' => [], ]; $names = ''; foreach ($this->guards as $guardName => $config) { try { $guard = $this->auth->guard($guardName); if ($this->hasUser($guard)) { $user = $guard->user(); if (!is_null($user)) { $data['guards'][$guardName] = $this->getUserInformation($user); $names .= $guardName . ": " . $data['guards'][$guardName]['name'] . ', '; } } else { $data['guards'][$guardName] = null; } } catch (\Exception $e) { continue; } } foreach ($data['guards'] as $key => $var) { if (!is_string($data['guards'][$key])) { $data['guards'][$key] = $this->formatVar($var); } } $data['names'] = rtrim($names, ', '); if (!$this->showGuardsData) { unset($data['guards']); } return $data; } private function hasUser(Guard $guard) { if (method_exists($guard, 'hasUser')) { return $guard->hasUser(); } return false; } /** * Get displayed user information * @param \Illuminate\Auth\UserInterface $user * @return array */ protected function getUserInformation($user = null) { // Defaults if (is_null($user)) { return [ 'name' => 'Guest', 'user' => ['guest' => true], ]; } // The default auth identifer is the ID number, which isn't all that // useful. Try username, email and name. $identifier = $user instanceof Authenticatable ? $user->getAuthIdentifier() : $user->getKey(); if (is_numeric($identifier) || Str::isUuid($identifier) || Str::isUlid($identifier)) { try { if (isset($user->username)) { $identifier = $user->username; } elseif (isset($user->email)) { $identifier = $user->email; } elseif (isset($user->name)) { $identifier = Str::limit($user->name, 24); } } catch (\Throwable $e) { } } return [ 'name' => $identifier, 'user' => $user instanceof Arrayable ? $user->toArray() : $user, ]; } /** * @{inheritDoc} */ public function getName() { return 'auth'; } /** * @{inheritDoc} */ public function getWidgets() { $widgets = []; if ($this->showGuardsData) { $widgets["auth"] = [ "icon" => "lock", "widget" => "PhpDebugBar.Widgets.VariableListWidget", "map" => "auth.guards", "default" => "{}", ]; } if ($this->showName) { $widgets['auth.name'] = [ 'icon' => 'user', 'tooltip' => 'Auth status', 'map' => 'auth.names', 'default' => '', ]; } return $widgets; } } PKk]7laravel-debugbar/src/DataCollector/PennantCollector.phpnuW+Amanager = $manager; } /** * {@inheritdoc} */ public function collect() { $store = $this->manager->store(Config::get('pennant.default')); return $store->values($store->stored()); } /** * {@inheritDoc} */ public function getName() { return 'pennant'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "pennant" => [ "icon" => "flag", "widget" => "PhpDebugBar.Widgets.VariableListWidget", "map" => "pennant", "default" => "{}" ] ]; } } PKk]A6]]5laravel-debugbar/src/DataCollector/QueryCollector.phpnuW+AtimeCollector = $timeCollector; } /** * @param int|null $softLimit After the soft limit, no parameters/backtrace are captured * @param int|null $hardLimit After the hard limit, queries are ignored * @return void */ public function setLimits(?int $softLimit, ?int $hardLimit): void { $this->softLimit = $softLimit; $this->hardLimit = $hardLimit; } /** * Renders the SQL of traced statements with params embedded * * @param boolean $enabled * @param string $quotationChar NOT USED */ public function setRenderSqlWithParams($enabled = true, $quotationChar = "'") { $this->renderSqlWithParams = $enabled; } /** * Show or hide the hints in the parameters * * @param boolean $enabled */ public function setShowHints($enabled = true) { $this->showHints = $enabled; } /** * Show or hide copy button next to the queries * * @param boolean $enabled */ public function setShowCopyButton($enabled = true) { $this->showCopyButton = $enabled; } /** * Enable/disable finding the source * * @param bool|int $value * @param array $middleware */ public function setFindSource($value, array $middleware) { $this->findSource = $value; $this->middleware = $middleware; } public function mergeExcludePaths(array $excludePaths) { $this->excludePaths = array_merge($this->excludePaths, $excludePaths); } /** * Set additional paths to exclude from the backtrace * * @param array $excludePaths Array of file paths to exclude from backtrace */ public function mergeBacktraceExcludePaths(array $excludePaths) { $this->backtraceExcludePaths = array_merge($this->backtraceExcludePaths, $excludePaths); } /** * Enable/disable the shaded duration background on queries * * @param bool $enabled */ public function setDurationBackground($enabled = true) { $this->durationBackground = $enabled; } /** * Enable/disable the EXPLAIN queries * * @param bool $enabled * @param array|null $types Array of types to explain queries (select/insert/update/delete) */ public function setExplainSource($enabled, $types) { $this->explainQuery = $enabled; } public function startMemoryUsage() { $this->lastMemoryUsage = memory_get_usage(false); } /** * * @param \Illuminate\Database\Events\QueryExecuted $query */ public function addQuery($query) { $this->queryCount++; if ($this->hardLimit && $this->queryCount > $this->hardLimit) { return; } $limited = $this->softLimit && $this->queryCount > $this->softLimit; $sql = (string) $query->sql; $time = $query->time / 1000; $endTime = microtime(true); $startTime = $endTime - $time; $hints = $this->performQueryAnalysis($sql); $pdo = null; try { $pdo = $query->connection->getPdo(); if(! ($pdo instanceof \PDO)) { $pdo = null; } } catch (\Throwable $e) { // ignore error for non-pdo laravel drivers } $source = []; if (!$limited && $this->findSource) { try { $source = $this->findSource(); } catch (\Exception $e) { } } $bindings = match (true) { $limited && filled($query->bindings) => [], default => $query->connection->prepareBindings($query->bindings), }; $this->queries[] = [ 'query' => $sql, 'type' => 'query', 'bindings' => $bindings, 'start' => $startTime, 'time' => $time, 'memory' => $this->lastMemoryUsage ? memory_get_usage(false) - $this->lastMemoryUsage : 0, 'source' => $source, 'connection' => $query->connection, 'driver' => $query->connection->getConfig('driver'), 'hints' => ($this->showHints && !$limited) ? $hints : null, 'show_copy' => $this->showCopyButton, ]; if ($this->timeCollector !== null) { $this->timeCollector->addMeasure(Str::limit($sql, 100), $startTime, $endTime, [], 'db', 'Database Query'); } } /** * Mimic mysql_real_escape_string * * @param string $value * @return string */ protected function emulateQuote($value) { $search = ["\\", "\x00", "\n", "\r", "'", '"', "\x1a"]; $replace = ["\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z"]; return "'" . str_replace($search, $replace, (string) $value) . "'"; } /** * Explainer::performQueryAnalysis() * * Perform simple regex analysis on the code * * @package xplain (https://github.com/rap2hpoutre/mysql-xplain-xplain) * @author e-doceo * @copyright 2014 * @version $Id$ * @access public * @param string $query * @return string[] */ protected function performQueryAnalysis($query) { // @codingStandardsIgnoreStart $hints = []; if (preg_match('/^\\s*SELECT\\s*`?[a-zA-Z0-9]*`?\\.?\\*/i', $query)) { $hints[] = 'Use SELECT * only if you need all columns from table'; } if (preg_match('/ORDER BY RAND()/i', $query)) { $hints[] = 'ORDER BY RAND() is slow, try to avoid if you can. You can read this or this'; } if (strpos($query, '!=') !== false) { $hints[] = 'The != operator is not standard. Use the <> operator to test for inequality instead.'; } if (stripos($query, 'WHERE') === false && preg_match('/^(SELECT) /i', $query)) { $hints[] = 'The SELECT statement has no WHERE clause and could examine many more rows than intended'; } if (preg_match('/LIMIT\\s/i', $query) && stripos($query, 'ORDER BY') === false) { $hints[] = 'LIMIT without ORDER BY causes non-deterministic results, depending on the query execution plan'; } if (preg_match('/LIKE\\s[\'"](%.*?)[\'"]/i', $query, $matches)) { $hints[] = 'An argument has a leading wildcard character: ' . $matches[1] . '. The predicate with this argument is not sargable and cannot use an index if one exists.'; } return $hints; // @codingStandardsIgnoreEnd } /** * Use a backtrace to search for the origins of the query. * * @return array */ protected function findSource() { $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT, app('config')->get('debugbar.debug_backtrace_limit', 50)); $sources = []; foreach ($stack as $index => $trace) { $sources[] = $this->parseTrace($index, $trace); } return array_slice(array_filter($sources), 0, is_int($this->findSource) ? $this->findSource : 5); } /** * Parse a trace element from the backtrace stack. * * @param int $index * @param array $trace * @return object|bool */ protected function parseTrace($index, array $trace) { $frame = (object) [ 'index' => $index, 'namespace' => null, 'name' => null, 'file' => null, 'line' => $trace['line'] ?? '1', ]; if (isset($trace['function']) && $trace['function'] == 'substituteBindings') { $frame->name = 'Route binding'; return $frame; } if ( isset($trace['class']) && isset($trace['file']) && !$this->fileIsInExcludedPath($trace['file']) ) { $frame->file = $trace['file']; if (isset($trace['object']) && is_a($trace['object'], '\Twig\Template')) { list($frame->file, $frame->line) = $this->getTwigInfo($trace); } elseif (strpos($frame->file, storage_path()) !== false) { $hash = pathinfo($frame->file, PATHINFO_FILENAME); if ($frame->name = $this->findViewFromHash($hash)) { $frame->file = $frame->name[1]; $frame->name = $frame->name[0]; } else { $frame->name = $hash; } $frame->namespace = 'view'; return $frame; } elseif (strpos($frame->file, 'Middleware') !== false) { $frame->name = $this->findMiddlewareFromFile($frame->file); if ($frame->name) { $frame->namespace = 'middleware'; } else { $frame->name = $this->normalizeFilePath($frame->file); } return $frame; } $frame->name = $this->normalizeFilePath($frame->file); return $frame; } return false; } /** * Check if the given file is to be excluded from analysis * * @param string $file * @return bool */ protected function fileIsInExcludedPath($file) { $normalizedPath = str_replace('\\', '/', $file); foreach ($this->backtraceExcludePaths as $excludedPath) { if (strpos($normalizedPath, $excludedPath) !== false) { return true; } } return false; } /** * Find the middleware alias from the file. * * @param string $file * @return string|null */ protected function findMiddlewareFromFile($file) { $filename = pathinfo($file, PATHINFO_FILENAME); foreach ($this->middleware as $alias => $class) { if (!is_null($class) && !is_null($filename) && strpos($class, $filename) !== false) { return $alias; } } } /** * Find the template name from the hash. * * @param string $hash * @return null|array */ protected function findViewFromHash($hash) { $finder = app('view')->getFinder(); if (isset($this->reflection['viewfinderViews'])) { $property = $this->reflection['viewfinderViews']; } else { $reflection = new \ReflectionClass($finder); $property = $reflection->getProperty('views'); $property->setAccessible(true); $this->reflection['viewfinderViews'] = $property; } $xxh128Exists = in_array('xxh128', hash_algos()); foreach ($property->getValue($finder) as $name => $path) { if (($xxh128Exists && hash('xxh128', 'v2' . $path) == $hash) || sha1('v2' . $path) == $hash) { return [$name, $path]; } } } /** * Get the filename/line from a Twig template trace * * @param array $trace * @return array The file and line */ protected function getTwigInfo($trace) { $file = $trace['object']->getTemplateName(); if (isset($trace['line'])) { foreach ($trace['object']->getDebugInfo() as $codeLine => $templateLine) { if ($codeLine <= $trace['line']) { return [$file, $templateLine]; } } } return [$file, -1]; } /** * Collect a database transaction event. * @param string $event * @param \Illuminate\Database\Connection $connection * @return array */ public function collectTransactionEvent($event, $connection) { $this->transactionEventsCount++; $source = []; if ($this->findSource) { try { $source = $this->findSource(); } catch (\Exception $e) { } } $this->queries[] = [ 'query' => $event, 'type' => 'transaction', 'bindings' => [], 'start' => microtime(true), 'time' => 0, 'memory' => 0, 'source' => $source, 'connection' => $connection, 'driver' => $connection->getConfig('driver'), 'hints' => null, 'show_copy' => false, ]; } /** * Reset the queries. */ public function reset() { $this->queries = []; $this->queryCount = 0; $this->infoStatements = 0 ; } /** * {@inheritDoc} */ public function collect() { $totalTime = 0; $totalMemory = 0; $queries = $this->queries; $statements = []; foreach ($queries as $query) { $source = reset($query['source']); $normalizedPath = is_object($source) ? $this->normalizeFilePath($source->file ?: '') : ''; if ($query['type'] != 'transaction' && Str::startsWith($normalizedPath, $this->excludePaths)) { continue; } $totalTime += $query['time']; $totalMemory += $query['memory']; $connectionName = $query['connection']->getDatabaseName(); if (str_ends_with($connectionName, '.sqlite')) { $connectionName = $this->normalizeFilePath($connectionName); } $canExplainQuery = match (true) { in_array($query['driver'], ['mariadb', 'mysql', 'pgsql']) => $query['bindings'] !== null && preg_match('/^\s*(' . implode('|', $this->explainTypes) . ') /i', $query['query']), default => false, }; $statements[] = [ 'sql' => $this->getSqlQueryToDisplay($query), 'type' => $query['type'], 'params' => [], 'bindings' => $query['bindings'] ?? [], 'hints' => $query['hints'], 'show_copy' => $query['show_copy'], 'backtrace' => array_values($query['source']), 'start' => $query['start'] ?? null, 'duration' => $query['time'], 'duration_str' => ($query['type'] == 'transaction') ? '' : $this->formatDuration($query['time']), 'memory' => $query['memory'], 'memory_str' => $query['memory'] ? $this->getDataFormatter()->formatBytes($query['memory']) : null, 'filename' => $this->getDataFormatter()->formatSource($source, true), 'source' => $source, 'xdebug_link' => is_object($source) ? $this->getXdebugLink($source->file ?: '', $source->line) : null, 'connection' => $connectionName, 'explain' => $this->explainQuery && $canExplainQuery ? [ 'url' => route('debugbar.queries.explain'), 'driver' => $query['driver'], 'connection' => $query['connection']->getName(), 'query' => $query['query'], 'hash' => (new Explain())->hash($query['connection']->getName(), $query['query'], $query['bindings']), ] : null, ]; } if ($this->durationBackground) { if ($totalTime > 0) { // For showing background measure on Queries tab $start_percent = 0; foreach ($statements as $i => $statement) { if (!isset($statement['duration'])) { continue; } $width_percent = $statement['duration'] / $totalTime * 100; $statements[$i] = array_merge($statement, [ 'start_percent' => round($start_percent, 3), 'width_percent' => round($width_percent, 3), ]); $start_percent += $width_percent; } } } if ($this->softLimit && $this->hardLimit && ($this->queryCount > $this->softLimit && $this->queryCount > $this->hardLimit)) { array_unshift($statements, [ 'sql' => '# Query soft and hard limit for Debugbar are reached. Only the first ' . $this->softLimit . ' queries show details. Queries after the first ' . $this->hardLimit . ' are ignored. Limits can be raised in the config (debugbar.options.db.soft/hard_limit).', 'type' => 'info', ]); $statements[] = [ 'sql' => '... ' . ($this->queryCount - $this->hardLimit) . ' additional queries are executed but now shown because of Debugbar query limits. Limits can be raised in the config (debugbar.options.db.soft/hard_limit)', 'type' => 'info', ]; $this->infoStatements+= 2; } elseif ($this->hardLimit && $this->queryCount > $this->hardLimit) { array_unshift($statements, [ 'sql' => '# Query hard limit for Debugbar is reached after ' . $this->hardLimit . ' queries, additional ' . ($this->queryCount - $this->hardLimit) . ' queries are not shown.. Limits can be raised in the config (debugbar.options.db.hard_limit)', 'type' => 'info', ]); $statements[] = [ 'sql' => '... ' . ($this->queryCount - $this->hardLimit) . ' additional queries are executed but now shown because of Debugbar query limits. Limits can be raised in the config (debugbar.options.db.hard_limit)', 'type' => 'info', ]; $this->infoStatements+= 2; } elseif ($this->softLimit && $this->queryCount > $this->softLimit) { array_unshift($statements, [ 'sql' => '# Query soft limit for Debugbar is reached after ' . $this->softLimit . ' queries, additional ' . ($this->queryCount - $this->softLimit) . ' queries only show the query. Limits can be raised in the config (debugbar.options.db.soft_limit)', 'type' => 'info', ]); $this->infoStatements++; } $visibleStatements = count($statements) - $this->infoStatements; $data = [ 'count' => $visibleStatements, 'nb_statements' => $this->queryCount, 'nb_visible_statements' => $visibleStatements, 'nb_excluded_statements' => $this->queryCount + $this->transactionEventsCount - $visibleStatements, 'nb_failed_statements' => 0, 'accumulated_duration' => $totalTime, 'accumulated_duration_str' => $this->formatDuration($totalTime), 'memory_usage' => $totalMemory, 'memory_usage_str' => $totalMemory ? $this->getDataFormatter()->formatBytes($totalMemory) : null, 'statements' => $statements ]; return $data; } /** * {@inheritDoc} */ public function getName() { return 'queries'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "queries" => [ "icon" => "database", "widget" => "PhpDebugBar.Widgets.LaravelQueriesWidget", "map" => "queries", "default" => "[]" ], "queries:badge" => [ "map" => "queries.nb_statements", "default" => 0 ] ]; } private function getSqlQueryToDisplay(array $query): string { $sql = $query['query']; if ($query['type'] === 'query' && $this->renderSqlWithParams && $query['connection']->getQueryGrammar() instanceof \Illuminate\Database\Query\Grammars\Grammar && method_exists($query['connection']->getQueryGrammar(), 'substituteBindingsIntoRawSql')) { try { $sql = $query['connection']->getQueryGrammar()->substituteBindingsIntoRawSql($sql, $query['bindings'] ?? []); return $this->getDataFormatter()->formatSql($sql); } catch (\Throwable $e) { // Continue using the old substitute } } if ($query['type'] === 'query' && $this->renderSqlWithParams) { $bindings = $this->getDataFormatter()->checkBindings($query['bindings']); if (!empty($bindings)) { $pdo = null; try { $pdo = $query->connection->getPdo(); } catch (\Throwable) { // ignore error for non-pdo laravel drivers } foreach ($bindings as $key => $binding) { // This regex matches placeholders only, not the question marks, // nested in quotes, while we iterate through the bindings // and substitute placeholders by suitable values. $regex = is_numeric($key) ? "/(?quote((string) $binding); } catch (\Exception $e) { $binding = $this->emulateQuote($binding); } } else { $binding = $this->emulateQuote($binding); } } $sql = preg_replace($regex, addcslashes($binding, '$'), $sql, 1); } } } return $this->getDataFormatter()->formatSql($sql); } } PKk]ylQ-Q-7laravel-debugbar/src/DataCollector/RequestCollector.phpnuW+A * */ class RequestCollector extends DataCollector implements DataCollectorInterface, Renderable { /** @var \Symfony\Component\HttpFoundation\Request $request */ protected $request; /** @var \Symfony\Component\HttpFoundation\Response $response */ protected $response; /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */ protected $session; /** @var string|null */ protected $currentRequestId; /** @var array */ protected $hiddens; /** * Create a new SymfonyRequestCollector * * @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\HttpFoundation\Response $response * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session * @param string|null $currentRequestId * @param array $hiddens */ public function __construct($request, $response, $session = null, $currentRequestId = null, $hiddens = []) { $this->request = $request; $this->response = $response; $this->session = $session; $this->currentRequestId = $currentRequestId; $this->hiddens = array_merge($hiddens, [ 'request_request.password', 'request_headers.php-auth-pw.0', ]); } /** * {@inheritDoc} */ public function getName() { return 'request'; } /** * {@inheritDoc} */ public function getWidgets() { $widgets = [ "request" => [ "icon" => "tags", "widget" => "PhpDebugBar.Widgets.HtmlVariableListWidget", "map" => "request.data", "order" => -100, "default" => "{}" ], 'request:badge' => [ "map" => "request.badge", "default" => "null" ] ]; if (Config::get('debugbar.options.request.label', true)) { $widgets['currentrequest'] = [ "icon" => "share", "map" => "request.data.uri", "link" => "request", "default" => "" ]; $widgets['currentrequest:tooltip'] = [ "map" => "request.tooltip", "default" => "{}" ]; } return $widgets; } /** * {@inheritdoc} */ public function collect() { $request = $this->request; $response = $this->response; $responseHeaders = $response->headers->all(); $cookies = []; foreach ($response->headers->getCookies() as $cookie) { $cookies[] = $this->getCookieHeader( $cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly() ); } if (count($cookies) > 0) { $responseHeaders['Set-Cookie'] = $cookies; } $statusCode = $response->getStatusCode(); $startTime = defined('LARAVEL_START') ? LARAVEL_START : $request->server->get('REQUEST_TIME_FLOAT'); $query = $request->getQueryString(); $htmlData = []; $data = [ 'status' => $statusCode . ' ' . (isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : ''), 'duration' => $startTime ? $this->formatDuration(microtime(true) - $startTime) : null, 'peak_memory' => $this->formatBytes(memory_get_peak_usage(true), 1), ]; if ($request instanceof Request) { if ($route = $request->route()) { $htmlData += $this->getRouteInformation($route); } $fulLUrl = $request->fullUrl(); $data += [ 'full_url' => strlen($fulLUrl) > 100 ? [$fulLUrl] : $fulLUrl, ]; } if ($response instanceof RedirectResponse) { $data['response'] = 'Redirect to ' . $response->getTargetUrl(); } $data += [ 'response' => $response->headers->get('Content-Type') ? $response->headers->get( 'Content-Type' ) : 'text/html', 'request_format' => $request->getRequestFormat(), 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), 'request_headers' => $request->headers->all(), 'request_cookies' => $request->cookies->all(), 'response_headers' => $responseHeaders, ]; if ($this->session) { $data['session_attributes'] = $this->session->all(); } if (isset($data['request_headers']['authorization'][0])) { $data['request_headers']['authorization'][0] = substr($data['request_headers']['authorization'][0], 0, 12) . '******'; } foreach ($this->hiddens as $key) { if (Arr::has($data, $key)) { Arr::set($data, $key, '******'); } } foreach ($data as $key => $var) { if (!is_string($data[$key])) { $data[$key] = DataCollector::getDefaultVarDumper()->renderVar($var); } else { $data[$key] = e($data[$key]); } } if (class_exists(Telescope::class)) { $entry = IncomingEntry::make([ 'requestId' => $this->currentRequestId, ])->type('debugbar'); Telescope::$entriesQueue[] = $entry; $url = route('debugbar.telescope', [$entry->uuid]); $htmlData['telescope'] = 'View in Telescope'; } $tooltip = [ 'status' => $data['status'], 'full_url' => Str::limit($request->fullUrl(), 100), ]; if ($this->request instanceof Request) { $tooltip += [ 'action_name' => optional($this->request->route())->getName(), 'controller_action' => optional($this->request->route())->getActionName(), ]; } unset($htmlData['as'], $htmlData['uses']); return [ 'data' => $tooltip + $htmlData + $data, 'tooltip' => array_filter($tooltip), 'badge' => $statusCode >= 300 ? $data['status'] : null, ]; } protected function getRouteInformation($route) { if (!is_a($route, 'Illuminate\Routing\Route')) { return []; } $uri = head($route->methods()) . ' ' . $route->uri(); $action = $route->getAction(); $result = [ 'uri' => $uri ?: '-', ]; $result = array_merge($result, $action); $uses = $action['uses'] ?? null; $controller = is_string($action['controller'] ?? null) ? $action['controller'] : ''; if (request()->hasHeader('X-Livewire')) { try { $component = request('components')[0]; $name = json_decode($component['snapshot'], true)['memo']['name']; $method = $component['calls'][0]['method']; $class = app(\Livewire\Mechanisms\ComponentRegistry::class)->getClass($name); if (class_exists($class) && method_exists($class, $method)) { $controller = $class . '@' . $method; $result['controller'] = ltrim($controller, '\\'); } } catch (\Throwable $e) { // } } if (str_contains($controller, '@')) { list($controller, $method) = explode('@', $controller); if (class_exists($controller) && method_exists($controller, $method)) { $reflector = new \ReflectionMethod($controller, $method); } unset($result['uses']); } elseif ($uses instanceof \Closure) { $reflector = new \ReflectionFunction($uses); $result['uses'] = $this->formatVar($uses); } elseif (is_string($uses) && str_contains($uses, '@__invoke')) { if (class_exists($controller) && method_exists($controller, 'render')) { $reflector = new \ReflectionMethod($controller, 'render'); $result['controller'] = $controller . '@render'; } } if (isset($reflector)) { $filename = $this->normalizeFilePath($reflector->getFileName()); if ($link = $this->getXdebugLink($reflector->getFileName(), $reflector->getStartLine())) { $result['file'] = sprintf( '%s:%s-%s', $link['url'], $link['ajax'] ? 'event.preventDefault();$.ajax(this.href);' : '', $filename, $reflector->getStartLine(), $reflector->getEndLine() ); if (isset($result['controller']) && is_string($result['controller'])) { $result['controller'] .= ''; } } else { $result['file'] = sprintf('%s:%s-%s', $filename, $reflector->getStartLine(), $reflector->getEndLine()); } } if (isset($result['middleware']) && is_array($result['middleware'])) { $middleware = implode(', ', $result['middleware']); unset($result['middleware']); $result['middleware'] = $middleware; } return array_filter($result); } private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly) { $cookie = sprintf('%s=%s', $name, urlencode($value ?? '')); if (0 !== $expires) { if (is_numeric($expires)) { $expires = (int) $expires; } elseif ($expires instanceof \DateTime) { $expires = $expires->getTimestamp(); } else { $expires = strtotime($expires); if (false === $expires || -1 == $expires) { throw new \InvalidArgumentException( sprintf('The "expires" cookie parameter is not valid.', $expires) ); } } $cookie .= '; expires=' . substr( \DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'), 0, -5 ); } if ($domain) { $cookie .= '; domain=' . $domain; } $cookie .= '; path=' . $path; if ($secure) { $cookie .= '; secure'; } if ($httponly) { $cookie .= '; httponly'; } return $cookie; } } PKk]dLss5laravel-debugbar/src/DataCollector/RouteCollector.phpnuW+Arouter = $router; } /** * {@inheritDoc} */ public function collect() { $route = $this->router->current(); return $this->getRouteInformation($route); } /** * Get the route information for a given route. * * @param \Illuminate\Routing\Route $route * @return array */ protected function getRouteInformation($route) { if (!is_a($route, 'Illuminate\Routing\Route')) { return []; } $uri = head($route->methods()) . ' ' . $route->uri(); $action = $route->getAction(); $result = [ 'uri' => $uri ?: '-', ]; $result = array_merge($result, $action); $uses = $action['uses'] ?? null; $controller = is_string($action['controller'] ?? null) ? $action['controller'] : ''; if (request()->hasHeader('X-Livewire')) { try { $component = request('components')[0]; $name = json_decode($component['snapshot'], true)['memo']['name']; $method = $component['calls'][0]['method']; $class = app(\Livewire\Mechanisms\ComponentRegistry::class)->getClass($name); if (class_exists($class) && method_exists($class, $method)) { $controller = $class . '@' . $method; $result['controller'] = ltrim($controller, '\\'); } } catch (\Throwable $e) { // } } if (str_contains($controller, '@')) { list($controller, $method) = explode('@', $controller); if (class_exists($controller) && method_exists($controller, $method)) { $reflector = new \ReflectionMethod($controller, $method); } unset($result['uses']); } elseif ($uses instanceof \Closure) { $reflector = new \ReflectionFunction($uses); $result['uses'] = $this->formatVar($uses); } elseif (is_string($uses) && str_contains($uses, '@__invoke')) { if (class_exists($controller) && method_exists($controller, 'render')) { $reflector = new \ReflectionMethod($controller, 'render'); $result['controller'] = $controller . '@render'; } } if (isset($reflector)) { $filename = $this->normalizeFilePath($reflector->getFileName()); if ($link = $this->getXdebugLink($reflector->getFileName(), $reflector->getStartLine())) { $result['file'] = sprintf( '%s:%s-%s', $link['url'], $link['ajax'] ? 'event.preventDefault();$.ajax(this.href);' : '', $filename, $reflector->getStartLine(), $reflector->getEndLine() ); if (isset($result['controller'])) { $result['controller'] .= ''; } } else { $result['file'] = sprintf('%s:%s-%s', $filename, $reflector->getStartLine(), $reflector->getEndLine()); } } if ($middleware = $this->getMiddleware($route)) { $result['middleware'] = $middleware; } return array_filter($result); } /** * Get middleware * * @param \Illuminate\Routing\Route $route * @return string */ protected function getMiddleware($route) { return implode(', ', array_map(function ($middleware) { return $middleware instanceof Closure ? 'Closure' : $middleware; }, $route->gatherMiddleware())); } /** * {@inheritDoc} */ public function getName() { return 'route'; } /** * {@inheritDoc} */ public function getWidgets() { $widgets = [ "route" => [ "icon" => "share", "widget" => "PhpDebugBar.Widgets.HtmlVariableListWidget", "map" => "route", "default" => "{}" ] ]; return $widgets; } /** * Display the route information on the console. * * @param array $routes * @return void */ protected function displayRoutes(array $routes) { $this->table->setHeaders($this->headers)->setRows($routes); $this->table->render($this->getOutput()); } } PKk]w97laravel-debugbar/src/DataCollector/SessionCollector.phpnuW+Asession = $session; $this->hiddens = $hiddens; } /** * {@inheritdoc} */ public function collect() { $data = $this->session->all(); foreach ($this->hiddens as $key) { if (Arr::has($data, $key)) { Arr::set($data, $key, '******'); } } foreach ($data as $key => $value) { $data[$key] = is_string($value) ? $value : $this->formatVar($value); } return $data; } /** * {@inheritDoc} */ public function getName() { return 'session'; } /** * {@inheritDoc} */ public function getWidgets() { return [ "session" => [ "icon" => "archive", "widget" => "PhpDebugBar.Widgets.VariableListWidget", "map" => "session", "default" => "{}" ] ]; } } PKk]'c]]4laravel-debugbar/src/DataCollector/ViewCollector.phpnuW+AsetDataFormatter(new SimpleFormatter()); $this->collect_data = $collectData; $this->templates = []; $this->exclude_paths = $excludePaths; $this->group = $group; $this->timeCollector = $timeCollector; } public function getName() { return 'views'; } public function getWidgets() { return [ 'views' => [ 'icon' => 'leaf', 'widget' => 'PhpDebugBar.Widgets.TemplatesWidget', 'map' => 'views', 'default' => '[]' ], 'views:badge' => [ 'map' => 'views.nb_templates', 'default' => 0 ] ]; } /** * @return array */ public function getAssets() { return [ 'css' => 'widgets/templates/widget.css', 'js' => 'widgets/templates/widget.js', ]; } /** * Add a View instance to the Collector * * @param \Illuminate\View\View $view */ public function addView(View $view) { $name = $view->getName(); $type = null; $data = $view->getData(); $path = $view->getPath(); if (class_exists('\Inertia\Inertia')) { list($name, $type, $data, $path) = $this->getInertiaView($name, $data, $path); } if (is_object($path)) { $type = get_class($view); $path = null; } if ($path) { if (!$type) { if (substr($path, -10) == '.blade.php') { $type = 'blade'; } else { $type = pathinfo($path, PATHINFO_EXTENSION); } } $shortPath = $this->normalizeFilePath($path); foreach ($this->exclude_paths as $excludePath) { if (str_starts_with($shortPath, $excludePath)) { return; } } } $this->addTemplate($name, $data, $type, $path); if ($this->timeCollector !== null) { $time = microtime(true); $this->timeCollector->addMeasure('View: ' . $name, $time, $time, [], 'views', 'View'); } } private function getInertiaView(string $name, array $data, ?string $path) { if (isset($data['page']) && is_array($data['page'])) { $data = $data['page']; } if (isset($data['props'], $data['component'])) { $name = $data['component']; $data = $data['props']; if ($files = glob(resource_path(config('debugbar.options.views.inertia_pages') .'/'. $name . '.*'))) { $path = $files[0]; $type = pathinfo($path, PATHINFO_EXTENSION); if (in_array($type, ['js', 'jsx'])) { $type = 'react'; } } } return [$name, $type ?? '', $data, $path]; } public function addInertiaAjaxView(array $data) { list($name, $type, $data, $path) = $this->getInertiaView('', $data, ''); if (! $name) { return; } $this->addTemplate($name, $data, $type, $path); } private function addTemplate(string $name, array $data, ?string $type, ?string $path) { // Prevent duplicates $hash = $type . $path . $name . ($this->collect_data ? implode(array_keys($data)) : ''); if ($this->collect_data === 'keys') { $params = array_keys($data); } elseif ($this->collect_data) { $params = array_map( fn ($value) => $this->getDataFormatter()->formatVar($value), $data ); } else { $params = []; } $template = [ 'name' => $name, 'param_count' => $this->collect_data ? count($params) : null, 'params' => $params, 'start' => microtime(true), 'type' => $type, 'hash' => $hash, ]; if ($path && $this->getXdebugLinkTemplate()) { $template['xdebug_link'] = $this->getXdebugLink($path); } $this->templates[] = $template; } public function collect() { if ($this->group === true || count($this->templates) > $this->group) { $templates = []; foreach ($this->templates as $template) { $hash = $template['hash']; if (!isset($templates[$hash])) { $template['render_count'] = 0; $template['name_original'] = $template['name']; $templates[$hash] = $template; } $templates[$hash]['render_count']++; $templates[$hash]['name'] = $templates[$hash]['render_count'] . 'x ' . $templates[$hash]['name_original']; } $templates = array_values($templates); } else { $templates = $this->templates; } return [ 'count' => count($this->templates), 'nb_templates' => count($this->templates), 'templates' => $templates, ]; } } PKk]885laravel-debugbar/src/DataFormatter/QueryFormatter.phpnuW+AcheckBindings($binding); $binding = '[' . implode(',', $binding) . ']'; } if (is_object($binding)) { $binding = json_encode($binding); } } return $bindings; } /** * Format a source object. * * @param object|null $source If the backtrace is disabled, the $source will be null. * @return string */ public function formatSource($source, $short = false) { if (! is_object($source)) { return ''; } $parts = []; if (!$short && $source->namespace) { $parts['namespace'] = $source->namespace . '::'; } $parts['name'] = $short ? basename($source->name) : $source->name; $parts['line'] = ':' . $source->line; return implode($parts); } } PKk]ea@Q| | 6laravel-debugbar/src/DataFormatter/SimpleFormatter.phpnuW+AexportValue($data); } /** * Converts a PHP value to a string. * * @param mixed $value The PHP value * @param int $depth Only for internal usage * @param bool $deep Only for internal usage * * @return string The string representation of the given value * @author Bernhard Schussek */ private function exportValue($value, $depth = 1, $deep = false) { if ($value instanceof \__PHP_Incomplete_Class) { return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value)); } if (is_object($value)) { if ($value instanceof \DateTimeInterface) { return sprintf('Object(%s) - %s', get_class($value), $value->format(\DateTime::ATOM)); } return sprintf('Object(%s)', get_class($value)); } if (is_array($value)) { if (empty($value)) { return '[]'; } $indent = str_repeat(' ', $depth); $a = []; foreach ($value as $k => $v) { if (is_array($v)) { $deep = true; } $a[] = sprintf('%s => %s', $k, $this->exportValue($v, $depth + 1, $deep)); } if ($deep) { $args = [$indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1)]; return sprintf("[\n%s%s\n%s]", ...$args); } $s = sprintf('[%s]', implode(', ', $a)); if (80 > strlen($s)) { return $s; } return sprintf("[\n%s%s\n]", $indent, implode(sprintf(",\n%s", $indent), $a)); } if (is_resource($value)) { return sprintf('Resource(%s#%d)', get_resource_type($value), $value); } if (null === $value) { return 'null'; } if (false === $value) { return 'false'; } if (true === $value) { return 'true'; } return (string) $value; } /** * @param \__PHP_Incomplete_Class $value * @return mixed * @author Bernhard Schussek */ private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) { $array = new \ArrayObject($value); return $array['__PHP_Incomplete_Class_Name']; } } PKk]}/(laravel-debugbar/src/debugbar-routes.phpnuW+A 'Barryvdh\Debugbar\Controllers', 'prefix' => app('config')->get('debugbar.route_prefix'), 'domain' => app('config')->get('debugbar.route_domain'), 'middleware' => array_merge(app('config')->get('debugbar.route_middleware', []), [\Barryvdh\Debugbar\Middleware\DebugbarEnabled::class]), ]; app('router')->group($routeConfig, function ($router) { $router->get('open', [ 'uses' => 'OpenHandlerController@handle', 'as' => 'debugbar.openhandler', ]); $router->get('clockwork/{id}', [ 'uses' => 'OpenHandlerController@clockwork', 'as' => 'debugbar.clockwork', ]); if (class_exists(\Laravel\Telescope\Telescope::class)) { $router->get('telescope/{id}', [ 'uses' => 'TelescopeController@show', 'as' => 'debugbar.telescope', ]); } $router->get('assets/stylesheets', [ 'uses' => 'AssetController@css', 'as' => 'debugbar.assets.css', ]); $router->get('assets/javascript', [ 'uses' => 'AssetController@js', 'as' => 'debugbar.assets.js', ]); $router->delete('cache/{key}/{tags?}', [ 'uses' => 'CacheController@delete', 'as' => 'debugbar.cache.delete', ]); $router->post('queries/explain', [ 'uses' => 'QueriesController@explain', 'as' => 'debugbar.queries.explain', ]); }); PKk]b_))+laravel-debugbar/src/DebugbarViewEngine.phpnuW+Aengine = $engine; $this->laravelDebugbar = $laravelDebugbar; $this->exclude_paths = app('config')->get('debugbar.options.views.exclude_paths', []); } /** * @param string $path * @param array $data * @return string */ public function get($path, array $data = []) { $basePath = base_path(); $shortPath = @file_exists((string) $path) ? realpath($path) : $path; if (str_starts_with($shortPath, $basePath)) { $shortPath = ltrim( str_replace('\\', '/', substr($shortPath, strlen($basePath))), '/' ); } foreach ($this->exclude_paths as $excludePath) { if (str_starts_with($shortPath, $excludePath)) { return $this->engine->get($path, $data); } } return $this->laravelDebugbar->measure($shortPath, function () use ($path, $data) { return $this->engine->get($path, $data); }, 'views'); } /** * NOTE: This is done to support other Engine swap (example: Livewire). * @param $name * @param $arguments * @return mixed */ public function __call($name, $arguments) { return $this->engine->$name(...$arguments); } } PKk]1#""laravel-debugbar/src/Facade.phpnuW+AaddMessage($value, 'debug'); } } } if (!function_exists('start_measure')) { /** * Starts a measure * * @param string $name Internal name, used to stop the measure * @param string $label Public name */ function start_measure($name, $label = null) { debugbar()->startMeasure($name, $label); } } if (!function_exists('stop_measure')) { /** * Stop a measure * * @param string $name Internal name, used to stop the measure */ function stop_measure($name) { debugbar()->stopMeasure($name); } } if (!function_exists('add_measure')) { /** * Adds a measure * * @param string $label * @param float $start * @param float $end */ function add_measure($label, $start, $end) { debugbar()->addMeasure($label, $start, $end); } } if (!function_exists('measure')) { /** * Utility function to measure the execution of a Closure * * @param string $label * @param \Closure $closure * @return mixed */ function measure($label, \Closure $closure) { return debugbar()->measure($label, $closure); } } PKk]YùKK+laravel-debugbar/src/JavascriptRenderer.phpnuW+AcssFiles['laravel'] = __DIR__ . '/Resources/laravel-debugbar.css'; $this->jsFiles['laravel-cache'] = __DIR__ . '/Resources/cache/widget.js'; $this->jsFiles['laravel-queries'] = __DIR__ . '/Resources/queries/widget.js'; $this->setTheme(config('debugbar.theme', 'auto')); } /** * Set the URL Generator * * @param \Illuminate\Routing\UrlGenerator $url * @deprecated */ public function setUrlGenerator($url) { } /** * {@inheritdoc} */ public function renderHead() { $cssRoute = preg_replace('/\Ahttps?:\/\/[^\/]+/', '', route('debugbar.assets.css', [ 'v' => $this->getModifiedTime('css'), ])); $jsRoute = preg_replace('/\Ahttps?:\/\/[^\/]+/', '', route('debugbar.assets.js', [ 'v' => $this->getModifiedTime('js') ])); $nonce = $this->getNonceAttribute(); $html = ""; $html .= ""; if ($this->isJqueryNoConflictEnabled()) { $html .= "jQuery.noConflict(true);" . "\n"; } $inlineHtml = $this->getInlineHtml(); if ($nonce != '') { $inlineHtml = preg_replace("/<(script|style)>/", "<$1{$nonce}>", $inlineHtml); } $html .= $inlineHtml; return $html; } protected function getInlineHtml() { $html = ''; foreach (['head', 'css', 'js'] as $asset) { foreach ($this->getAssets('inline_' . $asset) as $item) { $html .= $item . "\n"; } } return $html; } /** * Get the last modified time of any assets. * * @param string $type 'js' or 'css' * @return int */ protected function getModifiedTime($type) { $files = $this->getAssets($type); $latest = 0; foreach ($files as $file) { $mtime = filemtime($file); if ($mtime > $latest) { $latest = $mtime; } } return $latest; } /** * Return assets as a string * * @param string $type 'js' or 'css' * @return string */ public function dumpAssetsToString($type) { $files = $this->getAssets($type); $content = ''; foreach ($files as $file) { $content .= file_get_contents($file) . "\n"; } return $content; } /** * Makes a URI relative to another * * @param string|array $uri * @param string $root * @return string */ protected function makeUriRelativeTo($uri, $root) { if (!$root) { return $uri; } if (is_array($uri)) { $uris = []; foreach ($uri as $u) { $uris[] = $this->makeUriRelativeTo($u, $root); } return $uris; } if (substr($uri ?? '', 0, 1) === '/' || preg_match('/^([a-zA-Z]+:\/\/|[a-zA-Z]:\/|[a-zA-Z]:\\\)/', $uri ?? '')) { return $uri; } return rtrim($root, '/') . "/$uri"; } } PKk] i{(laravel-debugbar/src/LaravelDebugbar.phpnuW+Aapp = $app; $this->version = $app->version(); $this->is_lumen = Str::contains($this->version, 'Lumen'); if ($this->is_lumen) { $this->version = Str::betweenFirst($app->version(), '(', ')'); } else { $this->setRequestIdGenerator(new RequestIdGenerator()); } } /** * Returns the HTTP driver * * If no http driver where defined, a PhpHttpDriver is automatically created * * @return HttpDriverInterface */ public function getHttpDriver() { if ($this->httpDriver === null) { $this->httpDriver = $this->app->make(SymfonyHttpDriver::class); } return $this->httpDriver; } /** * Enable the Debugbar and boot, if not already booted. */ public function enable() { $this->enabled = true; if (!$this->booted) { $this->boot(); } } /** * Boot the debugbar (add collectors, renderer and listener) */ public function boot() { if ($this->booted) { return; } /** @var Application $app */ $app = $this->app; /** @var \Illuminate\Config\Repository $config */ $config = $app['config']; /** @var \Illuminate\Events\Dispatcher|null $events */ $events = isset($app['events']) ? $app['events'] : null; $this->editorTemplateLink = $config->get('debugbar.editor') ?: null; $this->remoteServerReplacements = $this->getRemoteServerReplacements(); // Set custom error handler if ($config->get('debugbar.error_handler', false)) { $this->prevErrorHandler = set_error_handler([$this, 'handleError']); } $this->selectStorage($this); if ($this->shouldCollect('phpinfo', true)) { $this->addCollector(new PhpInfoCollector()); } if ($this->shouldCollect('messages', true)) { $this->addCollector(new MessagesCollector()); if ($config->get('debugbar.options.messages.trace', true)) { $this['messages']->collectFileTrace(true); } if ($config->get('debugbar.options.messages.capture_dumps', false)) { $originalHandler = \Symfony\Component\VarDumper\VarDumper::setHandler(function ($var) use (&$originalHandler) { if ($originalHandler) { $originalHandler($var); } self::addMessage($var); }); } } if ($this->shouldCollect('time', true)) { $startTime = $app['request']->server('REQUEST_TIME_FLOAT'); if (!$this->hasCollector('time')) { $this->addCollector(new TimeDataCollector($startTime)); } if ($config->get('debugbar.options.time.memory_usage')) { $this['time']->showMemoryUsage(); } if ($startTime && !$this->isLumen()) { $app->booted( function () use ($startTime) { $this->addMeasure('Booting', $startTime, microtime(true), [], 'time'); } ); } $this->startMeasure('application', 'Application', 'time'); if ($events) { $events->listen(\Illuminate\Routing\Events\Routing::class, function() { $this->startMeasure('Routing'); }); $events->listen(\Illuminate\Routing\Events\RouteMatched::class, function() { $this->stopMeasure('Routing'); }); $events->listen(\Illuminate\Routing\Events\PreparingResponse::class, function() { $this->startMeasure('Preparing Response'); }); $events->listen(\Illuminate\Routing\Events\ResponsePrepared::class, function() { $this->stopMeasure('Preparing Response'); }); } } if ($this->shouldCollect('memory', true)) { $this->addCollector(new MemoryCollector()); $this['memory']->setPrecision($config->get('debugbar.options.memory.precision', 0)); if (function_exists('memory_reset_peak_usage') && $config->get('debugbar.options.memory.reset_peak')) { memory_reset_peak_usage(); } if ($config->get('debugbar.options.memory.with_baseline')) { $this['memory']->resetMemoryBaseline(); } } if ($this->shouldCollect('exceptions', true)) { try { $this->addCollector(new ExceptionsCollector()); $this['exceptions']->setChainExceptions( $config->get('debugbar.options.exceptions.chain', true) ); } catch (Exception $e) { } } if ($this->shouldCollect('laravel', false)) { $this->addCollector(new LaravelCollector($app)); } if ($this->shouldCollect('default_request', false)) { $this->addCollector(new RequestDataCollector()); } if ($this->shouldCollect('events', false) && $events) { try { $startTime = $app['request']->server('REQUEST_TIME_FLOAT'); $collectData = $config->get('debugbar.options.events.data', false); $excludedEvents = $config->get('debugbar.options.events.excluded', []); $this->addCollector(new EventCollector($startTime, $collectData, $excludedEvents)); $events->subscribe($this['event']); } catch (Exception $e) { $this->addCollectorException('Cannot add EventCollector', $e); } } if ($this->shouldCollect('views', true) && $events) { try { $collectData = $config->get('debugbar.options.views.data', true); $excludePaths = $config->get('debugbar.options.views.exclude_paths', []); $group = $config->get('debugbar.options.views.group', true); if ($this->hasCollector('time') && $config->get('debugbar.options.views.timeline', false)) { $timeCollector = $this['time']; } else { $timeCollector = null; } $this->addCollector(new ViewCollector($collectData, $excludePaths, $group, $timeCollector)); $events->listen( 'composing:*', function ($event, $params) { $this['views']->addView($params[0]); } ); } catch (Exception $e) { $this->addCollectorException('Cannot add ViewCollector', $e); } } if (!$this->isLumen() && $this->shouldCollect('route')) { try { $this->addCollector($app->make(RouteCollector::class)); } catch (Exception $e) { $this->addCollectorException('Cannot add RouteCollector', $e); } } if (!$this->isLumen() && $this->shouldCollect('log', true)) { try { if ($this->hasCollector('messages')) { $logger = new MessagesCollector('log'); $this['messages']->aggregate($logger); $app['log']->listen( function (\Illuminate\Log\Events\MessageLogged $log) use ($logger) { try { $logMessage = (string) $log->message; if (mb_check_encoding($logMessage, 'UTF-8')) { $context = $log->context; $logMessage .= (!empty($context) ? ' ' . json_encode($context, JSON_PRETTY_PRINT) : ''); } else { $logMessage = "[INVALID UTF-8 DATA]"; } } catch (Exception $e) { $logMessage = "[Exception: " . $e->getMessage() . "]"; } $logger->addMessage( '[' . date('H:i:s') . '] ' . "LOG.{$log->level}: " . $logMessage, $log->level, false ); } ); } else { $this->addCollector(new MonologCollector($this->getMonologLogger())); } } catch (Exception $e) { $this->addCollectorException('Cannot add LogsCollector', $e); } } if ($this->shouldCollect('db', true) && isset($app['db']) && $events) { if ($this->hasCollector('time') && $config->get('debugbar.options.db.timeline', false)) { $timeCollector = $this['time']; } else { $timeCollector = null; } $queryCollector = new QueryCollector($timeCollector); $queryCollector->setDataFormatter(new QueryFormatter()); $queryCollector->setLimits($config->get('debugbar.options.db.soft_limit'), $config->get('debugbar.options.db.hard_limit')); $queryCollector->setDurationBackground($config->get('debugbar.options.db.duration_background')); if ($config->get('debugbar.options.db.with_params')) { $queryCollector->setRenderSqlWithParams(true); } if ($dbBacktrace = $config->get('debugbar.options.db.backtrace')) { $middleware = ! $this->is_lumen ? $app['router']->getMiddleware() : []; $queryCollector->setFindSource($dbBacktrace, $middleware); } if ($excludePaths = $config->get('debugbar.options.db.exclude_paths')) { $queryCollector->mergeExcludePaths($excludePaths); } if ($excludeBacktracePaths = $config->get('debugbar.options.db.backtrace_exclude_paths')) { $queryCollector->mergeBacktraceExcludePaths($excludeBacktracePaths); } if ($config->get('debugbar.options.db.explain.enabled')) { $types = $config->get('debugbar.options.db.explain.types'); $queryCollector->setExplainSource(true, $types); } if ($config->get('debugbar.options.db.hints', true)) { $queryCollector->setShowHints(true); } if ($config->get('debugbar.options.db.show_copy', false)) { $queryCollector->setShowCopyButton(true); } $this->addCollector($queryCollector); try { $events->listen( function (\Illuminate\Database\Events\QueryExecuted $query) { if (!app(static::class)->shouldCollect('db', true)) { return; // Issue 776 : We've turned off collecting after the listener was attached } //allow collecting only queries slower than a specified amount of milliseconds $threshold = app('config')->get('debugbar.options.db.slow_threshold', false); if (!$threshold || $query->time > $threshold) { $this['queries']->addQuery($query); } } ); } catch (Exception $e) { $this->addCollectorException('Cannot listen to Queries', $e); } try { $events->listen( \Illuminate\Database\Events\TransactionBeginning::class, function ($transaction) { $this['queries']->collectTransactionEvent('Begin Transaction', $transaction->connection); } ); $events->listen( \Illuminate\Database\Events\TransactionCommitted::class, function ($transaction) { $this['queries']->collectTransactionEvent('Commit Transaction', $transaction->connection); } ); $events->listen( \Illuminate\Database\Events\TransactionRolledBack::class, function ($transaction) { $this['queries']->collectTransactionEvent('Rollback Transaction', $transaction->connection); } ); $events->listen( 'connection.*.beganTransaction', function ($event, $params) { $this['queries']->collectTransactionEvent('Begin Transaction', $params[0]); } ); $events->listen( 'connection.*.committed', function ($event, $params) { $this['queries']->collectTransactionEvent('Commit Transaction', $params[0]); } ); $events->listen( 'connection.*.rollingBack', function ($event, $params) { $this['queries']->collectTransactionEvent('Rollback Transaction', $params[0]); } ); $events->listen( function (\Illuminate\Database\Events\ConnectionEstablished $event) { $this['queries']->collectTransactionEvent('Connection Established', $event->connection); if (app('config')->get('debugbar.options.db.memory_usage')) { $event->connection->beforeExecuting(function () { $this['queries']->startMemoryUsage(); }); } } ); } catch (Exception $e) { $this->addCollectorException('Cannot listen transactions to Queries', $e); } } if ($this->shouldCollect('models', true) && $events) { try { $this->addCollector(new ObjectCountCollector('models')); $eventList = ['retrieved', 'created', 'updated', 'deleted']; $this['models']->setKeyMap(array_combine($eventList, array_map('ucfirst', $eventList))); $this['models']->collectCountSummary(true); foreach ($eventList as $event) { $events->listen("eloquent.{$event}: *", function ($event, $models) { $event = explode(': ', $event); $count = count(array_filter($models)); $this['models']->countClass($event[1], $count, explode('.', $event[0])[1]); }); } } catch (Exception $e) { $this->addCollectorException('Cannot add Models Collector', $e); } } if ($this->shouldCollect('livewire', true) && $app->bound('livewire')) { try { $this->addCollector($app->make(LivewireCollector::class)); } catch (Exception $e) { $this->addCollectorException('Cannot add Livewire Collector', $e); } } if ($this->shouldCollect('mail', true) && class_exists('Illuminate\Mail\MailServiceProvider') && $events) { try { $mailCollector = new SymfonyMailCollector(); $this->addCollector($mailCollector); $events->listen(function (MessageSent $event) use ($mailCollector) { $mailCollector->addSymfonyMessage($event->sent->getSymfonySentMessage()); }); if ($config->get('debugbar.options.mail.show_body') || $config->get('debugbar.options.mail.full_log')) { $mailCollector->showMessageBody(); } if ($this->hasCollector('time') && $config->get('debugbar.options.mail.timeline')) { $transport = $app['mailer']->getSymfonyTransport(); $app['mailer']->setSymfonyTransport(new class ($transport, $this) extends AbstractTransport{ private $originalTransport; private $laravelDebugbar; public function __construct($transport, $laravelDebugbar) { $this->originalTransport = $transport; $this->laravelDebugbar = $laravelDebugbar; } public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage { return $this->laravelDebugbar['time']->measure( 'mail: ' . Str::limit($message->getSubject(), 100), function () use ($message, $envelope) { return $this->originalTransport->send($message, $envelope); }, 'mail' ); } protected function doSend(SentMessage $message): void { } public function __toString(): string { return $this->originalTransport->__toString(); } }); } } catch (Exception $e) { $this->addCollectorException('Cannot add SymfonyMailCollector', $e); } } if ($this->shouldCollect('logs', false)) { try { $file = $config->get('debugbar.options.logs.file'); $this->addCollector(new LogsCollector($file)); } catch (Exception $e) { $this->addCollectorException('Cannot add LogsCollector', $e); } } if ($this->shouldCollect('files', false)) { $this->addCollector(new FilesCollector($app)); } if ($this->shouldCollect('auth', false)) { try { $guards = $config->get('auth.guards', []); $this->addCollector(new MultiAuthCollector($app['auth'], $guards)); $this['auth']->setShowName( $config->get('debugbar.options.auth.show_name') ); $this['auth']->setShowGuardsData( $config->get('debugbar.options.auth.show_guards', true) ); } catch (Exception $e) { $this->addCollectorException('Cannot add AuthCollector', $e); } } if ($this->shouldCollect('gate', false)) { try { $this->addCollector($app->make(GateCollector::class)); if ($config->get('debugbar.options.gate.trace', false)) { $this['gate']->collectFileTrace(true); $this['gate']->addBacktraceExcludePaths($config->get('debugbar.options.gate.exclude_paths',[])); } } catch (Exception $e) { $this->addCollectorException('Cannot add GateCollector', $e); } } if ($this->shouldCollect('cache', false) && $events) { try { $collectValues = $config->get('debugbar.options.cache.values', true); $startTime = $app['request']->server('REQUEST_TIME_FLOAT'); $this->addCollector(new CacheCollector($startTime, $collectValues)); $events->subscribe($this['cache']); } catch (Exception $e) { $this->addCollectorException('Cannot add CacheCollector', $e); } } if ($this->shouldCollect('jobs', false) && $events) { try { $this->addCollector(new ObjectCountCollector('jobs', 'briefcase')); $events->listen(\Illuminate\Queue\Events\JobQueued::class, function ($event) { $this['jobs']->countClass($event->job); }); } catch (Exception $e) { $this->addCollectorException('Cannot add Jobs Collector', $e); } } if ($this->shouldCollect('pennant', false)) { if (class_exists('Laravel\Pennant\FeatureManager') && $app->bound(\Laravel\Pennant\FeatureManager::class)) { $featureManager = $app->make(\Laravel\Pennant\FeatureManager::class); try { $this->addCollector(new PennantCollector($featureManager)); } catch (Exception $e) { $this->addCollectorException('Cannot add PennantCollector', $e); } } } $renderer = $this->getJavascriptRenderer(); $renderer->setHideEmptyTabs($config->get('debugbar.hide_empty_tabs', false)); $renderer->setIncludeVendors($config->get('debugbar.include_vendors', true)); $renderer->setBindAjaxHandlerToFetch($config->get('debugbar.capture_ajax', true)); $renderer->setBindAjaxHandlerToXHR($config->get('debugbar.capture_ajax', true)); $renderer->setDeferDatasets($config->get('debugbar.defer_datasets', false)); $this->booted = true; } public function shouldCollect($name, $default = false) { return $this->app['config']->get('debugbar.collectors.' . $name, $default); } /** * Adds a data collector * * @param DataCollectorInterface $collector * * @throws DebugBarException * @return $this */ public function addCollector(DataCollectorInterface $collector) { parent::addCollector($collector); if (method_exists($collector, 'useHtmlVarDumper')) { $collector->useHtmlVarDumper(); } if (method_exists($collector, 'setEditorLinkTemplate') && $this->editorTemplateLink) { $collector->setEditorLinkTemplate($this->editorTemplateLink); } if (method_exists($collector, 'addXdebugReplacements') && $this->remoteServerReplacements) { $collector->addXdebugReplacements($this->remoteServerReplacements); } return $this; } /** * Handle silenced errors * * @param $level * @param $message * @param string $file * @param int $line * @param array $context * @throws \ErrorException */ public function handleError($level, $message, $file = '', $line = 0, $context = []) { if ($this->hasCollector('exceptions')) { $this['exceptions']->addWarning($level, $message, $file, $line); } if ($this->hasCollector('messages')) { $file = $file ? ' on ' . $this['messages']->normalizeFilePath($file) . ":{$line}" : ''; $this['messages']->addMessage($message . $file, 'deprecation'); } if (! $this->prevErrorHandler) { return; } return call_user_func($this->prevErrorHandler, $level, $message, $file, $line, $context); } /** * Starts a measure * * @param string $name Internal name, used to stop the measure * @param string $label Public name * @param string|null $collector * @param string|null $group */ public function startMeasure($name, $label = null, $collector = null, $group = null) { if ($this->hasCollector('time')) { /** @var \DebugBar\DataCollector\TimeDataCollector */ $time = $this->getCollector('time'); $time->startMeasure($name, $label, $collector, $group); } } /** * Stops a measure * * @param string $name */ public function stopMeasure($name) { if ($this->hasCollector('time')) { /** @var \DebugBar\DataCollector\TimeDataCollector $collector */ $collector = $this->getCollector('time'); try { $collector->stopMeasure($name); } catch (Exception $e) { // $this->addThrowable($e); } } } /** * Adds an exception to be profiled in the debug bar * * @param Exception $e * @deprecated in favor of addThrowable */ public function addException(Exception $e) { return $this->addThrowable($e); } /** * Adds an exception to be profiled in the debug bar * * @param Throwable $e */ public function addThrowable($e) { if ($this->hasCollector('exceptions')) { /** @var \DebugBar\DataCollector\ExceptionsCollector $collector */ $collector = $this->getCollector('exceptions'); $collector->addThrowable($e); } } /** * Register collector exceptions * * @param string $message * @param Exception $exception */ protected function addCollectorException(string $message, Exception $exception) { $this->addThrowable( new Exception( $message . ' on Laravel Debugbar: ' . $exception->getMessage(), (int) $exception->getCode(), $exception ) ); } /** * Returns a JavascriptRenderer for this instance * * @param string $baseUrl * @param string $basePath * @return JavascriptRenderer */ public function getJavascriptRenderer($baseUrl = null, $basePath = null) { if ($this->jsRenderer === null) { $this->jsRenderer = new JavascriptRenderer($this, $baseUrl, $basePath); } return $this->jsRenderer; } /** * Modify the response and inject the debugbar (or data in headers) * * @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\HttpFoundation\Response $response * @return \Symfony\Component\HttpFoundation\Response */ public function modifyResponse(Request $request, Response $response) { /** @var Application $app */ $app = $this->app; if (!$this->isEnabled() || !$this->booted || $this->isDebugbarRequest() || $this->responseIsModified) { return $response; } // Prevent duplicate modification $this->responseIsModified = true; // Set the Response if required $httpDriver = $this->getHttpDriver(); if ($httpDriver instanceof SymfonyHttpDriver) { $httpDriver->setResponse($response); } // Show the Http Response Exception in the Debugbar, when available if (isset($response->exception)) { $this->addThrowable($response->exception); } if ($this->shouldCollect('config', false)) { try { $configCollector = new ConfigCollector(); $configCollector->setData($app['config']->all()); $this->addCollector($configCollector); } catch (Exception $e) { $this->addCollectorException('Cannot add ConfigCollector', $e); } } $sessionHiddens = $app['config']->get('debugbar.options.session.hiddens', []); if ($app->bound(SessionManager::class)) { /** @var \Illuminate\Session\SessionManager $sessionManager */ $sessionManager = $app->make(SessionManager::class); if ($this->shouldCollect('session') && ! $this->hasCollector('session')) { try { $this->addCollector(new SessionCollector($sessionManager, $sessionHiddens)); } catch (Exception $e) { $this->addCollectorException('Cannot add SessionCollector', $e); } } } else { $sessionManager = null; } $requestHiddens = array_merge( $app['config']->get('debugbar.options.symfony_request.hiddens', []), array_map(fn ($key) => 'session_attributes.' . $key, $sessionHiddens) ); if ($this->shouldCollect('symfony_request', true) && !$this->hasCollector('request')) { try { $reqId = $this->getCurrentRequestId(); $this->addCollector(new RequestCollector($request, $response, $sessionManager, $reqId, $requestHiddens)); } catch (Exception $e) { $this->addCollectorException('Cannot add SymfonyRequestCollector', $e); } } if ($app['config']->get('debugbar.clockwork') && ! $this->hasCollector('clockwork')) { try { $this->addCollector(new ClockworkCollector($request, $response, $sessionManager, $requestHiddens)); } catch (Exception $e) { $this->addCollectorException('Cannot add ClockworkCollector', $e); } $this->addClockworkHeaders($response); } try { if ($this->hasCollector('views') && $response->headers->has('X-Inertia')) { $content = $response->getContent(); if (is_string($content)) { $content = json_decode($content, true); } if (is_array($content)) { $this['views']->addInertiaAjaxView($content); } } } catch (Exception $e) { } if ($app['config']->get('debugbar.add_ajax_timing', false)) { $this->addServerTimingHeaders($response); } if ($response->isRedirection()) { try { $this->stackData(); } catch (Exception $e) { $app['log']->error('Debugbar exception: ' . $e->getMessage()); } return $response; } try { // Collect + store data, only inject the ID in theheaders $this->sendDataInHeaders(true); } catch (Exception $e) { $app['log']->error('Debugbar exception: ' . $e->getMessage()); } // Check if it's safe to inject the Debugbar if ( $app['config']->get('debugbar.inject', true) && str_contains($response->headers->get('Content-Type', 'text/html'), 'html') && !$this->isJsonRequest($request, $response) && $response->getContent() !== false && in_array($request->getRequestFormat(), [null, 'html'], true) ) { try { $this->injectDebugbar($response); } catch (Exception $e) { $app['log']->error('Debugbar exception: ' . $e->getMessage()); } } return $response; } /** * Check if the Debugbar is enabled * @return boolean */ public function isEnabled() { if ($this->enabled === null) { /** @var \Illuminate\Config\Repository $config */ $config = $this->app['config']; $configEnabled = value($config->get('debugbar.enabled')); if ($configEnabled === null) { $configEnabled = $config->get('app.debug'); } $this->enabled = $configEnabled && !$this->app->runningInConsole() && !$this->app->environment('testing'); } return $this->enabled; } /** * Check if this is a request to the Debugbar OpenHandler * * @return bool */ protected function isDebugbarRequest() { return $this->app['request']->is($this->app['config']->get('debugbar.route_prefix') . '*'); } /** * @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\HttpFoundation\Response $response * @return bool */ protected function isJsonRequest(Request $request, Response $response) { // If XmlHttpRequest, Live or HTMX, return true if ( $request->isXmlHttpRequest() || $request->headers->has('X-Livewire') || ($request->headers->has('Hx-Request') && $request->headers->has('Hx-Target')) ) { return true; } // Check if the request wants Json $acceptable = $request->getAcceptableContentTypes(); if (isset($acceptable[0]) && in_array($acceptable[0], ['application/json', 'application/javascript'], true)) { return true; } // Check if content looks like JSON without actually validating $content = $response->getContent(); if (is_string($content) && strlen($content) > 0 && in_array($content[0], ['{', '['], true)) { return true; } return false; } /** * Collects the data from the collectors * * @return array */ public function collect() { /** @var Request $request */ $request = $this->app['request']; $this->data = [ '__meta' => [ 'id' => $this->getCurrentRequestId(), 'datetime' => date('Y-m-d H:i:s'), 'utime' => microtime(true), 'method' => $request->getMethod(), 'uri' => $request->getRequestUri(), 'ip' => $request->getClientIp() ] ]; foreach ($this->collectors as $name => $collector) { $this->data[$name] = $collector->collect(); } // Remove all invalid (non UTF-8) characters array_walk_recursive( $this->data, function (&$item) { if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) { $item = mb_convert_encoding($item, 'UTF-8', 'UTF-8'); } } ); if ($this->storage !== null) { $this->storage->save($this->getCurrentRequestId(), $this->data); } return $this->data; } /** * Injects the web debug toolbar into the given Response. * * @param \Symfony\Component\HttpFoundation\Response $response A Response instance * Based on https://github.com/symfony/WebProfilerBundle/blob/master/EventListener/WebDebugToolbarListener.php */ public function injectDebugbar(Response $response) { /** @var \Illuminate\Config\Repository $config */ $config = $this->app['config']; $content = $response->getContent(); $renderer = $this->getJavascriptRenderer(); $autoShow = $config->get('debugbar.ajax_handler_auto_show', true); $renderer->setAjaxHandlerAutoShow($autoShow); $enableTab = $config->get('debugbar.ajax_handler_enable_tab', true); $renderer->setAjaxHandlerEnableTab($enableTab); if ($this->getStorage()) { $openHandlerUrl = route('debugbar.openhandler'); $renderer->setOpenHandlerUrl($openHandlerUrl); } $head = $renderer->renderHead(); $widget = $renderer->render(); // Try to put the js/css directly before the $pos = stripos($content, ''); if (false !== $pos) { $content = substr($content, 0, $pos) . $head . substr($content, $pos); } else { // Append the head before the widget $widget = $head . $widget; } // Try to put the widget at the end, directly before the $pos = strripos($content, ''); if (false !== $pos) { $content = substr($content, 0, $pos) . $widget . substr($content, $pos); } else { $content = $content . $widget; } $original = null; if ($response instanceof \Illuminate\Http\Response && $response->getOriginalContent()) { $original = $response->getOriginalContent(); } // Update the new content and reset the content length $response->setContent($content); $response->headers->remove('Content-Length'); // Restore original response (e.g. the View or Ajax data) if ($original) { $response->original = $original; } } /** * Checks if there is stacked data in the session * * @return boolean */ public function hasStackedData() { return count($this->getStackedData(false)) > 0; } /** * Returns the data stacked in the session * * @param boolean $delete Whether to delete the data in the session * @return array */ public function getStackedData($delete = true): array { $this->stackedData = array_merge($this->stackedData, parent::getStackedData($delete)); return $this->stackedData; } /** * Disable the Debugbar */ public function disable() { $this->enabled = false; } /** * Adds a measure * * @param string $label * @param float $start * @param float $end * @param array|null $params * @param string|null $collector * @param string|null $group */ public function addMeasure($label, $start, $end, $params = [], $collector = null, $group = null) { if ($this->hasCollector('time')) { /** @var \DebugBar\DataCollector\TimeDataCollector */ $time = $this->getCollector('time'); $time->addMeasure($label, $start, $end, $params, $collector, $group); } } /** * Utility function to measure the execution of a Closure * * @param string $label * @param \Closure $closure * @param string|null $collector * @param string|null $group * @return mixed */ public function measure($label, \Closure $closure, $collector = null, $group = null) { if ($this->hasCollector('time')) { /** @var \DebugBar\DataCollector\TimeDataCollector */ $time = $this->getCollector('time'); $result = $time->measure($label, $closure, $collector, $group); } else { $result = $closure(); } return $result; } /** * Collect data in a CLI request * * @return array */ public function collectConsole() { if (!$this->isEnabled()) { return; } $this->data = [ '__meta' => [ 'id' => $this->getCurrentRequestId(), 'datetime' => date('Y-m-d H:i:s'), 'utime' => microtime(true), 'method' => 'CLI', 'uri' => isset($_SERVER['argv']) ? implode(' ', $_SERVER['argv']) : null, 'ip' => isset($_SERVER['SSH_CLIENT']) ? $_SERVER['SSH_CLIENT'] : null ] ]; foreach ($this->collectors as $name => $collector) { $this->data[$name] = $collector->collect(); } // Remove all invalid (non UTF-8) characters array_walk_recursive( $this->data, function (&$item) { if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) { $item = mb_convert_encoding($item, 'UTF-8', 'UTF-8'); } } ); if ($this->storage !== null) { $this->storage->save($this->getCurrentRequestId(), $this->data); } return $this->data; } /** * Magic calls for adding messages * * @param string $method * @param array $args * @return mixed|void */ public function __call($method, $args) { $messageLevels = ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug', 'log']; if (in_array($method, $messageLevels)) { foreach ($args as $arg) { $this->addMessage($arg, $method); } } } /** * Adds a message to the MessagesCollector * * A message can be anything from an object to a string * * @param mixed $message * @param string $label */ public function addMessage($message, $label = 'info') { if ($this->hasCollector('messages')) { /** @var \DebugBar\DataCollector\MessagesCollector $collector */ $collector = $this->getCollector('messages'); $collector->addMessage($message, $label); } } /** * Check the version of Laravel * * @param string $version * @param string $operator (default: '>=') * @return boolean */ protected function checkVersion($version, $operator = ">=") { return version_compare($this->version, $version, $operator); } protected function isLumen() { return $this->is_lumen; } /** * @param DebugBar $debugbar */ protected function selectStorage(DebugBar $debugbar) { /** @var \Illuminate\Config\Repository $config */ $config = $this->app['config']; if ($config->get('debugbar.storage.enabled')) { $driver = $config->get('debugbar.storage.driver', 'file'); switch ($driver) { case 'pdo': $connection = $config->get('debugbar.storage.connection'); $table = $this->app['db']->getTablePrefix() . 'phpdebugbar'; $pdo = $this->app['db']->connection($connection)->getPdo(); $storage = new PdoStorage($pdo, $table); break; case 'redis': $connection = $config->get('debugbar.storage.connection'); $client = $this->app['redis']->connection($connection); if (is_a($client, 'Illuminate\Redis\Connections\Connection', false)) { $client = $client->client(); } $storage = new RedisStorage($client); break; case 'custom': $class = $config->get('debugbar.storage.provider'); $storage = $this->app->make($class); break; case 'socket': $hostname = $config->get('debugbar.storage.hostname', '127.0.0.1'); $port = $config->get('debugbar.storage.port', 2304); $storage = new SocketStorage($hostname, $port); break; case 'file': default: $path = $config->get('debugbar.storage.path'); $storage = new FilesystemStorage($this->app['files'], $path); break; } $debugbar->setStorage($storage); } } protected function addClockworkHeaders(Response $response) { $prefix = $this->app['config']->get('debugbar.route_prefix'); $response->headers->set('X-Clockwork-Id', $this->getCurrentRequestId(), true); $response->headers->set('X-Clockwork-Version', 9, true); $response->headers->set('X-Clockwork-Path', $prefix . '/clockwork/', true); } /** * Add Server-Timing headers for the TimeData collector * * @see https://www.w3.org/TR/server-timing/ * @param Response $response */ protected function addServerTimingHeaders(Response $response) { if ($this->hasCollector('time')) { $collector = $this->getCollector('time'); $headers = []; foreach ($collector->collect()['measures'] as $m) { $headers[] = sprintf('app;desc="%s";dur=%F', str_replace(array("\n", "\r"), ' ', str_replace('"', "'", $m['label'])), $m['duration'] * 1000); } $response->headers->set('Server-Timing', $headers, false); } } /** * @return array */ private function getRemoteServerReplacements() { $localPath = $this->app['config']->get('debugbar.local_sites_path') ?: base_path(); $remotePaths = array_filter(explode(',', $this->app['config']->get('debugbar.remote_sites_path') ?: '')) ?: [base_path()]; return array_fill_keys($remotePaths, $localPath); } /** * @return \Monolog\Logger * @throws Exception */ private function getMonologLogger() { $logger = $this->app['log']->getLogger(); if (get_class($logger) !== 'Monolog\Logger') { throw new Exception('Logger is not a Monolog\Logger instance'); } return $logger; } } PKk]b 00-laravel-debugbar/src/LumenServiceProvider.phpnuW+Aapp->call( function () { $debugBar = $this->app->get(LaravelDebugbar::class); if ($debugBar->shouldCollect('time', true)) { $startTime = $this->app['request']->server('REQUEST_TIME_FLOAT'); if (!$debugBar->hasCollector('time')) { $debugBar->addCollector(new TimeDataCollector($startTime)); } if ($this->app['config']->get('debugbar.options.time.memory_usage')) { $debugBar['time']->showMemoryUsage(); } if ($startTime) { $debugBar->addMeasure('Booting', $startTime, microtime(true), [], 'time'); } } } ); } /** * Get the active router. * * @return Application */ protected function getRouter() { return $this->app->router; } /** * Get the config path * * @return string */ protected function getConfigPath() { return base_path('config/debugbar.php'); } /** * Register the Debugbar Middleware * * @param string $middleware */ protected function registerMiddleware($middleware) { $this->app->middleware([$middleware]); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['debugbar', 'command.debugbar.clear']; } } PKk]Cm3laravel-debugbar/src/Middleware/DebugbarEnabled.phpnuW+Adebugbar = $debugbar; } /** * Handle an incoming request. * * @param Request $request * @param Closure $next * @return mixed */ public function handle($request, Closure $next) { if (!$this->debugbar->isEnabled()) { abort(404); } return $next($request); } } PKk]-Y 2laravel-debugbar/src/Middleware/InjectDebugbar.phpnuW+Acontainer = $container; $this->debugbar = $debugbar; $this->except = config('debugbar.except') ?: []; } /** * Handle an incoming request. * * @param Request $request * @param Closure $next * @return mixed */ public function handle($request, Closure $next) { if (!$this->debugbar->isEnabled() || $this->inExceptArray($request)) { return $next($request); } $this->debugbar->boot(); try { /** @var \Illuminate\Http\Response $response */ $response = $next($request); } catch (Throwable $e) { $response = $this->handleException($request, $e); } // Modify the response to add the Debugbar $this->debugbar->modifyResponse($request, $response); return $response; } /** * Handle the given exception. * * (Copy from Illuminate\Routing\Pipeline by Taylor Otwell) * * @param $passable * @param Throwable $e * @return mixed * @throws Exception */ protected function handleException($passable, $e) { if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) { throw $e; } $handler = $this->container->make(ExceptionHandler::class); $handler->report($e); return $handler->render($passable, $e); } /** * Determine if the request has a URI that should be ignored. * * @param \Illuminate\Http\Request $request * @return bool */ protected function inExceptArray($request) { foreach ($this->except as $except) { if ($except !== '/') { $except = trim($except, '/'); } if ($request->is($except)) { return true; } } return false; } } PKk]03!!.laravel-debugbar/src/Resources/cache/widget.jsnuW+A(function ($) { var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-'); /** * Widget for the displaying cache events * * Options: * - data */ var LaravelCacheWidget = PhpDebugBar.Widgets.LaravelCacheWidget = PhpDebugBar.Widgets.TimelineWidget.extend({ tagName: 'ul', className: csscls('timeline cache'), onForgetClick: function (e, el) { e.stopPropagation(); $.ajax({ url: $(el).attr("data-url"), type: 'DELETE', success: function (result) { $(el).fadeOut(200); } }); }, render: function () { LaravelCacheWidget.__super__.render.apply(this); this.bindAttr('data', function (data) { if (data.measures) { var self = this; var lines = this.$el.find('.' + csscls('measure')); for (var i = 0; i < data.measures.length; i++) { var measure = data.measures[i]; var m = lines[i]; if (measure.params && !$.isEmptyObject(measure.params)) { if (measure.params.delete) { $(m).next().find('td.phpdebugbar-widgets-name:contains(delete)').closest('tr').remove(); } if (measure.params.delete && measure.params.key) { $('') .addClass(csscls('forget')) .text('forget') .attr('data-url', measure.params.delete) .one('click', function (e) { self.onForgetClick(e, this); }) .appendTo(m); } } } } }); } }); })(PhpDebugBar.$); PKk]˼tjtj3laravel-debugbar/src/Resources/laravel-debugbar.cssnuW+Adiv.phpdebugbar, div.phpdebugbar-openhandler { --debugbar-red-vivid: #eb4432; /*--debugbar-background: #fff;*/ --debugbar-background-alt: #f5f5f5; --debugbar-text: #222; /*--debugbar-text-muted: #888;*/ --debugbar-border: #bbb; --debugbar-header: #fff; --debugbar-header-text: #555; /*--debugbar-header-border: #ddd;*/ /*--debugbar-active: #ccc;*/ /*--debugbar-active-text: #666;*/ --debugbar-icons: var(--debugbar-header-text); --debugbar-badge: #fff; --debugbar-badge-text: var(--debugbar-red-vivid); --debugbar-badge-active: var(--debugbar-red-vivid); --debugbar-badge-active-text: #fff; --debugbar-link: #777; --debugbar-hover: #666; --debugbar-header-hover: #ebebeb; } /* Dark mode */ div.phpdebugbar[data-theme='dark'], div.phpdebugbar-openhandler[data-theme='dark'] { --debugbar-white: #FFFFFF; --debugbar-gray-100: #F7FAFC; --debugbar-gray-200: #EDF2F7; --debugbar-gray-300: #E2E8F0; --debugbar-gray-400: #CBD5E0; --debugbar-gray-500: #A0AEC0; --debugbar-gray-600: #718096; --debugbar-gray-700: #4A5568; --debugbar-gray-800: #252a37; --debugbar-gray-900: #18181b; --debugbar-red-vivid: #eb4432; --debugbar-background: var(--debugbar-gray-800); --debugbar-background-alt: var(--debugbar-gray-900); --debugbar-text: var(--debugbar-gray-100); --debugbar-text-muted: var(--debugbar-gray-600); --debugbar-border: var(--debugbar-gray-600); --debugbar-header:var(--debugbar-gray-900); --debugbar-header-text: var(--debugbar-gray-200); --debugbar-header-border: var(--debugbar-gray-800); --debugbar-header-hover: var(--debugbar-gray-700); --debugbar-active: var(--debugbar-gray-800); --debugbar-active-text: var(--debugbar-gray-100); --debugbar-icons: var(--debugbar-header-text); --debugbar-badge: var(--debugbar-white); --debugbar-badge-text: var(--debugbar-red-vivid); --debugbar-badge-active: var(--debugbar-red-vivid); --debugbar-badge-active-text: var(--debugbar-white); --debugbar-link: var(--debugbar-gray-300); --debugbar-hover: var(--debugbar-gray-100); --debugbar-hover-bg: var(--debugbar-gray-700); } div.phpdebugbar[data-theme='dark'] code.phpdebugbar-widgets-sql, div.phpdebugbar[data-theme='dark'] .phpdebugbar-widgets-name, div.phpdebugbar[data-theme='dark'] .phpdebugbar-widgets-key, div.phpdebugbar[data-theme='dark'] .phpdebugbar-widgets-success > pre.sf-dump > .sf-dump-note { color: #fdfd96; } /* Force Laravel Whoops exception handler to be displayed under the debug bar */ .Whoops.container { z-index: 5999999; } div.phpdebugbar { font-size: 13px; z-index: 6000000; } div.phpdebugbar-openhandler-overlay { z-index: 6000001; cursor: pointer; } div.phpdebugbar-openhandler { border: 1px solid var(--debugbar-border); border-top: 3px solid var(--debugbar-red-vivid); border-radius: 5px; overflow-y: scroll; z-index: 6000002; cursor: default; } div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions > form { margin: 15px 0px 5px; font-size: 13px; font-weight: bold; } div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions button, div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions select, div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions input { height: 24px; } div.phpdebugbar-resize-handle { display: block!important; height: 3px; margin-top: -3px; width: 100%; background: none; cursor: ns-resize; border-top: none; border-bottom: 0px; background-color: var(--debugbar-red-vivid); } .phpdebugbar.phpdebugbar-minimized div.phpdebugbar-resize-handle { cursor: default!important; } div.phpdebugbar-closed, div.phpdebugbar-minimized { border-top-color: var(--debugbar-border); } div.phpdebugbar .hljs { padding: 0; } div.phpdebugbar .phpdebugbar-widgets-messages .hljs > code { padding-bottom: 3px; } div.phpdebugbar code, div.phpdebugbar pre { color: var(--debugbar-text); } div.phpdebugbar-widgets-exceptions .phpdebugbar-widgets-filename { margin-top: 4px; } div.phpdebugbar-widgets-exceptions li.phpdebugbar-widgets-list-item pre.phpdebugbar-widgets-file[style="display: block;"] ~ div { display: block; } div.phpdebugbar pre.sf-dump { color: var(--debugbar-text); outline: none; padding-left: 0px; } div.phpdebugbar-body { border-top: 1px solid var(--debugbar-header-border); } div.phpdebugbar-header span.phpdebugbar-text, div.phpdebugbar-header > div > span > span, div.phpdebugbar-header > div > span > i{ display: inline-block; } a.phpdebugbar-restore-btn:after { background: url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2048%2048%22%20fill%3D%22none%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M47.973%2010.859a.74.74%200%200%201%20.027.196v10.303a.735.735%200%200%201-.104.377.763.763%200%200%201-.285.275l-8.902%204.979v9.868a.75.75%200%200%201-.387.652L19.74%2047.9c-.043.023-.09.038-.135.054-.018.006-.034.016-.053.021a.801.801%200%200%201-.396%200c-.021-.006-.04-.017-.061-.024-.043-.015-.087-.029-.128-.051L.39%2037.509a.763.763%200%200%201-.285-.276.736.736%200%200%201-.104-.376V5.947c0-.067.01-.133.027-.196.006-.022.02-.042.027-.063.015-.04.028-.08.05-.117.014-.024.035-.044.053-.067.022-.03.042-.06.068-.087.022-.021.051-.037.077-.056.028-.023.053-.047.085-.065L9.677.1a.793.793%200%200%201%20.774%200l9.29%205.196h.002c.03.019.057.042.085.064.025.019.053.036.075.056.027.027.047.058.07.088.016.023.038.043.052.067.022.038.035.077.05.117.008.021.021.04.027.063a.74.74%200%200%201%20.027.197v19.305l7.742-4.33v-9.869c0-.066.01-.132.027-.195.006-.023.019-.042.027-.064.015-.04.029-.08.05-.116.014-.025.036-.045.052-.067.023-.03.043-.061.07-.087.022-.022.05-.038.075-.057.03-.022.054-.047.085-.065l9.292-5.195a.792.792%200%200%201%20.773%200l9.29%205.195c.033.02.058.043.087.064.025.02.053.036.075.057.027.027.046.058.07.088.017.022.038.042.052.067.022.036.034.077.05.116.009.022.021.041.027.064ZM46.45%2020.923v-8.567l-3.25%201.818-4.492%202.512v8.567l7.743-4.33Zm-9.29%2015.5v-8.574l-4.417%202.45-12.616%206.995v8.654l17.033-9.526ZM1.55%207.247v29.174l17.03%209.525v-8.653l-8.897-4.89-.003-.003-.003-.002c-.03-.017-.056-.041-.084-.062-.024-.018-.052-.033-.073-.054l-.002-.003c-.025-.023-.042-.053-.064-.079-.02-.025-.042-.047-.058-.073v-.003c-.018-.028-.029-.062-.041-.094-.013-.028-.03-.054-.037-.084-.01-.036-.012-.075-.016-.111-.003-.028-.011-.056-.011-.085V11.58L4.8%209.064%201.549%207.248Zm8.516-5.628-7.74%204.328%207.738%204.328%207.74-4.33-7.74-4.326h.002Zm4.026%2027.01%204.49-2.51V7.247L15.33%209.066l-4.492%202.512V30.45l3.253-1.819ZM37.935%206.727l-7.74%204.328%207.74%204.328%207.738-4.329-7.738-4.327Zm-.775%209.959-4.49-2.512-3.252-1.818v8.567l4.49%202.511%203.252%201.82v-8.568ZM19.353%2035.993l11.352-6.295%205.674-3.146-7.733-4.325-8.904%204.98-8.116%204.538%207.727%204.248Z%22%20fill%3D%22%23FF2D20%22/%3E%3C/svg%3E) no-repeat 11px center / 20px 20px !important; } div.phpdebugbar-openhandler .phpdebugbar-openhandler-header { background: url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2048%2048%22%20fill%3D%22none%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M47.973%2010.859a.74.74%200%200%201%20.027.196v10.303a.735.735%200%200%201-.104.377.763.763%200%200%201-.285.275l-8.902%204.979v9.868a.75.75%200%200%201-.387.652L19.74%2047.9c-.043.023-.09.038-.135.054-.018.006-.034.016-.053.021a.801.801%200%200%201-.396%200c-.021-.006-.04-.017-.061-.024-.043-.015-.087-.029-.128-.051L.39%2037.509a.763.763%200%200%201-.285-.276.736.736%200%200%201-.104-.376V5.947c0-.067.01-.133.027-.196.006-.022.02-.042.027-.063.015-.04.028-.08.05-.117.014-.024.035-.044.053-.067.022-.03.042-.06.068-.087.022-.021.051-.037.077-.056.028-.023.053-.047.085-.065L9.677.1a.793.793%200%200%201%20.774%200l9.29%205.196h.002c.03.019.057.042.085.064.025.019.053.036.075.056.027.027.047.058.07.088.016.023.038.043.052.067.022.038.035.077.05.117.008.021.021.04.027.063a.74.74%200%200%201%20.027.197v19.305l7.742-4.33v-9.869c0-.066.01-.132.027-.195.006-.023.019-.042.027-.064.015-.04.029-.08.05-.116.014-.025.036-.045.052-.067.023-.03.043-.061.07-.087.022-.022.05-.038.075-.057.03-.022.054-.047.085-.065l9.292-5.195a.792.792%200%200%201%20.773%200l9.29%205.195c.033.02.058.043.087.064.025.02.053.036.075.057.027.027.046.058.07.088.017.022.038.042.052.067.022.036.034.077.05.116.009.022.021.041.027.064ZM46.45%2020.923v-8.567l-3.25%201.818-4.492%202.512v8.567l7.743-4.33Zm-9.29%2015.5v-8.574l-4.417%202.45-12.616%206.995v8.654l17.033-9.526ZM1.55%207.247v29.174l17.03%209.525v-8.653l-8.897-4.89-.003-.003-.003-.002c-.03-.017-.056-.041-.084-.062-.024-.018-.052-.033-.073-.054l-.002-.003c-.025-.023-.042-.053-.064-.079-.02-.025-.042-.047-.058-.073v-.003c-.018-.028-.029-.062-.041-.094-.013-.028-.03-.054-.037-.084-.01-.036-.012-.075-.016-.111-.003-.028-.011-.056-.011-.085V11.58L4.8%209.064%201.549%207.248Zm8.516-5.628-7.74%204.328%207.738%204.328%207.74-4.33-7.74-4.326h.002Zm4.026%2027.01%204.49-2.51V7.247L15.33%209.066l-4.492%202.512V30.45l3.253-1.819ZM37.935%206.727l-7.74%204.328%207.74%204.328%207.738-4.329-7.738-4.327Zm-.775%209.959-4.49-2.512-3.252-1.818v8.567l4.49%202.511%203.252%201.82v-8.568ZM19.353%2035.993l11.352-6.295%205.674-3.146-7.733-4.325-8.904%204.98-8.116%204.538%207.727%204.248Z%22%20fill%3D%22%23FF2D20%22/%3E%3C/svg%3E) no-repeat 11px center / 20px 20px !important; padding: 4px 4px 6px 38px; margin: 0px !important; } div.phpdebugbar-openhandler .phpdebugbar-openhandler-header a { display: flex; cursor: pointer; } div.phpdebugbar-header, div.phpdebugbar-openhandler-header { background-size: 21px auto; background-position: 9px center; } a.phpdebugbar-restore-btn { border-right-color: var(--debugbar-border) !important; height: 20px; width: 24px; background-position: center; background-size: 21px; } .phpdebugbar:not(.phpdebugbar-closed) a.phpdebugbar-restore-btn { border-right: none; } div.phpdebugbar-header .phpdebugbar-tab { border-left: 1px solid var(--debugbar-header-border); display: flex; align-items: center; justify-content: center; min-width: 16px; } a.phpdebugbar-tab.phpdebugbar-tab-history { display: flex; justify-content: center; align-items: center; } div.phpdebugbar-header .phpdebugbar-header-left { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } div.phpdebugbar .phpdebugbar-header select { margin: 0 4px; padding: 2px 3px 3px 3px; border-radius: 3px; width: auto; cursor: pointer; } dl.phpdebugbar-widgets-kvlist dt, dl.phpdebugbar-widgets-kvlist dd, table.phpdebugbar-widgets-tablevar td { min-height: 20px; line-height: 20px; padding: 4px 5px 5px; border-top: 0px; } dl.phpdebugbar-widgets-kvlist dd.phpdebugbar-widgets-value.phpdebugbar-widgets-pretty .phpdebugbar-widgets-code-block { padding: 0px 0px; background: transparent; } dl.phpdebugbar-widgets-kvlist dt, table.phpdebugbar-widgets-tablevar td:first-child { width: calc(25% - 10px); } dl.phpdebugbar-widgets-kvlist dd { margin-left: 25%; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-label, div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-collector { text-transform: uppercase; font-style: normal; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-collector { text-transform: none; } .phpdebugbar-widgets-toolbar i.phpdebugbar-fa.phpdebugbar-fa-search { position: relative; top: -1px; padding: 0px 10px; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter, div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded { display: inline-block; background-color: #6d6d6d; margin-left: 3px; border-radius: 3px; text-transform: uppercase; font-size: 10px; transition: background-color .25s linear 0s, color .25s linear 0s; color: #FFF; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="alert"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="alert"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="info"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="info"] { background-color: #5896e2; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="debug"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="debug"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="success"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="success"] { background-color: #45ab45; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="critical"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="critical"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="error"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="error"] { background-color: var(--debugbar-red-vivid); } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="notice"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="notice"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter[rel="warning"], div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded[rel="warning"] { background-color: #f99400; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter:hover { color: #FFF; opacity: 0.85; } div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter.phpdebugbar-widgets-excluded { opacity: 0.45; } a.phpdebugbar-tab.phpdebugbar-active { background: var(--debugbar-red-vivid); background-image: none; color: #fff !important; } a.phpdebugbar-tab.phpdebugbar-active span.phpdebugbar-badge { background-color: var(--debugbar-badge); color: var(--debugbar-badge-text); } a.phpdebugbar-tab span.phpdebugbar-badge { vertical-align: 0px; padding: 2px 8px; text-align: center; background: var(--debugbar-red-vivid); font-size: 11px; font-family: var(--font-mono); color: var(--debugbar-badge-active-text); border-radius: 10px; position: relative; } .phpdebugbar-indicator { cursor: text; } div.phpdebugbar-mini-design a.phpdebugbar-tab:hover span.phpdebugbar-text { left: 0px; right: auto; } .phpdebugbar-widgets-toolbar > .fa { width: 25px; font-size: 15px; text-align: center; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item { padding: 7px 10px; border: none; font-family: inherit; overflow: visible; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-sql { line-height: 20px; } .phpdebugbar-widgets-templates ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item { display: block; } .phpdebugbar-widgets-templates ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item, .phpdebugbar-widgets-mails ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item { line-height: 15px; } .phpdebugbar-widgets-mails ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item { cursor: pointer; display: block; } .phpdebugbar-widgets-mails ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-subject { display: inline-block; margin-right: 15px; } .phpdebugbar-widgets-mails ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-headers { margin: 10px 0px; padding: 7px 10px; border-left: 2px solid var(--debugbar-header); line-height: 17px; } .phpdebugbar-widgets-sql.phpdebugbar-widgets-name { font-weight: bold; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-sql { flex: 1; margin-right: 5px; max-width: 100%; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-copy-clipboard, ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-duration, ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-stmt-id, ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-memory { margin-left: auto; margin-right: 5px; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-database { margin-left: auto; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-stmt-id a { color: #888; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-stmt-id a:hover { color: #aaa; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item table.phpdebugbar-widgets-params { margin: 10px 0px; font-size: 12px; border-left: 2px solid var(--debugbar-border); } div.phpdebugbar-widgets-templates table.phpdebugbar-widgets-params th, div.phpdebugbar-widgets-templates table.phpdebugbar-widgets-params td { padding: 1px 10px!important; } div.phpdebugbar-widgets-templates table.phpdebugbar-widgets-params th { padding: 2px 10px!important; background-color: var(--debugbar-background); } div.phpdebugbar-widgets-templates ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(odd) table.phpdebugbar-widgets-params th { background-color: var(--debugbar-background-alt); } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-name { width: auto; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-name .phpdebugbar-fa { position: relative; top: 1px; margin-left: 3px; } ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(even), table.phpdebugbar-widgets-tablevar tr:nth-child(even) { background-color: var(--debugbar-background-alt); } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value { display: inline-flex; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value:before { font-family: PhpDebugbarFontAwesome; content: "\f005"; color: #333; font-size: 15px !important; margin-right: 8px; float: left; } table.phpdebugbar-widgets-tablevar td { border: 0; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-info { color: #1299DA; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-info:before { content: "\f05a"; color: #5896e2; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-success:before { content: "\f058"; color: #45ab45; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error { color: #e74c3c; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error:before { color: var(--debugbar-red-vivid); } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-warning:before, div.phpdebugbar-widgets-messages .phpdebugbar-widgets-value.phpdebugbar-widgets-warning { color: #FF9800; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-deprecation:before { content: "\f1f6"; color: #FF9800; } div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item pre.sf-dump { display: inline-block !important; position: relative; top: -1px; } div.phpdebugbar-panel div.phpdebugbar-widgets-status { padding: 9px 10px !important; width: calc(100% - 20px); margin-top: 0px !important; line-height: 11px!important; font-weight: bold!important; background: var(--debugbar-background-alt) !important; border-bottom: 1px solid var(--debugbar-border) !important; } div.phpdebugbar-panel div.phpdebugbar-widgets-status > * { color: var(--debugbar-header-text)!important; } div.phpdebugbar-panel div.phpdebugbar-widgets-status > span:first-child:before { font-family: PhpDebugbarFontAwesome; content: "\f05a"; color: var(--debugbar-icons); font-size: 14px; position: relative; top: 1px; margin-right: 8px; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params th, div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td { padding: 4px 10px; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params th { background-color: var(--debugbar-background-alt); } div.phpdebugbar-widgets-sqlqueries ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(even) table.phpdebugbar-widgets-params th { background-color: var(--debugbar-background); } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-name { text-align: right; vertical-align: top; white-space: nowrap; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-value { text-align: left; } div.phpdebugbar-widgets-templates .phpdebugbar-widgets-list-item table.phpdebugbar-widgets-params { width: auto!important; } ul.phpdebugbar-widgets-list ul.phpdebugbar-widgets-table-list { text-align: left; line-height: 150%; } ul.phpdebugbar-widgets-cache a.phpdebugbar-widgets-forget { float: right; font-size: 12px; padding: 0 4px; background: var(--debugbar-red-vivid); margin: 0 2px; border-radius: 4px; color: #fff; text-decoration: none; line-height: 1.25rem; } div.phpdebugbar-mini-design div.phpdebugbar-header-left a.phpdebugbar-tab { border-right: none; } div.phpdebugbar-header-right { display:flex; flex-direction: row-reverse; align-items: center; flex-wrap: wrap; } div.phpdebugbar-header-right > * { border-right: 1px solid var(--debugbar-header); } div.phpdebugbar-header-right > *:first-child { border-right: 0; } div.phpdebugbar-header-right a.phpdebugbar-tab.phpdebugbar-tab-settings { border-left: 0; } div.phpdebugbar-panel[data-collector="__datasets"] { padding: 0 10px; } div.phpdebugbar-panel table { margin: 10px 0px!important; width: 100%!important; } div.phpdebugbar-panel table .phpdebugbar-widgets-name { font-size: 13px; } dl.phpdebugbar-widgets-kvlist > :nth-child(4n-1), dl.phpdebugbar-widgets-kvlist > :nth-child(4n) { background-color: var(--debugbar-background-alt); } .phpdebugbar pre.sf-dump:after { clear: none!important; } div.phpdebugbar-widgets-exceptions li.phpdebugbar-widgets-list-item > div { display: none; } div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-database:before, div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-duration:before, div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-memory:before, div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-row-count:before, div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-copy-clipboard:before, div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-stmt-id:before, div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-param-count:before { margin-right: 6px!important; } div.phpdebugbar dl.phpdebugbar-widgets-kvlist > :nth-child(4n)::before { background-color: var(--background-color-alt); } dt.phpdebugbar-widgets-key { padding-left: 10px !important; } dt.phpdebugbar-widgets-key { position: relative; /*background: white;*/ z-index: 1; } dd.phpdebugbar-widgets-value { position: relative; } dd.phpdebugbar-widgets-value::before { content: " "; position: absolute; height: 100%; left: 0; top: 0; width: 33.33%; margin-left: -33.33%; } dd.phpdebugbar-widgets-value pre.sf-dump { padding-top: 0; padding-bottom: 0; } ul.phpdebugbar-widgets-table-list { padding: 4px 0; } ul.phpdebugbar-widgets-table-list li { margin-bottom: 4px; } ul.phpdebugbar-widgets-table-list li:last-child { margin-bottom: 0; } div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-copy-clipboard { margin-left: 8px !important; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-name { width: 150px; } div.phpdebugbar-widgets-sqlqueries a.phpdebugbar-widgets-connection { font-size: 12px; padding: 2px 4px; background: #737373; margin-left: 6px; border-radius: 4px; color: #fff !important; } div.phpdebugbar-widgets-sqlqueries button.phpdebugbar-widgets-explain-btn { cursor: pointer; background: #383838; color: #fff; font-size: 13px; padding: 0 8px; border-radius: 4px; line-height: 1.25rem; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-explain { margin: 0 !important; } div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-explain th { border: 1px solid var(--debugbar-border); text-align: center; } div.phpdebugbar-widgets-sqlqueries a.phpdebugbar-widgets-visual-explain { display: inline-block; font-weight: bold; text-decoration: underline; margin-top: 6px; } div.phpdebugbar-widgets-sqlqueries a.phpdebugbar-widgets-visual-link { margin-left: 6px; } div.phpdebugbar-widgets-sqlqueries a.phpdebugbar-widgets-visual-explain:after { content: "\f08e"; font-family: PhpDebugbarFontAwesome; margin-left: 4px; font-size: 12px; } div.phpdebugbar-widgets-sqlqueries li.phpdebugbar-widgets-list-item.phpdebugbar-widgets-expandable { cursor: pointer; } div.phpdebugbar-widgets-sqlqueries li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-params { cursor: default; } PKk]g7FF0laravel-debugbar/src/Resources/queries/widget.jsnuW+A(function($) { let css = PhpDebugBar.utils.makecsscls('phpdebugbar-'); let csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-'); /** * Widget for displaying sql queries. * * Options: * - data */ const QueriesWidget = PhpDebugBar.Widgets.LaravelQueriesWidget = PhpDebugBar.Widget.extend({ className: csscls('sqlqueries'), duplicateQueries: new Set(), hiddenConnections: new Set(), copyToClipboard: function (code) { if (document.selection) { const range = document.body.createTextRange(); range.moveToElementText(code); range.select(); } else if (window.getSelection) { const range = document.createRange(); range.selectNodeContents(code); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } var isCopied = false; try { isCopied = document.execCommand('copy'); console.log('Query copied to the clipboard'); } catch (err) { alert('Oops, unable to copy'); } window.getSelection().removeAllRanges(); return isCopied; }, explainMysql: function ($element, statement, rows, visual) { const headings = []; for (const key in rows[0]) { headings.push($('').text(key)); } const values = []; for (const row of rows) { const $tr = $(''); for (const key in row) { $tr.append($('').text(row[key])); } values.push($tr); } const $table = $('
').addClass(csscls('explain')); $table.find('thead').append($('').append(headings)); $table.find('tbody').append(values); $element.append($table); if (visual) { $element.append(this.explainVisual(statement, visual.confirm)); } }, explainPgsql: function ($element, statement, rows, visual) { const $ul = $('