update v1.0.7.9 R.C.

This is a Release Candidate. We are still testing.
This commit is contained in:
Sujit Prasad
2016-08-03 20:04:36 +05:30
parent 8b6b924d09
commit ffa56a43cb
3830 changed files with 181529 additions and 495353 deletions

View File

@@ -0,0 +1,4 @@
/vendor
composer.phar
composer.lock
.DS_Store

View File

@@ -0,0 +1,19 @@
Copyright (C) 2013-2014 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.

View File

@@ -0,0 +1,86 @@
# Changelog for Laravel Debugbar
## 1.8.4 (2014-10-31)
- Add Redis/PDO storage options
## 1.8.3 (2014-11-23)
- Base EventCollector on TimeData Collector
## 1.8.2 (2014-11-18)
- Use XHR handler instead of jQuery handler
## 1.8.1 (2014-11-14)
- Fix compatability with Symfony 2.3 (Laravel 4.)
## 1.8.0 (2014-10-31)
- Fix L5 compatability
- add hints + explain options to QueryLogger
- update to Debugbar 1.10.x
- new ViewCollector layout with more information
## 1.7.7 (2014-09-15)
- Make it compatible with Laravel 5.0-dev
- Allow anonymous function as `enabled` setting (for IP checks etc)
- Escape query bindings, to prevent executing of scripts/html
## 1.7.6 (2014-09-12)
- Fix reflash bug
- Fix caching of debugbar assets
## 1.7.5 (2014-09-12)
- Reflash data for all debugbar requests
## 1.7.4 (2014-09-08)
- Rename assets routes to prevent Nginx conflicts
## 1.7.3 (2014-09-05)
- Add helper functions (debug(), add/start/stop_measure() and measure()
- Collect data on responses that are not redirect/ajax/html also.
## 1.7.2 (2014-09-04)
- Fix 4.0 compatibility (problem with Controller namespace)
- Give deprecation notice instead of publishing assets.
## 1.7.1 (2014-09-03)
- Deprecated `debugbar:publish` command in favor of AssetController
- Fixed issue with detecting absolute paths in Windows
## 1.7.0 (2014-09-03)
- Use AssetController instead of publishing assets to the public folder.
- Inline fonts + images to base64 Data-URI
- Use PSR-4 file structure
## 1.6.8 (2014-08-27)
- Change OpenHandler layout
- Add backtrace option for query origin
## 1.6.7 (2014-08-09)
- Add Twig extensions for better integration with rcrowe/TwigBridge
## 1.6.6 (2014-07-08)
- Check if Requests wantsJSON instead of only isXmlHttpRequest
- Make sure closure for timing is run, even when disabled
## 1.6.5 (2014-06-24)
- Add Laravel style
## 1.6.4 (2014-06-15)
- Work on non-UTF-8 handling

View File

@@ -0,0 +1,31 @@
{
"name": "barryvdh/laravel-debugbar",
"description": "PHP Debugbar integration for Laravel",
"keywords": ["laravel", "debugbar", "profiler", "debug", "webprofiler"],
"license": "MIT",
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/support": "5.1.*|5.2.*",
"symfony/finder": "~2.7|~3.0",
"maximebf/debugbar": "~1.11.0"
},
"autoload": {
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Debugbar Settings
|--------------------------------------------------------------------------
|
| Debugbar is enabled by default, when debug is set to true in app.php.
| You can override the value by setting enable to true or false instead of null.
|
*/
'enabled' => null,
/*
|--------------------------------------------------------------------------
| 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.
|
*/
'storage' => array(
'enabled' => true,
'driver' => 'file', // redis, file, pdo, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '' // Instance of StorageInterface for custom driver
),
/*
|--------------------------------------------------------------------------
| 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 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' => 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.
|
*/
'capture_ajax' => true,
/*
|--------------------------------------------------------------------------
| 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' => false,
/*
|--------------------------------------------------------------------------
| DataCollectors
|--------------------------------------------------------------------------
|
| Enable/disable DataCollectors
|
*/
'collectors' => array(
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
'memory' => true, // Memory usage
'exceptions' => true, // Exception displayer
'log' => true, // Logs from Monolog (merged in messages if enabled)
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'laravel' => false, // Laravel version and environment
'events' => false, // All events fired
'default_request' => false, // Regular or special Symfony request logger
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'logs' => false, // Add the latest log messages
'files' => false, // Show the included files
'config' => false, // Display config settings
'auth' => false, // Display Laravel authentication status
'gate' => false, // Display Laravel Gate checks
'session' => true, // Display session data
),
/*
|--------------------------------------------------------------------------
| Extra options
|--------------------------------------------------------------------------
|
| Configure some DataCollectors
|
*/
'options' => array(
'auth' => array(
'show_name' => false, // Also show the users name/email in the debugbar
),
'db' => array(
'with_params' => true, // Render SQL with the parameters substituted
'timeline' => false, // Add the queries to the timeline
'backtrace' => false, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files.
'explain' => array( // EXPERIMENTAL: Show EXPLAIN output on queries
'enabled' => false,
'types' => array('SELECT'), // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
),
'hints' => true, // Show hints for common mistakes
),
'mail' => array(
'full_log' => false
),
'views' => array(
'data' => false, //Note: Can slow down the application, because the data can be quite large..
),
'route' => array(
'label' => true // show complete route on bar
),
'logs' => array(
'file' => null
),
),
/*
|--------------------------------------------------------------------------
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| Usually, the debugbar is added just before <body>, 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' => 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' => '_debugbar',
);

View File

@@ -0,0 +1,194 @@
## Laravel Debugbar
[![Packagist License](https://poser.pugx.org/barryvdh/laravel-debugbar/license.png)](http://choosealicense.com/licenses/mit/)
[![Latest Stable Version](https://poser.pugx.org/barryvdh/laravel-debugbar/version.png)](https://packagist.org/packages/barryvdh/laravel-debugbar)
[![Total Downloads](https://poser.pugx.org/barryvdh/laravel-debugbar/d/total.png)](https://packagist.org/packages/barryvdh/laravel-debugbar)
### For Laravel 4, please use the [1.8 branch](https://github.com/barryvdh/laravel-debugbar/tree/1.8)!
This is a package to integrate [PHP Debug Bar](http://phpdebugbar.com/) with Laravel 5.
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 (jQuery) Ajax Requests. (Shown in a dropdown)
Read [the documentation](http://phpdebugbar.com/docs/) for more configuration options.
![Screenshot](https://cloud.githubusercontent.com/assets/973269/4270452/740c8c8c-3ccb-11e4-8d9a-5a9e64f19351.png)
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.
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)
Bootstraps the following collectors for Laravel:
- LogCollector: Show all Log messages
- SwiftMailCollector and SwiftLogCollector for Mail
And the default collectors:
- PhpInfoCollector
- MessagesCollector
- TimeDataCollector (With Booting and Application timing)
- MemoryCollector
- ExceptionsCollector
It also provides a Facade interface for easy logging Messages, Exceptions and Time
## Installation
Require this package with composer:
```
composer require barryvdh/laravel-debugbar
```
After updating composer, add the ServiceProvider to the providers array in config/app.php
> If you use a catch-all/fallback route, make sure you load the Debugbar ServiceProvider before your own App ServiceProviders.
### Laravel 5.x:
```
Barryvdh\Debugbar\ServiceProvider::class,
```
If you want to use the facade to log messages, add this to your facades in app.php:
```
'Debugbar' => Barryvdh\Debugbar\Facade::class,
```
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`
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 of 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:
```
php artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider"
```
### Lumen:
For Lumen, register a different Provider in `bootstrap/app.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:
```
$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::addException($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);
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 `</body>`. 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.
## 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.
```
{{ 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.
```
{% stopwatch "foo" %}
…some things that gets timed
{% endstopwatch %}
```

View File

@@ -0,0 +1,30 @@
<?php namespace Barryvdh\Debugbar\Console;
use DebugBar\DebugBar;
use Illuminate\Console\Command;
class ClearCommand extends Command
{
protected $name = 'debugbar:clear';
protected $description = 'Clear the Debugbar Storage';
protected $debugbar;
public function __construct(DebugBar $debugbar)
{
$this->debugbar = $debugbar;
parent::__construct();
}
public function fire()
{
$this->debugbar->boot();
if ($storage = $this->debugbar->getStorage()) {
$storage->clear();
$this->info('Debugbar Storage cleared!');
} else {
$this->error('No Debugbar Storage found..');
}
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Barryvdh\Debugbar\Console;
use Illuminate\Console\Command;
/**
* Publish the Debugbar assets to the public directory
*
* @author Barry vd. Heuvel <barryvdh@gmail.com>
* @deprecated No longer needed because of the AssetController
*/
class PublishCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'debugbar:publish';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish the Debugbar assets';
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$this->info(
'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.'
);
}
}

View File

@@ -0,0 +1,58 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Illuminate\Http\Response;
class AssetController extends BaseController
{
/**
* Return the javascript for the Debugbar
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function js()
{
$renderer = $this->debugbar->getJavascriptRenderer();
$content = $renderer->dumpAssetsToString('js');
$response = new Response(
$content, 200, array(
'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, array(
'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;
}
}

View File

@@ -0,0 +1,38 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Routing\Controller;
use Illuminate\Http\Request;
if (class_exists('Illuminate\Routing\Controller')) {
class BaseController extends Controller
{
protected $debugbar;
public function __construct(Request $request, LaravelDebugbar $debugbar)
{
$this->debugbar = $debugbar;
if ($request->hasSession()){
$request->session()->reflash();
}
}
}
} else {
class BaseController
{
protected $debugbar;
public function __construct(Request $request, LaravelDebugbar $debugbar)
{
$this->debugbar = $debugbar;
if ($request->hasSession()){
$request->session()->reflash();
}
}
}
}

View File

@@ -0,0 +1,59 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Barryvdh\Debugbar\Support\Clockwork\Converter;
use DebugBar\OpenHandler;
use Illuminate\Http\Response;
class OpenHandlerController extends BaseController
{
public function handle()
{
$debugbar = $this->debugbar;
if (!$debugbar->isEnabled()) {
$this->app->abort('500', 'Debugbar is not enabled');
}
$openHandler = new OpenHandler($debugbar);
$data = $openHandler->handle(null, false, false);
return new Response(
$data, 200, array(
'Content-Type' => 'application/json'
)
);
}
/**
* Return Clockwork output
*
* @param $id
* @return mixed
* @throws \DebugBar\DebugBarException
*/
public function clockwork($id)
{
$request = [
'op' => 'get',
'id' => $id,
];
$debugbar = $this->debugbar;
if (!$debugbar->isEnabled()) {
$this->app->abort('500', 'Debugbar is not enabled');
}
$openHandler = new OpenHandler($debugbar);
$data = $openHandler->handle($request, false, false);
// Convert to Clockwork
$converter = new Converter();
$output = $converter->convert(json_decode($data, true));
return response()->json($output);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Contracts\Support\Arrayable;
/**
* Collector for Laravel's Auth provider
*/
class AuthCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Auth\AuthManager */
protected $auth;
/** @var bool */
protected $showName = false;
/**
* @param \Illuminate\Auth\AuthManager $auth
*/
public function __construct($auth)
{
$this->auth = $auth;
}
/**
* Set to show the users name/email
* @param bool $showName
*/
public function setShowName($showName)
{
$this->showName = (bool) $showName;
}
/**
* @{inheritDoc}
*/
public function collect()
{
try {
$user = $this->auth->user();
} catch (\Exception $e) {
$user = null;
}
return $this->getUserInformation($user);
}
/**
* Get displayed user information
* @param \Illuminate\Auth\UserInterface $user
* @return array
*/
protected function getUserInformation($user = null)
{
// Defaults
if (is_null($user)) {
return array(
'name' => 'Guest',
'user' => array('guest' => true),
);
}
// The default auth identifer is the ID number, which isn't all that
// useful. Try username and email.
$identifier = $user->getAuthIdentifier();
if (is_numeric($identifier)) {
try {
if ($user->username) {
$identifier = $user->username;
} elseif ($user->email) {
$identifier = $user->email;
}
} catch (\Exception $e) {
}
}
return array(
'name' => $identifier,
'user' => $user instanceof Arrayable ? $user->toArray() : $user,
);
}
/**
* @{inheritDoc}
*/
public function getName()
{
return 'auth';
}
/**
* @{inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
'auth' => array(
'icon' => 'lock',
'widget' => 'PhpDebugBar.Widgets.VariableListWidget',
'map' => 'auth.user',
'default' => '{}'
)
);
if ($this->showName) {
$widgets['auth.name'] = array(
'icon' => 'user',
'tooltip' => 'Auth status',
'map' => 'auth.name',
'default' => '',
);
}
return $widgets;
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
class EventCollector extends TimeDataCollector
{
/** @var Dispatcher */
protected $events;
/** @var ValueExporter */
protected $exporter;
public function __construct($requestStartTime = null)
{
parent::__construct($requestStartTime);
$this->exporter = new ValueExporter();
}
public function onWildcardEvent()
{
$name = $this->events->firing();
$time = microtime(true);
// Get the arguments passed to the event
$params = $this->prepareParams(func_get_args());
// 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()), '/');
$listener = $reflector->getName() . ' (' . $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine() . ')';
} else {
// Not sure if this is possible, but to prevent edge cases
$listener = $this->formatVar($listener);
}
$params['listeners.' . $i] = $listener;
}
$this->addMeasure($name, $time, $time, $params);
}
public function subscribe(Dispatcher $events)
{
$this->events = $events;
$events->listen('*', array($this, 'onWildcardEvent'));
}
protected function prepareParams($params)
{
$data = array();
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->exporter->exportValue($value), ENT_QUOTES, 'UTF-8', false);
}
return $data;
}
public function collect()
{
$data = parent::collect();
$data['nb_measures'] = count($data['measures']);
return $data;
}
public function getName()
{
return 'event';
}
public function getWidgets()
{
return array(
"events" => array(
"icon" => "tasks",
"widget" => "PhpDebugBar.Widgets.TimelineWidget",
"map" => "event",
"default" => "{}",
),
'events:badge' => array(
'map' => 'event.nb_measures',
'default' => 0,
),
);
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Contracts\Foundation\Application;
class FilesCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Contracts\Foundation\Application */
protected $app;
protected $basePath;
/**
* @param \Illuminate\Contracts\Foundation\Application $app
*/
public function __construct(Application $app = null)
{
$this->app = $app;
$this->basePath = base_path();
}
/**
* {@inheritDoc}
*/
public function collect()
{
$files = $this->getIncludedFiles();
$compiled = $this->getCompiledFiles();
$included = array();
$alreadyCompiled = array();
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[] = array(
'message' => "'" . $this->stripBasePath($file) . "',",
// Use PHP syntax so we can copy-paste to compile config file.
'is_string' => true,
);
} else {
$alreadyCompiled[] = array(
'message' => "* '" . $this->stripBasePath($file) . "',",
// Mark with *, so know they are compiled anyways.
'is_string' => true,
);
}
}
// First the included files, then those that are going to be compiled.
$messages = array_merge($included, $alreadyCompiled);
return array(
'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 array();
}
/**
* 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 array(
"$name" => array(
"icon" => "files-o",
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
"map" => "$name.messages",
"default" => "{}"
),
"$name:badge" => array(
"map" => "$name.count",
"default" => "null"
)
);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'files';
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\MessagesCollector;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Auth\Authenticatable;
/**
* Collector for Laravel's Auth provider
*/
class GateCollector extends MessagesCollector
{
/**
* @param Gate $gate
*/
public function __construct(Gate $gate)
{
parent::__construct('gate');
if (method_exists($gate, 'after')) {
$gate->after([$this, 'addCheck']);
}
}
public function addCheck(Authenticatable $user, $ability, $result, $arguments = [])
{
$label = $result ? 'success' : 'error';
$this->addMessage([
'ability' => $ability,
'result' => $result,
'user' => $user->getAuthIdentifier(),
'arguments' => $arguments,
], $label, false);
}
}

View File

