Update v1.0.6

This commit is contained in:
Bhanu Slathia
2016-02-16 23:24:52 +05:30
parent c710c20b9e
commit b1f62846ab
7662 changed files with 1361647 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
example/ export-ignore
tests/ export-ignore
phpunit.xml export-ignore

View File

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

View File

@@ -0,0 +1,18 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
before_script:
- travis_retry composer install --no-interaction --prefer-source
script:
- phpunit
notifications:
hipchat:
rooms:
secure: h9501ANwjT/oDK9YM1fmLV9+1WuhEWpRu35VCqJrOHEHpDQjk7W0LZw4xJo/kK10AKCN861U5VT1U5ncxujFLBZ2HnrKGraTCvXRss/dC2wn+fG2P+T4hsQGWAyU/rU/A8uPwZT71gqCmNtt1Xo/uGHt1UHT+H59J3d3GoFjgBY=

View File

@@ -0,0 +1,121 @@
Changelog
=========
1.6.3
-----
### Bug Fixes
- Avoid initializing Bugsnag when no API key is set
| [Dries Vints](https://github.com/driesvints)
| [#72](https://github.com/bugsnag/bugsnag-laravel/pull/72)
1.6.2
-----
### Enhancements
- Add support for configuring the notifier completely from
[environment variables](https://github.com/bugsnag/bugsnag-laravel#environment-variables)
| [Andrew](https://github.com/browner12)
| [#71](https://github.com/bugsnag/bugsnag-laravel/pull/71)
1.6.1
-----
- Fix array syntax for older php
1.6.0
-----
- Move to using .env for api key in laravel 5+
- Support for artisan vendor:publish
1.5.1
-----
- Lumen Service Provider use statement
1.5.0
-----
- Lumen support
- Fix bug in instructions
- Fix bug with reading settings from service file
1.4.2
-----
- Try/catch for missing/nonstandard auth service
1.4.1
-----
- Default severity to 'error'
1.4.0
-----
- Better laravel 5 support!
1.3.0
-----
- Laravel 5 support!
1.2.1
-----
- Protect against missing configuration variables (thanks @jasonlfunk!)
1.2.0
-----
- Update `bugsnag-php` dependency to enable support for code snippets on
your Bugsnag dashboard
- Allow configuring of more Bugsnag settings from your `config.php`
(thanks @jacobmarshall!)
1.1.1
-----
- Fix issue where sending auth information with complex users could fail (thanks @hannesvdvreken!)
1.1.0
-----
- Send user/auth information if available (thanks @hannesvdvreken!)
1.0.10
------
- Laravel 5 support
1.0.9
------
- Split strip paths from `inProject`
1.0.8
-----
- Bump the bugsnag-php dependency to include recent fixes
1.0.7
-----
- Fix major notification bug introduced in 1.0.6
1.0.6
-----
- Fix incompatibility with PHP 5.3
1.0.5
-----
- Identify as Laravel notifier instead of PHP
1.0.4
-----
- Allow configuration of notify_release_stages from config file
1.0.3
-----
- Fix bug when setting releaseStage in the ServiceProvider
1.0.2
-----
- Fix laravel requirement to work with 4.1
- Add a `Bugsnag` facade for quick access to $app["bugsnag"]
1.0.1
-----
- Fixed fatal error handling
- Set release stage based on laravel's `App::environment` setting
1.0.0
-----
- Initial release

View File

@@ -0,0 +1,26 @@
Contributing
============
- [Fork](https://help.github.com/articles/fork-a-repo) the [notifier on github](https://github.com/bugsnag/bugsnag-laravel)
- Build and test your changes:
```
composer install && ./vendor/bin/phpunit
```
- Commit and push until you are happy with your contribution
- [Make a pull request](https://help.github.com/articles/using-pull-requests)
- Thanks!
Releasing
=========
1. Commit all outstanding changes
1. Bump the version in `src/Bugsnag/BugsnagLaravel/BugsnagLaravelServiceProvider.php` and `src/Bugsnag/BugsnagLaravel/BugsnagLumenServiceProvider.php`
2. Update the CHANGELOG.md, and README if appropriate.
3. Commit, tag push
git commit -am v1.x.x
git tag v1.x.x
git push origin master v1.x.x

View File

@@ -0,0 +1,20 @@
Copyright (c) 2013 Bugsnag
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.

349
vendor/bugsnag/bugsnag-laravel/README.md vendored Normal file
View File

@@ -0,0 +1,349 @@
Bugsnag Notifier for Laravel and Lumen
=====================================
The Bugsnag Notifier for Laravel gives you instant notification of errors and
exceptions in your Laravel PHP applications. We support Laravel 5, Laravel 4,
Laravel 3, and Lumen.
[Bugsnag](https://bugsnag.com) captures errors in real-time from your web,
mobile and desktop applications, helping you to understand and resolve them
as fast as possible. [Create a free account](https://bugsnag.com) to start
capturing errors from your applications.
Check out this excellent [Laracasts
screencast](https://laracasts.com/lessons/better-error-tracking-with-bugsnag)
for a quick overview of how to use Bugsnag with your Laravel apps.
Contents
--------
- [Getting Started](#getting-started)
- [Installation](#installation)
- [Laravel 5.0+](#laravel-50)
- [Laravel (Older Versions)](#laravel-older-versions)
- [Lumen](#lumen)
- [Environment Variables](#environment-variables)
- [Usage](#usage)
- [Catching and Reporting Exceptions](#catching-and-reporting-exceptions)
- [Sending Non-fatal Exceptions](#sending-non-fatal-exceptions)
- [Configuration Options](#configuration-options)
- [Error Reporting Levels](#error-reporting-levels)
- [Callbacks](#callbacks)
- [Demo Applications](#demo-applications)
- [Support](#support)
- [Contributing](#contributing)
- [License](#license)
Getting Started
---------------
### Installation
#### Laravel 5.0+
1. Install the `bugsnag/bugsnag-laravel` package
```shell
$ composer require bugsnag/bugsnag-laravel:1.*
```
1. Update `config/app.php` to activate Bugsnag
```php
# Add `BugsnagLaravelServiceProvider` to the `providers` array
'providers' => array(
...
Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider::class,
)
# Add the `BugsnagFacade` to the `aliases` array
'aliases' => array(
...
'Bugsnag' => Bugsnag\BugsnagLaravel\BugsnagFacade::class,
)
```
1. Use the Bugsnag exception handler from `App/Exceptions/Handler.php`.
```php
# DELETE this line
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
```
```php
# ADD this line instead
use Bugsnag\BugsnagLaravel\BugsnagExceptionHandler as ExceptionHandler;
```
After this change, your file should look like this:
```php
<?php namespace App\Exceptions;
use Exception;
use Bugsnag\BugsnagLaravel\BugsnagExceptionHandler as ExceptionHandler;
class Handler extends ExceptionHandler {
...
}
```
1. Create the configuration file `config/bugsnag.php`:
```shell
$ php artisan vendor:publish --provider="Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider"
```
1. Configure your `api_key` in your `.env` file:
```shell
BUGSNAG_API_KEY=YOUR-API-KEY-HERE
```
1. Optionally, you can add the `notify_release_stages` key to the
`config/bugsnag.php` file to define which Laravel environments will send
Exceptions to Bugsnag.
```php
return array(
'api_key' => env('BUGSNAG_API_KEY'),
'notify_release_stages' => ['production', 'staging']
);
```
#### Laravel (Older Versions)
For versions of Laravel before 5.0:
1. Install the `bugsnag/bugsnag-laravel` package
```shell
$ composer require bugsnag/bugsnag-laravel:1.*
```
1. Update app/config/app.php` to activate Bugsnag
```php
# Add `BugsnagLaravelServiceProvider` to the `providers` array
'providers' => array(
...
'Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider',
)
# Add the `BugsnagFacade` to the `aliases` array
'aliases' => array(
...
'Bugsnag' => 'Bugsnag\BugsnagLaravel\BugsnagFacade',
)
```
1. Generate a template Bugsnag config file
```shell
$ php artisan config:publish bugsnag/bugsnag-laravel
```
1. Update `app/config/packages/bugsnag/bugsnag-laravel/config.php` with your
Bugsnag API key:
```php
return array(
'api_key' => 'YOUR-API-KEY-HERE'
);
```
1. Optionally, you can add the `notify_release_stages` key to the same file
above to define which Laravel environments will send Exceptions to Bugsnag.
```php
return array(
'api_key' => 'YOUR-API-KEY-HERE',
'notify_release_stages' => ['production', 'staging']
);
```
#### Lumen
1. In `bootstrap/app.php` add the line
```php
$app->register('Bugsnag\BugsnagLaravel\BugsnagLumenServiceProvider');
```
just before the line
```php
require __DIR__ . '/../app/Http/routes.php';
```
2. Change the function `report` in `app/Exceptions/Handler.php` to look like
this:
```php
public function report(Exception $e) {
app('bugsnag')->notifyException($e, []);
return parent::report($e);
}
```
3. Create a file `config/bugsnag.php` that contains your API key
```php
<?php # config/bugsnag.php
return array(
'api_key' => 'YOUR-API-KEY-HERE'
);
```
### Environment Variables
In addition to `BUGSNAG_API_KEY`, other configuration keys can be automatically
populated in `config.php` from your `.env` file:
- `BUGSNAG_API_KEY`: Your API key. You can find your API key on your Bugsnag
dashboard.
- `BUGSNAG_NOTIFY_RELEASE_STAGES`: Set which release stages should send
notifications to Bugsnag.
- `BUGSNAG_ENDPOINT`: Set what server to which the Bugsnag notifier should send
errors. The default is https://notify.bugsnag.com, but for Bugsnag Enterprise
the endpoint should be the URL of your Bugsnag instance.
- `BUGSNAG_FILTERS`: Set which keys are filtered from metadata is sent to
Bugsnag.
- `BUGSNAG_PROXY`: Set the configuration options for your server if it is behind
a proxy server. Additional details are available in the
[sample configuration](src/Bugsnag/BugsnagLaravel/config.php#L56).
Usage
-----
### Catching and Reporting Exceptions
Bugsnag works "out of the box" for reporting unhandled exceptions in
Laravel and Lumen apps.
### Sending Non-fatal Exceptions
You can easily tell Bugsnag about non-fatal or caught exceptions by
calling `Bugsnag::notifyException`:
```php
Bugsnag::notifyException(new Exception("Something bad happened"));
```
You can also send custom errors to Bugsnag with `Bugsnag::notifyError`:
```php
Bugsnag::notifyError("ErrorType", "Something bad happened here too");
```
Both of these functions can also be passed an optional `$metaData` parameter,
which should take the following format:
```php
$metaData = array(
"user" => array(
"name" => "James",
"email" => "james@example.com"
)
);
```
### Configuration Options
The [Bugsnag PHP Client](https://bugsnag.com/docs/notifiers/php)
is available as `Bugsnag`, which allows you to set various
configuration options. These options are listed in the
[documentation for Bugsnag PHP](https://bugsnag.com/docs/notifiers/php#additional-options).
#### Error Reporting Levels
By default we'll use the value of `error_reporting` from your `php.ini`
or any value you set at runtime using the `error_reporting(...)` function.
If you'd like to send different levels of errors to Bugsnag, you can call
`setErrorReportingLevel`, for example:
```php
Bugsnag::setErrorReportingLevel(E_ALL & ~E_NOTICE);
```
#### Callbacks
It is often useful to send additional meta-data about your app, such as
information about the currently logged in user, along with any
error or exceptions, to help debug problems.
To send custom data, you should define a *before-notify* function,
adding an array of "tabs" of custom data to the $metaData parameter. For example:
```php
Bugsnag::setBeforeNotifyFunction("before_bugsnag_notify");
function before_bugsnag_notify($error) {
// Do any custom error handling here
// Also add some meta data to each error
$error->setMetaData(array(
"user" => array(
"name" => "James",
"email" => "james@example.com"
)
));
}
```
This example snippet adds a "user" tab to the Bugsnag error report. See the
[setBeforeNotifyFunction](https://bugsnag.com/docs/notifiers/php#setbeforenotifyfunction)
documentation on the `bugsnag-php` library for more information.
Demo Applications
-----------------
The [Bugsnag Laravel source
repository](https://github.com/bugsnag/bugsnag-laravel) includes example
applications for [Laravel 4, Laravel 5, and
Lumen](https://github.com/bugsnag/bugsnag-laravel/tree/master/example).
Before running one of the example applications, install the prerequisites:
brew tap josegonzalez/homebrew-php
brew install php56 php56-mcrypt composer
Then open the example directory (such as `example/laravel-5.1`) in a terminal
and start the server:
composer install
php56 artisan serve --port 8004
Support
-------
* [Additional Documentation](https://github.com/bugsnag/bugsnag-laravel/tree/master/docs)
* [Search open and closed issues](https://github.com/bugsnag/bugsnag-laravel/issues?utf8=✓&q=is%3Aissue) for similar problems
* [Report a bug or request a feature](https://github.com/bugsnag/bugsnag-laravel/issues/new)
Contributing
------------
We'd love you to file issues and send pull requests. The [contributing
guidelines](https://github.com/bugsnag/bugsnag-laravel/CONTRIBUTING.md) details
the process of building and testing `bugsnag-laravel`, as well as the pull
request process. Feel free to comment on [existing
issues](https://github.com/bugsnag/bugsnag-laravel/issues) for clarification or
starting points.
License
-------
The Bugsnag Laravel notifier is free software released under the MIT License.
See [LICENSE.txt](LICENSE.txt) for details.

View File

@@ -0,0 +1,23 @@
{
"name": "bugsnag/bugsnag-laravel",
"description": "Official Bugsnag notifier for Laravel applications.",
"keywords": ["bugsnag", "exceptions", "errors", "logging", "tracking", "laravel"],
"homepage": "https://github.com/bugsnag/bugsnag-laravel",
"license": "MIT",
"authors": [
{
"name": "James Smith",
"email": "notifiers@bugsnag.com"
}
],
"require": {
"php": ">=5.3.0",
"illuminate/support": "4.*|5.*",
"bugsnag/bugsnag": ">=2.5.0"
},
"autoload": {
"psr-0": {
"Bugsnag\\BugsnagLaravel\\": "src/"
}
}
}

View File

@@ -0,0 +1,11 @@
{
"providers": [
"Bugsnag\BugsnagLaravel\BugsnagLaravelServiceProvider"
],
"aliases": [
{
"alias": "Bugsnag",
"facade": "Bugsnag\BugsnagLaravel\BugsnagFacade"
}
]
}

View File

@@ -0,0 +1,29 @@
<?php namespace Bugsnag\BugsnagLaravel;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class BugsnagExceptionHandler extends ExceptionHandler {
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
foreach ($this->dontReport as $type) {
if ($e instanceof $type) {
return parent::report($e);
}
}
if (app()->bound('bugsnag')) {
app('bugsnag')->notifyException($e, null, "error");
}
return parent::report($e);
}
}

View File

@@ -0,0 +1,11 @@
<?php namespace Bugsnag\BugsnagLaravel;
use Illuminate\Support\Facades\Facade;
class BugsnagFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'bugsnag';
}
}

View File

@@ -0,0 +1,115 @@
<?php namespace Bugsnag\BugsnagLaravel;
use Illuminate\Support\ServiceProvider;
class BugsnagLaravelServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$app = $this->app;
if (version_compare($app::VERSION, '5.0') < 0) {
$this->package('bugsnag/bugsnag-laravel', 'bugsnag');
// Register for exception handling
$app->error(function (\Exception $exception) use ($app) {
if ('Symfony\Component\Debug\Exception\FatalErrorException'
!== get_class($exception)
) {
$app['bugsnag']->notifyException($exception, null, "error");
}
});
// Register for fatal error handling
$app->fatal(function ($exception) use ($app) {
$app['bugsnag']->notifyException($exception, null, "error");
});
} else {
$this->publishes(array(
__DIR__.'/config.php' => config_path('bugsnag.php'),
));
}
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('bugsnag', function ($app) {
$config = isset($app['config']['services']['bugsnag']) ? $app['config']['services']['bugsnag'] : null;
if (is_null($config)) {
$config = $app['config']['bugsnag'] ?: $app['config']['bugsnag::config'];
}
$client = new \Bugsnag_Client($config['api_key']);
$client->setStripPath(base_path());
$client->setProjectRoot(app_path());
$client->setAutoNotify(false);
$client->setBatchSending(false);
$client->setReleaseStage($app->environment());
$client->setNotifier(array(
'name' => 'Bugsnag Laravel',
'version' => '1.6.3',
'url' => 'https://github.com/bugsnag/bugsnag-laravel'
));
if (isset($config['notify_release_stages']) && is_array($config['notify_release_stages'])) {
$client->setNotifyReleaseStages($config['notify_release_stages']);
}
if (isset($config['endpoint'])) {
$client->setEndpoint($config['endpoint']);
}
if (isset($config['filters']) && is_array($config['filters'])) {
$client->setFilters($config['filters']);
}
if (isset($config['proxy']) && is_array($config['proxy'])) {
$client->setProxySettings($config['proxy']);
}
// Check if someone is logged in.
try {
if ($app['auth']->check()) {
// User is logged in.
$user = $app['auth']->user();
// If these attributes are available: pass them on.
$client->setUser(array('id' => $user->getAuthIdentifier()));
}
} catch (\Exception $e) {
// Do nothing.
}
return $client;
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array("bugsnag");
}
}

View File

@@ -0,0 +1,91 @@
<?php namespace Bugsnag\BugsnagLaravel;
use Illuminate\Support\ServiceProvider;
class BugsnagLumenServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->app->configure('bugsnag');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('bugsnag', function ($app) {
$config = isset($app['config']['services']['bugsnag']) ? $app['config']['services']['bugsnag'] : null;
if (is_null($config)) {
$config = $app['config']['bugsnag'] ?: $app['config']['bugsnag::config'];
}
$client = new \Bugsnag_Client($config['api_key']);
$client->setStripPath(base_path());
$client->setProjectRoot(base_path() . '/app');
$client->setAutoNotify(false);
$client->setBatchSending(false);
$client->setReleaseStage($app->environment());
$client->setNotifier(array(
'name' => 'Bugsnag Lumen',
'version' => '1.6.3',
'url' => 'https://github.com/bugsnag/bugsnag-laravel'
));
if (isset($config['notify_release_stages']) && is_array($config['notify_release_stages'])) {
$client->setNotifyReleaseStages($config['notify_release_stages']);
}
if (isset($config['endpoint'])) {
$client->setEndpoint($config['endpoint']);
}
if (isset($config['filters']) && is_array($config['filters'])) {
$client->setFilters($config['filters']);
}
if (isset($config['proxy']) && is_array($config['proxy'])) {
$client->setProxySettings($config['proxy']);
}
// Check if someone is logged in.
try {
if ($app['auth']->check()) {
// User is logged in.
$user = $app['auth']->user();
// If these attributes are available: pass them on.
$client->setUser(array('id' => $user->getAuthIdentifier()));
}
} catch (\Exception $e) {
// Do nothing.
}
return $client;
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array("bugsnag");
}
}

View File

@@ -0,0 +1,77 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| API Key
|--------------------------------------------------------------------------
|
| You can find your API key on your Bugsnag dashboard.
|
| This api key points the Bugsnag notifier to the project in your account
| which should receive your application's uncaught exceptions.
|
*/
'api_key' => env('BUGSNAG_API_KEY'),
/*
|--------------------------------------------------------------------------
| Notify Release Stages
|--------------------------------------------------------------------------
|
| Set which release stages should send notifications to Bugsnag.
|
| Example: array('development', 'production')
|
*/
'notify_release_stages' => env('BUGSNAG_NOTIFY_RELEASE_STAGES', null),
/*
|--------------------------------------------------------------------------
| Endpoint
|--------------------------------------------------------------------------
|
| Set what server the Bugsnag notifier should send errors to. By default
| this is set to 'https://notify.bugsnag.com', but for Bugsnag Enterprise
| this should be the URL to your Bugsnag instance.
|
*/
'endpoint' => env('BUGSNAG_ENDPOINT', null),
/*
|--------------------------------------------------------------------------
| Filters
|--------------------------------------------------------------------------
|
| Use this if you want to ensure you don't send sensitive data such as
| passwords, and credit card numbers to our servers. Any keys which
| contain these strings will be filtered.
|
*/
'filters' => env('BUGSNAG_FILTERS', array('password')),
/*
|--------------------------------------------------------------------------
| Proxy
|--------------------------------------------------------------------------
|
| If your server is behind a proxy server, you can configure this as well.
| Other than the host, none of these settings are mandatory.
|
| Note: Proxy configuration is only possible if the PHP cURL extension
| is installed.
|
| Example:
|
| 'proxy' => array(
| 'host' => 'bugsnag.com',
| 'port' => 42,
| 'user' => 'username',
| 'password' => 'password123'
| )
|
*/
'proxy' => env('BUGSNAG_PROXY', null)
);

View File

@@ -0,0 +1,77 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| API Key
|--------------------------------------------------------------------------
|
| You can find your API key on your Bugsnag dashboard.
|
| This api key points the Bugsnag notifier to the project in your account
| which should receive your application's uncaught exceptions.
|
*/
'api_key' => 'YOUR-API-KEY-HERE',
/*
|--------------------------------------------------------------------------
| Notify Release Stages
|--------------------------------------------------------------------------
|
| Set which release stages should send notifications to Bugsnag.
|
| Example: array('development', 'production')
|
*/
'notify_release_stages' => null,
/*
|--------------------------------------------------------------------------
| Endpoint
|--------------------------------------------------------------------------
|
| Set what server the Bugsnag notifier should send errors to. By default
| this is set to 'https://notify.bugsnag.com', but for Bugsnag Enterprise
| this should be the URL to your Bugsnag instance.
|
*/
'endpoint' => null,
/*
|--------------------------------------------------------------------------
| Filters
|--------------------------------------------------------------------------
|
| Use this if you want to ensure you don't send sensitive data such as
| passwords, and credit card numbers to our servers. Any keys which
| contain these strings will be filtered.
|
*/
'filters' => array('password'),
/*
|--------------------------------------------------------------------------
| Proxy
|--------------------------------------------------------------------------
|
| If your server is behind a proxy server, you can configure this as well.
| Other than the host, none of these settings are mandatory.
|
| Note: Proxy configuration is only possible if the PHP cURL extension
| is installed.
|
| Example:
|
| 'proxy' => array(
| 'host' => 'bugsnag.com',
| 'port' => 42,
| 'user' => 'username',
| 'password' => 'password123'
| )
|
*/
'proxy' => null
);

13
vendor/bugsnag/bugsnag/.editorconfig vendored Normal file
View File

@@ -0,0 +1,13 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

4
vendor/bugsnag/bugsnag/.gitignore vendored Normal file
View File

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

10
vendor/bugsnag/bugsnag/.travis.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
sudo: false
language: php
php:
- 7.0
- 5.6
- 5.5
- 5.4
- 5.3
- 5.2
- hhvm

209
vendor/bugsnag/bugsnag/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,209 @@
Changelog
=========
2.6.1 (2016-01-28)
-----
### Bug Fixes
* Fixes an error thrown when sending an `Error` instance using PHP 7
[Petr Bugyík](https://github.com/o5)
[#110](https://github.com/bugsnag/bugsnag-php/pull/110)
2.6.0 (23 Dec 2015)
-----
### Enhancements
* Add support for PHP 7's Throwable
| [Chris Stone](https://github.com/cmstone)
| [#106](https://github.com/bugsnag/bugsnag-php/pull/106)
* Fix errors which arise from from error payloads not encoded using UTF-8
| [GaetanNaulin](https://github.com/GaetanNaulin)
| [#104](https://github.com/bugsnag/bugsnag-php/pull/104)
| [#105](https://github.com/bugsnag/bugsnag-php/pull/105)
2.5.6
-----
- Added a debug flag to help diagnose notification problems
2.5.5
-----
- Ensure no unnecessary code is executed when errors should be skipped
2.5.4
-----
- Fix HHVM support for release 2.5.3
2.5.3
-----
- Add support for custom curl options
2.5.2
-----
- Add support for setHostname
2.5.1
-----
- Extract file and line numbers better for crashes in eval'd code
2.5.0
-----
- Collect and send snippets of source code to Bugsnag for easier debugging
- Update `setEndpoint` to accept full URLs
- Add support for `Error#setGroupingHash` to customize error grouping in
`setBeforeNotify` functions
2.4.0
-----
- Don't send $_ENV by default
2.3.1
-----
- Warn if neither curl or fopen are available
2.3.0
-----
- Remove cURL requirement, fallback to using fopen() if cURL not available
2.2.10
------
- Remove default for `setProjectRoot` since it was sometimes overzealous
2.2.9
-----
- Fix boolean metadata handling
2.2.8
-----
- Fix various metadata-encoding bugs
2.2.7
-----
- Allow configuration of projectRoot stripping from stacktraces
2.2.6
-----
- Fix calling `mb_detect_encoding` on non-objects
2.2.5
-----
- Remove deprecated "fatal" severity state
2.2.4
-----
- Prepare 'severity' feature for release
2.2.3
-----
- Fix invalid utf-8 errors for people using iso-8859-1 by default.
2.2.2
-----
- Make frames public on the stacktrace.
2.2.1
-----
- Log any curl errors to the command line, increase default timeout to 10s
2.2.0
-----
- Support previous exceptions on PHP >= 5.3.0
- Allow overriding notifier
- Use manual loading in place of custom autoloading
2.1.4
-----
- Make cURL timeout configurable (thanks pauloschilling)
2.1.3
-----
- Fix crash during stacktrace generation that happened when a closure was
the first stackframe.
2.1.2
-----
- Add `ErrorTypes::getLevelsForSeverity` function to fetch an
`error_reporting` bitmask for a particular Bugsnag severity
2.1.1
-----
- Fix crash during stacktrace generation for frameworks that have their own
`shutdown_handler` method (eg. Laravel)
2.1.0
-----
- Add `setAppType` for sending app type (script, request, resque, etc)
- Add `setUser` for sending structured user data
- Automatically send the severity level of each PHP error
- Added ability to chain setters (eg $bugsnag->setUser(...)->setReleaseStage(...))
2.0.4
-----
- Add hostname collection to help with debugging
2.0.3
-----
- Add `setBatchSending` function to disable batch sending of errors at the
end of each request
2.0.2
-----
- Fix bug which caused `setNotifyReleaseStages` being ignored
2.0.1
-----
- Fix minor request meta-data issues introduced in 2.0.0
2.0.0
-----
- Backwards-incompatible rewrite (using non-static access)
- Full suite of tests and Travis CI testing on PHP 5.2+
- Add `setBeforeNotify` functionality to add meta-data or execute code
before each error is sent to Bugsnag
1.0.9
-----
- Add `setAutoNotify` function to allow disabling of automatic error handling
- Fix bug where error reporting level was being ignored for fatal errors
1.0.8
-----
- Added a `setMetaData` function for sending custom data with every error
1.0.7
-----
- Don't default `notifyReleaseStages` to anything to reduce confusion
1.0.6
-----
- Fix PHP 5.2 bug with missing constants
1.0.5
-----
- Protect against missing $_SERVER variables
1.0.4
-----
- Send JSON POST params to Bugsnag if available
- Send HTTP headers to Bugsnag if available
1.0.3
-----
- Remove unnecessary post to Bugsnag when error list is empty
1.0.2
-----
- Fix bug with 'internal' stacktrace lines (missing line/file)
1.0.1
-----
- Renamed default error classes for clarity
- Batch-send errors at the end of each request
- `Bugsnag::errorHandler` now respects PHP's `error_reporting` settings
- Added `setErrorReportingLevel` function to override PHP's error_reporting settings
1.0.0
-----
- First public release

48
vendor/bugsnag/bugsnag/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,48 @@
Contributing
============
- [Fork](https://help.github.com/articles/fork-a-repo) the [notifier on github](https://github.com/bugsnag/bugsnag-laravel)
- Build and test your changes. Run the tests using [phpunit](https://phpunit.de) (vendored to `vendor/bin/phpunit`)
- Commit and push until you are happy with your contribution
- [Make a pull request](https://help.github.com/articles/using-pull-requests)
- Thanks!
Example apps
============
Test the notifier by running the application locally.
[Install composer](http://getcomposer.org/doc/01-basic-usage.md), and then cd into `example/php` and start the server:
composer install
php index.php
Releasing
=========
1. Commit all outstanding changes
2. Bump the version in `src/Bugsnag/Configuration.php`.
3. Update the CHANGELOG.md, and README if appropriate.
4. Build a new phar package
* NB: You may need to set `phar.readonly = Off` in /usr/local/etc/php/5.4/php.ini
* If not located in /usr/local/etc, check /private/etc/php.ini
* If not in /private/etc/php.ini:
```
sudo cp /private/etc/php.ini.default /private/etc/php.ini
```
* Then:
```
composer install
php pharbuilder.php
```
4. Commit, tag push
```
git commit -am v2.x.x
git tag v2.x.x
git push origin master && git push --tags
```

20
vendor/bugsnag/bugsnag/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright (c) 2013 Bugsnag
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.

481
vendor/bugsnag/bugsnag/README.md vendored Normal file
View File

@@ -0,0 +1,481 @@
Bugsnag Notifier for PHP <img src="https://travis-ci.org/bugsnag/bugsnag-php.svg?branch=master" alt="build status" class="build-status">
========================
The Bugsnag Notifier for PHP gives you instant notification of errors and
exceptions in your PHP applications.
[Bugsnag](https://bugsnag.com) captures errors in real-time from your web,
mobile and desktop applications, helping you to understand and resolve them
as fast as possible. [Create a free account](https://bugsnag.com) to start
capturing errors from your applications.
The Bugsnag Notifier for PHP supports PHP 5.2+.
How to Install
--------------
### Using [Composer](http://getcomposer.org/) (Recommended)
1. Install the `bugsnag/bugsnag-php` package:
```shell
$ composer require "bugsnag/bugsnag:2.*"
```
### Using Phar Package
1. Download the latest [bugsnag.phar](https://raw.github.com/bugsnag/bugsnag-php/master/build/bugsnag.phar)
to your PHP project.
2. Require it in your app.
```php
require_once "/path/to/bugsnag.phar";
```
### Manual Installation
1. Download and extract the [latest Bugsnag source code](https://github.com/bugsnag/bugsnag-php/archive/master.zip)
to your PHP project.
2. Require it in your app using the provided autoloader.
```php
require_once "/path/to/Bugsnag/Autoload.php";
```
Configuration
-------------
1. Configure Bugsnag with your API key:
```php
$bugsnag = new Bugsnag_Client('YOUR-API-KEY-HERE');
```
2. Enable automatic error and exception notification by attaching Bugsnag's
error and exception handlers:
```php
set_error_handler(array($bugsnag, 'errorHandler'));
set_exception_handler(array($bugsnag, 'exceptionHandler'));
```
If you app or PHP framework already has error handling functions, you can
also call `$bugsnag->errorHandler` and `$bugsnag->exceptionHandler`
directly from your existing functions, simply pass all parameters through.
Sending Custom Data With Exceptions
-----------------------------------
It is often useful to send additional meta-data about your app, such as
information about the currently logged in user, along with any
error or exceptions, to help debug problems.
Bugsnag supports sending user information, such as the user's name or email
address, by calling the [setUser](#setUser) function.
To send other custom data, you should define a *before-notify* function,
adding an array of "tabs" of custom data to the $metaData parameter.
For an example, see the [setBeforeNotifyFunction](#setbeforenotifyfunction)
documentation below.
Sending Custom Errors or Non-Fatal Exceptions
---------------------------------------------
You can easily tell Bugsnag about non-fatal or caught exceptions by
calling `notifyException`:
```php
$bugsnag->notifyException(new Exception('Something bad happened'));
```
You can also send custom errors to Bugsnag with `notifyError`:
```php
$bugsnag->notifyError('ErrorType', 'Something bad happened here too');
```
Both of these functions can also be passed an optional `$metaData` parameter,
which should take the following format:
```php
$metaData = array(
'account' => array(
'paying' => true,
'name' => 'Acme Co'
)
);
```
### Severity
You can set the severity of an error in Bugsnag by including the severity option as the fourth parameter when
notifying bugsnag of the error,
```php
$bugsnag->notifyError('ErrorType', 'Something bad happened here too', NULL, "error")
```
Valid severities are `error`, `warning` and `info`.
Severity is displayed in the dashboard and can be used to filter the error list.
By default all crashes (or unhandled exceptions) are set to `error` and all
`$bugsnag->notify` calls default to `warning`.
Additional Configuration
------------------------
###setUser
Bugsnag helps you understand how many of your users are affected by each
error, and allows you to search for which errors affect a particular user
using your Bugsnag dashboard. To send useful user-specific information you can
call `setUser`:
```php
$bugsnag->setUser(array(
'name' => 'Leeroy Jenkins',
'email' => 'leeeeroy@jenkins.com'
));
```
The `name`, `email` and `id` fields are searchable, and everything you send in
this array will be displayed on your Bugsnag dashboard.
The `id` field is used also used by Bugsnag to determine the number of
impacted users. By default, we use the IP address of the request as the `id`.
###setReleaseStage
If you would like to distinguish between errors that happen in different
stages of the application release process (development, production, etc)
you can set the `releaseStage` that is reported to Bugsnag.
```php
$bugsnag->setReleaseStage('development');
```
By default this is set to "production".
###setNotifyReleaseStages
By default, we will notify Bugsnag of errors that happen in *any*
`releaseStage` If you would like to change which release stages notify
Bugsnag of errors you can call `setNotifyReleaseStages`:
```php
$bugsnag->setNotifyReleaseStages(array('development', 'production'));
```
###setMetaData
Sets additional meta-data to send with every bugsnag notification,
for example:
```php
$bugsnag->setMetaData(array(
'account' => array(
'paying' => true,
'name' => 'Acme Co'
)
));
```
###setContext
Bugsnag uses the concept of "contexts" to help display and group your
errors. Contexts represent what was happening in your application at the
time an error occurs. By default this will be set to the current request
URL and HTTP method, eg "GET /pages/documentation".
If you would like to set the bugsnag context manually, you can call
`setContext`:
```php
$bugsnag->setContext('Backport Job');
```
###setType
You can set the type of application executing the current code by using
`setType`:
```php
$bugsnag->setType('resque');
```
This is usually used to represent if you are running plain PHP code "php", via
a framework, eg "laravel", or executing through delayed worker code,
eg "resque". By default this is `NULL`.
###setFilters
Sets the strings to filter out from the `metaData` arrays before sending
them to Bugsnag. Use this if you want to ensure you don't send
sensitive data such as passwords, and credit card numbers to our
servers. Any keys which contain these strings will be filtered.
```php
$bugsnag->setFilters(array('password', 'credit_card'));
```
By default, this is set to be `array("password")`.
###setEndpoint
Set the endpoint to send error reports to. By default we'll send reports to
the standard `https://notify.bugsnag.com` endpoint, but you can override this
if you are using [Bugsnag Enterprise](https://bugsnag.com/enterprise), to
point to your own Bugsnag endpoint:
```php
$bugsnag->setEndpoint("http://bugsnag.internal.example.com");
```
###setTimeout
> Note: Timeout configuration is only possible if the PHP cURL extension is installed.
Define a custom timeout, in seconds, for cURL connection when notifying bugsnag.com.
```php
$bugsnag->setTimeout(2);
```
By default, this is set to be `2`.
###setBeforeNotifyFunction
Set a custom function to call before notifying Bugsnag of an error.
You can use this to call your own error handling functions, to add custom
tabs of data to each error on your Bugsnag dashboard, or to modify the
stacktrace.
To add custom tabs of meta-data, simply add to the `$metaData` array
that is passed as the first parameter to your function, for example:
```php
$bugsnag->setBeforeNotifyFunction('before_bugsnag_notify');
function before_bugsnag_notify(Bugsnag_Error $error) {
// Do any custom error handling here
// Also add some meta data to each error
$error->setMetaData(array(
"user" => array(
"name" => "James",
"email" => "james@example.com"
)
));
}
```
If Bugsnag is called by a wrapper library, you can remove stack frames from the
back-trace. For example:
```php
function before_bugsnag_notify(Bugsnag_Error $error) {
$firstFrame = $error->stacktrace->frames[0];
if ($firstFrame && $firstFrame['file'] === 'My_Logger.php') {
array_splice($error->stacktrace->frames, 0, 1);
}
}
```
You can also return `FALSE` from your beforeNotifyFunction to stop this error
from being sent to bugsnag.
###setAutoNotify
Controls whether bugsnag should automatically notify about any errors it detects in
the PHP error handlers.
```php
$bugsnag->setAutoNotify(FALSE);
```
By default, this is set to `TRUE`.
###setErrorReportingLevel
Set the levels of PHP errors to report to Bugsnag, by default we'll use
the value of `error_reporting` from your `php.ini` or any value you set
at runtime using the `error_reporting(...)` function.
If you'd like to send different levels of errors to Bugsnag, you can call
`setErrorReportingLevel`:
```php
$bugsnag->setErrorReportingLevel(E_ALL & ~E_NOTICE);
```
See PHP's [error reporting documentation](http://php.net/manual/en/errorfunc.configuration.php#ini.error-reporting)
for allowed values.
<!-- Custom anchor for linking from alerts -->
<div id="set-project-root"></div>
###setProjectRoot
We mark stacktrace lines as in-project if they come from files inside your
`projectRoot`. By default this value is automatically set to be
`$_SERVER['DOCUMENT_ROOT']` but sometimes this can cause problems with
stacktrace highlighting. You can set this manually by calling `setProjectRoot`:
```php
$bugsnag->setProjectRoot('/path/to/your/app');
```
If your app has files in many different locations, you should consider using
[setProjectRootRegex](#setprojectrootregex) instead.
###setProjectRootRegex
If your app has files in many different locations, you can set the a regular
expression for matching filenames in stacktrace lines that are part of your
application:
```php
$bugsnag->setProjectRootRegex('('.preg_quote('/app').'|'.preg_quote('/libs').')');
```
###setProxySettings
> Note: Proxy configuration is only possible if the PHP cURL extension is installed.
If your server is behind a proxy server, you can configure this as well:
```php
$bugsnag->setProxySettings(array(
'host' => 'bugsnag.com',
'port' => 42,
'user' => 'username',
'password' => 'password123'
));
```
Other than the host, none of these settings are mandatory.
###setAppVersion
If you tag your app releases with version numbers, Bugsnag can display these
on your dashboard if you call `setAppVersion`:
```php
$bugsnag->setAppVersion('1.2.3');
```
###setSendEnvironment
Bugsnag can transmit your `$_ENV` environment to help diagnose issues. This can
contain private/sensitive information, so we do not transmit this by default. To
send your environment, you can call `setSendEnvironment`:
```php
$bugsnag->setSendEnvironment(true);
```
###setSendCode
Bugsnag automatically sends a small snippet of the code that crashed to help
you diagnose even faster from within your dashboard. If you don't want to send
this snippet, you can call `setSendCode`:
```php
$bugsnag->setSendCode(false);
```
###setGroupingHash
Sets the grouping hash of the error report. All errors with the same grouping hash are grouped together. This is an advanced usage of the library and mis-using it will cause your errors not to group properly in your dashboard.
```php
$error->setGroupingHash($exception->message . $exception->class);
```
PHP Frameworks
--------------
### Laravel
Check out the [bugsnag-laravel](https://github.com/bugsnag/bugsnag-laravel) plugin.
### WordPress
Check out the [WordPress Error Monitoring by Bugsnag](http://wordpress.org/plugins/bugsnag/) plugin.
### CakePHP
Check out the third-party [Label305/bugsnag-cakephp](https://github.com/Label305/bugsnag-cakephp) plugin.
### Magento
Check out the official [Bugsnag Magento Extension](http://www.magentocommerce.com/magento-connect/bugsnag-notifier.html).
### Symfony2
Check out the third-party [evolution7/Evolution7BugsnagBundle](https://github.com/evolution7/Evolution7BugsnagBundle) or [wrep/bugsnag-php-symfony](https://github.com/wrep/bugsnag-php-symfony) bundles.
### Monolog
Check out the 3rd party log handler for monolog: [meadsteve/MonoSnag/](https://github.com/meadsteve/MonoSnag/)
### Silverstripe
Check out the third-party [evolution7/silverstripe-bugsnag-logger](https://github.com/evolution7/silverstripe-bugsnag-logger) plugin.
### Zend Framework 2
Check out the third-party [nickurt/bugsnag-php](https://github.com/nickurt/zf-bugsnag) plugin.
Building a Phar from Source
---------------------------
- Install the composer dependencies
```shell
$ composer install
```
- Build the phar using `pharbuilder.php`. You may need to set `phar.readonly = Off` in your `php.ini`.
```shell
php pharbuilder.php
```
A new `bugsnag.phar` will be generated in the `build` folder.
Reporting Bugs or Feature Requests
----------------------------------
Please report any bugs or feature requests on the github issues page for this
project here:
<https://github.com/bugsnag/bugsnag-php/issues>
Contributing
------------
- [Fork](https://help.github.com/articles/fork-a-repo) the [notifier on github](https://github.com/bugsnag/bugsnag-php)
- Commit and push until you are happy with your contribution
- Run the tests to make sure they all pass: `composer install && vendor/bin/phpunit`
- [Make a pull request](https://help.github.com/articles/using-pull-requests)
- Thanks!
License
-------
The Bugsnag PHP notifier is free software released under the MIT License.
See [LICENSE.txt](https://github.com/bugsnag/bugsnag-php/blob/master/LICENSE.txt) for details.

Binary file not shown.

27
vendor/bugsnag/bugsnag/composer.json vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "bugsnag/bugsnag",
"type": "library",
"description": "Official Bugsnag notifier for PHP applications.",
"keywords": ["bugsnag", "exceptions", "errors", "logging", "tracking"],
"homepage": "https://github.com/bugsnag/bugsnag-php",
"license": "MIT",
"authors": [{
"name": "James Smith",
"email": "notifiers@bugsnag.com",
"homepage": "https://bugsnag.com"
}],
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0"
},
"autoload": {
"psr-0" : {
"Bugsnag_" : "src/"
}
}
}

View File

@@ -0,0 +1,16 @@
- Install composer
<http://getcomposer.org/doc/01-basic-usage.md>
- Install bugsnag using composer
```shell
composer install
```
- Add your API key to the example script
- Run the example script
```shell
php index.php
```

View File

@@ -0,0 +1,5 @@
{
"require": {
"bugsnag/bugsnag": "1.*"
}
}

View File

@@ -0,0 +1,8 @@
<?php
require_once "../../build/bugsnag.phar";
$bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
$bugsnag->notifyError("Broken", "Something broke", array("tab" => array("paying" => true, "object" => (object)array("key" => "value"), "null" => NULL, "string" => "test", "int" => 4)));
?>

12
vendor/bugsnag/bugsnag/pharbuilder.php vendored Normal file
View File

@@ -0,0 +1,12 @@
<?php
function build_phar()
{
$phar = new Phar('build/bugsnag.phar');
$phar->buildFromDirectory(dirname(__FILE__) . '/src','/\.php$/');
$phar->compressFiles(Phar::GZ);
$phar->stopBuffering();
$phar->setStub($phar->createDefaultStub('Bugsnag/Autoload.php'));
}
build_phar();

16
vendor/bugsnag/bugsnag/phpunit.xml vendored Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
bootstrap="./src/Bugsnag/Autoload.php">
<testsuites>
<testsuite name="Bugsnag tests">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,15 @@
<?php
# We used to have an autoloader, but it caused problems in some
# environments. So now we manually load the entire library upfront.
#
# The file is still called Autoload so that existing integration
# instructions continue to work.
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Client.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Configuration.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Diagnostics.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Error.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."ErrorTypes.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Notification.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Request.php";
require_once dirname(__FILE__).DIRECTORY_SEPARATOR."Stacktrace.php";

View File

@@ -0,0 +1,557 @@
<?php
class Bugsnag_Client
{
private $config;
/** @var Bugsnag_Notification|null */
private $notification;
/**
* Initialize Bugsnag
*
* @param String $apiKey your Bugsnag API key
* @throws Exception
*/
public function __construct($apiKey)
{
// Check API key has been passed
if (!is_string($apiKey)) {
throw new Exception('Bugsnag Error: Invalid API key');
}
// Create a configuration object
$this->config = new Bugsnag_Configuration();
$this->config->apiKey = $apiKey;
// Build a Diagnostics object
$this->diagnostics = new Bugsnag_Diagnostics($this->config);
// Register a shutdown function to check for fatal errors
// and flush any buffered errors
register_shutdown_function(array($this, 'shutdownHandler'));
}
/**
* Set your release stage, eg "production" or "development"
*
* @param String $releaseStage the app's current release stage
* @return $this
*/
public function setReleaseStage($releaseStage)
{
$this->config->releaseStage = $releaseStage;
return $this;
}
/**
* Set your app's semantic version, eg "1.2.3"
*
* @param String $appVersion the app's version
* @return $this
*/
public function setAppVersion($appVersion)
{
$this->config->appVersion = $appVersion;
return $this;
}
/**
* Set the host name
*
* @param String $hostname the host name
* @return $this
*/
public function setHostname($hostname)
{
$this->config->hostname = $hostname;
return $this;
}
/**
* Set which release stages should be allowed to notify Bugsnag
* eg array("production", "development")
*
* @param Array $notifyReleaseStages array of release stages to notify for
* @return $this
*/
public function setNotifyReleaseStages(array $notifyReleaseStages)
{
$this->config->notifyReleaseStages = $notifyReleaseStages;
return $this;
}
/**
* Set which Bugsnag endpoint to send errors to.
*
* @param String $endpoint endpoint URL
* @return $this
*/
public function setEndpoint($endpoint)
{
$this->config->endpoint = $endpoint;
return $this;
}
/**
* Enable debug mode to help diagnose problems.
*
* @param Boolean $debug whether to enable debug mode
* @return $this
*/
public function setDebug($debug)
{
$this->config->debug = $debug;
return $this;
}
/**
* Set whether or not to use SSL when notifying bugsnag
*
* @param Boolean $useSSL whether to use SSL
* @deprecated you can now pass full URLs to setEndpoint
* @return $this
*/
public function setUseSSL($useSSL)
{
$this->config->useSSL = $useSSL;
return $this;
}
/**
* Set the desired timeout for cURL connection when notifying bugsnag
*
* @param Integer $timeout the desired timeout in seconds
* @return $this
*/
public function setTimeout($timeout)
{
$this->config->timeout = $timeout;
return $this;
}
/**
* Set the absolute path to the root of your application.
* We use this to help with error grouping and to highlight "in project"
* stacktrace lines.
*
* @param String $projectRoot the root path for your application
* @return $this
*/
public function setProjectRoot($projectRoot)
{
$this->config->setProjectRoot($projectRoot);
return $this;
}
/**
* Set the path that should be stripped from the beginning of
* any stacktrace file line. This helps to normalise filenames
* for grouping and reduces the noise in stack traces.
*
* @param String $stripPath the path to strip from filenames
* @return $this
*/
public function setStripPath($stripPath)
{
$this->config->setStripPath($stripPath);
return $this;
}
/**
* Set the a regular expression for matching filenames in stacktrace lines
* that are part of your application.
*
* @param String $projectRootRegex regex matching paths belong to your project
* @return $this
*/
public function setProjectRootRegex($projectRootRegex)
{
$this->config->projectRootRegex = $projectRootRegex;
return $this;
}
/**
* Set the strings to filter out from metaData arrays before sending then
* to Bugsnag. Eg. array("password", "credit_card")
*
* @param Array $filters an array of metaData filters
* @return $this
*/
public function setFilters(array $filters)
{
$this->config->filters = $filters;
return $this;
}
/**
* Set information about the current user of your app, including
* id, name and email.
*
* @param Array $user an array of user information. Eg:
* array(
* 'name' => 'Bob Hoskins',
* 'email' => 'bob@hoskins.com'
* )
* @return $this
*/
public function setUser(array $user)
{
$this->config->user = $user;
return $this;
}
/**
* @deprecated deprecated since version 2.1
* @param $userId
* @return $this
*/
public function setUserId($userId)
{
if (!is_array($this->config->user)) {
$this->config->user = array();
}
$this->config->user['id'] = $userId;
return $this;
}
/**
* Set a context representing the current type of request, or location in code.
*
* @param String $context the current context
* @return $this
*/
public function setContext($context)
{
$this->config->context = $context;
return $this;
}
/**
* Set the type of application executing the code. This is usually used to
* represent if you are running plain PHP code "php", via a framework,
* eg "laravel", or executing through delayed worker code, eg "resque".
*
* @param String $type the current type
* @return $this
*/
public function setType($type)
{
$this->config->type = $type;
return $this;
}
/**
* Set custom metadata to send to Bugsnag with every error. You can use
* this to add custom tabs of data to each error on your Bugsnag dashboard
*
* @param Array $metaData an array of arrays of custom data. Eg:
* array(
* "user" => array(
* "name" => "James",
* "email" => "james@example.com"
* )
* )
* @return $this
*/
public function setMetaData(array $metaData)
{
$this->config->metaData = $metaData;
return $this;
}
/**
* Set proxy configuration
*
* @param Array $proxySettings an array with proxy settings. Eg:
* array(
* 'host' => "bugsnag.com",
* 'port' => 42,
* 'user' => "username"
* 'password' => "password123"
* )
* @return $this
*/
public function setProxySettings(array $proxySettings)
{
$this->config->proxySettings = $proxySettings;
return $this;
}
/**
* Set custom curl options
*
* @param Array $curlOptions an array with curl options. Eg:
* array(
* CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4
* )
* @return $this
*/
public function setCurlOptions(array $curlOptions)
{
$this->config->curlOptions = $curlOptions;
return $this;
}
/**
* Set a custom function to call before notifying Bugsnag of an error.
* You can use this to call your own error handling functions, or to add
* custom tabs of data to each error on your Bugsnag dashboard.
*
* // Adding meta-data example
* function before_bugsnag_notify($error) {
* $error->addMetaData(array(
* "user" => array(
* "name" => "James"
* )
* ));
* }
* $bugsnag->setBeforeNotifyFunction("before_bugsnag_notify");
* @param callable $beforeNotifyFunction
* @return $this
*/
public function setBeforeNotifyFunction($beforeNotifyFunction)
{
$this->config->beforeNotifyFunction = $beforeNotifyFunction;
return $this;
}
/**
* Set Bugsnag's error reporting level.
* If this is not set, we'll use your current PHP error_reporting value
* from your ini file or error_reporting(...) calls.
*
* @param Integer $errorReportingLevel the error reporting level integer
* exactly as you would pass to PHP's error_reporting
* @return $this
*/
public function setErrorReportingLevel($errorReportingLevel)
{
$this->config->errorReportingLevel = $errorReportingLevel;
return $this;
}
/**
* Sets whether Bugsnag should be automatically notified of unhandled
* exceptions and errors.
*
* @param Boolean $autoNotify whether to auto notify or not
* @return $this
*/
public function setAutoNotify($autoNotify)
{
$this->config->autoNotify = $autoNotify;
return $this;
}
/**
* Sets whether errors should be batched together and send at the end of
* each request.
*
* @param Boolean $batchSending whether to batch together errors
* @return $this
*/
public function setBatchSending($batchSending)
{
$this->config->batchSending = $batchSending;
return $this;
}
/**
* Sets the notifier to report as to Bugsnag. This should only be
* set by other notifier libraries.
*
* @param Array $notifier an array of name, version, url.
* @return $this
*/
public function setNotifier($notifier)
{
$this->config->notifier = $notifier;
return $this;
}
/**
* Sets whether Bugsnag should send $_ENV with each error.
*
* @param Boolean $sendEnvironment whether to send the environment
* @return $this
*/
public function setSendEnvironment($sendEnvironment)
{
$this->config->sendEnvironment = $sendEnvironment;
return $this;
}
/**
* Sets whether Bugsnag should send $_COOKIE with each error.
*
* @param Boolean $sendCookies whether to send the environment
* @return $this
*/
public function setSendCookies($sendCookies)
{
$this->config->sendCookies = $sendCookies;
return $this;
}
/**
* Sets whether Bugsnag should send $_SESSION with each error.
*
* @param Boolean $sendSession whether to send the environment
* @return $this
*/
public function setSendSession($sendSession)
{
$this->config->sendSession = $sendSession;
return $this;
}
/**
* Should we send a small snippet of the code that crashed to help you
* diagnose even faster from within your dashboard.
*
* @param Boolean $sendCode whether to send code to Bugsnag
* @return $this
*/
public function setSendCode($sendCode)
{
$this->config->sendCode = $sendCode;
return $this;
}
/**
* Notify Bugsnag of a non-fatal/handled throwable
*
* @param Throwable $throwable the throwable to notify Bugsnag about
* @param Array $metaData optional metaData to send with this error
* @param String $severity optional severity of this error (fatal/error/warning/info)
*/
public function notifyException($throwable, array $metaData = null, $severity = null)
{
if (is_subclass_of($throwable, 'Throwable') || is_subclass_of($throwable, 'Exception') || get_class($throwable) == 'Exception') {
$error = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $throwable);
$error->setSeverity($severity);
$this->notify($error, $metaData);
}
}
/**
* Notify Bugsnag of a non-fatal/handled error
*
* @param String $name the name of the error, a short (1 word) string
* @param String $message the error message
* @param Array $metaData optional metaData to send with this error
* @param String $severity optional severity of this error (fatal/error/warning/info)
*/
public function notifyError($name, $message, array $metaData = null, $severity = null)
{
$error = Bugsnag_Error::fromNamedError($this->config, $this->diagnostics, $name, $message);
$error->setSeverity($severity);
$this->notify($error, $metaData);
}
// Exception handler callback, should only be called internally by PHP's set_exception_handler
public function exceptionHandler($throwable)
{
if(!$this->config->autoNotify) {
return;
}
$error = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $throwable);
$error->setSeverity("error");
$this->notify($error);
}
// Exception handler callback, should only be called internally by PHP's set_error_handler
public function errorHandler($errno, $errstr, $errfile = '', $errline = 0)
{
if(!$this->config->autoNotify || $this->config->shouldIgnoreErrorCode($errno)) {
return;
}
$error = Bugsnag_Error::fromPHPError($this->config, $this->diagnostics, $errno, $errstr, $errfile, $errline);
$this->notify($error);
}
// Shutdown handler callback, called when the PHP process has finished running
// Should only be called internally by PHP's register_shutdown_function
public function shutdownHandler()
{
// Get last error
$lastError = error_get_last();
// Check if a fatal error caused this shutdown
if (!is_null($lastError) && Bugsnag_ErrorTypes::isFatal($lastError['type']) && $this->config->autoNotify && !$this->config->shouldIgnoreErrorCode($lastError['type'])) {
$error = Bugsnag_Error::fromPHPError($this->config, $this->diagnostics, $lastError['type'], $lastError['message'], $lastError['file'], $lastError['line'], true);
$error->setSeverity("error");
$this->notify($error);
}
// Flush any buffered errors
if ($this->notification) {
$this->notification->deliver();
$this->notification = null;
}
}
/**
* Batches up errors into notifications for later sending
*
* @param Bugsnag_Error $error the error to batch up
* @param array $metaData optional meta data to send with the error
*/
public function notify(Bugsnag_Error $error, $metaData = array())
{
// Queue or send the error
if ($this->sendErrorsOnShutdown()) {
// Create a batch notification unless we already have one
if (is_null($this->notification)) {
$this->notification = new Bugsnag_Notification($this->config);
}
// Add this error to the notification
$this->notification->addError($error, $metaData);
} else {
// Create and deliver notification immediately
$notif = new Bugsnag_Notification($this->config);
$notif->addError($error, $metaData);
$notif->deliver();
}
}
// Should we send errors immediately or on shutdown
private function sendErrorsOnShutdown()
{
return $this->config->batchSending && Bugsnag_Request::isRequest();
}
}

View File

@@ -0,0 +1,101 @@
<?php
class Bugsnag_Configuration
{
public static $DEFAULT_TIMEOUT = 10;
public static $DEFAULT_ENDPOINT = 'https://notify.bugsnag.com';
public static $DEFAULT_NON_SSL_ENDPOINT = 'http://notify.bugsnag.com';
public $apiKey;
public $autoNotify = true;
public $batchSending = true;
public $useSSL = true;
public $endpoint;
public $notifyReleaseStages;
public $filters = array('password');
public $projectRoot;
public $projectRootRegex;
public $proxySettings = array();
public $notifier = array(
'name' => 'Bugsnag PHP (Official)',
'version' => '2.6.1',
'url' => 'https://bugsnag.com',
);
public $sendEnvironment = false;
public $sendCookies = true;
public $sendSession = true;
public $sendCode = true;
public $stripPath;
public $stripPathRegex;
public $context;
public $type;
public $user;
public $releaseStage = 'production';
public $appVersion;
public $hostname;
public $metaData;
public $beforeNotifyFunction;
public $errorReportingLevel;
public $curlOptions = array();
public $debug = false;
public function __construct()
{
$this->timeout = Bugsnag_Configuration::$DEFAULT_TIMEOUT;
}
public function getNotifyEndpoint()
{
if (is_null($this->endpoint)) {
return $this->useSSL ? Bugsnag_Configuration::$DEFAULT_ENDPOINT : Bugsnag_Configuration::$DEFAULT_NON_SSL_ENDPOINT;
} elseif (preg_match('/^(http:\/\/|https:\/\/)/', $this->endpoint)) {
return $this->endpoint;
} else {
return ($this->useSSL ? "https" : "http")."://".$this->endpoint;
}
}
public function shouldNotify()
{
return is_null($this->notifyReleaseStages) || (is_array($this->notifyReleaseStages) && in_array($this->releaseStage, $this->notifyReleaseStages));
}
public function shouldIgnoreErrorCode($code)
{
if (isset($this->errorReportingLevel)) {
return !($this->errorReportingLevel & $code);
} else {
return !(error_reporting() & $code);
}
}
public function setProjectRoot($projectRoot)
{
$this->projectRoot = $projectRoot;
$this->projectRootRegex = '/'.preg_quote($projectRoot, '/')."[\\/]?/i";
if (is_null($this->stripPath)) {
$this->setStripPath($projectRoot);
}
}
public function setStripPath($stripPath)
{
$this->stripPath = $stripPath;
$this->stripPathRegex = '/'.preg_quote($stripPath, '/')."[\\/]?/i";
}
public function get($prop, $default = null)
{
$configured = $this->$prop;
if (is_array($configured) && is_array($default)) {
return array_merge($default, $configured);
} else {
return $configured ? $configured : $default;
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
class Bugsnag_Diagnostics
{
private $config;
public function __construct(Bugsnag_Configuration $config)
{
$this->config = $config;
}
public function getAppData()
{
$appData = array();
if (!is_null($this->config->appVersion)) {
$appData['version'] = $this->config->appVersion;
}
if (!is_null($this->config->releaseStage)) {
$appData['releaseStage'] = $this->config->releaseStage;
}
if (!is_null($this->config->type)) {
$appData['type'] = $this->config->type;
}
return $appData;
}
public function getDeviceData()
{
return array(
'hostname' => $this->config->get('hostname', php_uname('n')),
);
}
public function getContext()
{
return $this->config->get('context', Bugsnag_Request::getContext());
}
public function getUser()
{
$defaultUser = array();
$userId = Bugsnag_Request::getUserId();
if (!is_null($userId)) {
$defaultUser['id'] = $userId;
}
return $this->config->get('user', $defaultUser);
}
}

View File

@@ -0,0 +1,245 @@
<?php
class Bugsnag_Error
{
private static $VALID_SEVERITIES = array(
'error',
'warning',
'info',
);
public $name;
public $payloadVersion = "2";
public $message;
public $severity = "warning";
/** @var Bugsnag_Stacktrace */
public $stacktrace;
public $metaData = array();
public $config;
public $diagnostics;
/** @var Bugsnag_Error|null */
public $previous;
public $groupingHash;
// Static error creation methods, to ensure that Error object is always complete
public static function fromPHPError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $code, $message, $file, $line, $fatal = false)
{
$error = new Bugsnag_Error($config, $diagnostics);
$error->setPHPError($code, $message, $file, $line, $fatal);
return $error;
}
public static function fromPHPThrowable(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $throwable)
{
$error = new Bugsnag_Error($config, $diagnostics);
$error->setPHPException($throwable);
return $error;
}
public static function fromNamedError(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics, $name, $message = null)
{
$error = new Bugsnag_Error($config, $diagnostics);
$error->setName($name)
->setMessage($message)
->setStacktrace(Bugsnag_Stacktrace::generate($config));
return $error;
}
// Private constructor (for use only by the static methods above)
private function __construct(Bugsnag_Configuration $config, Bugsnag_Diagnostics $diagnostics)
{
$this->config = $config;
$this->diagnostics = $diagnostics;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function setMessage($message)
{
$this->message = $message;
return $this;
}
public function setGroupingHash($groupingHash)
{
$this->groupingHash = $groupingHash;
return $this;
}
public function setStacktrace(Bugsnag_Stacktrace $stacktrace)
{
$this->stacktrace = $stacktrace;
return $this;
}
public function setSeverity($severity)
{
if (!is_null($severity)) {
if (in_array($severity, Bugsnag_Error::$VALID_SEVERITIES)) {
$this->severity = $severity;
} else {
error_log('Bugsnag Warning: Tried to set error severity to '.$severity.' which is not allowed.');
}
}
return $this;
}
public function setPHPException($exception)
{
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
if (!$exception instanceof \Throwable) {
error_log('Bugsnag Warning: Exception must implement interface \Throwable.');
return;
}
} else {
if (!$exception instanceof \Exception) {
error_log('Bugsnag Warning: Exception must be instance of \Exception.');
return;
}
}
$this->setName(get_class($exception))
->setMessage($exception->getMessage())
->setStacktrace(Bugsnag_Stacktrace::fromBacktrace($this->config, $exception->getTrace(), $exception->getFile(), $exception->getLine()));
if (method_exists($exception, 'getPrevious')) {
$this->setPrevious($exception->getPrevious());
}
return $this;
}
public function setPHPError($code, $message, $file, $line, $fatal = false)
{
if ($fatal) {
// Generating stacktrace for PHP fatal errors is not possible,
// since this code executes when the PHP process shuts down,
// rather than at the time of the crash.
//
// In these situations, we generate a "stacktrace" containing only
// the line and file number where the crash occurred.
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $file, $line);
} else {
$stacktrace = Bugsnag_Stacktrace::generate($this->config);
}
$this->setName(Bugsnag_ErrorTypes::getName($code))
->setMessage($message)
->setSeverity(Bugsnag_ErrorTypes::getSeverity($code))
->setStacktrace($stacktrace);
return $this;
}
public function setMetaData($metaData)
{
if (is_array($metaData)) {
$this->metaData = array_merge_recursive($this->metaData, $metaData);
}
return $this;
}
public function setPrevious($exception)
{
if ($exception) {
$this->previous = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $exception);
}
return $this;
}
public function toArray()
{
$errorArray = array(
'app' => $this->diagnostics->getAppData(),
'device' => $this->diagnostics->getDeviceData(),
'user' => $this->diagnostics->getUser(),
'context' => $this->diagnostics->getContext(),
'payloadVersion' => $this->payloadVersion,
'severity' => $this->severity,
'exceptions' => $this->exceptionArray(),
'metaData' => $this->cleanupObj($this->metaData),
);
if (isset($this->groupingHash)) {
$errorArray['groupingHash'] = $this->groupingHash;
}
return $errorArray;
}
public function exceptionArray()
{
if ($this->previous) {
$exceptionArray = $this->previous->exceptionArray();
} else {
$exceptionArray = array();
}
$exceptionArray[] = array(
'errorClass' => $this->name,
'message' => $this->message,
'stacktrace' => $this->stacktrace->toArray(),
);
return $this->cleanupObj($exceptionArray);
}
private function cleanupObj($obj)
{
if (is_null($obj)) {
return null;
}
if (is_array($obj)) {
$cleanArray = array();
foreach ($obj as $key => $value) {
// Apply filters if required
if (is_array($this->config->filters)) {
// Check if this key should be filtered
$shouldFilter = false;
foreach ($this->config->filters as $filter) {
if (strpos($key, $filter) !== false) {
$shouldFilter = true;
break;
}
}
// Apply filters
if ($shouldFilter) {
$cleanArray[$key] = '[FILTERED]';
} else {
$cleanArray[$key] = $this->cleanupObj($value);
}
}
}
return $cleanArray;
} elseif (is_string($obj)) {
// UTF8-encode if not already encoded
if (function_exists('mb_detect_encoding') && !mb_detect_encoding($obj, 'UTF-8', true)) {
return utf8_encode($obj);
} else {
return $obj;
}
} elseif (is_object($obj)) {
// json_encode -> json_decode trick turns an object into an array
return $this->cleanupObj(json_decode(json_encode($obj), true));
} else {
return $obj;
}
}
}

View File

@@ -0,0 +1,118 @@
<?php
class Bugsnag_ErrorTypes
{
private static $ERROR_TYPES = array(
E_ERROR => array(
'name' => 'PHP Fatal Error',
'severity' => 'error',
),
E_WARNING => array(
'name' => 'PHP Warning',
'severity' => 'warning',
),
E_PARSE => array(
'name' => 'PHP Parse Error',
'severity' => 'error',
),
E_NOTICE => array(
'name' => 'PHP Notice',
'severity' => 'info',
),
E_CORE_ERROR => array(
'name' => 'PHP Core Error',
'severity' => 'error',
),
E_CORE_WARNING => array(
'name' => 'PHP Core Warning',
'severity' => 'warning',
),
E_COMPILE_ERROR => array(
'name' => 'PHP Compile Error',
'severity' => 'error',
),
E_COMPILE_WARNING => array(
'name' => 'PHP Compile Warning',
'severity' => 'warning',
),
E_USER_ERROR => array(
'name' => 'User Error',
'severity' => 'error',
),
E_USER_WARNING => array(
'name' => 'User Warning',
'severity' => 'warning',
),
E_USER_NOTICE => array(
'name' => 'User Notice',
'severity' => 'info',
),
E_STRICT => array(
'name' => 'PHP Strict',
'severity' => 'info',
),
E_RECOVERABLE_ERROR => array(
'name' => 'PHP Recoverable Error',
'severity' => 'error',
),
// E_DEPRECATED (Since PHP 5.3.0)
8192 => array(
'name' => 'PHP Deprecated',
'severity' => 'info',
),
// E_USER_DEPRECATED (Since PHP 5.3.0)
16384 => array(
'name' => 'User Deprecated',
'severity' => 'info',
),
);
public static function isFatal($code)
{
return self::getSeverity($code) == 'error';
}
public static function getName($code)
{
if (array_key_exists($code, self::$ERROR_TYPES)) {
return self::$ERROR_TYPES[$code]['name'];
} else {
return "Unknown";
}
}
public static function getSeverity($code)
{
if (array_key_exists($code, self::$ERROR_TYPES)) {
return self::$ERROR_TYPES[$code]['severity'];
} else {
return "error";
}
}
public static function getLevelsForSeverity($severity)
{
$levels = 0;
foreach (Bugsnag_ErrorTypes::$ERROR_TYPES as $level => $info) {
if ($info['severity'] == $severity) {
$levels |= $level;
}
}
return $levels;
}
}

View File

@@ -0,0 +1,202 @@
<?php
class Bugsnag_Notification
{
private static $CONTENT_TYPE_HEADER = 'Content-type: application/json';
private $config;
/** @var Bugsnag_Error[] */
private $errorQueue = array();
public function __construct(Bugsnag_Configuration $config)
{
$this->config = $config;
}
public function addError(Bugsnag_Error $error, $passedMetaData = array())
{
// Check if this error should be sent to Bugsnag
if (!$this->config->shouldNotify()) {
return false;
}
// Add global meta-data to error
$error->setMetaData($this->config->metaData);
// Add request meta-data to error
if (Bugsnag_Request::isRequest()) {
$error->setMetaData(Bugsnag_Request::getRequestMetaData());
}
// Session Tab
if ($this->config->sendSession && !empty($_SESSION)) {
$error->setMetaData(array('session' => $_SESSION));
}
// Cookies Tab
if ($this->config->sendCookies && !empty($_COOKIE)) {
$error->setMetaData(array('cookies' => $_COOKIE));
}
// Add environment meta-data to error
if ($this->config->sendEnvironment && !empty($_ENV)) {
$error->setMetaData(array("Environment" => $_ENV));
}
// Add user-specified meta-data to error
$error->setMetaData($passedMetaData);
// Run beforeNotify function (can cause more meta-data to be merged)
if (isset($this->config->beforeNotifyFunction) && is_callable($this->config->beforeNotifyFunction)) {
$beforeNotifyReturn = call_user_func($this->config->beforeNotifyFunction, $error);
}
// Skip this error if the beforeNotify function returned FALSE
if (!isset($beforeNotifyReturn) || $beforeNotifyReturn !== false) {
$this->errorQueue[] = $error;
return true;
} else {
return false;
}
}
public function toArray()
{
$events = array();
foreach ($this->errorQueue as $error) {
$errorArray = $error->toArray();
if (!is_null($errorArray)) {
$events[] = $errorArray;
}
}
return array(
'apiKey' => $this->config->apiKey,
'notifier' => $this->config->notifier,
'events' => $events,
);
}
public function deliver()
{
if (!empty($this->errorQueue)) {
// Post the request to bugsnag
$this->postJSON($this->config->getNotifyEndpoint(), $this->toArray());
// Clear the error queue
$this->errorQueue = array();
}
}
public function postJSON($url, $data)
{
$body = json_encode($data);
// Prefer cURL if it is installed, otherwise fall back to fopen()
// cURL supports both timeouts and proxies
if (function_exists('curl_version')) {
$this->postWithCurl($url, $body);
} elseif (ini_get('allow_url_fopen')) {
$this->postWithFopen($url, $body);
} else {
error_log('Bugsnag Warning: Couldn\'t notify (neither cURL or allow_url_fopen are available on your PHP installation)');
}
}
private function postWithCurl($url, $body)
{
$http = curl_init($url);
// Default curl settings
curl_setopt($http, CURLOPT_HEADER, false);
curl_setopt($http, CURLOPT_RETURNTRANSFER, true);
curl_setopt($http, CURLOPT_POST, true);
curl_setopt($http, CURLOPT_HTTPHEADER, array(Bugsnag_Notification::$CONTENT_TYPE_HEADER));
curl_setopt($http, CURLOPT_POSTFIELDS, $body);
curl_setopt($http, CURLOPT_CONNECTTIMEOUT, $this->config->timeout);
curl_setopt($http, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($http, CURLOPT_VERBOSE, false);
if (defined('HHVM_VERSION')) {
curl_setopt($http, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
} else {
curl_setopt($http, CURL_IPRESOLVE_V4, true);
}
if (!empty($this->config->curlOptions)) {
foreach ($this->config->curlOptions as $option => $value) {
curl_setopt($http, $option, $value);
}
}
// Apply proxy settings (if present)
if (count($this->config->proxySettings)) {
if (isset($this->config->proxySettings['host'])) {
curl_setopt($http, CURLOPT_PROXY, $this->config->proxySettings['host']);
}
if (isset($this->config->proxySettings['port'])) {
curl_setopt($http, CURLOPT_PROXYPORT, $this->config->proxySettings['port']);
}
if (isset($this->config->proxySettings['user'])) {
$userPassword = $this->config->proxySettings['user'].':';
$userPassword .= isset($this->config->proxySettings['password']) ? $this->config->proxySettings['password'] : '';
curl_setopt($http, CURLOPT_PROXYUSERPWD, $userPassword);
}
}
// Execute the request and fetch the response
$responseBody = curl_exec($http);
$statusCode = curl_getinfo($http, CURLINFO_HTTP_CODE);
if ($statusCode > 200) {
error_log('Bugsnag Warning: Couldn\'t notify ('.$responseBody.')');
if($this->config->debug) {
error_log('Bugsnag Debug: Attempted to post to URL - "'.$url.'"');
error_log('Bugsnag Debug: Attempted to post payload - "'.$body.'"');
}
}
if (curl_errno($http)) {
error_log('Bugsnag Warning: Couldn\'t notify ('.curl_error($http).')');
}
curl_close($http);
}
private function postWithFopen($url, $body)
{
// Warn about lack of proxy support if we are using fopen()
if (count($this->config->proxySettings)) {
error_log('Bugsnag Warning: Can\'t use proxy settings unless cURL is installed');
}
// Warn about lack of timeout support if we are using fopen()
if ($this->config->timeout != Bugsnag_Configuration::$DEFAULT_TIMEOUT) {
error_log('Bugsnag Warning: Can\'t change timeout settings unless cURL is installed');
}
// Create the request context
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => Bugsnag_Notification::$CONTENT_TYPE_HEADER.'\r\n',
'content' => $body,
),
'ssl' => array(
'verify_peer' => false,
),
));
// Execute the request and fetch the response
if ($stream = fopen($url, 'rb', false, $context)) {
$response = stream_get_contents($stream);
if (!$response) {
error_log('Bugsnag Warning: Couldn\'t notify (no response)');
}
} else {
error_log('Bugsnag Warning: Couldn\'t notify (fopen failed)');
}
}
}

View File

@@ -0,0 +1,88 @@
<?php
class Bugsnag_Request
{
public static function isRequest()
{
return isset($_SERVER['REQUEST_METHOD']);
}
public static function getRequestMetaData()
{
$requestData = array();
// Request Tab
$requestData['request'] = array();
$requestData['request']['url'] = self::getCurrentUrl();
if (isset($_SERVER['REQUEST_METHOD'])) {
$requestData['request']['httpMethod'] = $_SERVER['REQUEST_METHOD'];
}
if (!empty($_POST)) {
$requestData['request']['params'] = $_POST;
} else {
if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'], 'application/json') === 0) {
$requestData['request']['params'] = json_decode(file_get_contents('php://input'));
}
}
$requestData['request']['ip'] = self::getRequestIp();
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$requestData['request']['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
}
$headers = self::getRequestHeaders();
if (!empty($headers)) {
$requestData['request']['headers'] = $headers;
}
return $requestData;
}
public static function getContext()
{
if (self::isRequest() && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER["REQUEST_URI"])) {
return $_SERVER['REQUEST_METHOD'].' '.strtok($_SERVER["REQUEST_URI"], '?');
} else {
return null;
}
}
public static function getUserId()
{
if (self::isRequest()) {
return self::getRequestIp();
} else {
return null;
}
}
public static function getCurrentUrl()
{
$schema = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? 'https://' : 'http://';
return $schema.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
}
public static function getRequestIp()
{
return isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
}
public static function getRequestHeaders()
{
if (function_exists('getallheaders')) {
return getallheaders();
}
$headers = array();
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
}

View File

@@ -0,0 +1,145 @@
<?php
class Bugsnag_Stacktrace
{
private static $DEFAULT_NUM_LINES = 7;
private static $MAX_LINE_LENGTH = 200;
public $frames = array();
private $config;
public static function generate($config)
{
// Reduce memory usage by omitting args and objects from backtrace
if (version_compare(PHP_VERSION, '5.3.6') >= 0) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS & ~DEBUG_BACKTRACE_PROVIDE_OBJECT);
} elseif (version_compare(PHP_VERSION, '5.2.5') >= 0) {
$backtrace = debug_backtrace(false);
} else {
$backtrace = debug_backtrace();
}
return self::fromBacktrace($config, $backtrace, "[generator]", 0);
}
public static function fromFrame($config, $file, $line)
{
$stacktrace = new Bugsnag_Stacktrace($config);
$stacktrace->addFrame($file, $line, "[unknown]");
return $stacktrace;
}
public static function fromBacktrace($config, $backtrace, $topFile, $topLine)
{
$stacktrace = new Bugsnag_Stacktrace($config);
// PHP backtrace's are misaligned, we need to shift the file/line down a frame
foreach ($backtrace as $frame) {
if (!self::frameInsideBugsnag($frame)) {
$stacktrace->addFrame(
$topFile,
$topLine,
isset($frame['function']) ? $frame['function'] : null,
isset($frame['class']) ? $frame['class'] : null
);
}
if (isset($frame['file']) && isset($frame['line'])) {
$topFile = $frame['file'];
$topLine = $frame['line'];
} else {
$topFile = "[internal]";
$topLine = 0;
}
}
// Add a final stackframe for the "main" method
$stacktrace->addFrame($topFile, $topLine, '[main]');
return $stacktrace;
}
public static function frameInsideBugsnag($frame)
{
return isset($frame['class']) && strpos($frame['class'], 'Bugsnag_') === 0;
}
public function __construct($config)
{
$this->config = $config;
}
public function toArray()
{
return $this->frames;
}
public function addFrame($file, $line, $method, $class = null)
{
// Account for special "filenames" in eval'd code
$matches = array();
if (preg_match("/^(.*?)\((\d+)\) : (?:eval\(\)'d code|runtime-created function)$/", $file, $matches)) {
$file = $matches[1];
$line = $matches[2];
}
// Construct the frame
$frame = array(
'lineNumber' => $line,
'method' => $class ? "$class::$method" : $method,
);
// Attach some lines of code for context
if($this->config->sendCode) {
$frame['code'] = $this->getCode($file, $line, Bugsnag_Stacktrace::$DEFAULT_NUM_LINES);
}
// Check if this frame is inProject
$frame['inProject'] = !is_null($this->config->projectRootRegex) && preg_match($this->config->projectRootRegex, $file);
// Strip out projectRoot from start of file path
if (is_null($this->config->stripPathRegex)) {
$frame['file'] = $file;
} else {
$frame['file'] = preg_replace($this->config->stripPathRegex, '', $file);
}
$this->frames[] = $frame;
}
private function getCode($path, $line, $numLines)
{
if (empty($path) || empty($line) || !file_exists($path)) {
return NULL;
}
try {
// Get the number of lines in the file
$file = new SplFileObject($path);
$file->seek(PHP_INT_MAX);
$totalLines = $file->key() + 1;
// Work out which lines we should fetch
$start = max($line - floor($numLines / 2), 1);
$end = $start + ($numLines - 1);
if ($end > $totalLines) {
$end = $totalLines;
$start = max($end - ($numLines - 1), 1);
}
// Get the code for this range
$code = array();
$file->seek($start - 1);
while ($file->key() < $end) {
$code[$file->key() + 1] = rtrim(substr($file->current(), 0, Bugsnag_Stacktrace::$MAX_LINE_LENGTH));
$file->next();
}
return $code;
} catch (RuntimeException $ex) {
return null;
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
abstract class Bugsnag_TestCase extends PHPUnit_Framework_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
/** @var Bugsnag_Diagnostics */
protected $diagnostics;
protected function getError($name = "Name", $message = "Message")
{
return Bugsnag_Error::fromNamedError($this->config, $this->diagnostics, $name, $message);
}
protected function getFixturePath($file)
{
return realpath(dirname(__FILE__)."/../fixtures/".$file);
}
protected function getFixture($file)
{
return file_get_contents($this->getFixturePath($file));
}
protected function getJsonFixture($file)
{
return json_decode($this->getFixture($file), true);
}
}

View File

@@ -0,0 +1,97 @@
<?php
if (!defined('PHP_VERSION_ID')) {
$version = explode('.', PHP_VERSION);
define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
}
if (PHP_VERSION_ID < 50207) {
define('PHP_MAJOR_VERSION', $version[0]);
define('PHP_MINOR_VERSION', $version[1]);
define('PHP_RELEASE_VERSION', $version[2]);
}
class ClientTest extends PHPUnit_Framework_TestCase
{
/** @var PHPUnit_Framework_MockObject_MockObject|Bugsnag_Client */
protected $client;
protected function setUp()
{
// Mock the notify function
$this->client = $this->getMockBuilder('Bugsnag_Client')
->setMethods(array('notify'))
->setConstructorArgs(array('example-api-key'))
->getMock();
}
public function testErrorHandler()
{
$this->client->expects($this->once())
->method('notify');
$this->client->errorHandler(E_WARNING, "Something broke", "somefile.php", 123);
}
public function testExceptionHandler()
{
$this->client->expects($this->once())
->method('notify');
$this->client->exceptionHandler(new Exception("Something broke"));
}
public function testManualErrorNotification()
{
$this->client->expects($this->once())
->method('notify');
$this->client->notifyError("SomeError", "Some message");
}
public function testManualExceptionNotification()
{
$this->client->expects($this->once())
->method('notify');
$this->client->notifyException(new Exception("Something broke"));
}
public function testErrorReportingLevel()
{
$this->client->expects($this->once())
->method('notify');
$this->client->setErrorReportingLevel(E_NOTICE)
->errorHandler(E_NOTICE, "Something broke", "somefile.php", 123);
}
public function testErrorReportingLevelFails()
{
$this->client->expects($this->never())
->method('notify');
$this->client->setErrorReportingLevel(E_NOTICE)
->errorHandler(E_WARNING, "Something broke", "somefile.php", 123);
}
public function testErrorReportingWithoutNotice()
{
$this->client->expects($this->never())
->method('notify');
$this->client->setErrorReportingLevel(E_ALL & ~E_NOTICE)
->errorHandler(E_NOTICE, "Something broke", "somefile.php", 123);
}
public function testSetInvalidCurlOptions()
{
if (PHP_MAJOR_VERSION >= 7) {
$this->setExpectedException('TypeError');
} else {
$this->setExpectedException('PHPUnit_Framework_Error');
}
$this->client->setCurlOptions("option");
}
}

View File

@@ -0,0 +1,74 @@
<?php
class ConfigurationTest extends PHPUnit_Framework_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
protected function setUp()
{
$this->config = new Bugsnag_Configuration();
}
public function testDefaultEndpoint()
{
$this->assertEquals($this->config->getNotifyEndpoint(), "https://notify.bugsnag.com");
}
public function testNonSSLEndpoint()
{
$this->config->useSSL = false;
$this->assertEquals($this->config->getNotifyEndpoint(), "http://notify.bugsnag.com");
}
public function testCustomEndpoint()
{
$this->config->useSSL = false;
$this->config->endpoint = "localhost";
$this->assertEquals($this->config->getNotifyEndpoint(), "http://localhost");
}
public function testDefaultReleaseStageShouldNotify()
{
$this->assertTrue($this->config->shouldNotify());
}
public function testCustomReleaseStageShouldNotify()
{
$this->config->releaseStage = "staging";
$this->assertTrue($this->config->shouldNotify());
}
public function testCustomNotifyReleaseStagesShouldNotify()
{
$this->config->notifyReleaseStages = array("banana");
$this->assertFalse($this->config->shouldNotify());
}
public function testBothCustomShouldNotify()
{
$this->config->releaseStage = "banana";
$this->config->notifyReleaseStages = array("banana");
$this->assertTrue($this->config->shouldNotify());
}
public function testNotifier()
{
$this->assertEquals($this->config->notifier['name'], "Bugsnag PHP (Official)");
$this->assertEquals($this->config->notifier['url'], "https://bugsnag.com");
}
public function testShouldIgnore()
{
$this->config->errorReportingLevel = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED;
$this->assertTrue($this->config->shouldIgnoreErrorCode(E_NOTICE));
}
public function testShouldNotIgnore()
{
$this->config->errorReportingLevel = E_ALL;
$this->assertfalse($this->config->shouldIgnoreErrorCode(E_NOTICE));
}
}

View File

@@ -0,0 +1,54 @@
<?php
class DiagnosticsTest extends PHPUnit_Framework_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
/** @var Bugsnag_Diagnostics */
protected $diagnostics;
protected function setUp()
{
$this->config = new Bugsnag_Configuration();
$this->diagnostics = new Bugsnag_Diagnostics($this->config);
}
public function testDefaultAppData()
{
$this->config->releaseStage = 'qa1';
$this->config->appVersion = '1.2.3';
$this->config->type = "laravel";
$appData = $this->diagnostics->getAppData();
$this->assertEquals($appData['releaseStage'], 'qa1');
$this->assertEquals($appData['version'], '1.2.3');
$this->assertEquals($appData['type'], 'laravel');
}
public function testDefaultDeviceData()
{
$this->config->hostname = 'web1.example.com';
$deviceData = $this->diagnostics->getDeviceData();
$this->assertEquals($deviceData['hostname'], 'web1.example.com');
}
public function testDefaultContext()
{
$this->config->context = 'herp#derp';
$this->assertEquals($this->diagnostics->getContext(), 'herp#derp');
}
public function testDefaultUser()
{
$this->config->user = array('id' => 123, 'email' => "test@email.com", 'name' => "Bob Hoskins");
$userData = $this->diagnostics->getUser();
$this->assertEquals($userData['id'], 123);
$this->assertEquals($userData['email'], "test@email.com");
$this->assertEquals($userData['name'], "Bob Hoskins");
}
}

View File

@@ -0,0 +1,137 @@
<?php
require_once 'Bugsnag_TestCase.php';
class ErrorTest extends Bugsnag_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
/** @var Bugsnag_Diagnostics */
protected $diagnostics;
/** @var Bugsnag_Error */
protected $error;
protected function setUp()
{
$this->config = new Bugsnag_Configuration();
$this->diagnostics = new Bugsnag_Diagnostics($this->config);
$this->error = $this->getError();
}
public function testMetaData()
{
$this->error->setMetaData(array("Testing" => array("globalArray" => "hi")));
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['metaData']["Testing"]["globalArray"], "hi");
}
public function testMetaDataMerging()
{
$this->error->setMetaData(array("Testing" => array("globalArray" => "hi")));
$this->error->setMetaData(array("Testing" => array("localArray" => "yo")));
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['metaData']["Testing"]["globalArray"], "hi");
$this->assertEquals($errorArray['metaData']["Testing"]["localArray"], "yo");
}
public function testFiltering()
{
$this->error->setMetaData(array("Testing" => array("password" => "123456")));
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['metaData']['Testing']['password'], '[FILTERED]');
}
public function testNoticeName()
{
$this->error->setPHPError(E_NOTICE, "Broken", "file", 123);
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['exceptions'][0]['errorClass'], 'PHP Notice');
}
public function testErrorName()
{
$this->error->setPHPError(E_ERROR, "Broken", "file", 123);
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['exceptions'][0]['errorClass'], 'PHP Fatal Error');
}
public function testErrorPayloadVersion()
{
$this->error->setPHPError(E_ERROR, "Broken", "file", 123);
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['payloadVersion'], '2');
}
public function testNoticeSeverity()
{
$this->error->setPHPError(E_NOTICE, "Broken", "file", 123);
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['severity'], 'info');
}
public function testErrorSeverity()
{
$this->error->setPHPError(E_ERROR, "Broken", "file", 123);
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['severity'], 'error');
}
public function testManualSeverity()
{
$this->error->setSeverity("error");
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['severity'], 'error');
}
public function testInvalidSeverity()
{
$this->error->setSeverity("bunk");
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['severity'], 'warning');
}
public function testPreviousException()
{
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
$exception = new Exception("secondly", 65533, new Exception("firstly"));
$error = Bugsnag_Error::fromPHPThrowable($this->config, $this->diagnostics, $exception);
$errorArray = $error->toArray();
$this->assertEquals(count($errorArray['exceptions']), 2);
$this->assertEquals($errorArray['exceptions'][0]['message'], 'firstly');
$this->assertEquals($errorArray['exceptions'][1]['message'], 'secondly');
}
}
public function testErrorGroupingHash()
{
$this->error->setGroupingHash('herp#derp');
$errorArray = $this->error->toArray();
$this->assertEquals($errorArray['groupingHash'], 'herp#derp');
}
public function testErrorGroupingHashNotSet()
{
$errorArray = $this->error->toArray();
$this->assertArrayNotHasKey('groupingHash', $errorArray);
}
public function testSetPHPException()
{
$exception = version_compare(PHP_VERSION, '7.0.0', '>=') ? new \Error() : new Exception();
$this->error->setPHPException($exception);
}
}

View File

@@ -0,0 +1,11 @@
<?php
class ErrorTypesTest extends PHPUnit_Framework_TestCase
{
public function testGetLevelsForSeverity()
{
$this->assertEquals(Bugsnag_ErrorTypes::getLevelsForSeverity("error"), 4437);
$this->assertEquals(Bugsnag_ErrorTypes::getLevelsForSeverity("warning"), 674);
$this->assertEquals(Bugsnag_ErrorTypes::getLevelsForSeverity("info"), 27656);
}
}

View File

@@ -0,0 +1,131 @@
<?php
require_once 'Bugsnag_TestCase.php';
class NotificationTest extends Bugsnag_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
/** @var Bugsnag_Diagnostics */
protected $diagnostics;
/** @var Bugsnag_Notification|PHPUnit_Framework_MockObject_MockObject */
protected $notification;
protected function setUp()
{
$this->config = new Bugsnag_Configuration();
$this->config->apiKey = "6015a72ff14038114c3d12623dfb018f";
$this->config->beforeNotifyFunction = "before_notify_skip_error";
$this->diagnostics = new Bugsnag_Diagnostics($this->config);
$this->notification = $this->getMockBuilder('Bugsnag_Notification')
->setMethods(array("postJSON"))
->setConstructorArgs(array($this->config))
->getMock();
}
public function testNotification()
{
// Create a mock notification object
$this->notification = $this->getMockBuilder('Bugsnag_Notification')
->setMethods(array("postJSON"))
->setConstructorArgs(array($this->config))
->getMock();
// Expect postJSON to be called
$this->notification->expects($this->once())
->method("postJSON")
->with($this->equalTo("https://notify.bugsnag.com"),
$this->anything());
// Add an error to the notification and deliver it
$this->notification->addError($this->getError());
$this->notification->deliver();
}
public function testBeforeNotifySkipsError()
{
$this->notification->expects($this->never())
->method("postJSON");
$this->notification->addError($this->getError("SkipMe", "Message"));
$this->notification->deliver();
}
/**
* Test for ensuring that the addError method calls shouldNotify
*
* If shouldNotify returns false, the error should not be added
*/
public function testAddErrorChecksShouldNotifyFalse()
{
$config = $this->getMockBuilder('Bugsnag_Configuration')
->setMethods(array("shouldNotify"))
->getMock();
$config->expects($this->once())
->method('shouldNotify')
->will($this->returnValue(false));
/** @var Bugsnag_Notification $notification */
$notification = $this->getMockBuilder('Bugsnag_Notification')
->setMethods(array("postJSON"))
->setConstructorArgs(array($config))
->getMock();
$this->assertFalse($notification->addError($this->getError()));
}
/**
* Test for ensuring that the deliver method calls shouldNotify
*
* If shouldNotify returns false, the error should not be sent
*/
public function testDeliverChecksShouldNotify()
{
$config = $this->getMockBuilder('Bugsnag_Configuration')
->setMethods(array("shouldNotify"))
->getMock();
$config->expects($this->once())
->method('shouldNotify')
->will($this->returnValue(false));
/** @var Bugsnag_Notification|PHPUnit_Framework_MockObject_MockObject $notification */
$notification = $this->getMockBuilder('Bugsnag_Notification')
->setMethods(array("postJSON"))
->setConstructorArgs(array($config))
->getMock();
$notification->expects($this->never())
->method("postJSON");
$notification->addError($this->getError());
$notification->deliver();
}
public function testNoEnvironmentByDefault()
{
$_ENV["SOMETHING"] = "blah";
$notification = new Bugsnag_Notification($this->config);
$notification->addError($this->getError());
$notificationArray = $notification->toArray();
$this->assertArrayNotHasKey("Environment", $notificationArray["events"][0]["metaData"]);
}
public function testEnvironmentPresentWhenRequested()
{
$_ENV["SOMETHING"] = "blah";
$this->config->sendEnvironment = true;
$notification = new Bugsnag_Notification($this->config);
$notification->addError($this->getError());
$notificationArray = $notification->toArray();
$this->assertEquals($notificationArray["events"][0]["metaData"]["Environment"]["SOMETHING"], "blah");
}
}
function before_notify_skip_error($error)
{
return $error->name != "SkipMe";
}

View File

@@ -0,0 +1,37 @@
<?php
class RequestTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
$_SERVER['REQUEST_METHOD'] = "GET";
$_SERVER['REQUEST_URI'] = "/blah/blah.php?some=param";
$_SERVER['REMOTE_ADDR'] = "123.45.67.8";
$_SERVER['SERVER_PORT'] = "80";
$_SERVER['HTTP_HOST'] = "example.com";
$_SERVER['HTTP_USER_AGENT'] = "Example Browser 1.2.3";
$_COOKIE = array("cookie" => "cookieval");
$_SESSION = array("session" => "sessionval");
}
public function testIsRequest()
{
$this->assertTrue(Bugsnag_Request::isRequest());
}
public function testGetContext()
{
$this->assertEquals(Bugsnag_Request::getContext(), "GET /blah/blah.php");
}
public function testGetCurrentUrl()
{
$this->assertEquals(Bugsnag_Request::getCurrentUrl(), "http://example.com/blah/blah.php?some=param");
}
public function testRequestIp()
{
$this->assertEquals(Bugsnag_Request::getRequestIp(), "123.45.67.8");
}
}

View File

@@ -0,0 +1,211 @@
<?php
require_once 'Bugsnag_TestCase.php';
class StacktraceTest extends Bugsnag_TestCase
{
/** @var Bugsnag_Configuration */
protected $config;
/** @var Bugsnag_Diagnostics */
protected $diagnostics;
protected function setUp()
{
$this->config = new Bugsnag_Configuration();
$this->diagnostics = new Bugsnag_Diagnostics($this->config);
}
protected function assertFrameEquals($frame, $method, $file, $line)
{
$this->assertEquals($frame["method"], $method);
$this->assertEquals($frame["file"], $file);
$this->assertEquals($frame["lineNumber"], $line);
}
protected function assertCodeEquals($expected, $actual)
{
$this->assertEquals(rtrim(substr($expected, 0, 200)), $actual);
}
public function testFromFrame()
{
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, "some_file.php", 123)->toarray();
$this->assertCount(1, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "[unknown]", "some_file.php", 123);
}
public function testFrameInsideBugsnag()
{
$frame = $this->getJsonFixture('frames/non_bugsnag.json');
$bugsnagFrame = $this->getJsonFixture('frames/bugsnag.json');
$this->assertFalse(Bugsnag_Stacktrace::frameInsideBugsnag($frame));
$this->assertTrue(Bugsnag_Stacktrace::frameInsideBugsnag($bugsnagFrame));
}
public function testTriggeredErrorStacktrace()
{
$fixture = $this->getJsonFixture('backtraces/trigger_error.json');
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], $fixture['file'], $fixture['line'])->toArray();
$this->assertCount(4, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "trigger_error", "[internal]", 0);
$this->assertFrameEquals($stacktrace[1], "crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 17);
$this->assertFrameEquals($stacktrace[2], "parent_of_crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 13);
$this->assertFrameEquals($stacktrace[3], "[main]", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 20);
}
public function testErrorHandlerStacktrace()
{
$fixture = $this->getJsonFixture('backtraces/error_handler.json');
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], $fixture['file'], $fixture['line'])->toArray();
$this->assertCount(3, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 22);
$this->assertFrameEquals($stacktrace[1], "parent_of_crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 13);
$this->assertFrameEquals($stacktrace[2], "[main]", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 25);
}
public function testExceptionHandlerStacktrace()
{
$fixture = $this->getJsonFixture('backtraces/exception_handler.json');
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], $fixture['file'], $fixture['line'])->toArray();
$this->assertCount(3, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 25);
$this->assertFrameEquals($stacktrace[1], "parent_of_crashy_function", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 13);
$this->assertFrameEquals($stacktrace[2], "[main]", "/Users/james/src/bugsnag/bugsnag-php/testing.php", 28);
}
public function testAnonymousFunctionStackframes()
{
$fixture = $this->getJsonFixture('backtraces/anonymous_frame.json');
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], "somefile.php", 123)->toArray();
$this->assertCount(5, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "Illuminate\\Support\\Facades\\Facade::__callStatic", "somefile.php", 123);
$this->assertFrameEquals($stacktrace[1], "Bugsnag\\BugsnagLaravel\\BugsnagFacade::notifyError", "controllers/ExampleController.php", 12);
$this->assertFrameEquals($stacktrace[2], "ExampleController::index", "controllers/ExampleController.php", 12);
$this->assertFrameEquals($stacktrace[3], "call_user_func_array", "[internal]", 0);
$this->assertFrameEquals($stacktrace[4], "[main]", "Routing/Controller.php", 194);
}
public function testXdebugErrorStackframes()
{
$fixture = $this->getJsonFixture('backtraces/xdebug_error.json');
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], $fixture['file'], $fixture['line'])->toArray();
$this->assertCount(7, $stacktrace);
$this->assertFrameEquals($stacktrace[0], null, "somefile.php", 123);
$this->assertFrameEquals($stacktrace[1], "Illuminate\\View\\Engines\\PhpEngine::evaluatePath", "/View/Engines/PhpEngine.php", 39);
$this->assertFrameEquals($stacktrace[2], "Illuminate\\View\\Engines\\CompilerEngine::get", "View/Engines/CompilerEngine.php", 57);
$this->assertFrameEquals($stacktrace[3], "Illuminate\\View\\View::getContents", "View/View.php", 136);
$this->assertFrameEquals($stacktrace[4], "Illuminate\\View\\View::renderContents", "View/View.php", 104);
$this->assertFrameEquals($stacktrace[5], "Illuminate\\View\\View::render", "View/View.php", 78);
$this->assertFrameEquals($stacktrace[6], "[main]", "storage/views/f2df2d6b49591efeb36fc46e6dc25e0e", 5);
}
public function testEvaledStackframes()
{
$evalFrame = $this->getJsonFixture('frames/eval.json');
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $evalFrame["file"], $evalFrame["line"])->toArray();
$topFrame = $stacktrace[0];
$this->assertEquals($topFrame["file"], "path/some/file.php");
$this->assertEquals($topFrame["lineNumber"], 123);
$evalFrame = $this->getJsonFixture('frames/runtime_created.json');
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $evalFrame["file"], $evalFrame["line"])->toArray();
$topFrame = $stacktrace[0];
$this->assertEquals($topFrame["file"], "path/some/file.php");
$this->assertEquals($topFrame["lineNumber"], 123);
}
public function testStrippingPaths()
{
$fixture = $this->getJsonFixture('backtraces/exception_handler.json');
$this->config->setStripPath("/Users/james/src/bugsnag/bugsnag-php/");
$stacktrace = Bugsnag_Stacktrace::fromBacktrace($this->config, $fixture['backtrace'], $fixture['file'], $fixture['line'])->toArray();
$this->assertCount(3, $stacktrace);
$this->assertFrameEquals($stacktrace[0], "crashy_function", "testing.php", 25);
$this->assertFrameEquals($stacktrace[1], "parent_of_crashy_function", "testing.php", 13);
$this->assertFrameEquals($stacktrace[2], "[main]", "testing.php", 28);
}
public function testCode()
{
$fileContents = explode("\n", $this->getFixture('code/File.php'));
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $this->getFixturePath('code/File.php'), 12)->toArray();
$this->assertCount(1, $stacktrace);
$topFrame = $stacktrace[0];
$this->assertCount(7, $topFrame["code"]);
for ($i=9; $i<=15; $i++) {
$this->assertCodeEquals($fileContents[$i - 1], $topFrame["code"][$i]);
}
}
public function testCodeShortFile()
{
$fileContents = explode("\n", $this->getFixture('code/ShortFile.php'));
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $this->getFixturePath('code/ShortFile.php'), 1)->toArray();
$this->assertCount(1, $stacktrace);
$topFrame = $stacktrace[0];
$this->assertCount(3, $topFrame["code"]);
for ($i=1; $i<=2; $i++) {
$this->assertCodeEquals($fileContents[$i - 1], $topFrame["code"][$i]);
}
}
public function testCodeEndOfFile()
{
$fileContents = explode("\n", $this->getFixture('code/File.php'));
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $this->getFixturePath('code/File.php'), 22)->toArray();
$this->assertCount(1, $stacktrace);
$topFrame = $stacktrace[0];
$this->assertCount(7, $topFrame["code"]);
for ($i=16; $i<=22; $i++) {
$this->assertCodeEquals($fileContents[$i - 1], $topFrame["code"][$i]);
}
}
public function testCodeStartOfFile()
{
$fileContents = explode("\n", $this->getFixture('code/File.php'));
$stacktrace = Bugsnag_Stacktrace::fromFrame($this->config, $this->getFixturePath('code/File.php'), 1)->toArray();
$this->assertCount(1, $stacktrace);
$topFrame = $stacktrace[0];
$this->assertCount(7, $topFrame["code"]);
for ($i=1; $i<=7; $i++) {
$this->assertCodeEquals($fileContents[$i - 1], $topFrame["code"][$i]);
}
}
public function testCodeDisabled()
{
$config = new Bugsnag_Configuration();
$config->sendCode = false;
$stacktrace = Bugsnag_Stacktrace::fromFrame($config, $this->getFixturePath('code/File.php'), 1)->toArray();
$this->assertCount(1, $stacktrace);
$topFrame = $stacktrace[0];
$this->assertArrayNotHasKey('code', $topFrame);
}
}

View File

@@ -0,0 +1,25 @@
{
"backtrace": [
{
"file": "controllers/ExampleController.php",
"line": "12",
"class": "Illuminate\\Support\\Facades\\Facade",
"function": "__callStatic"
},
{
"file": "controllers/ExampleController.php",
"line": "12",
"class": "Bugsnag\\BugsnagLaravel\\BugsnagFacade",
"function": "notifyError"
},
{
"class": "ExampleController",
"function": "index"
},
{
"file": "Routing/Controller.php",
"line": "194",
"function": "call_user_func_array"
}
]
}

View File

@@ -0,0 +1,40 @@
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 22,
"backtrace": [
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Error.php",
"line": 116,
"function": "generate",
"class": "Bugsnag_Stacktrace"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Error.php",
"line": 25,
"function": "setPHPError",
"class": "Bugsnag_Error"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Client.php",
"line": 346,
"function": "fromPHPError",
"class": "Bugsnag_Error"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 22,
"function": "errorHandler",
"class": "Bugsnag_Client"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 13,
"function": "crashy_function"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 25,
"function": "parent_of_crashy_function"
}
]
}

View File

@@ -0,0 +1,16 @@
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 25,
"backtrace": [
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 13,
"function": "crashy_function"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 28,
"function": "parent_of_crashy_function"
}
]
}

View File

@@ -0,0 +1,43 @@
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 17,
"backtrace": [
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Error.php",
"line": 116,
"function": "generate",
"class": "Bugsnag_Stacktrace"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Error.php",
"line": 25,
"function": "setPHPError",
"class": "Bugsnag_Error"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/src/Bugsnag/Client.php",
"line": 346,
"function": "fromPHPError",
"class": "Bugsnag_Error"
},
{
"function": "errorHandler",
"class": "Bugsnag_Client"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 17,
"function": "trigger_error"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 13,
"function": "crashy_function"
},
{
"file": "/Users/james/src/bugsnag/bugsnag-php/testing.php",
"line": 20,
"function": "parent_of_crashy_function"
}
]
}

View File

@@ -0,0 +1,52 @@
{
"file": "somefile.php",
"line": 123,
"backtrace": [
{
"file": "/View/Engines/PhpEngine.php",
"line": 39,
"include_filename": "storage/framework/views/9159822bf9c110749a4f033b96974fef",
"args": []
},
{
"function": "evaluatePath",
"type": "->",
"class": "Illuminate\\View\\Engines\\PhpEngine",
"file": "View/Engines/CompilerEngine.php",
"line": 57,
"args": []
},
{
"function": "get",
"type": "->",
"class": "Illuminate\\View\\Engines\\CompilerEngine",
"file": "View/View.php",
"line": 136,
"args": []
},
{
"function": "getContents",
"type": "->",
"class": "Illuminate\\View\\View",
"file": "View/View.php",
"line": 104,
"args": []
},
{
"function": "renderContents",
"type": "->",
"class": "Illuminate\\View\\View",
"file": "View/View.php",
"line": 78,
"args": []
},
{
"function": "render",
"type": "->",
"class": "Illuminate\\View\\View",
"file": "storage/views/f2df2d6b49591efeb36fc46e6dc25e0e",
"line": 5,
"args": []
}
]
}

View File

@@ -0,0 +1,21 @@
<?
//
// Example PHP file
//
// Some variables
$a = 1;
$b = 2;
// Create an exception
$exception = new Exception("Exception!");
// Throw the exception
throw $exception;
// Some more variables
$c = 3;
$d = 4;
?>

View File

@@ -0,0 +1,2 @@
$a = 1;
$b = 2;

View File

@@ -0,0 +1,6 @@
{
"file": "Bugsnag/Client.php",
"line": "123",
"class": "Bugsnag_Client",
"function": "example_function"
}

View File

@@ -0,0 +1,5 @@
{
"file": "path/some/file.php(123) : eval()'d code",
"line": "12",
"function": "something"
}

View File

@@ -0,0 +1,6 @@
{
"file": "controllers/ExampleController.php",
"line": "12",
"class": "Illuminate\\Support\\Facades\\Facade",
"function": "__callStatic"
}

View File

@@ -0,0 +1,5 @@
{
"file": "path/some/file.php(123) : runtime-created function",
"line": "12",
"function": "something"
}