├── .gitignore ├── src ├── Facade.php ├── Resources │ ├── vendor │ │ └── font-awesome │ │ │ └── generator_config.txt │ ├── sqlqueries │ │ └── widget.js │ └── laravel-debugbar.css ├── Controllers │ ├── BaseController.php │ ├── AssetController.php │ └── OpenHandlerController.php ├── Console │ ├── PublishCommand.php │ └── ClearCommand.php ├── DataCollector │ ├── GateCollector.php │ ├── SessionCollector.php │ ├── LaravelCollector.php │ ├── ViewCollector.php │ ├── MultiAuthCollector.php │ ├── AuthCollector.php │ ├── EventCollector.php │ ├── IlluminateRouteCollector.php │ ├── LogsCollector.php │ ├── FilesCollector.php │ ├── SymfonyRequestCollector.php │ └── QueryCollector.php ├── LumenServiceProvider.php ├── migrations │ └── 2014_12_01_120000_create_phpdebugbar_storage_table.php ├── Twig │ ├── Node │ │ └── StopwatchNode.php │ ├── Extension │ │ ├── Stopwatch.php │ │ ├── Dump.php │ │ └── Debug.php │ └── TokenParser │ │ └── StopwatchTokenParser.php ├── DataFormatter │ └── QueryFormatter.php ├── helpers.php ├── SymfonyHttpDriver.php ├── Middleware │ └── Debugbar.php ├── Support │ └── Clockwork │ │ ├── ClockworkCollector.php │ │ └── Converter.php ├── JavascriptRenderer.php ├── Storage │ └── FilesystemStorage.php ├── ServiceProvider.php └── LaravelDebugbar.php ├── LICENSE ├── composer.json ├── changelog.md ├── readme.md └── config └── debugbar.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store -------------------------------------------------------------------------------- /src/Facade.php: -------------------------------------------------------------------------------- 1 | debugbar = $debugbar; 16 | 17 | if ($request->hasSession()){ 18 | $request->session()->reflash(); 19 | } 20 | } 21 | } 22 | 23 | } else { 24 | 25 | class BaseController 26 | { 27 | protected $debugbar; 28 | 29 | public function __construct(Request $request, LaravelDebugbar $debugbar) 30 | { 31 | $this->debugbar = $debugbar; 32 | 33 | if ($request->hasSession()){ 34 | $request->session()->reflash(); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Console/PublishCommand.php: -------------------------------------------------------------------------------- 1 | 10 | * @deprecated No longer needed because of the AssetController 11 | */ 12 | class PublishCommand extends Command 13 | { 14 | /** 15 | * The console command name. 16 | * 17 | * @var string 18 | */ 19 | protected $name = 'debugbar:publish'; 20 | 21 | /** 22 | * The console command description. 23 | * 24 | * @var string 25 | */ 26 | protected $description = 'Publish the Debugbar assets'; 27 | 28 | /** 29 | * Execute the console command. 30 | * 31 | * @return void 32 | */ 33 | public function fire() 34 | { 35 | $this->info( 36 | 'NOTICE: Since laravel-debugbar 1.7.x, publishing assets is no longer necessary. The assets in public/packages/barryvdh/laravel-debugbar and maximebf/php-debugbar can be safely removed.' 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-2014 Barry vd. Heuvel 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "barryvdh/laravel-debugbar", 3 | "description": "PHP Debugbar integration for Laravel", 4 | "keywords": ["laravel", "debugbar", "profiler", "debug", "webprofiler"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Barry vd. Heuvel", 9 | "email": "barryvdh@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.5.9", 14 | "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*", 15 | "symfony/finder": "~2.7|~3.0", 16 | "maximebf/debugbar": "~1.13.0" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Barryvdh\\Debugbar\\": "src/" 21 | }, 22 | "files": [ 23 | "src/helpers.php" 24 | ] 25 | }, 26 | "extra": { 27 | "branch-alias": { 28 | "dev-master": "2.4-dev" 29 | }, 30 | "laravel": { 31 | "providers": [ 32 | "Barryvdh\\Debugbar\\ServiceProvider" 33 | ], 34 | "aliases": { 35 | "Debugbar": "Barryvdh\\Debugbar\\Facade" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Console/ClearCommand.php: -------------------------------------------------------------------------------- 1 | debugbar = $debugbar; 15 | 16 | parent::__construct(); 17 | } 18 | 19 | public function fire() 20 | { 21 | $this->debugbar->boot(); 22 | 23 | if ($storage = $this->debugbar->getStorage()) { 24 | try 25 | { 26 | $storage->clear(); 27 | } catch(\InvalidArgumentException $e) { 28 | // hide InvalidArgumentException if storage location does not exist 29 | if(strpos($e->getMessage(), 'does not exist') === false) { 30 | throw $e; 31 | } 32 | } 33 | $this->info('Debugbar Storage cleared!'); 34 | } else { 35 | $this->error('No Debugbar Storage found..'); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DataCollector/GateCollector.php: -------------------------------------------------------------------------------- 1 | exporter = new ValueExporter(); 24 | 25 | if (method_exists($gate, 'after')) { 26 | $gate->after([$this, 'addCheck']); 27 | } 28 | } 29 | 30 | public function addCheck(Authenticatable $user, $ability, $result, $arguments = []) 31 | { 32 | $label = $result ? 'success' : 'error'; 33 | 34 | $this->addMessage([ 35 | 'ability' => $ability, 36 | 'result' => $result, 37 | 'user' => $user->getAuthIdentifier(), 38 | 'arguments' => $this->exporter->exportValue($arguments), 39 | ], $label, false); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/LumenServiceProvider.php: -------------------------------------------------------------------------------- 1 | app; 18 | } 19 | 20 | /** 21 | * Get the config path 22 | * 23 | * @return string 24 | */ 25 | protected function getConfigPath() 26 | { 27 | return base_path('config/debugbar.php'); 28 | } 29 | 30 | /** 31 | * Register the Debugbar Middleware 32 | * 33 | * @param string $middleware 34 | */ 35 | protected function registerMiddleware($middleware) 36 | { 37 | $this->app->middleware([$middleware]); 38 | } 39 | 40 | /** 41 | * Check the App Debug status 42 | */ 43 | protected function checkAppDebug() 44 | { 45 | return env('APP_DEBUG'); 46 | } 47 | 48 | /** 49 | * Get the services provided by the provider. 50 | * 51 | * @return array 52 | */ 53 | public function provides() 54 | { 55 | return ['debugbar', 'command.debugbar.clear']; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/migrations/2014_12_01_120000_create_phpdebugbar_storage_table.php: -------------------------------------------------------------------------------- 1 | string('id'); 17 | $table->longText('data'); 18 | $table->string('meta_utime'); 19 | $table->dateTime('meta_datetime'); 20 | $table->string('meta_uri'); 21 | $table->string('meta_ip'); 22 | $table->string('meta_method'); 23 | 24 | $table->primary('id'); 25 | $table->index('meta_utime'); 26 | $table->index('meta_datetime'); 27 | $table->index('meta_uri'); 28 | $table->index('meta_ip'); 29 | $table->index('meta_method'); 30 | }); 31 | } 32 | /** 33 | * Reverse the migrations. 34 | * 35 | * @return void 36 | */ 37 | public function down() 38 | { 39 | Schema::drop('phpdebugbar'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Twig/Node/StopwatchNode.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class StopwatchNode extends \Twig_Node 9 | { 10 | public function __construct( 11 | \Twig_NodeInterface $name, 12 | $body, 13 | \Twig_Node_Expression_AssignName $var, 14 | $lineno = 0, 15 | $tag = null 16 | ) { 17 | parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno, $tag); 18 | } 19 | 20 | public function compile(\Twig_Compiler $compiler) 21 | { 22 | $compiler 23 | ->addDebugInfo($this) 24 | ->write('') 25 | ->subcompile($this->getNode('var')) 26 | ->raw(' = ') 27 | ->subcompile($this->getNode('name')) 28 | ->write(";\n") 29 | ->write("\$this->env->getExtension('stopwatch')->getDebugbar()->startMeasure(") 30 | ->subcompile($this->getNode('var')) 31 | ->raw(");\n") 32 | ->subcompile($this->getNode('body')) 33 | ->write("\$this->env->getExtension('stopwatch')->getDebugbar()->stopMeasure(") 34 | ->subcompile($this->getNode('var')) 35 | ->raw(");\n"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Twig/Extension/Stopwatch.php: -------------------------------------------------------------------------------- 1 | bound('debugbar')) { 26 | $this->debugbar = $app['debugbar']; 27 | } else { 28 | $this->debugbar = null; 29 | } 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function getName() 36 | { 37 | return 'stopwatch'; 38 | } 39 | 40 | public function getTokenParsers() 41 | { 42 | return [ 43 | /* 44 | * {% stopwatch foo %} 45 | * Some stuff which will be recorded on the timeline 46 | * {% endstopwatch %} 47 | */ 48 | new StopwatchTokenParser($this->debugbar !== null), 49 | ]; 50 | } 51 | 52 | public function getDebugbar() 53 | { 54 | return $this->debugbar; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Controllers/AssetController.php: -------------------------------------------------------------------------------- 1 | debugbar->getJavascriptRenderer(); 15 | 16 | $content = $renderer->dumpAssetsToString('js'); 17 | 18 | $response = new Response( 19 | $content, 200, [ 20 | 'Content-Type' => 'text/javascript', 21 | ] 22 | ); 23 | 24 | return $this->cacheResponse($response); 25 | } 26 | 27 | /** 28 | * Return the stylesheets for the Debugbar 29 | * 30 | * @return \Symfony\Component\HttpFoundation\Response 31 | */ 32 | public function css() 33 | { 34 | $renderer = $this->debugbar->getJavascriptRenderer(); 35 | 36 | $content = $renderer->dumpAssetsToString('css'); 37 | 38 | $response = new Response( 39 | $content, 200, [ 40 | 'Content-Type' => 'text/css', 41 | ] 42 | ); 43 | 44 | return $this->cacheResponse($response); 45 | } 46 | 47 | /** 48 | * Cache the response 1 year (31536000 sec) 49 | */ 50 | protected function cacheResponse(Response $response) 51 | { 52 | $response->setSharedMaxAge(31536000); 53 | $response->setMaxAge(31536000); 54 | $response->setExpires(new \DateTime('+1 year')); 55 | 56 | return $response; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Controllers/OpenHandlerController.php: -------------------------------------------------------------------------------- 1 | debugbar; 13 | 14 | if (!$debugbar->isEnabled()) { 15 | $this->app->abort('500', 'Debugbar is not enabled'); 16 | } 17 | 18 | $openHandler = new OpenHandler($debugbar); 19 | 20 | $data = $openHandler->handle(null, false, false); 21 | 22 | return new Response( 23 | $data, 200, [ 24 | 'Content-Type' => 'application/json' 25 | ] 26 | ); 27 | } 28 | 29 | /** 30 | * Return Clockwork output 31 | * 32 | * @param $id 33 | * @return mixed 34 | * @throws \DebugBar\DebugBarException 35 | */ 36 | public function clockwork($id) 37 | { 38 | $request = [ 39 | 'op' => 'get', 40 | 'id' => $id, 41 | ]; 42 | 43 | $debugbar = $this->debugbar; 44 | 45 | if (!$debugbar->isEnabled()) { 46 | $this->app->abort('500', 'Debugbar is not enabled'); 47 | } 48 | 49 | $openHandler = new OpenHandler($debugbar); 50 | 51 | $data = $openHandler->handle($request, false, false); 52 | 53 | // Convert to Clockwork 54 | $converter = new Converter(); 55 | $output = $converter->convert(json_decode($data, true)); 56 | 57 | return response()->json($output); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/DataCollector/SessionCollector.php: -------------------------------------------------------------------------------- 1 | session = $session; 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function collect() 28 | { 29 | $data = []; 30 | foreach ($this->session->all() as $key => $value) { 31 | $data[$key] = is_string($value) ? $value : $this->formatVar($value); 32 | } 33 | return $data; 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | public function getName() 40 | { 41 | return 'session'; 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | public function getWidgets() 48 | { 49 | return [ 50 | "session" => [ 51 | "icon" => "archive", 52 | "widget" => "PhpDebugBar.Widgets.VariableListWidget", 53 | "map" => "session", 54 | "default" => "{}" 55 | ] 56 | ]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Twig/TokenParser/StopwatchTokenParser.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class StopwatchTokenParser extends \Twig_TokenParser 11 | { 12 | protected $debugbarAvailable; 13 | 14 | public function __construct($debugbarAvailable) 15 | { 16 | $this->debugbarAvailable = $debugbarAvailable; 17 | } 18 | 19 | public function parse(\Twig_Token $token) 20 | { 21 | $lineno = $token->getLine(); 22 | $stream = $this->parser->getStream(); 23 | 24 | // {% stopwatch 'bar' %} 25 | $name = $this->parser->getExpressionParser()->parseExpression(); 26 | 27 | $stream->expect(\Twig_Token::BLOCK_END_TYPE); 28 | 29 | // {% endstopwatch %} 30 | $body = $this->parser->subparse([$this, 'decideStopwatchEnd'], true); 31 | $stream->expect(\Twig_Token::BLOCK_END_TYPE); 32 | 33 | if ($this->debugbarAvailable) { 34 | return new StopwatchNode( 35 | $name, 36 | $body, 37 | new \Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), 38 | $lineno, 39 | $this->getTag() 40 | ); 41 | } 42 | 43 | return $body; 44 | } 45 | 46 | public function getTag() 47 | { 48 | return 'stopwatch'; 49 | } 50 | 51 | public function decideStopwatchEnd(\Twig_Token $token) 52 | { 53 | return $token->test('endstopwatch'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/DataCollector/LaravelCollector.php: -------------------------------------------------------------------------------- 1 | app = $app; 20 | } 21 | 22 | /** 23 | * {@inheritDoc} 24 | */ 25 | public function collect() 26 | { 27 | // Fallback if not injected 28 | $app = $this->app ?: app(); 29 | 30 | return [ 31 | "version" => $app::VERSION, 32 | "environment" => $app->environment(), 33 | "locale" => $app->getLocale(), 34 | ]; 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | public function getName() 41 | { 42 | return 'laravel'; 43 | } 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | public function getWidgets() 49 | { 50 | return [ 51 | "version" => [ 52 | "icon" => "github", 53 | "tooltip" => "Version", 54 | "map" => "laravel.version", 55 | "default" => "" 56 | ], 57 | "environment" => [ 58 | "icon" => "desktop", 59 | "tooltip" => "Environment", 60 | "map" => "laravel.environment", 61 | "default" => "" 62 | ], 63 | "locale" => [ 64 | "icon" => "flag", 65 | "tooltip" => "Current locale", 66 | "map" => "laravel.locale", 67 | "default" => "", 68 | ], 69 | ]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/DataFormatter/QueryFormatter.php: -------------------------------------------------------------------------------- 1 | namespace) { 68 | $parts['namespace'] = $source->namespace . '::'; 69 | } 70 | 71 | $parts['name'] = $source->name; 72 | $parts['line'] = ':' . $source->line; 73 | 74 | return implode($parts); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/helpers.php: -------------------------------------------------------------------------------- 1 | addMessage($value, 'debug'); 27 | } 28 | } 29 | } 30 | 31 | if (!function_exists('start_measure')) { 32 | /** 33 | * Starts a measure 34 | * 35 | * @param string $name Internal name, used to stop the measure 36 | * @param string $label Public name 37 | */ 38 | function start_measure($name, $label = null) 39 | { 40 | app('debugbar')->startMeasure($name, $label); 41 | } 42 | } 43 | 44 | if (!function_exists('stop_measure')) { 45 | /** 46 | * Stop a measure 47 | * 48 | * @param string $name Internal name, used to stop the measure 49 | */ 50 | function stop_measure($name) 51 | { 52 | app('debugbar')->stopMeasure($name); 53 | } 54 | } 55 | 56 | if (!function_exists('add_measure')) { 57 | /** 58 | * Adds a measure 59 | * 60 | * @param string $label 61 | * @param float $start 62 | * @param float $end 63 | */ 64 | function add_measure($label, $start, $end) 65 | { 66 | app('debugbar')->addMeasure($label, $start, $end); 67 | } 68 | } 69 | 70 | if (!function_exists('measure')) { 71 | /** 72 | * Utility function to measure the execution of a Closure 73 | * 74 | * @param string $label 75 | * @param \Closure $closure 76 | */ 77 | function measure($label, \Closure $closure) 78 | { 79 | app('debugbar')->measure($label, $closure); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog for Laravel Debugbar 2 | 3 | ## 1.8.4 (2014-10-31) 4 | 5 | - Add Redis/PDO storage options 6 | 7 | ## 1.8.3 (2014-11-23) 8 | 9 | - Base EventCollector on TimeData Collector 10 | 11 | ## 1.8.2 (2014-11-18) 12 | 13 | - Use XHR handler instead of jQuery handler 14 | 15 | ## 1.8.1 (2014-11-14) 16 | 17 | - Fix compatability with Symfony 2.3 (Laravel 4.) 18 | 19 | ## 1.8.0 (2014-10-31) 20 | 21 | - Fix L5 compatability 22 | - add hints + explain options to QueryLogger 23 | - update to Debugbar 1.10.x 24 | - new ViewCollector layout with more information 25 | 26 | ## 1.7.7 (2014-09-15) 27 | 28 | - Make it compatible with Laravel 5.0-dev 29 | - Allow anonymous function as `enabled` setting (for IP checks etc) 30 | - Escape query bindings, to prevent executing of scripts/html 31 | 32 | ## 1.7.6 (2014-09-12) 33 | 34 | - Fix reflash bug 35 | - Fix caching of debugbar assets 36 | 37 | ## 1.7.5 (2014-09-12) 38 | 39 | - Reflash data for all debugbar requests 40 | 41 | ## 1.7.4 (2014-09-08) 42 | 43 | - Rename assets routes to prevent Nginx conflicts 44 | 45 | ## 1.7.3 (2014-09-05) 46 | 47 | - Add helper functions (debug(), add/start/stop_measure() and measure() 48 | - Collect data on responses that are not redirect/ajax/html also. 49 | 50 | ## 1.7.2 (2014-09-04) 51 | 52 | - Fix 4.0 compatibility (problem with Controller namespace) 53 | - Give deprecation notice instead of publishing assets. 54 | 55 | ## 1.7.1 (2014-09-03) 56 | 57 | - Deprecated `debugbar:publish` command in favor of AssetController 58 | - Fixed issue with detecting absolute paths in Windows 59 | 60 | ## 1.7.0 (2014-09-03) 61 | 62 | - Use AssetController instead of publishing assets to the public folder. 63 | - Inline fonts + images to base64 Data-URI 64 | - Use PSR-4 file structure 65 | 66 | ## 1.6.8 (2014-08-27) 67 | 68 | - Change OpenHandler layout 69 | - Add backtrace option for query origin 70 | 71 | ## 1.6.7 (2014-08-09) 72 | 73 | - Add Twig extensions for better integration with rcrowe/TwigBridge 74 | 75 | ## 1.6.6 (2014-07-08) 76 | 77 | - Check if Requests wantsJSON instead of only isXmlHttpRequest 78 | - Make sure closure for timing is run, even when disabled 79 | 80 | ## 1.6.5 (2014-06-24) 81 | 82 | - Add Laravel style 83 | 84 | ## 1.6.4 (2014-06-15) 85 | 86 | - Work on non-UTF-8 handling -------------------------------------------------------------------------------- /src/Twig/Extension/Dump.php: -------------------------------------------------------------------------------- 1 | formatter = $formatter; 26 | } 27 | 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | public function getName() 32 | { 33 | return 'Laravel_Debugbar_Dump'; 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | public function getFunctions() 40 | { 41 | return [ 42 | new Twig_SimpleFunction( 43 | 'dump', [$this, 'dump'], ['is_safe' => ['html'], 'needs_context' => true, 'needs_environment' => true] 44 | ), 45 | ]; 46 | } 47 | 48 | /** 49 | * Based on Twig_Extension_Debug / twig_var_dump 50 | * (c) 2011 Fabien Potencier 51 | * 52 | * @param Twig_Environment $env 53 | * @param $context 54 | * 55 | * @return string 56 | */ 57 | public function dump(Twig_Environment $env, $context) 58 | { 59 | $output = ''; 60 | 61 | $count = func_num_args(); 62 | if (2 === $count) { 63 | $data = []; 64 | foreach ($context as $key => $value) { 65 | if (is_object($value)) { 66 | if (method_exists($value, 'toArray')) { 67 | $data[$key] = $value->toArray(); 68 | } else { 69 | $data[$key] = "Object (" . get_class($value) . ")"; 70 | } 71 | } else { 72 | $data[$key] = $value; 73 | } 74 | } 75 | $output .= $this->formatter->formatVar($data); 76 | } else { 77 | for ($i = 2; $i < $count; $i++) { 78 | $output .= $this->formatter->formatVar(func_get_arg($i)); 79 | } 80 | } 81 | 82 | return '
'.$output.''; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/SymfonyHttpDriver.php: -------------------------------------------------------------------------------- 1 | session = $session; 22 | $this->response = $response; 23 | } 24 | 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | public function setHeaders(array $headers) 29 | { 30 | if (!is_null($this->response)) { 31 | $this->response->headers->add($headers); 32 | } 33 | } 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | public function isSessionStarted() 39 | { 40 | if (!$this->session->isStarted()) { 41 | $this->session->start(); 42 | } 43 | return $this->session->isStarted(); 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | public function setSessionValue($name, $value) 50 | { 51 | // In Laravel 5.4 the session changed to use their own custom implementation 52 | // instead of the one from Symfony. One of the changes was the set method 53 | // that was changed to put. Here we check if we are using the new one. 54 | if (method_exists($this->session, 'driver') && $this->session->driver() instanceof \Illuminate\Contracts\Session\Session) { 55 | $this->session->put($name, $value); 56 | return; 57 | } 58 | $this->session->set($name, $value); 59 | } 60 | 61 | /** 62 | * {@inheritDoc} 63 | */ 64 | public function hasSessionValue($name) 65 | { 66 | return $this->session->has($name); 67 | } 68 | 69 | /** 70 | * {@inheritDoc} 71 | */ 72 | public function getSessionValue($name) 73 | { 74 | return $this->session->get($name); 75 | } 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | public function deleteSessionValue($name) 81 | { 82 | $this->session->remove($name); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Twig/Extension/Debug.php: -------------------------------------------------------------------------------- 1 | bound('debugbar')) { 26 | $this->debugbar = $app['debugbar']; 27 | } else { 28 | $this->debugbar = null; 29 | } 30 | } 31 | 32 | /** 33 | * {@inheritDoc} 34 | */ 35 | public function getName() 36 | { 37 | return 'Laravel_Debugbar_Debug'; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public function getFunctions() 44 | { 45 | return [ 46 | new Twig_SimpleFunction( 47 | 'debug', [$this, 'debug'], ['needs_context' => true, 'needs_environment' => true] 48 | ), 49 | ]; 50 | } 51 | 52 | /** 53 | * Based on Twig_Extension_Debug / twig_var_dump 54 | * (c) 2011 Fabien Potencier 55 | * 56 | * @param Twig_Environment $env 57 | * @param $context 58 | */ 59 | public function debug(Twig_Environment $env, $context) 60 | { 61 | if (!$env->isDebug() || !$this->debugbar) { 62 | return; 63 | } 64 | 65 | $count = func_num_args(); 66 | if (2 === $count) { 67 | $data = []; 68 | foreach ($context as $key => $value) { 69 | if (is_object($value)) { 70 | if (method_exists($value, 'toArray')) { 71 | $data[$key] = $value->toArray(); 72 | } else { 73 | $data[$key] = "Object (" . get_class($value) . ")"; 74 | } 75 | } else { 76 | $data[$key] = $value; 77 | } 78 | } 79 | $this->debugbar->addMessage($data); 80 | } else { 81 | for ($i = 2; $i < $count; $i++) { 82 | $this->debugbar->addMessage(func_get_arg($i)); 83 | } 84 | } 85 | 86 | return; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Middleware/Debugbar.php: -------------------------------------------------------------------------------- 1 | container = $container; 37 | $this->debugbar = $debugbar; 38 | } 39 | 40 | /** 41 | * Handle an incoming request. 42 | * 43 | * @param Request $request 44 | * @param Closure $next 45 | * @return mixed 46 | */ 47 | public function handle($request, Closure $next) 48 | { 49 | try { 50 | /** @var \Illuminate\Http\Response $response */ 51 | $response = $next($request); 52 | } catch (Exception $e) { 53 | $response = $this->handleException($request, $e); 54 | } catch (Error $error) { 55 | $e = new FatalThrowableError($error); 56 | $response = $this->handleException($request, $e); 57 | } 58 | 59 | // Modify the response to add the Debugbar 60 | $this->debugbar->modifyResponse($request, $response); 61 | 62 | return $response; 63 | 64 | } 65 | 66 | /** 67 | * Handle the given exception. 68 | * 69 | * (Copy from Illuminate\Routing\Pipeline by Taylor Otwell) 70 | * 71 | * @param $passable 72 | * @param Exception $e 73 | * @return mixed 74 | * @throws Exception 75 | */ 76 | protected function handleException($passable, Exception $e) 77 | { 78 | if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) { 79 | throw $e; 80 | } 81 | 82 | $handler = $this->container->make(ExceptionHandler::class); 83 | 84 | $handler->report($e); 85 | 86 | return $handler->render($passable, $e); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Support/Clockwork/ClockworkCollector.php: -------------------------------------------------------------------------------- 1 | 13 | * 14 | */ 15 | class ClockworkCollector extends DataCollector implements DataCollectorInterface, Renderable 16 | { 17 | /** @var \Symfony\Component\HttpFoundation\Request $request */ 18 | protected $request; 19 | /** @var \Symfony\Component\HttpFoundation\Request $response */ 20 | protected $response; 21 | /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */ 22 | protected $session; 23 | 24 | /** 25 | * Create a new SymfonyRequestCollector 26 | * 27 | * @param \Symfony\Component\HttpFoundation\Request $request 28 | * @param \Symfony\Component\HttpFoundation\Request $response 29 | * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session 30 | */ 31 | public function __construct($request, $response, $session = null) 32 | { 33 | $this->request = $request; 34 | $this->response = $response; 35 | $this->session = $session; 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | public function getName() 42 | { 43 | return 'clockwork'; 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | public function getWidgets() 50 | { 51 | return null; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function collect() 58 | { 59 | $request = $this->request; 60 | $response = $this->response; 61 | 62 | $data = [ 63 | 'getData' => $request->query->all(), 64 | 'postData' => $request->request->all(), 65 | 'headers' => $request->headers->all(), 66 | 'cookies' => $request->cookies->all(), 67 | 'uri' => $request->getRequestUri(), 68 | 'method' => $request->getMethod(), 69 | 'responseStatus' => $response->getStatusCode(), 70 | ]; 71 | 72 | if ($this->session) { 73 | $sessionAttributes = []; 74 | foreach ($this->session->all() as $key => $value) { 75 | $sessionAttributes[$key] = $value; 76 | } 77 | $data['sessionData'] = $sessionAttributes; 78 | } 79 | 80 | if (isset($data['postData']['php-auth-pw'])) { 81 | $data['postData']['php-auth-pw'] = '******'; 82 | } 83 | 84 | if (isset($data['postData']['PHP_AUTH_PW'])) { 85 | $data['postData']['PHP_AUTH_PW'] = '******'; 86 | } 87 | 88 | return $data; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/DataCollector/ViewCollector.php: -------------------------------------------------------------------------------- 1 | collect_data = $collectData; 22 | $this->name = 'views'; 23 | $this->templates = []; 24 | $this->exporter = new ValueExporter(); 25 | } 26 | 27 | public function getName() 28 | { 29 | return 'views'; 30 | } 31 | 32 | public function getWidgets() 33 | { 34 | return [ 35 | 'views' => [ 36 | 'icon' => 'leaf', 37 | 'widget' => 'PhpDebugBar.Widgets.TemplatesWidget', 38 | 'map' => 'views', 39 | 'default' => '[]' 40 | ], 41 | 'views:badge' => [ 42 | 'map' => 'views.nb_templates', 43 | 'default' => 0 44 | ] 45 | ]; 46 | } 47 | 48 | /** 49 | * Add a View instance to the Collector 50 | * 51 | * @param \Illuminate\View\View $view 52 | */ 53 | public function addView(View $view) 54 | { 55 | $name = $view->getName(); 56 | $path = $view->getPath(); 57 | 58 | if (!is_object($path)) { 59 | if ($path) { 60 | $path = ltrim(str_replace(base_path(), '', realpath($path)), '/'); 61 | } 62 | 63 | if (substr($path, -10) == '.blade.php') { 64 | $type = 'blade'; 65 | } else { 66 | $type = pathinfo($path, PATHINFO_EXTENSION); 67 | } 68 | } else { 69 | $type = get_class($view); 70 | $path = ''; 71 | } 72 | 73 | if (!$this->collect_data) { 74 | $params = array_keys($view->getData()); 75 | } else { 76 | $data = []; 77 | foreach ($view->getData() as $key => $value) { 78 | $data[$key] = $this->exporter->exportValue($value); 79 | } 80 | $params = $data; 81 | } 82 | 83 | $this->templates[] = [ 84 | 'name' => $path ? sprintf('%s (%s)', $name, $path) : $name, 85 | 'param_count' => count($params), 86 | 'params' => $params, 87 | 'type' => $type, 88 | ]; 89 | } 90 | 91 | public function collect() 92 | { 93 | $templates = $this->templates; 94 | 95 | return [ 96 | 'nb_templates' => count($templates), 97 | 'templates' => $templates, 98 | ]; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/DataCollector/MultiAuthCollector.php: -------------------------------------------------------------------------------- 1 | guards = $guards; 25 | } 26 | 27 | 28 | /** 29 | * @{inheritDoc} 30 | */ 31 | public function collect() 32 | { 33 | $data = []; 34 | $names = ''; 35 | 36 | foreach($this->guards as $guardName) { 37 | $user = $this->resolveUser($this->auth->guard($guardName)); 38 | 39 | $data['guards'][$guardName] = $this->getUserInformation($user); 40 | 41 | if(!is_null($user)) { 42 | $names .= $guardName . ": " . $data['guards'][$guardName]['name'] . ', '; 43 | } 44 | } 45 | 46 | foreach ($data['guards'] as $key => $var) { 47 | if (!is_string($data['guards'][$key])) { 48 | $data['guards'][$key] = $this->formatVar($var); 49 | } 50 | } 51 | 52 | $data['names'] = rtrim($names, ', '); 53 | 54 | return $data; 55 | } 56 | 57 | private function resolveUser(Guard $guard) 58 | { 59 | // if we're logging in using remember token 60 | // then we must resolve user „manually” 61 | // to prevent csrf token regeneration 62 | 63 | $recaller = $guard instanceof SessionGuard 64 | ? $guard->getRequest()->cookies->get($guard->getRecallerName()) 65 | : null; 66 | 67 | if (is_string($recaller) && Str::contains($recaller, '|')) { 68 | $segments = explode('|', $recaller); 69 | if (count($segments) == 2 && trim($segments[0]) !== '' && trim($segments[1]) !== '') { 70 | return $guard->getProvider()->retrieveByToken($segments[0], $segments[1]); 71 | } 72 | } 73 | return $guard->user(); 74 | } 75 | 76 | /** 77 | * @{inheritDoc} 78 | */ 79 | public function getWidgets() 80 | { 81 | $widgets = [ 82 | "auth" => [ 83 | "icon" => "lock", 84 | "widget" => "PhpDebugBar.Widgets.VariableListWidget", 85 | "map" => "auth.guards", 86 | "default" => "{}" 87 | ] 88 | ]; 89 | 90 | if ($this->showName) { 91 | $widgets['auth.name'] = [ 92 | 'icon' => 'user', 93 | 'tooltip' => 'Auth status', 94 | 'map' => 'auth.names', 95 | 'default' => '', 96 | ]; 97 | } 98 | 99 | return $widgets; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/DataCollector/AuthCollector.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 25 | } 26 | 27 | /** 28 | * Set to show the users name/email 29 | * @param bool $showName 30 | */ 31 | public function setShowName($showName) 32 | { 33 | $this->showName = (bool) $showName; 34 | } 35 | 36 | /** 37 | * @{inheritDoc} 38 | */ 39 | public function collect() 40 | { 41 | try { 42 | $user = $this->auth->user(); 43 | } catch (\Exception $e) { 44 | $user = null; 45 | } 46 | return $this->getUserInformation($user); 47 | } 48 | 49 | /** 50 | * Get displayed user information 51 | * @param \Illuminate\Auth\UserInterface $user 52 | * @return array 53 | */ 54 | protected function getUserInformation($user = null) 55 | { 56 | // Defaults 57 | if (is_null($user)) { 58 | return [ 59 | 'name' => 'Guest', 60 | 'user' => ['guest' => true], 61 | ]; 62 | } 63 | 64 | // The default auth identifer is the ID number, which isn't all that 65 | // useful. Try username and email. 66 | $identifier = $user->getAuthIdentifier(); 67 | if (is_numeric($identifier)) { 68 | try { 69 | if ($user->username) { 70 | $identifier = $user->username; 71 | } elseif ($user->email) { 72 | $identifier = $user->email; 73 | } 74 | } catch (\Exception $e) { 75 | } 76 | } 77 | 78 | return [ 79 | 'name' => $identifier, 80 | 'user' => $user instanceof Arrayable ? $user->toArray() : $user, 81 | ]; 82 | } 83 | 84 | /** 85 | * @{inheritDoc} 86 | */ 87 | public function getName() 88 | { 89 | return 'auth'; 90 | } 91 | 92 | /** 93 | * @{inheritDoc} 94 | */ 95 | public function getWidgets() 96 | { 97 | $widgets = [ 98 | 'auth' => [ 99 | 'icon' => 'lock', 100 | 'widget' => 'PhpDebugBar.Widgets.VariableListWidget', 101 | 'map' => 'auth.user', 102 | 'default' => '{}' 103 | ] 104 | ]; 105 | if ($this->showName) { 106 | $widgets['auth.name'] = [ 107 | 'icon' => 'user', 108 | 'tooltip' => 'Auth status', 109 | 'map' => 'auth.name', 110 | 'default' => '', 111 | ]; 112 | } 113 | return $widgets; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/JavascriptRenderer.php: -------------------------------------------------------------------------------- 1 | cssFiles['laravel'] = __DIR__ . '/Resources/laravel-debugbar.css'; 21 | $this->cssVendors['fontawesome'] = __DIR__ . '/Resources/vendor/font-awesome/style.css'; 22 | $this->jsFiles['laravel-sql'] = __DIR__ . '/Resources/sqlqueries/widget.js'; 23 | } 24 | 25 | /** 26 | * Set the URL Generator 27 | * 28 | * @param \Illuminate\Routing\UrlGenerator $url 29 | * @deprecated 30 | */ 31 | public function setUrlGenerator($url) 32 | { 33 | 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function renderHead() 40 | { 41 | $cssRoute = route('debugbar.assets.css', [ 42 | 'v' => $this->getModifiedTime('css') 43 | ]); 44 | 45 | $jsRoute = route('debugbar.assets.js', [ 46 | 'v' => $this->getModifiedTime('js') 47 | ]); 48 | 49 | $cssRoute = preg_replace('/\Ahttps?:/', '', $cssRoute); 50 | $jsRoute = preg_replace('/\Ahttps?:/', '', $jsRoute); 51 | 52 | $html = ""; 53 | $html .= ""; 54 | 55 | if ($this->isJqueryNoConflictEnabled()) { 56 | $html .= '' . "\n"; 57 | } 58 | 59 | return $html; 60 | } 61 | 62 | /** 63 | * Get the last modified time of any assets. 64 | * 65 | * @param string $type 'js' or 'css' 66 | * @return int 67 | */ 68 | protected function getModifiedTime($type) 69 | { 70 | $files = $this->getAssets($type); 71 | 72 | $latest = 0; 73 | foreach ($files as $file) { 74 | $mtime = filemtime($file); 75 | if ($mtime > $latest) { 76 | $latest = $mtime; 77 | } 78 | } 79 | return $latest; 80 | } 81 | 82 | /** 83 | * Return assets as a string 84 | * 85 | * @param string $type 'js' or 'css' 86 | * @return string 87 | */ 88 | public function dumpAssetsToString($type) 89 | { 90 | $files = $this->getAssets($type); 91 | 92 | $content = ''; 93 | foreach ($files as $file) { 94 | $content .= file_get_contents($file) . "\n"; 95 | } 96 | 97 | return $content; 98 | } 99 | 100 | /** 101 | * Makes a URI relative to another 102 | * 103 | * @param string|array $uri 104 | * @param string $root 105 | * @return string 106 | */ 107 | protected function makeUriRelativeTo($uri, $root) 108 | { 109 | if (!$root) { 110 | return $uri; 111 | } 112 | 113 | if (is_array($uri)) { 114 | $uris = []; 115 | foreach ($uri as $u) { 116 | $uris[] = $this->makeUriRelativeTo($u, $root); 117 | } 118 | return $uris; 119 | } 120 | 121 | if (substr($uri, 0, 1) === '/' || preg_match('/^([a-zA-Z]+:\/\/|[a-zA-Z]:\/|[a-zA-Z]:\\\)/', $uri)) { 122 | return $uri; 123 | } 124 | return rtrim($root, '/') . "/$uri"; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/DataCollector/EventCollector.php: -------------------------------------------------------------------------------- 1 | exporter = new ValueExporter(); 22 | } 23 | 24 | public function onWildcardEvent($name = null, $data = []) 25 | { 26 | // Pre-Laravel 5.4, using 'firing' to get the current event name. 27 | if (method_exists($this->events, 'firing')) { 28 | $name = $this->events->firing(); 29 | 30 | // Get the arguments passed to the event 31 | $data = func_get_args(); 32 | } 33 | 34 | $params = $this->prepareParams($data); 35 | $time = microtime(true); 36 | 37 | // Find all listeners for the current event 38 | foreach ($this->events->getListeners($name) as $i => $listener) { 39 | 40 | // Check if it's an object + method name 41 | if (is_array($listener) && count($listener) > 1 && is_object($listener[0])) { 42 | list($class, $method) = $listener; 43 | 44 | // Skip this class itself 45 | if ($class instanceof static) { 46 | continue; 47 | } 48 | 49 | // Format the listener to readable format 50 | $listener = get_class($class) . '@' . $method; 51 | 52 | // Handle closures 53 | } elseif ($listener instanceof \Closure) { 54 | $reflector = new \ReflectionFunction($listener); 55 | 56 | // Skip our own listeners 57 | if ($reflector->getNamespaceName() == 'Barryvdh\Debugbar') { 58 | continue; 59 | } 60 | 61 | // Format the closure to a readable format 62 | $filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/'); 63 | $listener = $reflector->getName() . ' (' . $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine() . ')'; 64 | } else { 65 | // Not sure if this is possible, but to prevent edge cases 66 | $listener = $this->formatVar($listener); 67 | } 68 | 69 | $params['listeners.' . $i] = $listener; 70 | } 71 | $this->addMeasure($name, $time, $time, $params); 72 | } 73 | 74 | public function subscribe(Dispatcher $events) 75 | { 76 | $this->events = $events; 77 | $events->listen('*', [$this, 'onWildcardEvent']); 78 | } 79 | 80 | protected function prepareParams($params) 81 | { 82 | $data = []; 83 | foreach ($params as $key => $value) { 84 | if (is_object($value) && Str::is('Illuminate\*\Events\*', get_class($value))) { 85 | $value = $this->prepareParams(get_object_vars($value)); 86 | } 87 | $data[$key] = htmlentities($this->exporter->exportValue($value), ENT_QUOTES, 'UTF-8', false); 88 | } 89 | 90 | return $data; 91 | } 92 | 93 | public function collect() 94 | { 95 | $data = parent::collect(); 96 | $data['nb_measures'] = count($data['measures']); 97 | 98 | return $data; 99 | } 100 | 101 | public function getName() 102 | { 103 | return 'event'; 104 | } 105 | 106 | public function getWidgets() 107 | { 108 | return [ 109 | "events" => [ 110 | "icon" => "tasks", 111 | "widget" => "PhpDebugBar.Widgets.TimelineWidget", 112 | "map" => "event", 113 | "default" => "{}", 114 | ], 115 | 'events:badge' => [ 116 | 'map' => 'event.nb_measures', 117 | 'default' => 0, 118 | ], 119 | ]; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/DataCollector/IlluminateRouteCollector.php: -------------------------------------------------------------------------------- 1 | router = $router; 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function collect() 35 | { 36 | $route = $this->router->current(); 37 | return $this->getRouteInformation($route); 38 | } 39 | 40 | /** 41 | * Get the route information for a given route. 42 | * 43 | * @param \Illuminate\Routing\Route $route 44 | * @return array 45 | */ 46 | protected function getRouteInformation($route) 47 | { 48 | if (!is_a($route, 'Illuminate\Routing\Route')) { 49 | return []; 50 | } 51 | $uri = head($route->methods()) . ' ' . $route->uri(); 52 | $action = $route->getAction(); 53 | 54 | $result = [ 55 | 'uri' => $uri ?: '-', 56 | ]; 57 | 58 | $result = array_merge($result, $action); 59 | 60 | 61 | if (isset($action['controller']) && strpos($action['controller'], '@') !== false) { 62 | list($controller, $method) = explode('@', $action['controller']); 63 | if(class_exists($controller) && method_exists($controller, $method)) { 64 | $reflector = new \ReflectionMethod($controller, $method); 65 | } 66 | unset($result['uses']); 67 | } elseif (isset($action['uses']) && $action['uses'] instanceof \Closure) { 68 | $reflector = new \ReflectionFunction($action['uses']); 69 | $result['uses'] = $this->formatVar($result['uses']); 70 | } 71 | 72 | if (isset($reflector)) { 73 | $filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/'); 74 | $result['file'] = $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine(); 75 | } 76 | 77 | if ($middleware = $this->getMiddleware($route)) { 78 | $result['middleware'] = $middleware; 79 | } 80 | 81 | 82 | 83 | return $result; 84 | } 85 | 86 | /** 87 | * Get middleware 88 | * 89 | * @param \Illuminate\Routing\Route $route 90 | * @return string 91 | */ 92 | protected function getMiddleware($route) 93 | { 94 | return implode(', ', $route->middleware()); 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | public function getName() 101 | { 102 | return 'route'; 103 | } 104 | 105 | /** 106 | * {@inheritDoc} 107 | */ 108 | public function getWidgets() 109 | { 110 | $widgets = [ 111 | "route" => [ 112 | "icon" => "share", 113 | "widget" => "PhpDebugBar.Widgets.VariableListWidget", 114 | "map" => "route", 115 | "default" => "{}" 116 | ] 117 | ]; 118 | if (Config::get('debugbar.options.route.label', true)) { 119 | $widgets['currentroute'] = [ 120 | "icon" => "share", 121 | "tooltip" => "Route", 122 | "map" => "route.uri", 123 | "default" => "" 124 | ]; 125 | } 126 | return $widgets; 127 | } 128 | 129 | /** 130 | * Display the route information on the console. 131 | * 132 | * @param array $routes 133 | * @return void 134 | */ 135 | protected function displayRoutes(array $routes) 136 | { 137 | $this->table->setHeaders($this->headers)->setRows($routes); 138 | 139 | $this->table->render($this->getOutput()); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/DataCollector/LogsCollector.php: -------------------------------------------------------------------------------- 1 | getLogsFile(); 17 | $this->getStorageLogs($path); 18 | } 19 | 20 | /** 21 | * Get the path to the logs file 22 | * 23 | * @return string 24 | */ 25 | public function getLogsFile() 26 | { 27 | // default daily rotating logs (Laravel 5.0) 28 | $path = storage_path() . '/logs/laravel-' . date('Y-m-d') . '.log'; 29 | 30 | // single file logs 31 | if (!file_exists($path)) { 32 | $path = storage_path() . '/logs/laravel.log'; 33 | } 34 | 35 | return $path; 36 | } 37 | 38 | /** 39 | * get logs apache in app/storage/logs 40 | * only 24 last of current day 41 | * 42 | * @param string $path 43 | * 44 | * @return array 45 | */ 46 | public function getStorageLogs($path) 47 | { 48 | if (!file_exists($path)) { 49 | return; 50 | } 51 | 52 | //Load the latest lines, guessing about 15x the number of log entries (for stack traces etc) 53 | $file = implode("", $this->tailFile($path, $this->lines)); 54 | 55 | foreach ($this->getLogs($file) as $log) { 56 | $this->addMessage($log['header'] . $log['stack'], $log['level'], false); 57 | } 58 | } 59 | 60 | /** 61 | * By Ain Tohvri (ain) 62 | * http://tekkie.flashbit.net/php/tail-functionality-in-php 63 | * @param string $file 64 | * @param int $lines 65 | * @return array 66 | */ 67 | protected function tailFile($file, $lines) 68 | { 69 | $handle = fopen($file, "r"); 70 | $linecounter = $lines; 71 | $pos = -2; 72 | $beginning = false; 73 | $text = []; 74 | while ($linecounter > 0) { 75 | $t = " "; 76 | while ($t != "\n") { 77 | if (fseek($handle, $pos, SEEK_END) == -1) { 78 | $beginning = true; 79 | break; 80 | } 81 | $t = fgetc($handle); 82 | $pos--; 83 | } 84 | $linecounter--; 85 | if ($beginning) { 86 | rewind($handle); 87 | } 88 | $text[$lines - $linecounter - 1] = fgets($handle); 89 | if ($beginning) { 90 | break; 91 | } 92 | } 93 | fclose($handle); 94 | return array_reverse($text); 95 | } 96 | 97 | /** 98 | * Search a string for log entries 99 | * Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand 100 | * 101 | * @param $file 102 | * @return array 103 | */ 104 | public function getLogs($file) 105 | { 106 | $pattern = "/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\].*/"; 107 | 108 | $log_levels = $this->getLevels(); 109 | 110 | // There has GOT to be a better way of doing this... 111 | preg_match_all($pattern, $file, $headings); 112 | $log_data = preg_split($pattern, $file); 113 | 114 | $log = []; 115 | foreach ($headings as $h) { 116 | for ($i = 0, $j = count($h); $i < $j; $i++) { 117 | foreach ($log_levels as $ll) { 118 | if (strpos(strtolower($h[$i]), strtolower('.' . $ll))) { 119 | $log[] = ['level' => $ll, 'header' => $h[$i], 'stack' => $log_data[$i]]; 120 | } 121 | } 122 | } 123 | } 124 | 125 | $log = array_reverse($log); 126 | 127 | return $log; 128 | } 129 | 130 | /** 131 | * Get the log levels from psr/log. 132 | * Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand 133 | * 134 | * @access public 135 | * @return array 136 | */ 137 | public function getLevels() 138 | { 139 | $class = new ReflectionClass(new LogLevel()); 140 | return $class->getConstants(); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/DataCollector/FilesCollector.php: -------------------------------------------------------------------------------- 1 | app = $app; 21 | $this->basePath = base_path(); 22 | } 23 | 24 | /** 25 | * {@inheritDoc} 26 | */ 27 | public function collect() 28 | { 29 | $files = $this->getIncludedFiles(); 30 | $compiled = $this->getCompiledFiles(); 31 | 32 | $included = []; 33 | $alreadyCompiled = []; 34 | foreach ($files as $file) { 35 | // Skip the files from Debugbar, they are only loaded for Debugging and confuse the output. 36 | // Of course some files are stil always loaded (ServiceProvider, Facade etc) 37 | if (strpos($file, 'vendor/maximebf/debugbar/src') !== false || strpos( 38 | $file, 39 | 'vendor/barryvdh/laravel-debugbar/src' 40 | ) !== false 41 | ) { 42 | continue; 43 | } elseif (!in_array($file, $compiled)) { 44 | $included[] = [ 45 | 'message' => "'" . $this->stripBasePath($file) . "',", 46 | // Use PHP syntax so we can copy-paste to compile config file. 47 | 'is_string' => true, 48 | ]; 49 | } else { 50 | $alreadyCompiled[] = [ 51 | 'message' => "* '" . $this->stripBasePath($file) . "',", 52 | // Mark with *, so know they are compiled anyways. 53 | 'is_string' => true, 54 | ]; 55 | } 56 | } 57 | 58 | // First the included files, then those that are going to be compiled. 59 | $messages = array_merge($included, $alreadyCompiled); 60 | 61 | return [ 62 | 'messages' => $messages, 63 | 'count' => count($included), 64 | ]; 65 | } 66 | 67 | /** 68 | * Get the files included on load. 69 | * 70 | * @return array 71 | */ 72 | protected function getIncludedFiles() 73 | { 74 | return get_included_files(); 75 | } 76 | 77 | /** 78 | * Get the files that are going to be compiled, so they aren't as important. 79 | * 80 | * @return array 81 | */ 82 | protected function getCompiledFiles() 83 | { 84 | if ($this->app && class_exists('Illuminate\Foundation\Console\OptimizeCommand')) { 85 | $reflector = new \ReflectionClass('Illuminate\Foundation\Console\OptimizeCommand'); 86 | $path = dirname($reflector->getFileName()) . '/Optimize/config.php'; 87 | 88 | if (file_exists($path)) { 89 | $app = $this->app; 90 | $core = require $path; 91 | return array_merge($core, $app['config']['compile']); 92 | } 93 | } 94 | return []; 95 | } 96 | 97 | /** 98 | * Remove the basePath from the paths, so they are relative to the base 99 | * 100 | * @param $path 101 | * @return string 102 | */ 103 | protected function stripBasePath($path) 104 | { 105 | return ltrim(str_replace($this->basePath, '', $path), '/'); 106 | } 107 | 108 | /** 109 | * {@inheritDoc} 110 | */ 111 | public function getWidgets() 112 | { 113 | $name = $this->getName(); 114 | return [ 115 | "$name" => [ 116 | "icon" => "files-o", 117 | "widget" => "PhpDebugBar.Widgets.MessagesWidget", 118 | "map" => "$name.messages", 119 | "default" => "{}" 120 | ], 121 | "$name:badge" => [ 122 | "map" => "$name.count", 123 | "default" => "null" 124 | ] 125 | ]; 126 | } 127 | 128 | /** 129 | * {@inheritDoc} 130 | */ 131 | public function getName() 132 | { 133 | return 'files'; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Storage/FilesystemStorage.php: -------------------------------------------------------------------------------- 1 | files = $files; 26 | $this->dirname = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | */ 32 | public function save($id, $data) 33 | { 34 | if (!$this->files->isDirectory($this->dirname)) { 35 | if ($this->files->makeDirectory($this->dirname, 0777, true)) { 36 | $this->files->put($this->dirname . '.gitignore', "*\n!.gitignore"); 37 | } else { 38 | throw new \Exception("Cannot create directory '$this->dirname'.."); 39 | } 40 | } 41 | 42 | try { 43 | $this->files->put($this->makeFilename($id), json_encode($data)); 44 | } catch (\Exception $e) { 45 | //TODO; error handling 46 | } 47 | 48 | // Randomly check if we should collect old files 49 | if (rand(1, 100) <= $this->gc_probability) { 50 | $this->garbageCollect(); 51 | } 52 | } 53 | 54 | /** 55 | * Create the filename for the data, based on the id. 56 | * 57 | * @param $id 58 | * @return string 59 | */ 60 | public function makeFilename($id) 61 | { 62 | return $this->dirname . basename($id) . ".json"; 63 | } 64 | 65 | /** 66 | * Delete files older then a certain age (gc_lifetime) 67 | */ 68 | protected function garbageCollect() 69 | { 70 | foreach (Finder::create()->files()->name('*.json')->date('< ' . $this->gc_lifetime . ' hour ago')->in( 71 | $this->dirname 72 | ) as $file) { 73 | $this->files->delete($file->getRealPath()); 74 | } 75 | } 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | public function get($id) 81 | { 82 | return json_decode($this->files->get($this->makeFilename($id)), true); 83 | } 84 | 85 | /** 86 | * {@inheritDoc} 87 | */ 88 | public function find(array $filters = [], $max = 20, $offset = 0) 89 | { 90 | // Sort by modified time, newest first 91 | $sort = function (\SplFileInfo $a, \SplFileInfo $b) { 92 | return strcmp($b->getMTime(), $a->getMTime()); 93 | }; 94 | 95 | // Loop through .json files, filter the metadata and stop when max is found. 96 | $i = 0; 97 | $results = []; 98 | foreach (Finder::create()->files()->name('*.json')->in($this->dirname)->sort($sort) as $file) { 99 | if ($i++ < $offset && empty($filters)) { 100 | $results[] = null; 101 | continue; 102 | } 103 | $data = json_decode($file->getContents(), true); 104 | $meta = $data['__meta']; 105 | unset($data); 106 | if ($this->filter($meta, $filters)) { 107 | $results[] = $meta; 108 | } 109 | if (count($results) >= ($max + $offset)) { 110 | break; 111 | } 112 | } 113 | return array_slice($results, $offset, $max); 114 | } 115 | 116 | /** 117 | * Filter the metadata for matches. 118 | * 119 | * @param $meta 120 | * @param $filters 121 | * @return bool 122 | */ 123 | protected function filter($meta, $filters) 124 | { 125 | foreach ($filters as $key => $value) { 126 | if (!isset($meta[$key]) || fnmatch($value, $meta[$key]) === false) { 127 | return false; 128 | } 129 | } 130 | return true; 131 | } 132 | 133 | /** 134 | * {@inheritDoc} 135 | */ 136 | public function clear() 137 | { 138 | foreach (Finder::create()->files()->name('*.json')->in($this->dirname) as $file) { 139 | $this->files->delete($file->getRealPath()); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Support/Clockwork/Converter.php: -------------------------------------------------------------------------------- 1 | $meta['id'], 18 | 'method' => $meta['method'], 19 | 'uri' => $meta['uri'], 20 | 'time' => $meta['utime'], 21 | 'headers' => [], 22 | 'cookies' => [], 23 | 'emailsData' => [], 24 | 'getData' => [], 25 | 'log' => [], 26 | 'postData' => [], 27 | 'sessionData' => [], 28 | 'timelineData' => [], 29 | 'viewsData' => [], 30 | 'controller' => null, 31 | 'responseTime' => null, 32 | 'responseStatus' => null, 33 | 'responseDuration' => 0, 34 | ]; 35 | 36 | if (isset($data['clockwork'])) { 37 | $output = array_merge($output, $data['clockwork']); 38 | } 39 | 40 | if (isset($data['time'])) { 41 | $time = $data['time']; 42 | $output['time'] = $time['start']; 43 | $output['responseTime'] = $time['end']; 44 | $output['responseDuration'] = $time['duration'] * 1000; 45 | foreach($time['measures'] as $measure) { 46 | $output['timelineData'][] = [ 47 | 'data' => [], 48 | 'description' => $measure['label'], 49 | 'duration' => $measure['duration'] * 1000, 50 | 'end' => $measure['end'], 51 | 'start' => $measure['start'], 52 | 'relative_start' => $measure['start'] - $time['start'], 53 | ]; 54 | } 55 | } 56 | 57 | if (isset($data['route'])) { 58 | $route = $data['route']; 59 | 60 | $controller = null; 61 | if (isset($route['controller'])) { 62 | $controller = $route['controller']; 63 | } elseif (isset($route['uses'])) { 64 | $controller = $route['uses']; 65 | } 66 | 67 | $output['controller'] = $controller; 68 | 69 | list($method, $uri) = explode(' ', $route['uri'], 2); 70 | 71 | $output['routes'][] = [ 72 | 'action' => $controller, 73 | 'after' => isset($route['after']) ? $route['after'] : null, 74 | 'before' => isset($route['before']) ? $route['before'] : null, 75 | 'method' => $method, 76 | 'name' => isset($route['as']) ? $route['as'] : null, 77 | 'uri' => $uri, 78 | ]; 79 | } 80 | 81 | if (isset($data['messages'])) { 82 | foreach($data['messages']['messages'] as $message) { 83 | $output['log'][] = [ 84 | 'message' => $message['message'], 85 | 'time' => $message['time'], 86 | 'level' => $message['label'], 87 | ]; 88 | } 89 | } 90 | 91 | if (isset($data['queries'])) { 92 | $queries = $data['queries']; 93 | foreach($queries['statements'] as $statement){ 94 | $output['databaseQueries'][] = [ 95 | 'query' => $statement['sql'], 96 | 'bindings' => $statement['params'], 97 | 'duration' => $statement['duration'] * 1000, 98 | 'connection' => $statement['connection'] 99 | ]; 100 | } 101 | 102 | $output['databaseDuration'] = $queries['accumulated_duration'] * 1000; 103 | } 104 | 105 | if (isset($data['views'])) { 106 | foreach ($data['views']['templates'] as $view) { 107 | $output['viewsData'][] = [ 108 | 'description' => 'Rendering a view', 109 | 'duration' => 0, 110 | 'end' => 0, 111 | 'start' => 0, 112 | 'data' => [ 113 | 'name' => $view['name'], 114 | 'data' => $view['params'], 115 | ], 116 | ]; 117 | } 118 | } 119 | 120 | if (isset($data['swiftmailer_mails'])) { 121 | foreach($data['swiftmailer_mails']['mails'] as $mail) { 122 | $output['emailsData'][] = [ 123 | 'data' => [ 124 | 'to' => $mail['to'], 125 | 'subject' => $mail['subject'], 126 | 'headers' => isset($mail['headers']) ? explode("\n", $mail['headers']) : null, 127 | ], 128 | ]; 129 | } 130 | } 131 | 132 | return $output; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($configPath, 'debugbar'); 24 | 25 | $this->app->alias( 26 | 'DebugBar\DataFormatter\DataFormatter', 27 | 'DebugBar\DataFormatter\DataFormatterInterface' 28 | ); 29 | 30 | $this->app->singleton('debugbar', function ($app) { 31 | $debugbar = new LaravelDebugbar($app); 32 | 33 | if ($app->bound(SessionManager::class)) { 34 | $sessionManager = $app->make(SessionManager::class); 35 | $httpDriver = new SymfonyHttpDriver($sessionManager); 36 | $debugbar->setHttpDriver($httpDriver); 37 | } 38 | 39 | return $debugbar; 40 | } 41 | ); 42 | 43 | $this->app->alias('debugbar', 'Barryvdh\Debugbar\LaravelDebugbar'); 44 | 45 | $this->app->singleton('command.debugbar.clear', 46 | function ($app) { 47 | return new Console\ClearCommand($app['debugbar']); 48 | } 49 | ); 50 | 51 | $this->commands(['command.debugbar.clear']); 52 | } 53 | 54 | /** 55 | * Bootstrap the application events. 56 | * 57 | * @return void 58 | */ 59 | public function boot() 60 | { 61 | $app = $this->app; 62 | 63 | $configPath = __DIR__ . '/../config/debugbar.php'; 64 | $this->publishes([$configPath => $this->getConfigPath()], 'config'); 65 | 66 | // If enabled is null, set from the app.debug value 67 | $enabled = $this->app['config']->get('debugbar.enabled'); 68 | 69 | if (is_null($enabled)) { 70 | $enabled = $this->checkAppDebug(); 71 | } 72 | 73 | if (! $enabled) { 74 | return; 75 | } 76 | 77 | $routeConfig = [ 78 | 'namespace' => 'Barryvdh\Debugbar\Controllers', 79 | 'prefix' => $this->app['config']->get('debugbar.route_prefix'), 80 | 'domain' => $this->app['config']->get('debugbar.route_domain'), 81 | ]; 82 | 83 | $this->getRouter()->group($routeConfig, function($router) { 84 | $router->get('open', [ 85 | 'uses' => 'OpenHandlerController@handle', 86 | 'as' => 'debugbar.openhandler', 87 | ]); 88 | 89 | $router->get('clockwork/{id}', [ 90 | 'uses' => 'OpenHandlerController@clockwork', 91 | 'as' => 'debugbar.clockwork', 92 | ]); 93 | 94 | $router->get('assets/stylesheets', [ 95 | 'uses' => 'AssetController@css', 96 | 'as' => 'debugbar.assets.css', 97 | ]); 98 | 99 | $router->get('assets/javascript', [ 100 | 'uses' => 'AssetController@js', 101 | 'as' => 'debugbar.assets.js', 102 | ]); 103 | }); 104 | 105 | if ($app->runningInConsole() || $app->environment('testing')) { 106 | return; 107 | } 108 | 109 | /** @var LaravelDebugbar $debugbar */ 110 | $debugbar = $this->app['debugbar']; 111 | $debugbar->enable(); 112 | $debugbar->boot(); 113 | 114 | $this->registerMiddleware('Barryvdh\Debugbar\Middleware\Debugbar'); 115 | } 116 | 117 | /** 118 | * Get the active router. 119 | * 120 | * @return Router 121 | */ 122 | protected function getRouter() 123 | { 124 | return $this->app['router']; 125 | } 126 | 127 | /** 128 | * Get the config path 129 | * 130 | * @return string 131 | */ 132 | protected function getConfigPath() 133 | { 134 | return config_path('debugbar.php'); 135 | } 136 | 137 | /** 138 | * Publish the config file 139 | * 140 | * @param string $configPath 141 | */ 142 | protected function publishConfig($configPath) 143 | { 144 | $this->publishes([$configPath => config_path('debugbar.php')], 'config'); 145 | } 146 | 147 | /** 148 | * Register the Debugbar Middleware 149 | * 150 | * @param string $middleware 151 | */ 152 | protected function registerMiddleware($middleware) 153 | { 154 | $kernel = $this->app['Illuminate\Contracts\Http\Kernel']; 155 | $kernel->pushMiddleware($middleware); 156 | } 157 | 158 | /** 159 | * Check the App Debug status 160 | */ 161 | protected function checkAppDebug() 162 | { 163 | return $this->app['config']->get('app.debug'); 164 | } 165 | 166 | /** 167 | * Get the services provided by the provider. 168 | * 169 | * @return array 170 | */ 171 | public function provides() 172 | { 173 | return ['debugbar', 'command.debugbar.clear']; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/DataCollector/SymfonyRequestCollector.php: -------------------------------------------------------------------------------- 1 | 13 | * 14 | */ 15 | class SymfonyRequestCollector extends DataCollector implements DataCollectorInterface, Renderable 16 | { 17 | /** @var \Symfony\Component\HttpFoundation\Request $request */ 18 | protected $request; 19 | /** @var \Symfony\Component\HttpFoundation\Request $response */ 20 | protected $response; 21 | /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */ 22 | protected $session; 23 | 24 | /** 25 | * Create a new SymfonyRequestCollector 26 | * 27 | * @param \Symfony\Component\HttpFoundation\Request $request 28 | * @param \Symfony\Component\HttpFoundation\Request $response 29 | * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session 30 | */ 31 | public function __construct($request, $response, $session = null) 32 | { 33 | $this->request = $request; 34 | $this->response = $response; 35 | $this->session = $session; 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | public function getName() 42 | { 43 | return 'request'; 44 | } 45 | 46 | /** 47 | * {@inheritDoc} 48 | */ 49 | public function getWidgets() 50 | { 51 | return [ 52 | "request" => [ 53 | "icon" => "tags", 54 | "widget" => "PhpDebugBar.Widgets.VariableListWidget", 55 | "map" => "request", 56 | "default" => "{}" 57 | ] 58 | ]; 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function collect() 65 | { 66 | $request = $this->request; 67 | $response = $this->response; 68 | 69 | $responseHeaders = $response->headers->all(); 70 | $cookies = []; 71 | foreach ($response->headers->getCookies() as $cookie) { 72 | $cookies[] = $this->getCookieHeader( 73 | $cookie->getName(), 74 | $cookie->getValue(), 75 | $cookie->getExpiresTime(), 76 | $cookie->getPath(), 77 | $cookie->getDomain(), 78 | $cookie->isSecure(), 79 | $cookie->isHttpOnly() 80 | ); 81 | } 82 | if (count($cookies) > 0) { 83 | $responseHeaders['Set-Cookie'] = $cookies; 84 | } 85 | 86 | $statusCode = $response->getStatusCode(); 87 | 88 | $data = [ 89 | 'format' => $request->getRequestFormat(), 90 | 'content_type' => $response->headers->get('Content-Type') ? $response->headers->get( 91 | 'Content-Type' 92 | ) : 'text/html', 93 | 'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '', 94 | 'status_code' => $statusCode, 95 | 'request_query' => $request->query->all(), 96 | 'request_request' => $request->request->all(), 97 | 'request_headers' => $request->headers->all(), 98 | 'request_server' => $request->server->all(), 99 | 'request_cookies' => $request->cookies->all(), 100 | 'response_headers' => $responseHeaders, 101 | 'path_info' => $request->getPathInfo(), 102 | ]; 103 | 104 | if ($this->session) { 105 | $sessionAttributes = []; 106 | foreach ($this->session->all() as $key => $value) { 107 | $sessionAttributes[$key] = $value; 108 | } 109 | $data['session_attributes'] = $sessionAttributes; 110 | } 111 | 112 | foreach ($data['request_server'] as $key => $value) { 113 | if (str_is('*_KEY', $key) || str_is('*_PASSWORD', $key) 114 | || str_is('*_SECRET', $key) || str_is('*_PW', $key)) { 115 | $data['request_server'][$key] = '******'; 116 | } 117 | } 118 | 119 | if (isset($data['request_headers']['php-auth-pw'])) { 120 | $data['request_headers']['php-auth-pw'] = '******'; 121 | } 122 | 123 | if (isset($data['request_server']['PHP_AUTH_PW'])) { 124 | $data['request_server']['PHP_AUTH_PW'] = '******'; 125 | } 126 | 127 | foreach ($data as $key => $var) { 128 | if (!is_string($data[$key])) { 129 | $data[$key] = $this->formatVar($var); 130 | } 131 | } 132 | 133 | return $data; 134 | } 135 | 136 | private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly) 137 | { 138 | $cookie = sprintf('%s=%s', $name, urlencode($value)); 139 | 140 | if (0 !== $expires) { 141 | if (is_numeric($expires)) { 142 | $expires = (int) $expires; 143 | } elseif ($expires instanceof \DateTime) { 144 | $expires = $expires->getTimestamp(); 145 | } else { 146 | $expires = strtotime($expires); 147 | if (false === $expires || -1 == $expires) { 148 | throw new \InvalidArgumentException( 149 | sprintf('The "expires" cookie parameter is not valid.', $expires) 150 | ); 151 | } 152 | } 153 | 154 | $cookie .= '; expires=' . substr( 155 | \DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'), 156 | 0, 157 | -5 158 | ); 159 | } 160 | 161 | if ($domain) { 162 | $cookie .= '; domain=' . $domain; 163 | } 164 | 165 | $cookie .= '; path=' . $path; 166 | 167 | if ($secure) { 168 | $cookie .= '; secure'; 169 | } 170 | 171 | if ($httponly) { 172 | $cookie .= '; httponly'; 173 | } 174 | 175 | return $cookie; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Laravel Debugbar 2 | [](http://choosealicense.com/licenses/mit/) 3 | [](https://packagist.org/packages/barryvdh/laravel-debugbar) 4 | [](https://packagist.org/packages/barryvdh/laravel-debugbar) 5 | 6 | ### For Laravel 4, please use the [1.8 branch](https://github.com/barryvdh/laravel-debugbar/tree/1.8)! 7 | 8 | This is a package to integrate [PHP Debug Bar](http://phpdebugbar.com/) with Laravel 5. 9 | It includes a ServiceProvider to register the debugbar and attach it to the output. You can publish assets and configure it through Laravel. 10 | It bootstraps some Collectors to work with Laravel and implements a couple custom DataCollectors, specific for Laravel. 11 | It is configured to display Redirects and (jQuery) Ajax Requests. (Shown in a dropdown) 12 | Read [the documentation](http://phpdebugbar.com/docs/) for more configuration options. 13 | 14 |  15 | 16 | Note: Use the DebugBar only in development. It can slow the application down (because it has to gather data). So when experiencing slowness, try disabling some of the collectors. 17 | 18 | This package includes some custom collectors: 19 | - QueryCollector: Show all queries, including binding + timing 20 | - RouteCollector: Show information about the current Route. 21 | - ViewCollector: Show the currently loaded views. (Optionally: display the shared data) 22 | - EventsCollector: Show all events 23 | - LaravelCollector: Show the Laravel version and Environment. (disabled by default) 24 | - SymfonyRequestCollector: replaces the RequestCollector with more information about the request/response 25 | - LogsCollector: Show the latest log entries from the storage logs. (disabled by default) 26 | - FilesCollector: Show the files that are included/required by PHP. (disabled by default) 27 | - ConfigCollector: Display the values from the config files. (disabled by default) 28 | 29 | Bootstraps the following collectors for Laravel: 30 | - LogCollector: Show all Log messages 31 | - SwiftMailCollector and SwiftLogCollector for Mail 32 | 33 | And the default collectors: 34 | - PhpInfoCollector 35 | - MessagesCollector 36 | - TimeDataCollector (With Booting and Application timing) 37 | - MemoryCollector 38 | - ExceptionsCollector 39 | 40 | It also provides a Facade interface for easy logging Messages, Exceptions and Time 41 | 42 | ## Installation 43 | 44 | Require this package with composer: 45 | 46 | ```shell 47 | composer require barryvdh/laravel-debugbar 48 | ``` 49 | 50 | After updating composer, add the ServiceProvider to the providers array in config/app.php 51 | 52 | > Laravel 5.5 uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider 53 | 54 | > If you use a catch-all/fallback route, make sure you load the Debugbar ServiceProvider before your own App ServiceProviders. 55 | 56 | ### Laravel 5.x: 57 | 58 | ```php 59 | Barryvdh\Debugbar\ServiceProvider::class, 60 | ``` 61 | 62 | If you want to use the facade to log messages, add this to your facades in app.php: 63 | 64 | ```php 65 | 'Debugbar' => Barryvdh\Debugbar\Facade::class, 66 | ``` 67 | 68 | The profiler is enabled by default, if you have app.debug=true. You can override that in the config (`debugbar.enabled`). See more options in `config/debugbar.php` 69 | 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. 70 | 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) 71 | 72 | Copy the package config to your local config with the publish command: 73 | 74 | ```shell 75 | php artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider" 76 | ``` 77 | 78 | ### Lumen: 79 | 80 | For Lumen, register a different Provider in `bootstrap/app.php`: 81 | 82 | ```php 83 | if (env('APP_DEBUG')) { 84 | $app->register(Barryvdh\Debugbar\LumenServiceProvider::class); 85 | } 86 | ``` 87 | 88 | To change the configuration, copy the file to your config folder and enable it: 89 | 90 | ```php 91 | $app->configure('debugbar'); 92 | ``` 93 | 94 | ## Usage 95 | 96 | You can now add messages using the Facade (when added), using the PSR-3 levels (debug, info, notice, warning, error, critical, alert, emergency): 97 | 98 | ```php 99 | Debugbar::info($object); 100 | Debugbar::error('Error!'); 101 | Debugbar::warning('Watch out…'); 102 | Debugbar::addMessage('Another message', 'mylabel'); 103 | ``` 104 | 105 | And start/stop timing: 106 | 107 | ```php 108 | Debugbar::startMeasure('render','Time for rendering'); 109 | Debugbar::stopMeasure('render'); 110 | Debugbar::addMeasure('now', LARAVEL_START, microtime(true)); 111 | Debugbar::measure('My long operation', function() { 112 | // Do something… 113 | }); 114 | ``` 115 | 116 | Or log exceptions: 117 | 118 | ```php 119 | try { 120 | throw new Exception('foobar'); 121 | } catch (Exception $e) { 122 | Debugbar::addThrowable($e); 123 | } 124 | ``` 125 | 126 | There are also helper functions available for the most common calls: 127 | 128 | ```php 129 | // All arguments will be dumped as a debug message 130 | debug($var1, $someString, $intValue, $object); 131 | 132 | start_measure('render','Time for rendering'); 133 | stop_measure('render'); 134 | add_measure('now', LARAVEL_START, microtime(true)); 135 | measure('My long operation', function() { 136 | // Do something… 137 | }); 138 | ``` 139 | 140 | If you want you can add your own DataCollectors, through the Container or the Facade: 141 | 142 | ```php 143 | Debugbar::addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages')); 144 | //Or via the App container: 145 | $debugbar = App::make('debugbar'); 146 | $debugbar->addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages')); 147 | ``` 148 | 149 | By default, the Debugbar is injected just before `