@@ -0,0 +1,143 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Config;
/**
* Based on Illuminate\Foundation\Console\RoutesCommand for Taylor Otwell
* https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Console/RoutesCommand.php
*
*/
class IlluminateRouteCollector extends DataCollector implements Renderable
{
/**
* The router instance.
*
* @var \Illuminate\Routing\Router
*/
protected $router;
public function __construct(Router $router)
{
$this->router = $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 array();
}
$uri = head($route->methods()) . ' ' . $route->uri();
$action = $route->getAction();
$result = array(
'uri' => $uri ?: '-',
);
$result = array_merge($result, $action);
if (isset($action['controller']) && strpos($action['controller'], '@') !== false) {
list($controller, $method) = explode('@', $action['controller']);
if(class_exists($controller) && method_exists($controller, $method)) {
$reflector = new \ReflectionMethod($controller, $method);
}
unset($result['uses']);
} elseif (isset($action['uses']) && $action['uses'] instanceof \Closure) {
$reflector = new \ReflectionFunction($action['uses']);
$result['uses'] = $this->formatVar($result['uses']);
}
if (isset($reflector)) {
$filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/');
$result['file'] = $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine();
}
if ($middleware = $this->getMiddleware($route)) {
$result['middleware'] = $middleware;
}
return $result;
}
/**
* Get middleware
*
* @param \Illuminate\Routing\Route $route
* @return string
*/
protected function getMiddleware($route)
{
$middleware = array_keys($route->middleware());
return implode(', ', $middleware);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'route';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
"route" => array(
"icon" => "share",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "route",
"default" => "{}"
)
);
if (Config::get('debugbar.options.route.label', true)) {
$widgets['currentroute'] = array(
"icon" => "share",
"tooltip" => "Route",
"map" => "route.uri",
"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());
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Foundation\Application;
class LaravelCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Foundation\Application $app */
protected $app;
/**
* @param Application $app
*/
public function __construct(Application $app = null)
{
$this->app = $app;
}
/**
* {@inheritDoc}
*/
public function collect()
{
// Fallback if not injected
$app = $this->app ?: app();
return array(
"version" => $app::VERSION,
"environment" => $app->environment(),
"locale" => $app->getLocale(),
);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'laravel';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"version" => array(
"icon" => "github",
"tooltip" => "Version",
"map" => "laravel.version",
"default" => ""
),
"environment" => array(
"icon" => "desktop",
"tooltip" => "Environment",
"map" => "laravel.environment",
"default" => ""
),
"locale" => array(
"icon" => "flag",
"tooltip" => "Current locale",
"map" => "laravel.locale",
"default" => "",
),
);
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\MessagesCollector;
use Psr\Log\LogLevel;
use ReflectionClass;
class LogsCollector extends MessagesCollector
{
protected $lines = 124;
public function __construct($path = null, $name = 'logs')
{
parent::__construct($name);
$path = $path ?: $this->getLogsFile();
$this->getStorageLogs($path);
}
/**
* Get the path to the logs file
*
* @return string
*/
public function getLogsFile()
{
// default daily rotating logs (Laravel 5.0)
$path = storage_path() . '/logs/laravel-' . date('Y-m-d') . '.log';
// single file logs
if (!file_exists($path)) {
$path = storage_path() . '/logs/laravel.log';
}
return $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));
foreach ($this->getLogs($file) as $log) {
$this->addMessage($log['header'] . $log['stack'], $log['level'], 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 = array();
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}\].*/";
$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 = array();
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[] = array('level' => $ll, 'header' => $h[$i], 'stack' => $log_data[$i]);
}
}
}
}
$log = array_reverse($log);
return $log;
}
/**
* 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();
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
/**
* Collector for Laravel's Auth provider
*/
class MultiAuthCollector extends AuthCollector
{
/** @var array $guards */
protected $guards;
/**
* @param \Illuminate\Auth\AuthManager $auth
* @param array $guards
*/
public function __construct($auth, $guards)
{
parent::__construct($auth);
$this->guards = $guards;
}
/**
* @{inheritDoc}
*/
public function collect()
{
$data = [];
$names = '';
foreach($this->guards as $guardName) {
$user = $this->auth->guard($guardName)->user();
$data['guards'][$guardName] = $this->getUserInformation($user);
if(!is_null($user)) {
$names .= $guardName . ": " . $data['guards'][$guardName]['name'] . ', ';
}
}
foreach ($data['guards'] as $key => $var) {
if (!is_string($data['guards'][$key])) {
$data['guards'][$key] = $this->formatVar($var);
}
}
$data['names'] = rtrim($names, ', ');
return $data;
}
/**
* @{inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
"auth" => array(
"icon" => "lock",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "auth.guards",
"default" => "{}"
)
);
if ($this->showName) {
$widgets['auth.name'] = array(
'icon' => 'user',
'tooltip' => 'Auth status',
'map' => 'auth.names',
'default' => '',
);
}
return $widgets;
}
}

View File

@@ -0,0 +1,354 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\PDO\PDOCollector;
use DebugBar\DataCollector\TimeDataCollector;
/**
* Collects data about SQL statements executed with PDO
*/
class QueryCollector extends PDOCollector
{
protected $timeCollector;
protected $queries = array();
protected $renderSqlWithParams = false;
protected $findSource = false;
protected $explainQuery = false;
protected $explainTypes = array('SELECT'); // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
protected $showHints = false;
/**
* @param TimeDataCollector $timeCollector
*/
public function __construct(TimeDataCollector $timeCollector = null)
{
$this->timeCollector = $timeCollector;
}
/**
* 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;
}
/**
* Enable/disable finding the source
*
* @param bool $value
*/
public function setFindSource($value = true)
{
$this->findSource = (bool) $value;
}
/**
* 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;
if($types){
$this->explainTypes = $types;
}
}
/**
*
* @param string $query
* @param array $bindings
* @param float $time
* @param \Illuminate\Database\Connection $connection
*/
public function addQuery($query, $bindings, $time, $connection)
{
$explainResults = array();
$time = $time / 1000;
$endTime = microtime(true);
$startTime = $endTime - $time;
$hints = $this->performQueryAnalysis($query);
$pdo = $connection->getPdo();
$bindings = $connection->prepareBindings($bindings);
// Run EXPLAIN on this query (if needed)
if ($this->explainQuery && preg_match('/^('.implode($this->explainTypes).') /i', $query)) {
$statement = $pdo->prepare('EXPLAIN ' . $query);
$statement->execute($bindings);
$explainResults = $statement->fetchAll(\PDO::FETCH_CLASS);
}
$bindings = $this->checkBindings($bindings);
if (!empty($bindings) && $this->renderSqlWithParams) {
foreach ($bindings as $binding) {
$query = preg_replace('/\?/', $pdo->quote($binding), $query, 1);
}
}
$source = null;
if ($this->findSource) {
try {
$source = $this->findSource();
} catch (\Exception $e) {
}
}
$this->queries[] = array(
'query' => $query,
'bindings' => $this->escapeBindings($bindings),
'time' => $time,
'source' => $source,
'explain' => $explainResults,
'connection' => $connection->getDatabaseName(),
'hints' => $this->showHints ? $hints : null,
);
if ($this->timeCollector !== null) {
$this->timeCollector->addMeasure($query, $startTime, $endTime);
}
}
/**
* Check bindings for illegal (non UTF-8) strings, like Binary data.
*
* @param $bindings
* @return mixed
*/
protected function checkBindings($bindings)
{
foreach ($bindings as &$binding) {
if (is_string($binding) && !mb_check_encoding($binding, 'UTF-8')) {
$binding = '[BINARY DATA]';
}
}
return $bindings;
}
/**
* Make the bindings safe for outputting.
*
* @param array $bindings
* @return array
*/
protected function escapeBindings($bindings)
{
foreach ($bindings as &$binding) {
$binding = htmlentities($binding, ENT_QUOTES, 'UTF-8', false);
}
return $bindings;
}
/**
* 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)
{
$hints = array();
if (preg_match('/^\\s*SELECT\\s*`?[a-zA-Z0-9]*`?\\.?\\*/i', $query)) {
$hints[] = 'Use <code>SELECT *</code> only if you need all columns from table';
}
if (preg_match('/ORDER BY RAND()/i', $query)) {
$hints[] = '<code>ORDER BY RAND()</code> is slow, try to avoid if you can.
You can <a href="http://stackoverflow.com/questions/2663710/how-does-mysqls-order-by-rand-work" target="_blank">read this</a>
or <a href="http://stackoverflow.com/questions/1244555/how-can-i-optimize-mysqls-order-by-rand-function" target="_blank">this</a>';
}
if (strpos($query, '!=') !== false) {
$hints[] = 'The <code>!=</code> operator is not standard. Use the <code>&lt;&gt;</code> operator to test for inequality instead.';
}
if (stripos($query, 'WHERE') === false && preg_match('/^(SELECT) /i', $query)) {
$hints[] = 'The <code>SELECT</code> statement has no <code>WHERE</code> clause and could examine many more rows than intended';
}
if (preg_match('/LIMIT\\s/i', $query) && stripos($query, 'ORDER BY') === false) {
$hints[] = '<code>LIMIT</code> without <code>ORDER BY</code> 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: <code>' . $matches[1]. '</code>.
The predicate with this argument is not sargable and cannot use an index if one exists.';
}
return implode("<br />", $hints);
}
/**
* Use a backtrace to search for the origin of the query.
*/
protected function findSource()
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($traces as $trace) {
if (isset($trace['class']) && isset($trace['file']) && strpos(
$trace['file'],
DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR
) === false
) {
if (isset($trace['object']) && is_a($trace['object'], 'Twig_Template')) {
list($file, $line) = $this->getTwigInfo($trace);
} elseif (strpos($trace['file'], storage_path()) !== false) {
return 'Template file';
} else {
$file = $trace['file'];
$line = isset($trace['line']) ? $trace['line'] : '?';
}
return $this->normalizeFilename($file) . ':' . $line;
} elseif (isset($trace['function']) && $trace['function'] == 'Illuminate\Routing\{closure}') {
return 'Route binding';
}
}
}
/**
* 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 array($file, $templateLine);
}
}
}
return array($file, -1);
}
/**
* Shorten the path by removing the relative links and base dir
*
* @param string $path
* @return string
*/
protected function normalizeFilename($path)
{
if (file_exists($path)) {
$path = realpath($path);
}
return str_replace(base_path(), '', $path);
}
/**
* Reset the queries.
*/
public function reset()
{
$this->queries = array();
}
/**
* {@inheritDoc}
*/
public function collect()
{
$totalTime = 0;
$queries = $this->queries;
$statements = array();
foreach ($queries as $query) {
$totalTime += $query['time'];
$bindings = $query['bindings'];
if($query['hints']){
$bindings['hints'] = $query['hints'];
}
$statements[] = array(
'sql' => $this->formatSql($query['query']),
'params' => (object) $bindings,
'duration' => $query['time'],
'duration_str' => $this->formatDuration($query['time']),
'stmt_id' => $query['source'],
'connection' => $query['connection'],
);
//Add the results from the explain as new rows
foreach($query['explain'] as $explain){
$statements[] = array(
'sql' => ' - EXPLAIN #' . $explain->id . ': `' . $explain->table . '` (' . $explain->select_type . ')',
'params' => $explain,
'row_count' => $explain->rows,
'stmt_id' => $explain->id,
);
}
}
$data = array(
'nb_statements' => count($queries),
'nb_failed_statements' => 0,
'accumulated_duration' => $totalTime,
'accumulated_duration_str' => $this->formatDuration($totalTime),
'statements' => $statements
);
return $data;
}
/**
* Removes extra spaces at the beginning and end of the SQL query and its lines.
*
* @param string $sql
* @return string
*/
protected function formatSql($sql)
{
return trim(preg_replace("/\s*\n\s*/", "\n", $sql));
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'queries';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"queries" => array(
"icon" => "inbox",
"widget" => "PhpDebugBar.Widgets.SQLQueriesWidget",
"map" => "queries",
"default" => "[]"
),
"queries:badge" => array(
"map" => "queries.nb_statements",
"default" => 0
)
);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
class SessionCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SessionCollector
*
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($session)
{
$this->session = $session;
}
/**
* {@inheritdoc}
*/
public function collect()
{
$data = array();
foreach ($this->session->all() 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 array(
"session" => array(
"icon" => "archive",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "session",
"default" => "{}"
)
);
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
use Symfony\Component\HttpFoundation\Response;
/**
*
* Based on \Symfony\Component\HttpKernel\DataCollector\RequestDataCollector by Fabien Potencier <fabien@symfony.com>
*
*/
class SymfonyRequestCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Request $request */
protected $request;
/** @var \Symfony\Component\HttpFoundation\Request $response */
protected $response;
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SymfonyRequestCollector
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Request $response
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($request, $response, $session = null)
{
$this->request = $request;
$this->response = $response;
$this->session = $session;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'request';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"request" => array(
"icon" => "tags",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "request",
"default" => "{}"
)
);
}
/**
* {@inheritdoc}
*/
public function collect()
{
$request = $this->request;
$response = $this->response;
$responseHeaders = $response->headers->all();
$cookies = array();
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();
$data = array(
'format' => $request->getRequestFormat(),
'content_type' => $response->headers->get('Content-Type') ? $response->headers->get(
'Content-Type'
) : 'text/html',
'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '',
'status_code' => $statusCode,
'request_query' => $request->query->all(),
'request_request' => $request->request->all(),
'request_headers' => $request->headers->all(),
'request_server' => $request->server->all(),
'request_cookies' => $request->cookies->all(),
'response_headers' => $responseHeaders,
'path_info' => $request->getPathInfo(),
);
if ($this->session) {
$sessionAttributes = array();
foreach ($this->session->all() as $key => $value) {
$sessionAttributes[$key] = $value;
}
$data['session_attributes'] = $sessionAttributes;
}
foreach ($data['request_server'] as $key => $value) {
if (str_is('*_KEY', $key) || str_is('*_PASSWORD', $key)
|| str_is('*_SECRET', $key) || str_is('*_PW', $key)) {
$data['request_server'][$key] = '******';
}
}
if (isset($data['request_headers']['php-auth-pw'])) {
$data['request_headers']['php-auth-pw'] = '******';
}
if (isset($data['request_server']['PHP_AUTH_PW'])) {
$data['request_server']['PHP_AUTH_PW'] = '******';
}
foreach ($data as $key => $var) {
if (!is_string($data[$key])) {
$data[$key] = $this->formatVar($var);
}
}
return $data;
}
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;
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\Bridge\Twig\TwigCollector;
use Illuminate\View\View;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
class ViewCollector extends TwigCollector
{
protected $templates = array();
protected $collect_data;
/**
* Create a ViewCollector
*
* @param bool $collectData Collects view data when tru
*/
public function __construct($collectData = true)
{
$this->collect_data = $collectData;
$this->name = 'views';
$this->templates = array();
$this->exporter = new ValueExporter();
}
public function getName()
{
return 'views';
}
public function getWidgets()
{
return array(
'views' => array(
'icon' => 'leaf',
'widget' => 'PhpDebugBar.Widgets.TemplatesWidget',
'map' => 'views',
'default' => '[]'
),
'views:badge' => array(
'map' => 'views.nb_templates',
'default' => 0
)
);
}
/**
* Add a View instance to the Collector
*
* @param \Illuminate\View\View $view
*/
public function addView(View $view)
{
$name = $view->getName();
$path = $view->getPath();
if (!is_object($path)) {
if ($path) {
$path = ltrim(str_replace(base_path(), '', realpath($path)), '/');
}
if (substr($path, -10) == '.blade.php') {
$type = 'blade';
} else {
$type = pathinfo($path, PATHINFO_EXTENSION);
}
} else {
$type = get_class($view);
$path = '';
}
if (!$this->collect_data) {
$params = array_keys($view->getData());
} else {
$data = array();
foreach ($view->getData() as $key => $value) {
$data[$key] = $this->exporter->exportValue($value);
}
$params = $data;
}
$this->templates[] = array(
'name' => $path ? sprintf('%s (%s)', $name, $path) : $name,
'param_count' => count($params),
'params' => $params,
'type' => $type,
);
}
public function collect()
{
$templates = $this->templates;
return array(
'nb_templates' => count($templates),
'templates' => $templates,
);
}
}

View File

@@ -0,0 +1,12 @@
<?php namespace Barryvdh\Debugbar;
class Facade extends \Illuminate\Support\Facades\Facade
{
/**
* {@inheritDoc}
*/
protected static function getFacadeAccessor()
{
return 'debugbar';
}
}

View File

@@ -0,0 +1,122 @@
<?php namespace Barryvdh\Debugbar;
use DebugBar\DebugBar;
use DebugBar\JavascriptRenderer as BaseJavascriptRenderer;
use Illuminate\Routing\UrlGenerator;
/**
* {@inheritdoc}
*/
class JavascriptRenderer extends BaseJavascriptRenderer
{
// Use XHR handler by default, instead of jQuery
protected $ajaxHandlerBindToJquery = false;
protected $ajaxHandlerBindToXHR = true;
public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null)
{
parent::__construct($debugBar, $baseUrl, $basePath);
$this->cssFiles['laravel'] = __DIR__ . '/Resources/laravel-debugbar.css';
$this->cssVendors['fontawesome'] = __DIR__ . '/Resources/vendor/font-awesome/style.css';
}
/**
* Set the URL Generator
*
* @param \Illuminate\Routing\UrlGenerator $url
* @deprecated
*/
public function setUrlGenerator($url)
{
}
/**
* {@inheritdoc}
*/
public function renderHead()
{
$cssRoute = route('debugbar.assets.css', [
'v' => $this->getModifiedTime('css')
]);
$jsRoute = route('debugbar.assets.js', [
'v' => $this->getModifiedTime('js')
]);
$html = "<link rel='stylesheet' type='text/css' href='{$cssRoute}'>";
$html .= "<script type='text/javascript' src='{$jsRoute}'></script>";
if ($this->isJqueryNoConflictEnabled()) {
$html .= '<script type="text/javascript">jQuery.noConflict(true);</script>' . "\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 = array();
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";
}
}

View File

@@ -0,0 +1,880 @@
<?php namespace Barryvdh\Debugbar;
use Barryvdh\Debugbar\DataCollector\AuthCollector;
use Barryvdh\Debugbar\DataCollector\EventCollector;
use Barryvdh\Debugbar\DataCollector\FilesCollector;
use Barryvdh\Debugbar\DataCollector\GateCollector;
use Barryvdh\Debugbar\DataCollector\LaravelCollector;
use Barryvdh\Debugbar\DataCollector\LogsCollector;
use Barryvdh\Debugbar\DataCollector\MultiAuthCollector;
use Barryvdh\Debugbar\DataCollector\QueryCollector;
use Barryvdh\Debugbar\DataCollector\SessionCollector;
use Barryvdh\Debugbar\DataCollector\SymfonyRequestCollector;
use Barryvdh\Debugbar\DataCollector\ViewCollector;
use Barryvdh\Debugbar\Storage\FilesystemStorage;
use DebugBar\Bridge\MonologCollector;
use DebugBar\Bridge\SwiftMailer\SwiftLogCollector;
use DebugBar\Bridge\SwiftMailer\SwiftMailCollector;
use DebugBar\DataCollector\ConfigCollector;
use DebugBar\DataCollector\ExceptionsCollector;
use DebugBar\DataCollector\MemoryCollector;
use DebugBar\DataCollector\MessagesCollector;
use DebugBar\DataCollector\PhpInfoCollector;
use DebugBar\DataCollector\RequestDataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use Barryvdh\Debugbar\Support\Clockwork\ClockworkCollector;
use DebugBar\DebugBar;
use DebugBar\Storage\PdoStorage;
use DebugBar\Storage\RedisStorage;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Session\SessionManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Debug bar subclass which adds all without Request and with LaravelCollector.
* Rest is added in Service Provider
*
* @method void emergency($message)
* @method void alert($message)
* @method void critical($message)
* @method void error($message)
* @method void warning($message)
* @method void notice($message)
* @method void info($message)
* @method void debug($message)
* @method void log($message)
*/
class LaravelDebugbar extends DebugBar
{
/**
* The Laravel application instance.
*
* @var \Illuminate\Foundation\Application
*/
protected $app;
/**
* Normalized Laravel Version
*
* @var string
*/
protected $version;
/**
* True when booted.
*
* @var bool
*/
protected $booted = false;
/**
* True when enabled, false disabled an null for still unknown
*
* @var bool
*/
protected $enabled = null;
/**
* True when this is a Lumen application
*
* @var bool
*/
protected $is_lumen = false;
/**
* @param Application $app
*/
public function __construct($app = null)
{
if (!$app) {
$app = app(); //Fallback when $app is not given
}
$this->app = $app;
$this->version = $app->version();
$this->is_lumen = str_contains($this->version, 'Lumen');
}
/**
* 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 \Barryvdh\Debugbar\LaravelDebugbar $debugbar */
$debugbar = $this;
/** @var Application $app */
$app = $this->app;
$this->selectStorage($debugbar);
if ($this->shouldCollect('phpinfo', true)) {
$this->addCollector(new PhpInfoCollector());
}
if ($this->shouldCollect('messages', true)) {
$this->addCollector(new MessagesCollector());
}
if ($this->shouldCollect('time', true)) {
$this->addCollector(new TimeDataCollector());
if ( ! $this->isLumen()) {
$this->app->booted(
function () use ($debugbar) {
$startTime = $this->app['request']->server('REQUEST_TIME_FLOAT');
if ($startTime) {
$debugbar['time']->addMeasure('Booting', $startTime, microtime(true));
}
}
);
}
$debugbar->startMeasure('application', 'Application');
}
if ($this->shouldCollect('memory', true)) {
$this->addCollector(new MemoryCollector());
}
if ($this->shouldCollect('exceptions', true)) {
try {
$exceptionCollector = new ExceptionsCollector();
$exceptionCollector->setChainExceptions(
$this->app['config']->get('debugbar.options.exceptions.chain', true)
);
$this->addCollector($exceptionCollector);
} catch (\Exception $e) {
}
}
if ($this->shouldCollect('laravel', false)) {
$this->addCollector(new LaravelCollector($this->app));
}
if ($this->shouldCollect('default_request', false)) {
$this->addCollector(new RequestDataCollector());
}
if ($this->shouldCollect('events', false) && isset($this->app['events'])) {
try {
$startTime = $this->app['request']->server('REQUEST_TIME_FLOAT');
$eventCollector = new EventCollector($startTime);
$this->addCollector($eventCollector);
$this->app['events']->subscribe($eventCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add EventCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->shouldCollect('views', true) && isset($this->app['events'])) {
try {
$collectData = $this->app['config']->get('debugbar.options.views.data', true);
$this->addCollector(new ViewCollector($collectData));
$this->app['events']->listen(
'composing:*',
function ($view) use ($debugbar) {
$debugbar['views']->addView($view);
}
);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ViewCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if (!$this->isLumen() && $this->shouldCollect('route')) {
try {
$this->addCollector($this->app->make('Barryvdh\Debugbar\DataCollector\IlluminateRouteCollector'));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add RouteCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if (!$this->isLumen() && $this->shouldCollect('log', true)) {
try {
if ($this->hasCollector('messages')) {
$logger = new MessagesCollector('log');
$this['messages']->aggregate($logger);
$this->app['log']->listen(
function ($level, $message, $context) use ($logger) {
try {
$logMessage = (string) $message;
if (mb_check_encoding($logMessage, 'UTF-8')) {
$logMessage .= (!empty($context) ? ' ' . json_encode($context) : '');
} else {
$logMessage = "[INVALID UTF-8 DATA]";
}
} catch (\Exception $e) {
$logMessage = "[Exception: " . $e->getMessage() . "]";
}
$logger->addMessage(
'[' . date('H:i:s') . '] ' . "LOG.$level: " . $logMessage,
$level,
false
);
}
);
} else {
$this->addCollector(new MonologCollector($this->app['log']->getMonolog()));
}
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add LogsCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('db', true) && isset($this->app['db'])) {
$db = $this->app['db'];
if ($debugbar->hasCollector('time') && $this->app['config']->get(
'debugbar.options.db.timeline',
false
)
) {
$timeCollector = $debugbar->getCollector('time');
} else {
$timeCollector = null;
}
$queryCollector = new QueryCollector($timeCollector);
if ($this->app['config']->get('debugbar.options.db.with_params')) {
$queryCollector->setRenderSqlWithParams(true);
}
if ($this->app['config']->get('debugbar.options.db.backtrace')) {
$queryCollector->setFindSource(true);
}
if ($this->app['config']->get('debugbar.options.db.explain.enabled')) {
$types = $this->app['config']->get('debugbar.options.db.explain.types');
$queryCollector->setExplainSource(true, $types);
}
if ($this->app['config']->get('debugbar.options.db.hints', true)) {
$queryCollector->setShowHints(true);
}
$this->addCollector($queryCollector);
try {
$db->listen(
function ($query, $bindings = null, $time = null, $connectionName = null) use ($db, $queryCollector) {
// Laravel 5.2 changed the way some core events worked. We must account for
// the first argument being an "event object", where arguments are passed
// via object properties, instead of individual arguments.
if ( $query instanceof \Illuminate\Database\Events\QueryExecuted ) {
$bindings = $query->bindings;
$time = $query->time;
$connection = $query->connection;
$query = $query->sql;
} else {
$connection = $db->connection($connectionName);
}
$queryCollector->addQuery((string) $query, $bindings, $time, $connection);
}
);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add listen to Queries for Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->shouldCollect('mail', true) && class_exists('Illuminate\Mail\MailServiceProvider')) {
try {
$mailer = $this->app['mailer']->getSwiftMailer();
$this->addCollector(new SwiftMailCollector($mailer));
if ($this->app['config']->get('debugbar.options.mail.full_log') && $this->hasCollector(
'messages'
)
) {
$this['messages']->aggregate(new SwiftLogCollector($mailer));
}
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add MailCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('logs', false)) {
try {
$file = $this->app['config']->get('debugbar.options.logs.file');
$this->addCollector(new LogsCollector($file));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add LogsCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('files', false)) {
$this->addCollector(new FilesCollector($app));
}
if ($this->shouldCollect('auth', false)) {
try {
if($this->checkVersion('5.2')) {
// fix for compatibility with Laravel 5.2.*
$guards = array_keys($this->app['config']->get('auth.guards'));
$authCollector = new MultiAuthCollector($app['auth'], $guards);
} else {
$authCollector = new AuthCollector($app['auth']);
}
$authCollector->setShowName(
$this->app['config']->get('debugbar.options.auth.show_name')
);
$this->addCollector($authCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add AuthCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('gate', false)) {
try {
$gateCollector = $this->app->make('Barryvdh\Debugbar\DataCollector\GateCollector');
$this->addCollector($gateCollector);
} catch (\Exception $e){
// No Gate collector
}
}
$renderer = $this->getJavascriptRenderer();
$renderer->setIncludeVendors($this->app['config']->get('debugbar.include_vendors', true));
$renderer->setBindAjaxHandlerToXHR($app['config']->get('debugbar.capture_ajax', true));
$this->booted = true;
}
public function shouldCollect($name, $default = false)
{
return $this->app['config']->get('debugbar.collectors.' . $name, $default);
}
/**
* Starts a measure
*
* @param string $name Internal name, used to stop the measure
* @param string $label Public name
*/
public function startMeasure($name, $label = null)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->startMeasure($name, $label);
}
}
/**
* 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->addException($e);
}
}
}
/**
* Adds an exception to be profiled in the debug bar
*
* @param Exception $e
*/
public function addException(Exception $e)
{
if ($this->hasCollector('exceptions')) {
/** @var \DebugBar\DataCollector\ExceptionsCollector $collector */
$collector = $this->getCollector('exceptions');
$collector->addException($e);
}
}
/**
* Returns a JavascriptRenderer for this instance
*
* @param string $baseUrl
* @param string $basePathng
* @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)
{
$app = $this->app;
if ($app->runningInConsole() || !$this->isEnabled() || $this->isDebugbarRequest()) {
return $response;
}
// Show the Http Response Exception in the Debugbar, when available
if (isset($response->exception)) {
$this->addException($response->exception);
}
if ($this->shouldCollect('config', false)) {
try {
$configCollector = new ConfigCollector();
$configCollector->setData($app['config']->all());
$this->addCollector($configCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ConfigCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->app->bound(SessionManager::class)){
/** @var \Illuminate\Session\SessionManager $sessionManager */
$sessionManager = $app->make(SessionManager::class);
$httpDriver = new SymfonyHttpDriver($sessionManager, $response);
$this->setHttpDriver($httpDriver);
if ($this->shouldCollect('session') && ! $this->hasCollector('session')) {
try {
$this->addCollector(new SessionCollector($sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add SessionCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
} else {
$sessionManager = null;
}
if ($this->shouldCollect('symfony_request', true) && !$this->hasCollector('request')) {
try {
$this->addCollector(new SymfonyRequestCollector($request, $response, $sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add SymfonyRequestCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($app['config']->get('debugbar.clockwork') && ! $this->hasCollector('clockwork')) {
try {
$this->addCollector(new ClockworkCollector($request, $response, $sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ClockworkCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
$this->addClockworkHeaders($response);
}
if ($response->isRedirection()) {
try {
$this->stackData();
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif (
$this->isJsonRequest($request) &&
$app['config']->get('debugbar.capture_ajax', true)
) {
try {
$this->sendDataInHeaders(true);
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif (
($response->headers->has('Content-Type') &&
strpos($response->headers->get('Content-Type'), 'html') === false)
|| $request->getRequestFormat() !== 'html'
) {
try {
// Just collect + store data, don't inject it.
$this->collect();
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif ($app['config']->get('debugbar.inject', 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) {
$this->enabled = value($this->app['config']->get('debugbar.enabled'));
}
return $this->enabled;
}
/**
* Check if this is a request to the Debugbar OpenHandler
*
* @return bool
*/
protected function isDebugbarRequest()
{
return $this->app['request']->segment(1) == '_debugbar';
}
/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return bool
*/
protected function isJsonRequest(Request $request)
{
// If XmlHttpRequest, return true
if ($request->isXmlHttpRequest()) {
return true;
}
// Check if the request wants Json
$acceptable = $request->getAcceptableContentTypes();
return (isset($acceptable[0]) && $acceptable[0] == 'application/json');
}
/**
* Collects the data from the collectors
*
* @return array
*/
public function collect()
{
/** @var Request $request */
$request = $this->app['request'];
$this->data = array(
'__meta' => array(
'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)
{
$content = $response->getContent();
$renderer = $this->getJavascriptRenderer();
if ($this->getStorage()) {
$openHandlerUrl = route('debugbar.openhandler');
$renderer->setOpenHandlerUrl($openHandlerUrl);
}
$renderedContent = $renderer->renderHead() . $renderer->render();
$pos = strripos($content, '</body>');
if (false !== $pos) {
$content = substr($content, 0, $pos) . $renderedContent . substr($content, $pos);
} else {
$content = $content . $renderedContent;
}
$response->setContent($content);
}
/**
* Disable the Debugbar
*/
public function disable()
{
$this->enabled = false;
}
/**
* Adds a measure
*
* @param string $label
* @param float $start
* @param float $end
*/
public function addMeasure($label, $start, $end)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->addMeasure($label, $start, $end);
}
}
/**
* Utility function to measure the execution of a Closure
*
* @param string $label
* @param \Closure $closure
*/
public function measure($label, \Closure $closure)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->measure($label, $closure);
} else {
$closure();
}
}
/**
* Collect data in a CLI request
*
* @return array
*/
public function collectConsole()
{
if (!$this->isEnabled()) {
return;
}
$this->data = array(
'__meta' => array(
'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 = array('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)
{
$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');
$storage = new RedisStorage($this->app['redis']->connection($connection));
break;
case 'custom':
$class = $config->get('debugbar.storage.provider');
$storage = $this->app->make($class);
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', 1, true);
$response->headers->set('X-Clockwork-Path', $prefix .'/clockwork/', true);
}
}

View File

@@ -0,0 +1,57 @@
<?php namespace Barryvdh\Debugbar;
use Laravel\Lumen\Application;
class LumenServiceProvider extends ServiceProvider
{
/** @var Application */
protected $app;
/**
* Get the active router.
*
* @return Application
*/
protected function getRouter()
{
return $this->app;
}
/**
* 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]);
}
/**
* Check the App Debug status
*/
protected function checkAppDebug()
{
return env('APP_DEBUG');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('debugbar', 'command.debugbar.clear');
}
}

View File

@@ -0,0 +1,83 @@
<?php namespace Barryvdh\Debugbar\Middleware;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
class Debugbar
{
/**
* The App container
*
* @var Container
*/
protected $container;
/**
* The DebugBar instance
*
* @var LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new middleware instance.
*
* @param Container $container
* @param LaravelDebugbar $debugbar
*/
public function __construct(Container $container, LaravelDebugbar $debugbar)
{
$this->container = $container;
$this->debugbar = $debugbar;
}
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
try {
/** @var \Illuminate\Http\Response $response */
$response = $next($request);
} catch (Exception $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 Exception $e
* @return mixed
* @throws Exception
*/
protected function handleException($passable, Exception $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);
}
}

View File

@@ -0,0 +1,248 @@
div.phpdebugbar {
font-size: 13px;
font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
}
div.phpdebugbar-resize-handle {
border-bottom-color: #ddd;
}
div.phpdebugbar-closed,
div.phpdebugbar-minimized {
border-top-color: #ddd;
}
a.phpdebugbar-restore-btn {
border-right-color: #ddd !important;
}
div.phpdebugbar code, div.phpdebugbar pre {
background: none;
font-family: monospace;
font-size: 1em;
border: 0;
padding: 0;
}
div.phpdebugbar-body {
border-top: none;
}
div.phpdebugbar-header {
min-height: 30px;
line-height: 20px;
padding-left: 39px;
}
div.phpdebugbar-header,
a.phpdebugbar-restore-btn,
div.phpdebugbar-openhandler .phpdebugbar-openhandler-header {
background: #f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIcAAACHCAYAAAA850oKAAAMfElEQVR42u2dC5RVZRXH7zwQGRTEqUEDxMdEQSggWAYjomlKGOAyylJBs5AhYVgIKYQ5hrgIfPVQwXgYQ4lppTApqxdiZGqAYy8cHIyKfCGi9lCPqO3N3VOX6d57vn3u9zrn7LvWfy3E4dzvfPs35+xvf3vvL5NhfoLxw4eC5oKaQW2gN0HvirxTANpBdpqHdsuY+MCFu4AaQNtl0mOtp0EzQFW6wJgEek4mNlFCe14MKosKxeGgn8hEJlpo32ouGLWgZ2TyUiG0cy0HjOdl0lL3mumn8iqRJ0Z6nyDVxeBYJ5OUaj2Q10mFv5wok5NKvQ36d85/T8wXx3hWJirRQgC2glaBrgKNJf+yghg4GnQdvV4OyYVjukxeoiE4FlSuuCDpDxqT+xcS+UwZBJy9Eplsf/VP4xAUgWOOGMAbCH4LuhM0Gx/t5AeUZVx94MtXimFSDkEROAaA3hKjGYVhOWgC6BgvIQgBZLEY0YgeBr3XIzt3B50KmgZaBtpM+TiohYUCYN1kW96IBjiCoJxiGOeB5oPuB+1UGO/VhS54gRhTuwZaAAF/sUeA6kG3g35Dr7Ko0dKz8n1JGWijGFSrlmqEoBL0IdD5oAWgtYpPA672gPrmG8BA0D4xqja9AzotAgi9QaNBXwY1gVooJ9TWuHE11TnfwG4So2rV30A9FID4OOgh0F5Pxr1EnFM7WqMAR71v4y400AvFoNp1UQgcnUBb4gAHOqebxKBa9RpGQkMAeX8JKw07cNBAB4lzql2b2vMnisz7RO/hoIF+UwyqXV9R8D+a4gAHhltfEINqFe5jnRQy74dSqam/cEhuqTFhclXXkHkfZjm2EQkOcU4dRU/hZ2Z5DQcNcjDF3cWoejVW4Rdzvddw0EBvFWNq127QESHzXuOqAhG/fLgiHD1AL4pBtevBsAQgCq2/4wKOzYy09c+LMY3ocoW5/7oLOPAPlyrCUUb5AmJQvXo9LDGIwuuPuYADYxndFAEZIs6pET2Rd5v8wLk/jsLwVuFALRbn1LkWKcz9Z13AEYT2aDiwVcNLYkw3yUHwMytsw4FqZjw9vijGdJMchIXOoFbbcKDOZmQ4PybGdJYcNCQw3OYzHxzb0DNWBGSYi/W3JAfZ6Y6QKfA/ZjBeL0vEkM6SgzC00GwbjldUK7XEOTWqXyskB73HVOOdjI6aC/jZyWJIY5qnMP+nm4g9ZUKqnwYznNPNYkhjyUEfVrDBAptw7C8EZjw9PiLOqdHkoEMUKuIesQkH6jMMQL4jhjSmOxTm/2jyF63B8RdQF0U40Dl6WQxpTOMUbDDBJhyoaxhPjyliRKPJQUcq2OAOm3Bg57o+4pzGJjmoCvQnW3Cg7mI8PU4WIxrVNAUbnAB6wxYcqDoGICvEiMb0hkrXIPiZqczrYq3MMqqV7sOFYysjpbDGo3YCSVRLWHIQ2eG+Itd4KgeG3vn+MXdQX2A8Pb4kRjSqxYrbG7tyYFhC3YGOUDEgd0CYUthdEY4KSn8TQ5pLDjpdwQ7HKsGgAQ7UjYzrf1SMaFS7VDoHRW1EFmVAmFL4AXFOncc8fgyamddfcAgH6gHGd/QEvSoGLUkYqV5NQcb+gY1OyCUOeDTje+RMF57QeVxKK4m+rloel3IDrYyUQtw1fFKMXjA9AqPKN4PODRy3xKYVzqcyGm5sJuNL6wSE/waxsCEwHpt1dth2vAUYDgqyPdExJ+Tx9sQhHXCgL1HDGMiqFMLwKrVSmEO/IJ0zjj8whoNB44PsqdT/0hE+j5xrkDLnFGNB94IaqISgwgMYutJ+CwJxBagRdEOx7kEZjcGYIYyBNiQMhj+DvovRY9AHPTk+o5KCX2fSCqexgB4yDcf+lELV5RUN/A8xhgHHfjvVrfb2BIZy6sA0i8oVcF/rr0H2LJ3GEO0yDQc3pfDUmICwjyr78BE8Dj35jCcfrG0Osm2x8RW2p8D48WSFa0PgmE9lmEbhQFKrGDf3PQ9hwMSmDTShZwQhXf8sw4CnKUyiV9guxj1tUHh6fIP6hBiDA9XIuNkjbfabKKC99Bi+kvaBDvIIhmqMN9ArbHuJPuEKBUB+YBoOpO8oxgTMtAwDnghxN7ZaCrItvMs9ggGr5z9Br7AWzaUeL1PrqI5A4C/F57A3HD2ZbjMJB+pupldt0jnF7KaVoEtAtRmPPhR8GgX6WpDt9Wr6lM4nyGH9NBZK4TZ+x0UExT9aTMKBGsmYpFEal9QYov82OseRchjMwlBBnQnwZOmfkX9j+zVarzBOPL3hHxnDlJYzJm5NxNQBbGCHx16eYyyvoTQg8Fy2aZSut9eT0P3xCuM+P2N4IJMZk9gLaQ25Hp5F8nOso8H2SJyVkUUYsOrsUtpef97T5fkflQrVDA/iRdWUQhrL7DxO1P30nsRa3EoPYaihnExM1N0Ro0DeUtdwoG5iTHQn8pYx3Dsw8PBo7yB7zMhY0C2g38c87H+eazj2qSTB+voh7x2DYdeDHg2S1YN1b9Gwg6VBPBojGCopGDYP9MtSq8Zi0j2o0gUcL1HyCLZm6OcpDGUUDJtBkdLXEg5DPs03DQc+bv9OS0uMQC7qEImb4osPgcEw0GU0zt2SmbbfdqN0wvE65QK0p7pdqRC7P8ERDO+jRN2VlMUtqYr561+qo8LxCqWUYXRvRMcNKsoyCoNjuo2sKEqQPZcipdvE8Mpae8DTXdcGFb27JysAcpIBGKro6bWIsrilN5mO9g45f/k0aDno4qgbVBQdDINjVqnb4rRhVUfXezhwfIpiAjPjB7VP9ASdG1S0/RsGyCkRUuBOJLDWF8qWFmnTNiNJTtQ07qshcFyl2oSOrtmjSBqcyIyWmXIIxyg8Pc5kXrNeDGZXJjOa5obAgUvgnszI5e/EaDGHg4w5sgMMC6jabRMFy3BFsYZ5zdPEaMmAowvoW7Q/sZM24PJlbg1lXvdeMVzM4KA4x2BKGG6mxByltHnm9xzTMYVe5CEctEcxhVLaS9mj+CTze68T43kGR84exZ1UwKSzUUklYxxdyW8RI7qCw/IexdQIwTYxoi04aI/irJw9CptZT5hv2o3p4zwiRjQIB+1RXEOdZlzvUVzPfHrI6ZSG4fBpQLgK6cMERNpYpgQOVBMTjp4pTe1LJRz4mhjGBGS2GDMdcKA2Rsjv2C4GTQccqHFMQM4Rg6YHjlZu+SMlAolhUwAH6nImHP0t9LgQODzRbk4hNgFysxg2HXCgFjLhOIyirWLgFMCBgbG+TEAuE+OmAw7U6gjZ6lvFwOmA490IgbERYuDIQqf+wTjBsTFCMtL3xdCsPirrqWXV4Tb7c+jSeCYcvaQAKrS6/heUzVfjqnmLLmGIvBMTkLkCwf/tXf0qyHY47Om67ZO5Ql/1tk3PCBT7W1Y1YKonZ/LidpPYLegwJiDjUwoEdlW6ImC0G487HKhFEe7zpykBYgvVIh+no94kjhPwJtavMO9zQIHCqiQIW15eHTAOgk4yHKh7ItzrLQkCAss5sKG+uWPDYj5BdSnbd8EOyXiq0vEZG5+Yw7E5YHYoDLKH9MUNiIXcmmKBI6uJEfZdtnh+T1hNeCPo5MBle87AzZkfOoVlkVXMex7u4X08S10JhgeO+7VSpeMl+Ie2BDw9GiNMgA8nY6P/gwcBnBI4Pk6MgoXYH+4+Km7bjn+5LgFw4P5Jrwj1Li5OxsZjQvD4jY8Fjk+qplcsNsRZnmcu1mYoYJKEpd2qCJMz3dLYcOKbQKO5e0OGoBhE9dDFjh+dgz84NEEbStycD+wz9qSh8WDzmjXUpaCzB0D0CbItyFX7qg1u/4dPJQSQTREmrU5zSuMPg+zJTVUeANGdlu4bmAXnrbkXaUhQ5HCCZef0LfLbLuJmyhsCojNtNN5D2wyl7XwH2eZuzyUEDtyeP9iwc/o2beT9L2vKLRBltOJZSg6v3tAAtXNKytNjboQJnqqYJJM/a8oNFLiZiMeL7TQaVCT61iUEDlza9o7w29dUIElmBitJxiwQ2JdtpqHs+uawyNiOhAByV4SJryD/60e0xD/KEyAOBU0KsqdYm2rF1Rb6igyy7SNfSAggIzMx/QTZY1TH0HLYdN9VjHfUqg6sNiFPkBbXUcgIrzY8mfLWwN7Zc20B93wdesUkwQepjwEU/UDXOtjnQvtWl0LyhTFf5u7xYbmZZ25rKHz/uKMd4Em6bqQLOWpxjaTe5gkQ2Hn5Aiw1dJTP2kr1Kl1N3eBQ8uTX0WMwDvkg6OEPcgQEroDwcMLVgfphAbpC+W1kJ7TXidyx/wdIVCWo/YcgUwAAAABJRU5ErkJggg==) no-repeat 5px 3px;
}
a.phpdebugbar-close-btn {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAADDSURBVDhPxZCxCsIwFEUzuGdwCvQD7BIIcehUXDqVfGM/wsG/iG4ifkzMlRuSPLo4eeFBue8c6Iv6b4wxW557Hs0KnWa3seqDxTiOyVqbhmF4UND4Rofdruyce3rvE6bIRSo9GOI1McbLPM/vVm4l7MAQr0kpHaQsJTDE+6zrepym6SVFdNgR69M+hBTLzWCI10gJvydvBkO8ZlmWayvhJnkzGOI1+fBTCOHWPkT7YNiBId4HizxnCKy+r81uX/otSn0A7dioI/vYX+8AAAAASUVORK5CYII=) no-repeat 9px 6px;
color : #555;
}
a.phpdebugbar-open-btn {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAOCAYAAADJ7fe0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfdCgYULwwNKp3GAAAAGHRFWHRTb2Z0d2FyZQBwYWludC5uZXQgNC4wLjOM5pdQAAAA1UlEQVQ4T2OgKpCUlOQH4vdA/B8Jv4dKEwYgDdLS0v8NDQ3/GxsbwzGIj2YoGEO1oQJkjcRgqDZUAJKwsrJ6/v//fwdiMFQbKgAZkpGR0QR0ajy60wlgRJhBXSGhpqb2CNnZhHBkZORcqBEMDFBX2BsYGGBVjAv39vZaQ41gYIC6Ygs2hbiwr6/vdqA+DqgR4CiW19bWxqoYF87Ly4uFaocAZWXlydgU4sJ2dna3ga4QgGqHAC0trY/YFOPCKSkpDVCtCAA01QaIsaYJHFgCqpVagIEBACGlF2c3r4ViAAAAAElFTkSuQmCC) no-repeat 8px 6px;
}
div.phpdebugbar-header,
div.phpdebugbar-openhandler-header {
background-size: 21px auto;
background-position: 9px center;
}
a.phpdebugbar-restore-btn {
background-size: 20px;
width: 16px;
border-right-color: #ccc;
}
div.phpdebugbar-header > div > * {
font-size: 13px;
}
div.phpdebugbar-header .phpdebugbar-tab {
padding: 5px 6px;
}
div.phpdebugbar .phpdebugbar-header select {
padding: 1px 0;
}
dl.phpdebugbar-widgets-kvlist dt {
width: 200px;
min-height: 20px;
padding: 7px 5px;
line-height: 20px;
}
dl.phpdebugbar-widgets-kvlist dd {
min-height: 20px;
margin-left: 210px;
padding: 7px 5px;
line-height: 20px;
}
ul.phpdebugbar-widgets-timeline .phpdebugbar-widgets-measure {
height: 25px;
line-height: 25px;
border: none;
}
ul.phpdebugbar-widgets-timeline li:nth-child(even) {
background-color: #f9f9f9;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-value {
height: 15px;
background-color: #f4645f;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label,
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-collector {
top: 0px;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter {
background-color: #f4645f;
}
a.phpdebugbar-tab:hover,
span.phpdebugbar-indicator:hover,
a.phpdebugbar-indicator:hover,
a.phpdebugbar-close-btn:hover,
a.phpdebugbar-open-btn:hover {
background-color: #ebebeb;
transition: background-color .25s linear 0s, color .25s linear 0s;
}
a.phpdebugbar-tab.phpdebugbar-active {
background: #f4645f;
color: #fff;
}
a.phpdebugbar-tab.phpdebugbar-active span.phpdebugbar-badge {
background-color: white;
color: #f4645f;
}
a.phpdebugbar-tab span.phpdebugbar-badge {
vertical-align: 0px;
padding: 2px 6px;
background: #f4645f;
font-size: 12px;
color: #fff;
border-radius: 10px;
}
div.phpdebugbar-openhandler .phpdebugbar-openhandler-header {
background-size: 20px;
}
div.phpdebugbar-openhandler a {
color: #555;
}
div.phpdebugbar-openhandler table {
table-layout: fixed;
}
div.phpdebugbar-openhandler table td,
div.phpdebugbar-openhandler table th {
text-align: left;
}
div.phpdebugbar-openhandler table td a {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.phpdebugbar-indicator span.phpdebugbar-tooltip {
top: -36px;
border: none;
border-radius: 5px;
background: #f5f5f5;
font-size: 12px;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter {
margin: 0;
padding: 5px 8px;
border-radius: 0;
font-size: 12px;
transition: background-color .25s linear 0s, color .25s linear 0s;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter:hover {
background-color: #ad4844;
color: #fff;
}
.phpdebugbar-widgets-toolbar > .fa {
width: 25px;
font-size: 15px;
color: #555;
text-align: center;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item {
padding: 5px 10px;
border: none;
font-family: inherit;
overflow: visible;
display: flex;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-sql {
flex: 1 1 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-duration {
flex: 0 0 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-database {
flex: 0 0 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-params {
flex: 1 1 auto;
order: -1;
width: auto;
max-width: 200px;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(even) {
background-color: #f9f9f9;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error:before {
font-size: 12px;
color: #e74c3c;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-warning:before {
font-size: 12px;
color: #f1c40f;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error {
color: #e74c3c;
}
.phpdebugbar-widgets-value.phpdebugbar-widgets-warning {
color: #f1c40f;
}
div.phpdebugbar-widgets-sqlqueries .phpdebugbar-widgets-status {
background: none !important;
font-family: inherit !important;
font-weight: 400 !important;
}

View File

@@ -0,0 +1,5 @@
# Font Squirrel Font-face Generator Configuration File
# Upload this file to the generator to recreate the settings
# you used to create these fonts.
{"mode":"expert","formats":["woff"],"tt_instructor":"keep","fallback":"none","fallback_custom":"100","options_subset":"none","subset_custom":"","subset_custom_range":"","subset_ot_features":"all","subset_ot_features_list":"","base64":"Y","css_stylesheet":"style.css","filename_suffix":"","emsquare":"2048","spacing_adjustment":"0","rememberme":"Y"}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,174 @@
<?php namespace Barryvdh\Debugbar;
use Illuminate\Routing\Router;
use Illuminate\Session\SessionManager;
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$configPath = __DIR__ . '/../config/debugbar.php';
$this->mergeConfigFrom($configPath, 'debugbar');
$this->app->alias(
'DebugBar\DataFormatter\DataFormatter',
'DebugBar\DataFormatter\DataFormatterInterface'
);
$this->app->singleton('debugbar', function ($app) {
$debugbar = new LaravelDebugbar($app);
if ($app->bound(SessionManager::class)) {
$sessionManager = $app->make(SessionManager::class);
$httpDriver = new SymfonyHttpDriver($sessionManager);
$debugbar->setHttpDriver($httpDriver);
}
return $debugbar;
}
);
$this->app->alias('debugbar', 'Barryvdh\Debugbar\LaravelDebugbar');
$this->app['command.debugbar.clear'] = $this->app->share(
function ($app) {
return new Console\ClearCommand($app['debugbar']);
}
);
$this->commands(array('command.debugbar.clear'));
}
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$app = $this->app;
$configPath = __DIR__ . '/../config/debugbar.php';
$this->publishes([$configPath => $this->getConfigPath()], 'config');
// If enabled is null, set from the app.debug value
$enabled = $this->app['config']->get('debugbar.enabled');
if (is_null($enabled)) {
$enabled = $this->checkAppDebug();
}
if (! $enabled) {
return;
}
$routeConfig = [
'namespace' => 'Barryvdh\Debugbar\Controllers',
'prefix' => $this->app['config']->get('debugbar.route_prefix'),
];
$this->getRouter()->group($routeConfig, function($router) {
$router->get('open', [
'uses' => 'OpenHandlerController@handle',
'as' => 'debugbar.openhandler',
]);
$router->get('clockwork/{id}', [
'uses' => 'OpenHandlerController@clockwork',
'as' => 'debugbar.clockwork',
]);
$router->get('assets/stylesheets', [
'uses' => 'AssetController@css',
'as' => 'debugbar.assets.css',
]);
$router->get('assets/javascript', [
'uses' => 'AssetController@js',
'as' => 'debugbar.assets.js',
]);
});
if ($app->runningInConsole() || $app->environment('testing')) {
return;
}
/** @var LaravelDebugbar $debugbar */
$debugbar = $this->app['debugbar'];
$debugbar->enable();
$debugbar->boot();
$this->registerMiddleware('Barryvdh\Debugbar\Middleware\Debugbar');
}
/**
* Get the active router.
*
* @return Router
*/
protected function getRouter()
{
return $this->app['router'];
}
/**
* Get the config path
*
* @return string
*/
protected function getConfigPath()
{
return config_path('debugbar.php');
}
/**
* Publish the config file
*
* @param string $configPath
*/
protected function publishConfig($configPath)
{
$this->publishes([$configPath => config_path('debugbar.php')], 'config');
}
/**
* Register the Debugbar Middleware
*
* @param string $middleware
*/
protected function registerMiddleware($middleware)
{
$kernel = $this->app['Illuminate\Contracts\Http\Kernel'];
$kernel->pushMiddleware($middleware);
}
/**
* Check the App Debug status
*/
protected function checkAppDebug()
{
return $this->app['config']->get('app.debug');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('debugbar', 'command.debugbar.clear');
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Barryvdh\Debugbar\Storage;
use DebugBar\Storage\StorageInterface;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
/**
* Stores collected data into files
*/
class FilesystemStorage implements StorageInterface
{
protected $dirname;
protected $files;
protected $gc_lifetime = 24; // Hours to keep collected data;
protected $gc_probability = 5; // Probability of GC being run on a save request. (5/100)
/**
* @param \Illuminate\Filesystem\Filesystem $files The filesystem
* @param string $dirname Directories where to store files
*/
public function __construct($files, $dirname)
{
$this->files = $files;
$this->dirname = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
/**
* {@inheritDoc}
*/
public function save($id, $data)
{
if (!$this->files->isDirectory($this->dirname)) {
if ($this->files->makeDirectory($this->dirname, 0777, true)) {
$this->files->put($this->dirname . '.gitignore', "*\n!.gitignore");
} else {
throw new \Exception("Cannot create directory '$this->dirname'..");
}
}
try {
$this->files->put($this->makeFilename($id), json_encode($data));
} catch (\Exception $e) {
//TODO; error handling
}
// Randomly check if we should collect old files
if (rand(1, 100) <= $this->gc_probability) {
$this->garbageCollect();
}
}
/**
* Create the filename for the data, based on the id.
*
* @param $id
* @return string
*/
public function makeFilename($id)
{
return $this->dirname . basename($id) . ".json";
}
/**
* Delete files older then a certain age (gc_lifetime)
*/
protected function garbageCollect()
{
foreach (Finder::create()->files()->name('*.json')->date('< ' . $this->gc_lifetime . ' hour ago')->in(
$this->dirname
) as $file) {
$this->files->delete($file->getRealPath());
}
}
/**
* {@inheritDoc}
*/
public function get($id)
{
return json_decode($this->files->get($this->makeFilename($id)), true);
}
/**
* {@inheritDoc}
*/
public function find(array $filters = array(), $max = 20, $offset = 0)
{
// Sort by modified time, newest first
$sort = function (\SplFileInfo $a, \SplFileInfo $b) {
return strcmp($b->getMTime(), $a->getMTime());
};
// Loop through .json files, filter the metadata and stop when max is found.
$i = 0;
$results = array();
foreach (Finder::create()->files()->name('*.json')->in($this->dirname)->sort($sort) as $file) {
if ($i++ < $offset && empty($filters)) {
$results[] = null;
continue;
}
$data = json_decode($file->getContents(), true);
$meta = $data['__meta'];
unset($data);
if ($this->filter($meta, $filters)) {
$results[] = $meta;
}
if (count($results) >= ($max + $offset)) {
break;
}
}
return array_slice($results, $offset, $max);
}
/**
* Filter the metadata for matches.
*
* @param $meta
* @param $filters
* @return bool
*/
protected function filter($meta, $filters)
{
foreach ($filters as $key => $value) {
if (!isset($meta[$key]) || fnmatch($value, $meta[$key]) === false) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
public function clear()
{
foreach (Finder::create()->files()->name('*.json')->in($this->dirname) as $file) {
$this->files->delete($file->getRealPath());
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Barryvdh\Debugbar\Support\Clockwork;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
use Symfony\Component\HttpFoundation\Response;
/**
*
* Based on \Symfony\Component\HttpKernel\DataCollector\RequestDataCollector by Fabien Potencier <fabien@symfony.com>
*
*/
class ClockworkCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Request $request */
protected $request;
/** @var \Symfony\Component\HttpFoundation\Request $response */
protected $response;
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SymfonyRequestCollector
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Request $response
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($request, $response, $session = null)
{
$this->request = $request;
$this->response = $response;
$this->session = $session;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'clockwork';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return null;
}
/**
* {@inheritdoc}
*/
public function collect()
{
$request = $this->request;
$response = $this->response;
$data = array(
'getData' => $request->query->all(),
'postData' => $request->request->all(),
'headers' => $request->headers->all(),
'cookies' => $request->cookies->all(),
'uri' => $request->getRequestUri(),
'method' => $request->getMethod(),
'responseStatus' => $response->getStatusCode(),
);
if ($this->session) {
$sessionAttributes = array();
foreach ($this->session->all() as $key => $value) {
$sessionAttributes[$key] = $value;
}
$data['sessionData'] = $sessionAttributes;
}
if (isset($data['postData']['php-auth-pw'])) {
$data['postData']['php-auth-pw'] = '******';
}
if (isset($data['postData']['PHP_AUTH_PW'])) {
$data['postData']['PHP_AUTH_PW'] = '******';
}
return $data;
}
}

View File

@@ -0,0 +1,135 @@
<?php namespace Barryvdh\Debugbar\Support\Clockwork;
class Converter {
/**
* Convert the phpdebugbar data to Clockwork format.
*
* @param array $data
* @return array
*/
public function convert($data)
{
$meta = $data['__meta'];
// Default output
$output = [
'id' => $meta['id'],
'method' => $meta['method'],
'uri' => $meta['uri'],
'time' => $meta['utime'],
'headers' => [],
'cookies' => [],
'emailsData' => [],
'getData' => [],
'log' => [],
'postData' => [],
'sessionData' => [],
'timelineData' => [],
'viewsData' => [],
'controller' => null,
'responseTime' => null,
'responseStatus' => null,
'responseDuration' => 0,
];
if (isset($data['clockwork'])) {
$output = array_merge($output, $data['clockwork']);
}
if (isset($data['time'])) {
$time = $data['time'];
$output['time'] = $time['start'];
$output['responseTime'] = $time['end'];
$output['responseDuration'] = $time['duration'] * 1000;
foreach($time['measures'] as $measure) {
$output['timelineData'][] = [
'data' => [],
'description' => $measure['label'],
'duration' => $measure['duration'] * 1000,
'end' => $measure['end'],
'start' => $measure['start'],
'relative_start' => $measure['start'] - $time['start'],
];
}
}
if (isset($data['route'])) {
$route = $data['route'];
$controller = null;
if (isset($route['controller'])) {
$controller = $route['controller'];
} elseif (isset($route['uses'])) {
$controller = $route['uses'];
}
$output['controller'] = $controller;
list($method, $uri) = explode(' ', $route['uri'], 2);
$output['routes'][] = [
'action' => $controller,
'after' => isset($route['after']) ? $route['after'] : null,
'before' => isset($route['before']) ? $route['before'] : null,
'method' => $method,
'name' => isset($route['as']) ? $route['as'] : null,
'uri' => $uri,
];
}
if (isset($data['messages'])) {
foreach($data['messages']['messages'] as $message) {
$output['log'][] = [
'message' => $message['message'],
'time' => $message['time'],
'level' => $message['label'],
];
}
}
if (isset($data['queries'])) {
$queries = $data['queries'];
foreach($queries['statements'] as $statement){
$output['databaseQueries'][] = [
'query' => $statement['sql'],
'bindings' => $statement['params'],
'duration' => $statement['duration'] * 1000,
'connection' => $statement['connection']
];
}
$output['databaseDuration'] = $queries['accumulated_duration'] * 1000;
}
if (isset($data['views'])) {
foreach ($data['views']['templates'] as $view) {
$output['viewsData'][] = [
'description' => 'Rendering a view',
'duration' => 0,
'end' => 0,
'start' => 0,
'data' => [
'name' => $view['name'],
'data' => $view['params'],
],
];
}
}
if (isset($data['swiftmailer_mails'])) {
foreach($data['swiftmailer_mails']['mails'] as $mail) {
$output['emailsData'][] = [
'data' => [
'to' => $mail['to'],
'subject' => $mail['subject'],
'headers' => isset($mail['headers']) ? explode("\n", $mail['headers']) : null,
],
];
}
}
return $output;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Barryvdh\Debugbar;
use DebugBar\HttpDriverInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* HTTP driver for Symfony Request/Session
*/
class SymfonyHttpDriver implements HttpDriverInterface
{
/** @var \Symfony\Component\HttpFoundation\Session\Session */
protected $session;
/** @var \Symfony\Component\HttpFoundation\Response */
protected $response;
public function __construct($session, $response = null)
{
$this->session = $session;
$this->response = $response;
}
/**
* {@inheritDoc}
*/
public function setHeaders(array $headers)
{
if (!is_null($this->response)) {
$this->response->headers->add($headers);
}
}
/**
* {@inheritDoc}
*/
public function isSessionStarted()
{
if (!$this->session->isStarted()) {
$this->session->start();
}
return $this->session->isStarted();
}
/**
* {@inheritDoc}
*/
public function setSessionValue($name, $value)
{
$this->session->set($name, $value);
}
/**
* {@inheritDoc}
*/
public function hasSessionValue($name)
{
return $this->session->has($name);
}
/**
* {@inheritDoc}
*/
public function getSessionValue($name)
{
return $this->session->get($name);
}
/**
* {@inheritDoc}
*/
public function deleteSessionValue($name)
{
$this->session->remove($name);
}
}

View File

@@ -0,0 +1,88 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use Illuminate\Foundation\Application;
use Twig_Environment;
use Twig_Extension;
use Twig_SimpleFunction;
/**
* Access Laravels auth class in your Twig templates.
*/
class Debug extends Twig_Extension
{
/**
* @var \Barryvdh\Debugbar\LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new auth extension.
*
* @param \Illuminate\Foundation\Application $app
*/
public function __construct(Application $app)
{
if ($app->bound('debugbar')) {
$this->debugbar = $app['debugbar'];
} else {
$this->debugbar = null;
}
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'Laravel_Debugbar_Debug';
}
/**
* {@inheritDoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction(
'debug', [$this, 'debug'], array('needs_context' => true, 'needs_environment' => true)
),
);
}
/**
* Based on Twig_Extension_Debug / twig_var_dump
* (c) 2011 Fabien Potencier
*
* @param Twig_Environment $env
* @param $context
*/
public function debug(Twig_Environment $env, $context)
{
if (!$env->isDebug() || !$this->debugbar) {
return;
}
$count = func_num_args();
if (2 === $count) {
$data = array();
foreach ($context as $key => $value) {
if (is_object($value)) {
if (method_exists($value, 'toArray')) {
$data[$key] = $value->toArray();
} else {
$data[$key] = "Object (" . get_class($value) . ")";
}
} else {
$data[$key] = $value;
}
}
$this->debugbar->addMessage($data);
} else {
for ($i = 2; $i < $count; $i++) {
$this->debugbar->addMessage(func_get_arg($i));
}
}
return;
}
}

View File

@@ -0,0 +1,84 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use DebugBar\DataFormatter\DataFormatterInterface;
use Twig_Environment;
use Twig_Extension;
use Twig_SimpleFunction;
/**
* Dump variables using the DataFormatter
*/
class Dump extends Twig_Extension
{
/**
* @var \DebugBar\DataFormatter\DataFormatter
*/
protected $formatter;
/**
* Create a new auth extension.
*
* @param \DebugBar\DataFormatter\DataFormatterInterface $formatter
*/
public function __construct(DataFormatterInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'Laravel_Debugbar_Dump';
}
/**
* {@inheritDoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction(
'dump', [$this, 'dump'], array('is_safe' => ['html'], 'needs_context' => true, 'needs_environment' => true)
),
);
}
/**
* Based on Twig_Extension_Debug / twig_var_dump
* (c) 2011 Fabien Potencier
*
* @param Twig_Environment $env
* @param $context
*
* @return string
*/
public function dump(Twig_Environment $env, $context)
{
$output = '';
$count = func_num_args();
if (2 === $count) {
$data = array();
foreach ($context as $key => $value) {
if (is_object($value)) {
if (method_exists($value, 'toArray')) {
$data[$key] = $value->toArray();
} else {
$data[$key] = "Object (" . get_class($value) . ")";
}
} else {
$data[$key] = $value;
}
}
$output .= $this->formatter->formatVar($data);
} else {
for ($i = 2; $i < $count; $i++) {
$output .= $this->formatter->formatVar(func_get_arg($i));
}
}
return '<pre>'.$output.'</pre>';
}
}

View File

@@ -0,0 +1,56 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use Barryvdh\Debugbar\Twig\TokenParser\StopwatchTokenParser;
use Illuminate\Foundation\Application;
use Twig_Extension;
/**
* Access Laravels auth class in your Twig templates.
* Based on Symfony\Bridge\Twig\Extension\StopwatchExtension
*/
class Stopwatch extends Twig_Extension
{
/**
* @var \Barryvdh\Debugbar\LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new auth extension.
*
* @param \Illuminate\Foundation\Application $app
*/
public function __construct(Application $app)
{
if ($app->bound('debugbar')) {
$this->debugbar = $app['debugbar'];
} else {
$this->debugbar = null;
}
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'stopwatch';
}
public function getTokenParsers()
{
return array(
/*
* {% stopwatch foo %}
* Some stuff which will be recorded on the timeline
* {% endstopwatch %}
*/
new StopwatchTokenParser($this->debugbar !== null),
);
}
public function getDebugbar()
{
return $this->debugbar;
}
}

View File

@@ -0,0 +1,37 @@
<?php namespace Barryvdh\Debugbar\Twig\Node;
/**
* Represents a stopwatch node. Based on Symfony\Bridge\Twig\Node\StopwatchNode
*
* @author Wouter J <wouter@wouterj.nl>
*/
class StopwatchNode extends \Twig_Node
{
public function __construct(
\Twig_NodeInterface $name,
$body,
\Twig_Node_Expression_AssignName $var,
$lineno = 0,
$tag = null
) {
parent::__construct(array('body' => $body, 'name' => $name, 'var' => $var), array(), $lineno, $tag);
}
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('var'))
->raw(' = ')
->subcompile($this->getNode('name'))
->write(";\n")
->write("\$this->env->getExtension('stopwatch')->getDebugbar()->startMeasure(")
->subcompile($this->getNode('var'))
->raw(");\n")
->subcompile($this->getNode('body'))
->write("\$this->env->getExtension('stopwatch')->getDebugbar()->stopMeasure(")
->subcompile($this->getNode('var'))
->raw(");\n");
}
}

View File

@@ -0,0 +1,55 @@
<?php namespace Barryvdh\Debugbar\Twig\TokenParser;
use Barryvdh\Debugbar\Twig\Node\StopwatchNode;
/**
* Token Parser for the stopwatch tag. Based on Symfony\Bridge\Twig\TokenParser\StopwatchTokenParser;
*
* @author Wouter J <wouter@wouterj.nl>
*/
class StopwatchTokenParser extends \Twig_TokenParser
{
protected $debugbarAvailable;
public function __construct($debugbarAvailable)
{
$this->debugbarAvailable = $debugbarAvailable;
}
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
// {% stopwatch 'bar' %}
$name = $this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
// {% endstopwatch %}
$body = $this->parser->subparse(array($this, 'decideStopwatchEnd'), true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
if ($this->debugbarAvailable) {
return new StopwatchNode(
$name,
$body,
new \Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()),
$lineno,
$this->getTag()
);
}
return $body;
}
public function getTag()
{
return 'stopwatch';
}
public function decideStopwatchEnd(\Twig_Token $token)
{
return $token->test('endstopwatch');
}
}

View File

@@ -0,0 +1,81 @@
<?php
if (!function_exists('debugbar')) {
/**
* Get the Debugbar instance
*
* @return \Barryvdh\Debugbar\LaravelDebugbar
*/
function debugbar()
{
return app('debugbar');
}
}
if (!function_exists('debug')) {
/**
* Adds one or more messages to the MessagesCollector
*
* @param mixed ...$value
* @return string
*/
function debug($value)
{
$debugbar = app('debugbar');
foreach (func_get_args() as $value) {
$debugbar->addMessage($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)
{
app('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)
{
app('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)
{
app('debugbar')->addMeasure($label, $start, $end);
}
}
if (!function_exists('measure')) {
/**
* Utility function to measure the execution of a Closure
*
* @param string $label
* @param \Closure $closure
*/
function measure($label, \Closure $closure)
{
app('debugbar')->measure($label, $closure);
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePhpdebugbarStorageTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('phpdebugbar', function (Blueprint $table) {
$table->string('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.
*
* @return void
*/
public function down()
{
Schema::drop('phpdebugbar');
}
}

View File

@@ -1,78 +0,0 @@
## Filemanager ##
This package is to add [simogeo/Filemanager](https://github.com/simogeo/Filemanager) to Laravel 5.2 installation.
### Installation ###
Add Filemanager to your composer.json file to require Filemanager :
```
require : {
"laravel/framework": "5.2.*",
"bestmomo/filemanager": "1.1.*"
}
```
Update Composer :
```
composer update
```
The next required step is to add the service provider to config/app.php :
```
Bestmomo\Filemanager\FilemanagerServiceProvider::class,
```
### Publish ###
The last required step is to publish assets in your application with :
```
php artisan vendor:publish
```
### User model ###
For Filemanager php connector you must create at least this function in user model :
```
public function accessMediasAll()
{
// return true for access to all medias
}
```
If you want some users access only to one folder add this function :
```
public function accessMediasFolder()
{
// return true for access to one folder
}
```
A folder with user{id} name will be created in filemanager/userfiles folder.
### Integration ###
You can now integrate Filemanager with any editor.
Simple example integration with CKEditor :
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CKEditor</title>
<script src="//cdn.ckeditor.com/4.5.3/standard/ckeditor.js"></script>
</head>
<body>
<textarea name="editor"></textarea>
<script>
CKEDITOR.replace( 'editor', {
filebrowserBrowseUrl: '{!! url('filemanager/index.html') !!}'
});
</script>
</body>
</html>
```

View File

@@ -1,27 +0,0 @@
{
"name": "bestmomo/filemanager",
"description": "To add filemanager to Laravel 5.1",
"homepage": "http://github.com/bestmomo/filemanager",
"license": "MIT",
"authors": [
{
"name":"Simon Georget",
"email":"simon@linea21.com",
"homepage":"http://www.empreinte-urbaine.eu",
"role": "Developer"
},
{
"name": "Bestmomo",
"email": "grandheretique@free.fr",
"homepage":"http://laravel.sillo.org"
}
],
"require": {
"php": ">=5.5.9"
},
"autoload": {
"psr-4": {
"Bestmomo\\Filemanager\\": "src/"
}
}
}

View File

@@ -1,6 +0,0 @@
<?php
return [
// needs to be set in filemanager.config.js too
'folder_path' => "filemanager/userfiles/"
];

View File

@@ -1 +0,0 @@
scripts/filemanager.config.js

View File

@@ -1,500 +0,0 @@
Filemanager
========================
FM is an open-source file manager released under MIT license. It is an alternative to elfinder or CKFinder.
Support
-------
Filemanager is under free license. If you want to support the filemanager development or just thank its main maintainer by paying a beer, you can make a donation by clicking the following button :
[![Donate](https://www.paypal.com/en_US/i/btn/x-click-but21.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2M5GWH9NLNEZL)
Main features
-------------
* A Filemanager relying on jquery.
* Available in more than 20 languages.
* [Highly customizable](https://github.com/simogeo/Filemanager/wiki/Filemanager-configuration-file)
* Can work as standalone application
* Easy integration with RTE like CKEditor, TinyMCE and so on.
* Easy integration with [colorbox jquery plugin](https://github.com/simogeo/Filemanager/wiki/How-to-use-the-filemanager-with-colorbox-%3F) or [HTML simple textfield](https://github.com/simogeo/Filemanager/wiki/How-to-use-the-filemanager-from-a-simple-textfield-%3F)
* Several computer language connectors available. **PHP is up-to-date**
* Ability to upload, delete, modify, download and move files
* Ability to create folders
* Support user permissions - based on session
* Handle system permissions
* Ability to pass config user file in URL
* Multiple uploads support - based on [dropzonejs](http://www.dropzonejs.com)
* Online text / code edition - based on [codeMirror](http://codemirror.net/)
* Online documents viewer - based on [viewerJS](http://viewerjs.org/)
* [Opening a given folder](https://github.com/simogeo/Filemanager/wiki/How-to-open-a-given-folder-different-from-root-folder-when-opening-the-filemanager%3F)
* [Opening exclusively a given folder](https://github.com/simogeo/Filemanager/wiki/How-to-open-%28exclusively%29-a-given-subfolder-%3F)
* [Passing parameters to the FM](https://github.com/simogeo/Filemanager/wiki/Passing-parameters-to-the-FM)
* [File types restriction](https://github.com/simogeo/Filemanager/wiki/Set-up-upload-restriction-on-file-type)
* Video and audio player relying on web browser capabilities
* Textbox Search filter
* Thumbnails generation
* Image auto-resize
* File size limit
* File exclusion based on name and patterns
* Images files only
* Prevent files overwriting (or not)
* Switch from list to grid view and vice-versa
* Copy direct file URL
* [CSS Themes](https://github.com/simogeo/Filemanager/wiki/Create-your-own-theme) - **Please, share your themes with others !**
* and more ...
Screenshot
-------------
![Filemanager Screenshot](http://i57.tinypic.com/35cqw74.png)
Documentation
-------------
Filemanager is highly documented on the [wiki pages](https://github.com/simogeo/Filemanager/wiki). API, see below.
Installation and Setup
----------------------
**Preamble**
Since many changes have been done recently, only PHP and MVC connectors are now available. You can try the latest version for others connectors, but with no warranty they implement all features and work correctly.
To use other connectors, please download v0.8 version from https://github.com/simogeo/Filemanager/archive/v0.8.zip
(PHP, ASHX, ASP, CFM, lasso, PL and JSP connectors are available)
A JSP/Java connector implementation is available at : https://github.com/th-schwarz/C5Connector.Java
---
**(1)** Check out a copy of the FileManager from the repository using Git :
git clone http://github.com/simogeo/Filemanager.git
or download the archive from Github : https://github.com/simogeo/Filemanager/archive/master.zip
You can place the FileManager anywhere within your web serving root directory.
**(2)** Make a copy of the default configuration file ("filemanager.config.js.default" located in the scripts directory), removing the '.default' from the end of the filename, and edit the options according to the following wiki page : https://github.com/simogeo/Filemanager/wiki/Filemanager-configuration-file
Having a look on configuration cases study may also be helpful to you : https://github.com/simogeo/Filemanager/wiki/Specify-user-folder%2C-configuration-cases
**(3a)** If you are integrating the FileManager with FCKEditor, open your fckconfig.js file and find the lines which specify what file browser to use for images, links, etc. Look toward the bottom of the file. You will need to change lines such as this:
```javascript
FCKConfig.ImageBrowser = false ;
FCKConfig.ImageBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Image&Connector=../../connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ;
```
...to this:
```javascript
FCKConfig.ImageBrowser = true ;
FCKConfig.ImageBrowserURL = '[Path to Filemanager]/index.html' ;
```
**(3b)** If you are integrating the FileManager with CKEditor 3.x or higher, simply set the URL when you configure your instance, like so:
```javascript
CKEDITOR.replace('instancename', {
filebrowserBrowseUrl: '[Path to Filemanager]/index.html',
...other configuration options...
});
```
If you want to use the **modal dialog mode** (instead of pop-up), please refer to [the dedicated wiki page](https://github.com/simogeo/Filemanager/wiki/How-to-open-the-Filemanager-from-CKEditor-in-a-modal-window-%3F).
**(3c)** If you are integrating the FileManager with TinyMCE (>= 3.0), you should:
Create a Javascript callback function that will open the FileManager index.html base page (see URL below for examples)
Add a line like: "file_browser_callback : 'name_of_callback_function'" in the tinyMCE.init command
See http://www.tinymce.com/wiki.php/TinyMCE3x:How-to_implement_a_custom_file_browser for more details.
See also the dedicated wiki page, with TinyMCE 4 sample : https://github.com/simogeo/Filemanager/wiki/How-to-use-the-Filemanager-with-tinyMCE--3-or-4-%3F
**(4)** Last but not least, **worry about security**!
For **PHP connector** : copy/paste the `/connectors/php/default.config.php` to `/connectors/php/user.config.php` to define your own authentication function.
To do so, you will find an example on the [dedicated wiki page](https://github.com/simogeo/Filemanager/wiki/Security-concern).
**jQuery dependency and compatibility**
We try to keep updating jQuery core library regularly.
If, for any reason, you can't use the embedded jQuery version just now that the Filemanager will probably work with a jQuery version >= 1.6.
You'll have to use the [jQuery.migrate() plugin](https://github.com/jquery/jquery-migrate) to use it with jQuery version 1.9+.
Set-up & security
-----------------
**Important** : The Filemanager is designed to work without any special configuration but **using it without any configuration is VERY unsafe**.
Please set-up your own **authentication function**, based on [default file](https://github.com/simogeo/Filemanager/blob/master/connectors/php/default.config.php) and refering to the [dedicated wiki page](https://github.com/simogeo/Filemanager/wiki/Security-concern).
API
---
Connector Location
------------------
You can create a connector for your server side language of choice by following this simple API. You must have a script at the following location which can respond to HTTP GET requests by returning an appropriate JSON object:
[path to FileManager]/connectors/[language extension]/filemanager.[language extension]
FileManager currently includes connectors for PHP, MVC, JSP, lasso, ASP, ASHX, PL and CFM in the following locations:
PHP: .../connectors/php/filemanager.php
ASP.NET MVC Framework .../connectors/mvc/FilemanagerController.cs
JSP: .../connectors/jsp/filemanager.jsp
lasso: .../connectors/lasso/filemanager.lasso
ASP: .../connectors/asp/filemanager.asp
ASHX: .../connectors/ashx/filemanager.asp
PL: .../connectors/pl/filemanager.pl
CFM: .../connectors/cfm/filemanager.cfm
As long as a script exists at this location to respond to requests, you may split up the code (external libraries, configuration files, etc.) however you see fit.
Error Handling
--------------
Every response should include two keys specific to error handling: Error, and Code. If an error occurs in your script, you may populate these keys with whatever values you feel are most appropriate. If there is no error, Error should remain empty or null, and Code should be empty, null, or zero (0). Do not use zero for any actual errors. The following example would be an appropriate response if the connector uses an external file for configuration (recommended), but that file cannot be found:
```json
{
"Error": "Configuration file missing.",
"Code": -1
}
```
Methods
-------
Your script should include support for the following methods/functions. GET requests from FileManager include a parameter "mode" which will indicate which type of response to return. Additional parameters will provide other information required to fulfill the request, such as the current directory.
getinfo
-------
The `getinfo` method returns information about a single file. Requests with mode "getinfo" will include an additional parameter, "path", indicating which file to inspect. A boolean parameter "getsize" indicates whether the dimensions of the file (if an image) should be returned.
Example Request:
[path to connector]?mode=getinfo&path=/UserFiles/Image/logo.png&getsize=true
Example Response:
```json
{
"Path": "/UserFiles/Image/logo.png",
"Filename": "logo.png",
"File Type": "png",
"Preview": "/UserFiles/Image/logo.png",
"Protected": 0,
"Properties": {
"Date Created": null,
"Date Modified": "02/09/2007 14:01:06",
"filemtime": 1360237058,
"Height": 14,
"Width": 14,
"Size": 384
},
"Error": "",
"Code": 0
}
```
The keys are as follows:
Path: The path to the file. Should match what was passed in the request.
Filename: The name of the file, i.e., the last part of the path.
File Type: The file extension, "dir" if a directory, or "txt" if missing/unknown.
Preview: Path to a preview image. If the file is an image that can be displayed in a web browser (i.e., gif, jpg, or png), you should return the path to the image. Otherwise, check to see if there is a matching file icon based on the file extension, constructing the path like so:
Directories: images/fileicons/_Open.png
Files: images/fileicons/[extension].png
Unknown: images/fileicons/default.png
Protected: Indicates if the file has some reading / writing restrictions. If not, set to 0. Else set to 1.
Properties: A nested JSON object containing specific properties of the file.
Date Created: The file's creation date, if available.
Date Modified: The file's modification date, if available.
Height: If an image, the height in pixels.
Width: If an image, the width in pixels.
Size: The file size in bytes.
Capabilities (optional): You can limit the operation buttons shown for a specific file. It is an array containing ['select','delete','rename','download'] (for all capabilities), or [] (for no capabilities). If not present, all capabilities are enabled.
Error: An error message, or empty/null if there was no error.
Code: An error code, or 0 if there was no error.
getfolder
---------
The `getfolder` method returns an array of file and folder objects representing the contents of the given directory (indicated by a "path" parameter). It should call the getinfo method to retrieve the properties of each file. A boolean parameter "getsizes" indicates whether image dimensions should be returned for each item. Folders should always be returned before files.
Optionally a "type" parameter can be specified to restrict returned files (depending on the connector). If a "type" parameter is given for the main index.html URL, the same parameter value is reused and passed to getfolder. This can be used for example to only show image files in a file system tree.
Example Request:
[path to connector]?mode=getfolder&path=/UserFiles/Image/&getsizes=true&type=images
Example Response:
```json
{
"/UserFiles/Image/logo.png": {
"Path": "/UserFiles/Image/logo.png",
"Filename": "logo.png",
"File Type": "png",
"Preview": "/UserFiles/Image/logo.png",
"Protected": 0,
"Properties": {
"Date Created": null,
"Date Modified": "02/09/2007 14:01:06",
"filemtime": 1360237058,
"Height": 14,
"Width": 14,
"Size": 384
},
"Error": "",
"Code": 0
},
"/UserFiles/Image/icon.png": {
"Path": "/UserFiles/Image/icon.png",
"Filename": "icon.png",
"File Type": "png",
"Preview": "/UserFiles/Image/icon.png",
"Properties": {
"Date Created": null,
"Date Modified": "02/09/2007 14:01:06",
"filemtime": 1360237058,
"Height": 14,
"Width": 14,
"Size": 384
},
"Error": "",
"Code": 0
},
"/UserFiles/folder/":{
"Path":"/UserFiles/folder/",
"Filename":"folder",
"File Type":"dir",
"Preview":"images\/fileicons\/_Open.png",
"Properties": {
"Date Created":null,
"Date Modified": "02/09/2007 14:01:06",
"filemtime": 1360237058,
"Height":null,
"Width":null,
"Size":null
},
"Error":"",
"Code":0
}
}
```
Each key in the array is the path to an individual item, and the value is the file object for that item.
rename
------
The `rename` method renames the item at the path given in the "old" parameter with the name given in the "new" parameter and returns an object indicating the results of that action.
Example Request:
[path to connector]?mode=rename&old=/UserFiles/Image/logo.png&new=id.png
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Old Path": "/a_folder_renamed/thisisareallylongincrediblylongfilenamefortesting.txt",
"Old Name": "thisisareallylongincrediblylongfilenamefortesting.txt",
"New Path": "/a_folder_renamed/a_renamed_file",
"New Name": "a_renamed_file"
}
```
move
------
The `move` method move "old" file or directory to specified "new" directory. It is possible to specify absolute path from fileRoot dir or relative path from "old" item. "root" value is mandatory to secure that relative paths don't get above fileRoot.
Example Request: Move file
[path to connector]?mode=move&old=/uploads/images/original/Image/logo.png&new=/moved/&root=/uploads/images/
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Old Path": "/uploads/images/original/Image/",
"Old Name": "logo.png",
"New Path": "/uploads/images/moved/",
"New Name": "logo.png"
}
```
Example Request: Move directory to not existing directory (will be created)
[path to connector]?mode=move&old=/uploads/images/original/Image&new=../new_dir/&root=/uploads/images/
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Old Path": "/uploads/images/original/",
"Old Name": "Image",
"New Path": "/uploads/new_dir/",
"New Name": "Image"
}
```
delete
------
The `delete` method deletes the item at the given path.
Example Request:
[path to connector]?mode=delete&path=/UserFiles/Image/logo.png
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Path": "/UserFiles/Image/logo.png"
}
```
add
---
The `add` method adds the uploaded file to the specified path. Unlike the other methods, this method must return its JSON response wrapped in an HTML `<textarea>`, so the MIME type of the response is text/html instead of text/plain. The upload form in the File Manager passes the current path as a POST param along with the uploaded file. The response includes the path as well as the name used to store the file. The uploaded file's name should be safe to use as a path component in a URL, so URL-encoded at a minimum.
Example Response:
```json
{
"Path": "/UserFiles/Image/",
"Name": "new_logo.png",
"Error": "No error",
"Code": 0
}
```
replace
---
The `replace` method allow the user to replace a specific file whatever the new filename - at least, the new file should have the same extension the original has. The old file is automatically overwritten. Unlike the other methods, this method must return its JSON response wrapped in an HTML `<textarea>`, so the MIME type of the response is text/html instead of text/plain. The *dynamic* upload form in the File Manager passes the current file path as a POST param along with the uploaded file. The response includes the path as well as the name used to store the file.
Example Response:
```json
{
"Path": "/UserFiles/Image/",
"Name": "new_logo.png",
"Error": "No error",
"Code": 0
}
```
editfile
--------
The `editfile` method returns the content of a given file (passed as parameter). It gives the user the ability to edit a file online (extensions are specified in configuration file). Handled as GET request.
Example request:
[path to connector]?mode=editfile&path=/UserFiles/MyFolder/myfile.txt
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Path": "/UserFiles/MyFolder/myfile.txt",
"Content": "Content":"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\r\n\Phasellus eu erat lorem.\r\n\r\n\Bye!"
}
```
savefile
--------
The `save` method will overwrite the content of the current file. The edit form in the File Manager passes the mode (as `savefile`), path of the current file and the content as POST parameters.
Example Response:
```json
{
"Error": "No error",
"Code": 0,
"Path": "/UserFiles/MyFolder/myfile.txt"
}
```
preview
--------
The `preview` method serves the requested image for displaying. The image path is passed through the `path` parameter. If `thumbnail=true` parameter is passed, the method will return an image thumbnail. An extra parameter such as UNIX time can be added to the URL to prevent cache issue.
Example Request:
[path to connector]?mode=preview&path=/UserFiles/new%20logo.png&thumbnail=true
addfolder
---------
The `addfolder` method creates a new directory on the server within the given path.
Example Request:
[path to connector]?mode=addfolder&path=/UserFiles/&name=new%20logo.png
Example Response:
```json
{
"Parent": "/UserFiles/",
"Name": "new_logo.png",
"Error": "No error",
"Code": 0
}
```
download
--------
The `download` method serves the requested file to the user. We currently use a MIME type of "application/x-download" to force the file to be downloaded rather than displayed in a browser. In the future we may make exceptions for specific file types that often have in-browser viewers such as PDF's and various movie formats (Flash, Quicktime, etc.).
Example Request:
[path to connector]?mode=download&path=/UserFiles/new%20logo.png
MIT LICENSE
---
Copyright (c) 2011-2013 Jason Huck, Simon Georget
http://opensource.org/licenses/MIT
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.

View File

@@ -1,11 +0,0 @@
{
"name": "Filemanager",
"repo": "simogeo/Filemanager",
"description": "An open-source file manager released under MIT license. Up-to-date for PHP and MVC connector.",
"keywords": ["file", "upload", "dms", "document", "management", "system"],
"dependencies": {},
"development": {},
"main": [
"index.html"
]
}

View File

@@ -1,95 +0,0 @@
From version 2.3.0 to 2.4.0
---------------------------
- handle better language ISO 4 Letters | #428
- encode path on requests | #429
- catalan translation updated | #440
- security fix : Path Traversal Vulnerability | #453
From version 2.2.0 to 2.3.0
---------------------------
- PDF viewer added | #377 & #319
- fix is_valid_path bug when fileRoot is defined | #393
- adding https protocol for external resources | #395
- array_replace_recursive function implementation for php 5.2 compatibility | #396
- ASHX connector, fixing test bug | #399
- security fix related to WideImage lib | #405
- filemanager.ashx update | #409
- fix uploadRestrictions bug | #398
- ability to do not cache thumbnails | #417
- encode folder name when adding | #420
- ability to set panels size | #423
- ability to pass configuration file in url | #255
- ability to make Text editor fullscreen (by pressing F11) | #422
From version 2.1.0 to 2.2.0
---------------------------
- handle symlinks | #332
- bug fix : prevent "flickering" on image resize with custom-scrollbar | #334
- make relPath and connector setFileRoot() work together | #339
- relPath renamed baseUrl | #340
- adding .jpe extension support | #341
- update jquery | #345
- remove unused option maxuploadfilesize | #346
- set logfile path according to system if not set into config file | #353
- fix bug when using baseUrl without calling setFileRoot() | #354
- fix important security issue | #356
From version 2.0.0 to 2.1.0
---------------------------
- Detect syntax error in config file | #294
- "Upload" button localized | #295
- Adding loading screen | #298
- Adding version number | #292
- Adding navigation to Parent Directory | #315
- Better handling of non readable / non writable files and folders, depending on system permissions | #307, #308, #309
- Fixing bug with custom scrollbar on Google Chrome | #299
- Fixing bug when renaming file/folder with dynamic fileroot, using setFileRoot() | #297
- Fixing bug on 'upload' button when multiple-uploads option is enabled, on chrome. Should also work better with IE | #304
- Fixing bug is_valid_path() on WAMP | #306
- Fixing bug on filetree scrollbar | #302
- Fixing bug on clicking Home button | #320
- Fixing bug on allowed files test | #331
From version 1.8.0 to 2.0.0
---------------------------
- Adding multiple files upload, based on dropzone.js | #177, #185, #41
- Fixing bugs after 'Rename' action | #283, #284
- Adding logo | #285
- Adding folder infos | #287
- Adding help message on 'Move' action
- Code optimization
From version 1.7.0 to 1.8.0
---------------------------
- Adding Bosnian transalation | #281
- Security enhanced | #282 and much more
- Removing ability to move file to parent path using '../' syntax
- Ability to zip and download folder | #100
From version 1.6.0 to 1.7.0
---------------------------
- Add timer when logger is enabled #278
- Let user tweak scrollbar if wanted. See config.customScrollbar options | #279
- Add new themes : 'flat-dark' (as default), 'flat-turquoise', 'flat-oil'
From version 1.5.0 to 1.6.0
---------------------------
- Add ability to define your own CSS theme | #277
From version 1.4.0 to 1.5.0
---------------------------
- Add ability to copy direct file URL | #276
From version 1.3.0 to 1.4.0
---------------------------
- Modal dialog available for CKEditor | #205
- Security : checking for permissions before executing actions | #251
- Removing regex modifiers in config file to ease other languages portability
- Supporting extension changes ('rename' action) | #247, #249

View File

@@ -1,22 +0,0 @@
{
"name":"simogeo/filemanager",
"description":"An open-source file manager",
"type":"project",
"keywords":[
"filemanager",
"files",
"images"
],
"license": "MIT",
"authors":[
{
"name":"Simon Georget",
"email":"simon@linea21.com",
"homepage":"http://www.empreinte-urbaine.eu",
"role": "Developer"
}
],
"require":{
"php":">= 5.2.0"
}
}

View File

@@ -1,83 +0,0 @@
<?php
/**
* Filemanager PHP connector
* This file should at least declare auth() function
* and instantiate the Filemanager as '$fm'
*
* IMPORTANT : by default Read and Write access is granted to everyone
* Copy/paste this file to 'user.config.php' file to implement your own auth() function
* to grant access to wanted users only
*
* filemanager.php
* use for ckeditor filemanager
*
* @license MIT License
* @author Simon Georget <simon (at) linea21 (dot) com>
* @copyright Authors
*/
// Laravel init
require getcwd() . '/../../../../bootstrap/autoload.php';
$app = require_once getcwd() . '/../../../../bootstrap/app.php';
$kernel = $app->make('Illuminate\Contracts\Http\Kernel');
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$id = $app['encrypter']->decrypt($_COOKIE[$app['config']['session.cookie']]);
$app['session']->driver()->setId($id);
$app['session']->driver()->start();
// Folder path
$folderPath = config('filemanager.folder_path');
// Check if user in authentified
if(!$app['auth']->check())
{
$laravelAuth = false;
}
else
{
// Check if user has all access
if($app['auth']->user()->accessMediasAll())
{
$laravelAuth = true;
}
elseif(method_exists($app['auth']->user(), 'accessMediasFolder'))
{
// Check if user has access to one folder
if($app['auth']->user()->accessMediasFolder())
{
// Folder name with user id
$folderPath .= 'user' . $app['auth']->id();
$laravelAuth = true;
}
else
{
$laravelAuth = false;
}
}
else
{
$laravelAuth = false;
}
}
/**
* Check if user is authorized
*
*
* @return boolean true if access granted, false if no access
*/
function auth()
{
return $GLOBALS['laravelAuth'];
}
$fm = new Filemanager();
$fm->setFileRoot($folderPath, true);
?>

View File

@@ -1,182 +0,0 @@
<?php
// only for debug
// error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// ini_set('display_errors', '1');
/**
* Filemanager PHP connector
*
* filemanager.php
* use for ckeditor filemanager plug-in by Core Five - http://labs.corefive.com/Projects/FileManager/
*
* @license MIT License
* @author Riaan Los <mail (at) riaanlos (dot) nl>
* @author Simon Georget <simon (at) linea21 (dot) com>
* @copyright Authors
*/
require_once('filemanager.class.php');
// for php 5.2 compatibility
if (!function_exists('array_replace_recursive')) {
function array_replace_recursive($array, $array1) {
function recurse($array, $array1) {
foreach($array1 as $key => $value) {
// create new key in $array, if it is empty or not an array
if (!isset($array[$key]) || (isset($array[$key]) && !is_array($array[$key]))) {
$array[$key] = array();
}
// overwrite the value in the base array
if (is_array($value)) {
$value = recurse($array[$key], $value);
}
$array[$key] = $value;
}
return $array;
}
// handle the arguments, merge one by one
$args = func_get_args();
$array = $args[0];
if (!is_array($array)) {
return $array;
}
for ($i = 1; $i < count($args); $i++) {
if (is_array($args[$i])) {
$array = recurse($array, $args[$i]);
}
}
return $array;
}
}
// if user file is defined we include it, else we include the default file
(file_exists('user.config.php')) ? include_once('user.config.php') : include_once('default.config.php');
// auth() function is already defined
// and Filemanager is instantiated as $fm
$response = '';
if(!auth()) {
$fm->error($fm->lang('AUTHORIZATION_REQUIRED'));
}
if(!isset($_GET)) {
$fm->error($fm->lang('INVALID_ACTION'));
} else {
if(isset($_GET['mode']) && $_GET['mode']!='') {
switch($_GET['mode']) {
default:
$fm->error($fm->lang('MODE_ERROR'));
break;
case 'getinfo':
if($fm->getvar('path')) {
$response = $fm->getinfo();
}
break;
case 'getfolder':
if($fm->getvar('path')) {
$response = $fm->getfolder();
}
break;
case 'rename':
if($fm->getvar('old') && $fm->getvar('new')) {
$response = $fm->rename();
}
break;
case 'move':
// allow "../"
if($fm->getvar('old') && $fm->getvar('new') && $fm->getvar('root')) {
$response = $fm->move();
}
break;
case 'editfile':
if($fm->getvar('path')) {
$response = $fm->editfile();
}
break;
case 'delete':
if($fm->getvar('path')) {
$response = $fm->delete();
}
break;
case 'addfolder':
if($fm->getvar('path') && $fm->getvar('name')) {
$response = $fm->addfolder();
}
break;
case 'download':
if($fm->getvar('path')) {
$fm->download();
}
break;
case 'preview':
if($fm->getvar('path')) {
if(isset($_GET['thumbnail'])) {
$thumbnail = true;
} else {
$thumbnail = false;
}
$fm->preview($thumbnail);
}
break;
}
} else if(isset($_POST['mode']) && $_POST['mode']!='') {
switch($_POST['mode']) {
default:
$fm->error($fm->lang('MODE_ERROR'));
break;
case 'add':
if($fm->postvar('currentpath')) {
$fm->add();
}
break;
case 'replace':
if($fm->postvar('newfilepath')) {
$fm->replace();
}
break;
case 'savefile':
if($fm->postvar('content', false) && $fm->postvar('path')) {
$response = $fm->savefile();
}
break;
}
}
}
echo json_encode($response);
die();
?>

View File

@@ -1,16 +0,0 @@
WideImage, a PHP image manipulation library
Copyright 2007-2011 Gasper Kozak
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@@ -1,21 +0,0 @@
WideImage, a PHP image manipulation library
Copyright 2007-2011 Gasper Kozak
For documentation, please visit http://wideimage.sourceforge.net/
This file is part of WideImage.
WideImage is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
WideImage is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with WideImage; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

View File

@@ -1,2 +0,0 @@
Version: 11.02.19
Build date: 2011-02-19

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 B

View File

@@ -1,66 +0,0 @@
<?php
/**
* @package Demos
*/
?>
<form style="font-family: Verdana, Tahoma; font-size: 11px">
<input type="hidden" name="demo" value="<?php echo $activeDemo->name; ?>" />
<div style="background-color: #f0f0f0; padding: 5px;">
<input type="submit" value="refresh" />
<?php
foreach ($activeDemo->fields as $field)
$field->render();
?>
<br />
<span style="font-family: Verdana, Tahoma; font-size: 11px">
Read the <a href="../doc/WideImage/WideImage_Image.html#method<?php echo $activeDemo->name; ?>">API documentation</a> for this operation.
</span>
<div style="background-color: #d0d0d0; padding: 5px; text-align: right; float: right; width: 300px;">
<?php
$top_form['output']->render();
echo "<br />\n";
echo ' Palette options (only for <em>png8</em> and <em>gif</em> output):<br />';
$top_form['ncolors']->render();
echo "<br />\n";
$top_form['dither']->render();
$top_form['match_palette']->render();
?>
</div>
</div>
</form>
<?php
$activeDemo->text();
?>
<?php
$images_in_row = 2;
$in_row = 0;
$images = array();
$di = new DirectoryIterator(dirname(__FILE__) . '/images/');
foreach ($di as $file)
if (!$file->isDot() && strpos($file->getFilename(), '.') !== 0)
$images[] = $file->getFilename();
asort($images);
foreach ($images as $image_file)
{
echo '<div class="images">';
echo '<img src="images/' . $image_file . '" />';
$img_url = 'image.php?image=' . $image_file . '&output=' . $top_form['output']->value .
'&colors=' . $top_form['ncolors']->value . '&dither=' . $top_form['dither']->value .
'&match_palette=' . $top_form['match_palette']->value . '&demo=' . $activeDemo->name;
foreach ($activeDemo->fields as $field)
$img_url .= '&' . $field->getURLValue();
echo '&nbsp;';
echo '<a href="' . $img_url . '">';
echo '<img src="' . $img_url . '" />';
echo '</a>';
echo "</div>\n";
}
?>
<div style="clear: both"></div>

View File

@@ -1,19 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_addNoise extends Demo
{
public $order = 9350;
function init()
{
$this->addField(new IntField('amount', 300));
$this->addField(new SelectField('type', array('salt&pepper','mono','color'), 'mono'));
}
function execute($image, $request)
{
return $image->addNoise($this->fields['amount']->value, $this->fields['type']->value);
}
}

View File

@@ -1,45 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_applyConvolution extends Demo
{
public $order = 2025;
protected $base_matrix = array(array(2, 0, 0), array(0, -1, 0), array(0, 0, -1));
function init()
{
$this->addField(new Field('matrix', '2 0 0, 0 -1 0, 0 0 -1', '3x3 float matrix; separate rows with a comma, and columns with a space'));
$this->addField(new FloatField('div', 1));
$this->addField(new FloatField('offset', 220));
}
function execute($image, $request)
{
$mstr = $this->fval('matrix');
$rows = explode(',', $mstr);
$matrix = array();
foreach ($this->base_matrix as $idx => $base_row)
{
$build_row = array();
if (isset($rows[$idx]))
{
$row = trim($rows[$idx]);
$cols = explode(' ', $row);
for ($c = 0; $c < 3; $c++)
if (isset($cols[$c]))
$build_row[] = floatval(trim($cols[$c]));
else
$build_row[] = $base_row[$c];
}
else
$build_row = $base_row;
$matrix[] = $build_row;
}
return $image->applyConvolution($matrix, $this->fval('div'), $this->fval('offset'));
}
}

View File

@@ -1,39 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_applyFilter extends Demo
{
public $order = 2000;
function init()
{
$this->addField(new SelectField('filter', array(
'IMG_FILTER_NEGATE',
'IMG_FILTER_GRAYSCALE',
'IMG_FILTER_BRIGHTNESS',
'IMG_FILTER_CONTRAST',
'IMG_FILTER_COLORIZE',
'IMG_FILTER_EDGEDETECT',
'IMG_FILTER_EMBOSS',
'IMG_FILTER_GAUSSIAN_BLUR',
'IMG_FILTER_SELECTIVE_BLUR',
'IMG_FILTER_MEAN_REMOVAL',
'IMG_FILTER_SMOOTH'
))
);
$this->addField(new IntField('arg1', null));
$this->addField(new IntField('arg2', null));
$this->addField(new IntField('arg3', null));
}
function execute($image)
{
$filter = constant($this->fields['filter']->value);
$arg1 = $this->fields['arg1']->value;
$arg2 = $this->fields['arg2']->value;
$arg3 = $this->fields['arg3']->value;
return $image->applyFilter($filter, $arg1, $arg2, $arg3);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_applyMask extends Demo
{
public $order = 600;
function init()
{
$this->addField(new FileSelectField('mask', 'masks'));
$this->addField(new CoordinateField('left', 10));
$this->addField(new CoordinateField('top', '30%'));
if (!$this->request->get('mask'))
$this->request->set('mask', 'mask-circle.gif');
}
function execute($image)
{
$mask = WideImage::load(DEMO_PATH . 'masks/' . $this->fields['mask']->value);
$left = $this->fields['left']->value;
$top = $this->fields['top']->value;
return $image->applyMask($mask, $left, $top);
}
function getFormat()
{
return 'png';
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_asGrayscale extends Demo
{
public $order = 300;
function execute($img, $request)
{
return $img->asGrayscale();
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_asNegative extends Demo
{
public $order = 300;
function execute($img, $request)
{
return $img->asNegative();
}
}

View File

@@ -1,26 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_autoCrop extends Demo
{
public $order = 1050;
function init()
{
$this->addField(new IntField('margin', 0));
$this->addField(new IntField('rgb_threshold', 0));
$this->addField(new IntField('pixel_cutoff', 1));
$this->addField(new IntField('base_color', null, 'Index of the color'));
}
function execute($image, $request)
{
$margin = $this->fields['margin']->value;
$rgb_threshold = $this->fields['rgb_threshold']->value;
$pixel_cutoff = $this->fields['pixel_cutoff']->value;
$base_color = $this->fields['base_color']->value;
return $image->autoCrop($margin, $rgb_threshold, $pixel_cutoff, $base_color);
}
}

View File

@@ -1,19 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_correctGamma extends Demo
{
public $order = 2050;
function init()
{
$this->addField(new FloatField('in_gamma', 1.1));
$this->addField(new FloatField('out_gamma', 3.7));
}
function execute($image, $request)
{
return $image->correctGamma($this->fval('in_gamma'), $this->fval('out_gamma'));
}
}

View File

@@ -1,26 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_crop extends Demo
{
public $order = 1000;
function init()
{
$this->addField(new CoordinateField('left', 10));
$this->addField(new CoordinateField('top', 20));
$this->addField(new CoordinateField('width', 120));
$this->addField(new CoordinateField('height', 60));
}
function execute($image, $request)
{
$left = $this->fields['left']->value;
$top = $this->fields['top']->value;
$width = $this->fields['width']->value;
$height = $this->fields['height']->value;
return $image->crop($left, $top, $width, $height);
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_flip extends Demo
{
public $order = 1200;
function execute($image, $request)
{
return $image->flip();
}
}

View File

@@ -1,63 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_getCanvas extends Demo
{
public $order = 1300;
function init()
{
$this->addField(new Field('text', 'Hello world!'));
$this->addField(new CoordinateField('x', 'middle'));
$this->addField(new CoordinateField('y', 'bottom-5'));
$this->addField(new IntField('angle', 5));
$this->addField(new FileSelectField('font', 'fonts', array('show' => false, 'pattern' => '/(.*)\.ttf$/', 'default' => 'VeraSe.ttf')));
$this->addField(new IntField('size', 18));
}
function execute($image, $request)
{
$text = $this->fields['text']->value;
$x = $this->fields['x']->value;
$y = $this->fields['y']->value;
$angle = $this->fields['angle']->value;
$font = $this->fields['font']->value;
$font_size = $this->fields['size']->value;
$canvas = $image->getCanvas();
$canvas->filledRectangle(10, 10, 80, 40, $image->allocateColor(255, 127, 255));
$canvas->line(60, 80, 30, 100, $image->allocateColor(255, 0, 0));
$font_file = DEMO_PATH . 'fonts/' . $font;
$canvas->useFont($font_file, $font_size, $image->allocateColor(0, 0, 0));
$canvas->writeText("$x+1", "$y+1", $text, $angle);
$canvas->useFont($font_file, $font_size, $image->allocateColor(200, 220, 255));
$canvas->writeText($x, $y, $text, $angle);
return $image;
}
function et($name)
{
return htmlentities($this->fval($name));
}
function text()
{
echo "This demo executes:
<pre>
\$canvas->filledRectangle(10, 10, 80, 40, \$img->allocateColor(255, 127, 255));
\$canvas->line(60, 80, 30, 100, \$img->allocateColor(255, 0, 0));
\$canvas->useFont('{$this->et('font')}', '{$this->et('size')}', \$image->allocateColor(0, 0, 0));
\$canvas->writeText('{$this->et('x')}+1', '{$this->et('y')}+1', '{$this->et('text')}', {$this->et('angle')});
\$canvas->useFont('{$this->et('font')}', '{$this->et('size')}', \$image->allocateColor(200, 220, 255));
\$canvas->writeText('{$this->et('x')}', '{$this->et('y')}', '{$this->et('text')}', {$this->et('angle')});
</pre>";
}
}

View File

@@ -1,28 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_getChannels extends Demo
{
public $order = 500;
protected $channels = array('red', 'green', 'blue', 'alpha');
function init()
{
$this->addField(new CheckboxField('red', true));
$this->addField(new CheckboxField('green', false));
$this->addField(new CheckboxField('blue', true));
$this->addField(new CheckboxField('alpha', false));
}
function execute($img, $request)
{
$on = array();
foreach ($this->channels as $name)
if ($this->fields[$name]->value)
$on[] = $name;
return $img->getChannels($on);
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_getMask extends Demo
{
public $order = 550;
function execute($img, $request)
{
return $img->getMask();
}
}

View File

@@ -1,31 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_merge extends Demo
{
public $order = 800;
function init()
{
$this->addField(new FileSelectField('overlay', 'images', array('default' => '6-logo.gif')));
$this->addField(new CoordinateField('left', 'right-10'));
$this->addField(new CoordinateField('top', 'bottom-15%'));
$this->addField(new IntField('opacity', 50));
}
function execute($image, $request)
{
$overlay = WideImage::load(DEMO_PATH . 'images/' . $this->fields['overlay']->value);
$left = $this->fields['left']->value;
$top = $this->fields['top']->value;
$opacity = $this->fields['opacity']->value;
return $image->merge($overlay, $left, $top, $opacity);
}
function text()
{
echo "For alpha images, set opacity=100, otherwise alpha channel won't work.";
}
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_mirror extends Demo
{
public $order = 1150;
function execute($image, $request)
{
return $image->mirror();
}
}

View File

@@ -1,26 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_resize extends Demo
{
public $order = 900;
function init()
{
$this->addField(new CoordinateField('width', 120));
$this->addField(new CoordinateField('height', null));
$this->addField(new SelectField('fit', array('inside', 'fill', 'outside')));
$this->addField(new SelectField('scale', array('any', 'down', 'up')));
}
function execute($image, $request)
{
$width = $this->fields['width']->value;
$height = $this->fields['height']->value;
$fit = $this->fields['fit']->value;
$scale = $this->fields['scale']->value;
return $image->resize($width, $height, $fit, $scale);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_resizeCanvas extends Demo
{
public $order = 910;
function init()
{
$this->addField(new CoordinateField('width', '100%+30'));
$this->addField(new CoordinateField('height', 200));
$this->addField(new CoordinateField('left', '2'));
$this->addField(new CoordinateField('top', 'bottom-10'));
$this->addField(new ColorField('color', 'ffffff'));
$this->addField(new SelectField('scale', array('any', 'down', 'up'), 'any'));
$this->addField(new CheckboxField('merge', false, "Merge or copy over"));
}
function execute($image, $request)
{
$width = $this->fields['width']->value;
$height = $this->fields['height']->value;
$left = $this->fields['left']->value;
$top = $this->fields['top']->value;
$color = $this->fields['color']->value;
$scale = $this->fields['scale']->value;
$merge = $this->fields['merge']->value;
return $image->resizeCanvas($width, $height, $left, $top, $color ? hexdec($color) : null, $scale, $merge);
}
}

View File

@@ -1,22 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_rotate extends Demo
{
public $order = 1100;
function init()
{
$this->addField(new AngleField('angle', 25));
$this->addField(new ColorField('color', ''));
}
function execute($image, $request)
{
$angle = $this->fields['angle']->value;
$color = $this->fields['color']->value;
return $image->rotate($angle, $color ? hexdec($color) : null);
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_roundCorners extends Demo
{
public $order = 1075;
function init()
{
$this->addField(new IntField('radius', 30));
$this->addField(new ColorField('color', 'ffffff'));
$this->addField(new IntField('smoothness', 2));
$this->addField(new CheckboxField('top-left', true));
$this->addField(new CheckboxField('top-right', true));
$this->addField(new CheckboxField('bottom-right', true));
$this->addField(new CheckboxField('bottom-left', true));
}
function execute($image, $request)
{
$color = $this->fields['color']->value;
$radius = $this->fields['radius']->value;
$smoothness = $this->fields['smoothness']->value;
$corners = 0;
if ($this->fval('top-left'))
$corners += WideImage::SIDE_TOP_LEFT;
if ($this->fval('top-right'))
$corners += WideImage::SIDE_TOP_RIGHT;
if ($this->fval('bottom-right'))
$corners += WideImage::SIDE_BOTTOM_RIGHT;
if ($this->fval('bottom-left'))
$corners += WideImage::SIDE_BOTTOM_LEFT;
return $image->roundCorners($radius, $color ? hexdec($color) : null, $smoothness, $corners);
}
}

View File

@@ -1,20 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo_unsharp extends Demo
{
public $order = 1350;
function init()
{
$this->addField(new IntField('amount', 300));
$this->addField(new IntField('radius', 3));
$this->addField(new IntField('threshold', 2));
}
function execute($image, $request)
{
return $image->unsharp($this->fields['amount']->value, $this->fields['radius']->value, $this->fields['threshold']->value);
}
}

View File

@@ -1,99 +0,0 @@
<?php
include('../lib/WideImage.php');
$img = WideImage::createTrueColorImage(400, 200);
$canvas = $img->getCanvas();
$canvas->useFont('fonts/Vera.ttf', 36, $img->allocateColor(255, 0, 0));
$canvas->writeText('left', 'top', 'abc', 0);
$canvas->writeText('right', 'top', 'def', 15);
$canvas->writeText('right', 'bottom', 'ghi', 30);
$canvas->writeText('left', 'bottom', 'jkl', 45);
$canvas->writeText('center', 'center', 'mno', 60);
$img->output('png');
exit;
// Create a 300x150 image
$im = imagecreatetruecolor(600, 350);
$black = imagecolorallocate($im, 0, 0, 0);
$bgcolor = imagecolorallocate($im, 255, 255, 0);
// Set the background to be white
imagefilledrectangle($im, 0, 0, imagesx($im), imagesy($im), $bgcolor);
// Path to our font file
$font = './fonts/Vera.ttf';
$angle = 340;
$font_size = 20;
$text = 'jW| asdkasdlk alk,.,wedwer|w[r=?';
$text = '#j';
// First we create our bounding box
$bbox = imageftbbox($font_size, $angle, $font, $text);
function normalize_bbox($bbox)
{
return array(
'up-left' => array('x' => $bbox[6], 'y' => $bbox[7]),
'up-right' => array('x' => $bbox[4], 'y' => $bbox[5]),
'down-left' => array('x' => $bbox[0], 'y' => $bbox[1]),
'down-right' => array('x' => $bbox[2], 'y' => $bbox[3]),
);
}
function outer_box($box)
{
return array(
'left' => min($box['up-left']['x'], $box['up-right']['x'], $box['down-left']['x'], $box['down-right']['x']),
'top' => min($box['up-left']['y'], $box['up-right']['y'], $box['down-left']['y'], $box['down-right']['y']),
'right' => max($box['up-left']['x'], $box['up-right']['x'], $box['down-left']['x'], $box['down-right']['x']),
'bottom' => max($box['up-left']['y'], $box['up-right']['y'], $box['down-left']['y'], $box['down-right']['y'])
);
}
$box = normalize_bbox($bbox);
// This is our cordinates for X and Y
#$x = $bbox[0] + (imagesx($im) / 2) - ($bbox[4] / 2) - 5;
#$y = $bbox[1] + (imagesy($im) / 2) - ($bbox[5] / 2) - 5;
#$x = 300;
#$y = 175;
$obox = outer_box(normalize_bbox(imageftbbox($font_size, $angle, $font, '')));
$obox = outer_box(normalize_bbox(imageftbbox($font_size, $angle, $font, $text)));
#$x = imagesx($im) - $obox['right'] - 1;
#$y = imagesy($im) - $obox['bottom'] - 1;
$x = 0;
$y = 0;
$gc = imagecolorallocate($im, 255, 200, 200);
imageline($im, imagesx($im) / 2, 0, imagesx($im) / 2, imagesy($im), $gc);
imageline($im, 0, imagesy($im) / 2, imagesx($im), imagesy($im) / 2, $gc);
imagefttext($im, $font_size, $angle, $x, $y, $black, $font, $text);
#imagefttext($im, $font_size, $angle, $x, $y, $black, $font, 'aj');
$c = imagecolorallocate($im, 0, 255, 0);
imageline($im, $box['up-left']['x'] + $x, $box['up-left']['y'] + $y, $box['up-right']['x'] + $x, $box['up-right']['y'] + $y, $c);
imageline($im, $box['up-right']['x'] + $x, $box['up-right']['y'] + $y, $box['down-right']['x'] + $x, $box['down-right']['y'] + $y, $c);
imageline($im, $box['down-right']['x'] + $x, $box['down-right']['y'] + $y, $box['down-left']['x'] + $x, $box['down-left']['y'] + $y, $c);
imageline($im, $box['down-left']['x'] + $x, $box['down-left']['y'] + $y, $box['up-left']['x'] + $x, $box['up-left']['y'] + $y, $c);
$c = imagecolorallocate($im, 0, 127, 255);
$obox = outer_box($box);
imageline($im, $obox['left'] + $x, $obox['top'] + $y, $obox['right'] + $x, $obox['top'] + $y, $c);
imageline($im, $obox['right'] + $x, $obox['top'] + $y, $obox['right'] + $x, $obox['bottom'] + $y, $c);
imageline($im, $obox['right'] + $x, $obox['bottom'] + $y, $obox['left'] + $x, $obox['bottom'] + $y, $c);
imageline($im, $obox['left'] + $x, $obox['bottom'] + $y, $obox['left'] + $x, $obox['top'] + $y, $c);
imagefilledellipse($im, $x, $y, 3, 3, imagecolorallocate($im, 255, 0, 0));
// Output to browser
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);

View File

@@ -1,124 +0,0 @@
Bitstream Vera Fonts Copyright
The fonts have a generous copyright, allowing derivative works (as
long as "Bitstream" or "Vera" are not in the names), and full
redistribution (so long as they are not *sold* by themselves). They
can be be bundled, redistributed and sold with any software.
The fonts are distributed under the following copyright:
Copyright
=========
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information, contact:
fonts at gnome dot org.
Copyright FAQ
=============
1. I don't understand the resale restriction... What gives?
Bitstream is giving away these fonts, but wishes to ensure its
competitors can't just drop the fonts as is into a font sale system
and sell them as is. It seems fair that if Bitstream can't make money
from the Bitstream Vera fonts, their competitors should not be able to
do so either. You can sell the fonts as part of any software package,
however.
2. I want to package these fonts separately for distribution and
sale as part of a larger software package or system. Can I do so?
Yes. A RPM or Debian package is a "larger software package" to begin
with, and you aren't selling them independently by themselves.
See 1. above.
3. Are derivative works allowed?
Yes!
4. Can I change or add to the font(s)?
Yes, but you must change the name(s) of the font(s).
5. Under what terms are derivative works allowed?
You must change the name(s) of the fonts. This is to ensure the
quality of the fonts, both to protect Bitstream and Gnome. We want to
ensure that if an application has opened a font specifically of these
names, it gets what it expects (though of course, using fontconfig,
substitutions could still could have occurred during font
opening). You must include the Bitstream copyright. Additional
copyrights can be added, as per copyright law. Happy Font Hacking!
6. If I have improvements for Bitstream Vera, is it possible they might get
adopted in future versions?
Yes. The contract between the Gnome Foundation and Bitstream has
provisions for working with Bitstream to ensure quality additions to
the Bitstream Vera font family. Please contact us if you have such
additions. Note, that in general, we will want such additions for the
entire family, not just a single font, and that you'll have to keep
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
glyphs to the font, they must be stylistically in keeping with Vera's
design. Vera cannot become a "ransom note" font. Jim Lyles will be
providing a document describing the design elements used in Vera, as a
guide and aid for people interested in contributing to Vera.
7. I want to sell a software package that uses these fonts: Can I do so?
Sure. Bundle the fonts with your software and sell your software
with the fonts. That is the intent of the copyright.
8. If applications have built the names "Bitstream Vera" into them,
can I override this somehow to use fonts of my choosing?
This depends on exact details of the software. Most open source
systems and software (e.g., Gnome, KDE, etc.) are now converting to
use fontconfig (see www.fontconfig.org) to handle font configuration,
selection and substitution; it has provisions for overriding font
names and subsituting alternatives. An example is provided by the
supplied local.conf file, which chooses the family Bitstream Vera for
"sans", "serif" and "monospace". Other software (e.g., the XFree86
core server) has other mechanisms for font substitution.

View File

@@ -1,11 +0,0 @@
Contained herin is the Bitstream Vera font family.
The Copyright information is found in the COPYRIGHT.TXT file (along
with being incoporated into the fonts themselves).
The releases notes are found in the file "RELEASENOTES.TXT".
We hope you enjoy Vera!
Bitstream, Inc.
The Gnome Project

View File

@@ -1,162 +0,0 @@
Bitstream Vera Fonts - April 16, 2003
=====================================
The version number of these fonts is 1.10 to distinguish them from the
beta test fonts.
Note that the Vera copyright is incorporated in the fonts themselves.
The License field in the fonts contains the copyright license as it
appears below. The TrueType copyright field is not large enough to
contain the full license, so the license is incorporated (as you might
think if you thought about it) into the license field, which
unfortunately can be obscure to find. (In pfaedit, see: Element->Font
Info->TTFNames->License).
Our apologies for it taking longer to complete the fonts than planned.
Beta testers requested a tighter line spacing (less leading) and Jim
Lyles redesigned Vera's accents to bring its line spacing to more
typical of other fonts. This took additional time and effort. Our
thanks to Jim for this effort above and beyond the call of duty.
There are four monospace and sans faces (normal, oblique, bold, bold
oblique) and two serif faces (normal and bold). Fontconfig/Xft2 (see
www.fontconfig.org) can artificially oblique the serif faces for you:
this loses hinting and distorts the faces slightly, but is visibly
different than normal and bold, and reasonably pleasing.
On systems with fontconfig 2.0 or 2.1 installed, making your sans,
serif and monospace fonts default to these fonts is very easy. Just
drop the file local.conf into your /etc/fonts directory. This will
make the Bitstream fonts your default fonts for all applications using
fontconfig (if sans, serif, or monospace names are used, as they often
are as default values in many desktops). The XML in local.conf may
need modification to enable subpixel decimation, if appropriate,
however, the commented out phrase does so for XFree86 4.3, in the case
that the server does not have sufficient information to identify the
use of a flat panel. Fontconfig 2.2 adds Vera to the list of font
families and will, by default use it as the default sans, serif and
monospace fonts.
During the testing of the final Vera fonts, we learned that screen
fonts in general are only typically hinted to work correctly at
integer pixel sizes. Vera is coded internally for integer sizes only.
We need to investigate further to see if there are commonly used fonts
that are hinted to be rounded but are not rounded to integer sizes due
to oversights in their coding.
Most fonts work best at 8 pixels and below if anti-aliased only, as
the amount of work required to hint well at smaller and smaller sizes
becomes astronomical. GASP tables are typically used to control
whether hinting is used or not, but Freetype/Xft does not currently
support GASP tables (which are present in Vera).
To mitigate this problem, both for Vera and other fonts, there will be
(very shortly) a new fontconfig 2.2 release that will, by default not
apply hints if the size is below 8 pixels. if you should have a font
that in fact has been hinted more agressively, you can use fontconfig
to note this exception. We believe this should improve many hinted
fonts in addition to Vera, though implemeting GASP support is likely
the right long term solution.
Font rendering in Gnome or KDE is the combination of algorithms in
Xft2 and Freetype, along with hinting in the fonts themselves. It is
vital to have sufficient information to disentangle problems that you
may observe.
Note that having your font rendering system set up correctly is vital
to proper judgement of problems of the fonts:
* Freetype may or may not be configured to in ways that may
implement execution of possibly patented (in some parts of the world)
TrueType hinting algorithms, particularly at small sizes. Best
results are obtained while using these algorithms.
* The freetype autohinter (used when the possibly patented
algorithms are not used) continues to improve with each release. If
you are using the autohinter, please ensure you are using an up to
date version of freetype before reporting problems.
* Please identify what version of freetype you are using in any
bug reports, and how your freetype is configured.
* Make sure you are not using the freetype version included in
XFree86 4.3, as it has bugs that significantly degrade most fonts,
including Vera. if you build XFree86 4.3 from source yourself, you may
have installed this broken version without intending it (as I
did). Vera was verified with the recently released Freetype 2.1.4. On
many systems, 'ldd" can be used to see which freetype shared library
is actually being used.
* Xft/X Render does not (yet) implement gamma correction. This
causes significant problems rendering white text on a black background
(causing partial pixels to be insufficiently shaded) if the gamma of
your monitor has not been compensated for, and minor problems with
black text on a while background. The program "xgamma" can be used to
set a gamma correction value in the X server's color pallette. Most
monitors have a gamma near 2.
* Note that the Vera family uses minimal delta hinting. Your
results on other systems when not used anti-aliased may not be
entirely satisfying. We are primarily interested in reports of
problems on open source systems implementing Xft2/fontconfig/freetype
(which implements antialiasing and hinting adjustements, and
sophisticated subpixel decimation on flatpanels). Also, the
algorithms used by Xft2 adjust the hints to integer widths and the
results are crisper on open source systems than on Windows or
MacIntosh.
* Your fontconfig may (probably does) predate the release of
fontconfig 2.2, and you may see artifacts not present when the font is
used at very small sizes with hinting enabled. "vc-list -V" can be
used to see what version you have installed.
We believe and hope that these fonts will resolve the problems
reported during beta test. The largest change is the reduction of
leading (interline spacing), which had annoyed a number of people, and
reduced Vera's utility for some applcations. The Vera monospace font
should also now make '0' and 'O' and '1' and 'l' more clearly
distinguishable.
The version of these fonts is version 1.10. Fontconfig should be
choosing the new version of the fonts if both the released fonts and
beta test fonts are installed (though please discard them: they have
names of form tt20[1-12]gn.ttf). Note that older versions of
fontconfig sometimes did not rebuild their cache correctly when new
fonts are installed: please upgrade to fontconfig 2.2. "fc-cache -f"
can be used to force rebuilding fontconfig's cache files.
If you note problems, please send them to fonts at gnome dot org, with
exactly which face and size and unicode point you observe the problem
at. The xfd utility from XFree86 CVS may be useful for this (e.g. "xfd
-fa sans"). A possibly more useful program to examine fonts at a
variety of sizes is the "waterfall" program found in Keith Packard's
CVS.
$ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS login
Logging in to :pserver:anoncvs@keithp.com:2401/local/src/CVS
CVS password: <hit return>
$ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS co waterfall
$ cd waterfall
$ xmkmf -a
$ make
# make install
# make install.man
Again, please make sure you are running an up-to-date freetype, and
that you are only examining integer sizes.
Reporting Problems
==================
Please send problem reports to fonts at gnome org, with the following
information:
1. Version of Freetype, Xft2 and fontconfig
2. Whether TT hinting is being used, or the autohinter
3. Application being used
4. Character/Unicode code point that has problems (if applicable)
5. Version of which operating system
6. Please include a screenshot, when possible.
Please check the fonts list archives before reporting problems to cut
down on duplication.

View File

@@ -1,32 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- /etc/fonts.conf file to configure system font access -->
<fontconfig>
<!-- Enable sub-pixel rendering
<match target="font">
<test qual="all" name="rgba">
<const>unknown</const>
</test>
<edit name="rgba" mode="assign"><const>rgb</const></edit>
</match>
-->
<alias>
<family>serif</family>
<prefer>
<family>Bitstream Vera Serif</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Bitstream Vera Sans</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Bitstream Vera Sans Mono</family>
</prefer>
</alias>
</fontconfig>

View File

@@ -1,11 +0,0 @@
<?php
/**
* @package Demos
*/
class AngleField extends IntField
{
function __construct($name, $default, $hint = 'In degrees clockwise, negative values accepted')
{
parent::__construct($name, $default, $hint);
}
}

View File

@@ -1,22 +0,0 @@
<?php
/**
* @package Demos
*/
class CheckboxField extends Field
{
function init($request)
{
$this->value = $request->get($this->name, $this->default ? '1' : null) === '1';
}
function renderBody($name, $id)
{
if ($this->value)
$chk = 'checked="checked"';
else
$chk = '';
echo '<input type="hidden" name="' . $name . '" id="' . $id . '_val" value="' . ($this->value ? '1' : '') . '" />';
echo '<input type="checkbox" ' . $chk . ' name="' . $name . '_cb" id="' . $id . '" value="1" onclick="document.getElementById(\'' . $id . '_val\').value = Number(this.checked);" />';
}
}

View File

@@ -1,50 +0,0 @@
<?php
/**
* @package Demos
*/
class CheckboxSetField extends Field
{
public $options;
public $request;
function __construct($name, $options)
{
$this->name = $name;
$this->options = $options;
}
function init($request)
{
$this->value = array();
if (is_array($request->get($this->name)))
foreach ($request->get($this->name) as $val)
if (in_array($val, $this->options))
$this->value[] = $val;
}
function render()
{
$request = $this->request;
foreach ($this->options as $option)
{
if (is_array($request->get($this->name)) && in_array($option, $request->get($this->name)))
$chk = 'checked="checked"';
else
$chk = '';
$name = $this->name . '[]';
$id = $this->name . '_' . $option;
echo '<input type="checkbox" ' . $chk . ' name="' . $name . '" id="' . $id . '" value="' . $option . '" />';
echo '<label for="' . $id . '">' . $option . '</label> ';
}
}
function getURLValue()
{
$v = '';
foreach ($this->value as $value)
$v .= $this->name . '[]=' . $value . '&';
return $v;
}
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* @package Demos
*/
class ColorField extends Field
{
function __construct($name, $default, $hint = 'RRGGBB hex, leave blank for transparent background')
{
parent::__construct($name, $default, $hint);
}
function init($request)
{
$c = $request->getColor($this->name, $this->default);
if ($c === '')
$this->value = null;
else
$this->value = str_pad(dechex(hexdec($c)), 6, '0', STR_PAD_LEFT);
}
function getRenderValue()
{
return $this->value;
}
}

View File

@@ -1,18 +0,0 @@
<?php
/**
* @package Demos
*/
class CoordinateField extends Field
{
function __construct($name, $default, $hint = 'Smart coordinate')
{
parent::__construct($name, $default, $hint);
}
function init($request)
{
$this->value = $request->getCoordinate($this->name, $this->default);
if ($this->value > 1000)
$this->value = 1000;
}
}

View File

@@ -1,63 +0,0 @@
<?php
/**
* @package Demos
*/
class Demo
{
public $name;
public $format = null;
public $fields = array();
public $order = 1000;
function __construct($name)
{
$this->name = $name;
}
function init()
{
}
static function create($name)
{
$file = DEMO_PATH . '/demos/' . $name . '.php';
if (!file_exists($file))
throw new Exception("Invalid demo: {$name}");
include $file;
$className = 'Demo_' . $name;
$demo = new $className($name);
$demo->request = Request::getInstance();
$demo->init();
foreach ($demo->fields as $field)
{
$field->request = Request::getInstance();
$field->init(Request::getInstance());
}
return $demo;
}
function getFormat()
{
return 'as input';
}
function addField($field)
{
$this->fields[$field->name] = $field;
}
function __toString()
{
return $this->name;
}
function text()
{
}
function fval($name)
{
return $this->fields[$name]->value;
}
}

Some files were not shown because too many files have changed in this diff Show More