diff --git a/raven/.gitattributes b/raven/.gitattributes
new file mode 100755
index 0000000..33a59ae
--- /dev/null
+++ b/raven/.gitattributes
@@ -0,0 +1,3 @@
+/examples export-ignore
+/docs export-ignore
+/test export-ignore
diff --git a/raven/.gitignore b/raven/.gitignore
old mode 100644
new mode 100755
diff --git a/raven/.gitmodules b/raven/.gitmodules
old mode 100644
new mode 100755
diff --git a/raven/.php_cs b/raven/.php_cs
old mode 100644
new mode 100755
diff --git a/raven/.travis.yml b/raven/.travis.yml
old mode 100644
new mode 100755
index 8182db2..de0d100
--- a/raven/.travis.yml
+++ b/raven/.travis.yml
@@ -6,12 +6,13 @@ php:
- 5.5
- 5.6
- 7.0
+ - nightly
- hhvm
matrix:
allow_failures:
- php: hhvm
- - php: 7.0
+ - php: nightly
fast_finish: true
sudo: false
@@ -21,10 +22,12 @@ cache:
- $HOME/.composer/cache
before_install:
+ - if [[ ${TRAVIS_PHP_VERSION:0:1} > "5" ]]; then pecl install uopz; fi
+ - if [[ ${TRAVIS_PHP_VERSION:0:1} > "5" ]]; then echo "extension=uopz.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi
- composer self-update
install: travis_retry composer install --no-interaction --prefer-source
script:
- vendor/bin/php-cs-fixer fix --config-file=.php_cs --verbose --diff --dry-run
- - vendor/bin/phpunit
+ - vendor/bin/phpunit --verbose
diff --git a/raven/AUTHORS b/raven/AUTHORS
old mode 100644
new mode 100755
diff --git a/raven/CHANGES b/raven/CHANGES
old mode 100644
new mode 100755
index da768e5..094402d
--- a/raven/CHANGES
+++ b/raven/CHANGES
@@ -1,3 +1,122 @@
+1.6.2
+-----
+
+- Fixed behavior where fatal errors weren't correctly being reported in most situations.
+
+
+1.6.1
+-----
+
+- Correct handling of null in ``user_context``.
+
+1.6.0
+-----
+
+- Improved serialization of certain types to be more restrictive.
+- ``error_types`` can now be configured via ``RavenClient``.
+- Class serialization has been expanded to include attributes.
+- The session extension is no longer required.
+- Monolog is no longer a required dependency.
+- ``user_context`` now merges by default.
+
+1.5.0
+-----
+
+- Added named transaction support.
+
+1.4.0
+-----
+
+This version primarily overhauls the exception/stacktrace generation to fix
+a few bugs and improve the quality of data (#359).
+
+- Added ``excluded_app_paths`` config.
+- Removed ``shift_vars`` config.
+- Correct fatal error handling to only operate on expected types. This also
+ fixes some behavior with the error suppression operator.
+- Expose anonymous and similar frames in the stacktrace.
+- Default ``prefixes`` to PHP's include paths.
+- Remove ``module`` usage.
+- Better handle empty argument context.
+- Correct alignment of filename (current frame) and function (caller frame)
+
+1.3.0
+-----
+
+- Fixed an issue causing the error suppression operator to not be respected (#335)
+- Fixed some serialization behavior (#352)
+- Fixed an issue with app paths and trailing slashes (#350)
+- Handle non-latin encoding with source code context line (#345)
+
+1.2.0
+-----
+
+- Handle non-latin encoding in source code and exception values (#342)
+- Ensure pending events are sent on shutdown by default (#338)
+- Add ``captureLastError`` helper (#334)
+- Dont report duplicate errors with fatal error handler (#334)
+- Enforce maximum length for string serialization (#329)
+
+1.1.0
+-----
+
+- Uncoercable values should no longer prevent exceptions from sending
+ to the Sentry server.
+- ``install()`` can no longer be called multiple times.
+
+1.0.0
+-----
+
+- Removed deprecated error codes configuration from ErrorHandler.
+- Removed env data from HTTP interface.
+- Removed 'message' attribute from exceptions'.
+- appPath and prefixes are now resolved fully.
+- Fixed various getter methods requiring invalid args.
+- Fixed data mutation with 'send_callback'.
+
+0.22.0
+------
+
+- Improve handling of encodings.
+- Improve resiliency of variable serialization.
+- Add 'formatted' attribute to Message interface.
+
+0.21.0
+------
+
+- Added ``transport`` option.
+- Added ``install()`` shortcut.
+
+0.20.0
+------
+
+- Handle missing function names on frames.
+- Remove suppression operator usage in breadcrumbs buffer.
+- Force serialization of context values.
+
+0.19.0
+------
+
+- Add error_reporting breadcrumb handler.
+
+0.18.0
+------
+
+- Remove session from serialized data.
+- send_callback return value must now be false to prevent capture.
+- Add various getter/setter methods for configuration.
+
+0.17.0
+------
+
+- Don't attempt to serialize fixed SDK inputs.
+- Improvements to breadcrumbs support in Monolog.
+
+0.16.0
+------
+
+- Initial breadcrumbs support with Monolog handler.
+
0.15.0
------
diff --git a/raven/LICENSE b/raven/LICENSE
old mode 100644
new mode 100755
diff --git a/raven/Makefile b/raven/Makefile
old mode 100644
new mode 100755
diff --git a/raven/README.rst b/raven/README.rst
old mode 100644
new mode 100755
index 9da1bb3..b24f25f
--- a/raven/README.rst
+++ b/raven/README.rst
@@ -9,264 +9,41 @@ The official PHP SDK for `Sentry `_.
.. code-block:: php
- // Instantiate a new client with a compatible DSN
- $client = new Raven_Client('http://public:secret@example.com/1');
-
- // Capture a message
- $event_id = $client->getIdent($client->captureMessage('my log message'));
- if ($client->getLastError() !== null) {
- printf('There was an error sending the event to Sentry: %s', $client->getLastError());
- }
+ // Instantiate a new client with a compatible DSN and install built-in
+ // handlers
+ $client = (new Raven_Client('http://public:secret@example.com/1'))->install();
// Capture an exception
- $event_id = $client->getIdent($client->captureException($ex));
-
- // Provide some additional data with an exception
- $event_id = $client->getIdent($client->captureException($ex, array(
- 'extra' => array(
- 'php_version' => phpversion()
- ),
- )));
+ $event_id = $client->captureException($ex);
// Give the user feedback
echo "Sorry, there was an error!";
echo "Your reference ID is " . $event_id;
- // Install error handlers and shutdown function to catch fatal errors
- $error_handler = new Raven_ErrorHandler($client);
- $error_handler->registerExceptionHandler();
- $error_handler->registerErrorHandler();
- $error_handler->registerShutdownFunction();
-
-Installation
-------------
-
-Install with Composer
-~~~~~~~~~~~~~~~~~~~~~
-
-If you're using `Composer `_ to manage
-dependencies, you can add Raven with it.
-
-::
-
- $ composer require sentry/sentry:$VERSION
-
-(replace ``$VERSION`` with one of the available versions on `Packagist `_)
-or to get the latest version off the master branch:
-
-::
-
- $ composer require sentry/sentry:dev-master
-
-Note that using unstable versions is not recommended and should be avoided. Also
-you should define a maximum version, e.g. by doing ``>=0.6,<1.0`` or ``~0.6``.
-
-Alternatively, use the ``^`` operator for specifying a version, e.g.,
-
-::
-
- $ composer require sentry/sentry:^0.11.0
-
-Composer will take care of the autoloading for you, so if you require the
-``vendor/autoload.php``, you're good to go.
-
-
-Install source from GitHub
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To install the source code:
-
-::
-
- $ git clone git://github.com/getsentry/sentry-php.git
-
-And including it using the autoloader:
-
-.. code-block:: php
-
- require_once '/path/to/Raven/library/Raven/Autoloader.php';
- Raven_Autoloader::register();
-
-Testing Your Connection
------------------------
-
-The PHP client includes a simple helper script to test your connection and credentials with
-the Sentry master server:
-
-.. code-block:: bash
-
- $ bin/sentry test https://public:secret@app.getsentry.com/1
- Client configuration:
- -> server: [https://sentry.example.com/api/store/]
- -> project: 1
- -> public_key: public
- -> secret_key: secret
-
- Sending a test event:
- -> event ID: f1765c9aed4f4ceebe5a93df9eb2d34f
-
- Done!
-
-.. note:: The CLI enforces the synchronous option on HTTP requests whereas the default configuration is asyncrhonous.
-
-Configuration
--------------
-
-Several options exist that allow you to configure the behavior of the ``Raven_Client``. These are passed as the
-second parameter of the constructor, and is expected to be an array of key value pairs:
-
-.. code-block:: php
-
- $client = new Raven_Client($dsn, array(
- 'option_name' => 'value',
- ));
-
-``name``
-~~~~~~~~
-
-A string to override the default value for the server's hostname.
-
-Defaults to ``Raven_Compat::gethostname()``.
-
-``tags``
-~~~~~~~~
-
-An array of tags to apply to events in this context.
-
-.. code-block:: php
-
- 'tags' => array(
- 'php_version' => phpversion(),
- )
-
-
-``curl_method``
-~~~~~~~~~~~~~~~
-
-Defaults to 'sync'.
-
-Available methods:
-
-- sync (default): send requests immediately when they're made
-- async: uses a curl_multi handler for best-effort asynchronous submissions
-- exec: asynchronously send events by forking a curl process for each item
-
-``curl_path``
-~~~~~~~~~~~~~
-
-Defaults to 'curl'.
-
-Specify the path to the curl binary to be used with the 'exec' curl method.
-
-
-``trace``
-~~~~~~~~~
-
-Set this to ``false`` to disable reflection tracing (function calling arguments) in stacktraces.
-
-
-``logger``
-~~~~~~~~~~
-
-Adjust the default logger name for messages.
-
-Defaults to ``php``.
-
-``ca_cert``
-~~~~~~~~~~~
-
-The path to the CA certificate bundle.
-
-Defaults to the common bundle which includes getsentry.com: ./data/cacert.pem
-
-Caveats:
-
-- The CA bundle is ignored unless curl throws an error suggesting it needs a cert.
-- The option is only currently used within the synchronous curl transport.
-
-``curl_ssl_version``
-~~~~~~~~~~~~~~~~~~~~
-
-The SSL version (2 or 3) to use.
-By default PHP will try to determine this itself, although in some cases this must be set manually.
-
-``message_limit``
-~~~~~~~~~~~~~~~~~
-
-Defaults to 1024 characters.
-
-This value is used to truncate message and frame variables. However it is not guarantee that length of whole message will be restricted by this value.
-
-``processors``
-~~~~~~~~~~~~~~~~~
-
-An array of classes to use to process data before it is sent to Sentry. By default, Raven_SanitizeDataProcessor is used
-
-``processorOptions``
-~~~~~~~~~~~~~~~~~
-Options that will be passed on to a setProcessorOptions() function in a Raven_Processor sub-class before that Processor is added to the list of processors used by Raven_Client
-
-An example of overriding the regular expressions in Raven_SanitizeDataProcessor is below:
-
-.. code-block:: php
-
- 'processorOptions' => array(
- 'Raven_SanitizeDataProcessor' => array(
- 'fields_re' => '/(user_password|user_token|user_secret)/i',
- 'values_re' => '/^(?:\d[ -]*?){15,16}$/'
- )
- )
-
-Providing Request Context
--------------------------
-
-Most of the time you're not actually calling out to Raven directly, but you still want to provide some additional context. This lifecycle generally constists of something like the following:
-
-- Set some context via a middleware (e.g. the logged in user)
-- Send all given context with any events during the request lifecycle
-- Cleanup context
-
-There are three primary methods for providing request context:
-
-.. code-block:: php
-
- // bind the logged in user
- $client->user_context(array('email' => 'foo@example.com'));
-
- // tag the request with something interesting
- $client->tags_context(array('interesting' => 'yes'));
-
- // provide a bit of additional context
- $client->extra_context(array('happiness' => 'very'));
-
-
-If you're performing additional requests during the lifecycle, you'll also need to ensure you cleanup the context (to reset its state):
-
-.. code-block:: php
-
- $client->context->clear();
+For more information, see our `documentation `_.
Contributing
------------
-First, make sure you can run the test suite. Install development dependencies :
+Dependencies are managed through composer:
::
$ composer install
-You may now use phpunit :
+
+Tests can then be run via phpunit:
::
$ vendor/bin/phpunit
-
Resources
---------
+* `Documentation `_
* `Bug Tracker `_
* `Code `_
* `Mailing List `_
diff --git a/raven/bin/sentry b/raven/bin/sentry
index fddc0a8..4694cfc 100755
--- a/raven/bin/sentry
+++ b/raven/bin/sentry
@@ -76,6 +76,10 @@ function cmd_test($dsn)
function main() {
global $argv;
+ if (!isset($argv[1])) {
+ exit('Usage: sentry test ');
+ }
+
$cmd = $argv[1];
switch ($cmd) {
@@ -83,7 +87,7 @@ function main() {
cmd_test(@$argv[2]);
break;
default:
- exit('Usage: raven test ');
+ exit('Usage: sentry test ');
}
}
diff --git a/raven/composer.json b/raven/composer.json
old mode 100644
new mode 100755
index 1f6137d..a34bd16
--- a/raven/composer.json
+++ b/raven/composer.json
@@ -12,13 +12,19 @@
}
],
"require-dev": {
- "fabpot/php-cs-fixer": "^1.8.0",
- "phpunit/phpunit": "^4.6.6"
+ "friendsofphp/php-cs-fixer": "^1.8.0",
+ "phpunit/phpunit": "^4.8 || ^5.0",
+ "monolog/monolog": "*"
},
"require": {
"php": ">=5.2.4",
- "ext-curl": "*",
- "monolog/monolog": "*"
+ "ext-curl": "*"
+ },
+ "suggest": {
+ "monolog/monolog": "Automatically capture Monolog events as breadcrumbs"
+ },
+ "conflict": {
+ "raven/raven": "*"
},
"bin": [
"bin/sentry"
@@ -30,7 +36,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "0.17.x-dev"
+ "dev-master": "1.6.x-dev"
}
}
}
diff --git a/raven/lib/Raven/Autoloader.php b/raven/lib/Raven/Autoloader.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/Breadcrumbs.php b/raven/lib/Raven/Breadcrumbs.php
old mode 100644
new mode 100755
index a07e900..d1a9946
--- a/raven/lib/Raven/Breadcrumbs.php
+++ b/raven/lib/Raven/Breadcrumbs.php
@@ -38,10 +38,9 @@ public function fetch()
{
$results = array();
for ($i = 0; $i <= ($this->size - 1); $i++) {
- $node = @$this->buffer[($this->pos + $i) % $this->size];
-
- if (isset($node)) {
- $results[] = $node;
+ $idx = ($this->pos + $i) % $this->size;
+ if (isset($this->buffer[$idx])) {
+ $results[] = $this->buffer[$idx];
}
}
return $results;
diff --git a/raven/lib/Raven/Breadcrumbs/ErrorHandler.php b/raven/lib/Raven/Breadcrumbs/ErrorHandler.php
new file mode 100755
index 0000000..d48ab1d
--- /dev/null
+++ b/raven/lib/Raven/Breadcrumbs/ErrorHandler.php
@@ -0,0 +1,47 @@
+ravenClient = $ravenClient;
+ }
+
+ public function handleError($code, $message, $file = '', $line = 0, $context=array())
+ {
+ $this->ravenClient->breadcrumbs->record(array(
+ 'category' => 'error_reporting',
+ 'message' => $message,
+ 'level' => $this->ravenClient->translateSeverity($code),
+ 'data' => array(
+ 'code' => $code,
+ 'line' => $line,
+ 'file' => $file,
+ ),
+ ));
+
+ if ($this->existingHandler !== null) {
+ return call_user_func($this->existingHandler, $code, $message, $file, $line, $context);
+ } else {
+ return false;
+ }
+ }
+
+ public function install()
+ {
+ $this->existingHandler = set_error_handler(array($this, 'handleError'), E_ALL);
+ return $this;
+ }
+}
diff --git a/raven/lib/Raven/Breadcrumbs/MonologHandler.php b/raven/lib/Raven/Breadcrumbs/MonologHandler.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/Client.php b/raven/lib/Raven/Client.php
old mode 100644
new mode 100755
index f13918b..cb607e7
--- a/raven/lib/Raven/Client.php
+++ b/raven/lib/Raven/Client.php
@@ -16,7 +16,8 @@
class Raven_Client
{
- const VERSION = '0.17.0';
+ const VERSION = '1.6.2';
+
const PROTOCOL = '6';
const DEBUG = 'debug';
@@ -28,11 +29,18 @@ class Raven_Client
const MESSAGE_LIMIT = 1024;
- public $severity_map;
+ public $breadcrumbs;
+ public $context;
public $extra_data;
-
+ public $severity_map;
public $store_errors_for_bulk_send = false;
+ protected $error_handler;
+ protected $error_types;
+
+ protected $serializer;
+ protected $reprSerializer;
+
public function __construct($options_or_dsn=null, $options=array())
{
if (is_array($options_or_dsn)) {
@@ -69,37 +77,194 @@ public function __construct($options_or_dsn=null, $options=array())
$this->message_limit = Raven_Util::get($options, 'message_limit', self::MESSAGE_LIMIT);
$this->exclude = Raven_Util::get($options, 'exclude', array());
$this->severity_map = null;
- $this->shift_vars = (bool) Raven_Util::get($options, 'shift_vars', true);
$this->http_proxy = Raven_Util::get($options, 'http_proxy');
$this->extra_data = Raven_Util::get($options, 'extra', array());
$this->send_callback = Raven_Util::get($options, 'send_callback', null);
$this->curl_method = Raven_Util::get($options, 'curl_method', 'sync');
$this->curl_path = Raven_Util::get($options, 'curl_path', 'curl');
- $this->curl_ipv4 = Raven_util::get($options, 'curl_ipv4', true);
+ $this->curl_ipv4 = Raven_Util::get($options, 'curl_ipv4', true);
$this->ca_cert = Raven_Util::get($options, 'ca_cert', $this->get_default_ca_cert());
$this->verify_ssl = Raven_Util::get($options, 'verify_ssl', true);
$this->curl_ssl_version = Raven_Util::get($options, 'curl_ssl_version');
$this->trust_x_forwarded_proto = Raven_Util::get($options, 'trust_x_forwarded_proto');
- // a list of prefixes used to coerce absolute paths into relative
- $this->prefixes = Raven_Util::get($options, 'prefixes', null);
- // app path is used to determine if code is part of your application
- $this->app_path = Raven_Util::get($options, 'app_path', null);
+ $this->transport = Raven_Util::get($options, 'transport', null);
+ $this->mb_detect_order = Raven_Util::get($options, 'mb_detect_order', null);
+ $this->error_types = Raven_Util::get($options, 'error_types', null);
+ // app path is used to determine if code is part of your application
+ $this->setAppPath(Raven_Util::get($options, 'app_path', null));
+ $this->setExcludedAppPaths(Raven_Util::get($options, 'excluded_app_paths', null));
+ // a list of prefixes used to coerce absolute paths into relative
+ $this->setPrefixes(Raven_Util::get($options, 'prefixes', $this->getDefaultPrefixes()));
$this->processors = $this->setProcessorsFromOptions($options);
$this->_lasterror = null;
$this->_last_event_id = null;
$this->_user = null;
+ $this->_pending_events = array();
$this->context = new Raven_Context();
$this->breadcrumbs = new Raven_Breadcrumbs();
+
$this->sdk = Raven_Util::get($options, 'sdk', array(
'name' => 'sentry-php',
'version' => self::VERSION,
));
+ $this->serializer = new Raven_Serializer($this->mb_detect_order);
+ $this->reprSerializer = new Raven_ReprSerializer($this->mb_detect_order);
if ($this->curl_method == 'async') {
$this->_curl_handler = new Raven_CurlHandler($this->get_curl_options());
}
+
+ $this->transaction = new Raven_TransactionStack();
+ if ($this->is_http_request() && isset($_SERVER['PATH_INFO'])) {
+ $this->transaction->push($_SERVER['PATH_INFO']);
+ }
+
+ if (Raven_Util::get($options, 'install_default_breadcrumb_handlers', true)) {
+ $this->registerDefaultBreadcrumbHandlers();
+ }
+
+ register_shutdown_function(array($this, 'onShutdown'));
+ }
+
+ /**
+ * Installs any available automated hooks (such as error_reporting).
+ */
+ public function install()
+ {
+ if ($this->error_handler) {
+ throw new Raven_Exception(sprintf('%s->install() must only be called once', get_class($this)));
+ }
+ $this->error_handler = new Raven_ErrorHandler($this, false, $this->error_types);
+ $this->error_handler->registerExceptionHandler();
+ $this->error_handler->registerErrorHandler();
+ $this->error_handler->registerShutdownFunction();
+ return $this;
+ }
+
+ public function getRelease()
+ {
+ return $this->release;
+ }
+
+ public function setRelease($value)
+ {
+ $this->release = $value;
+ return $this;
+ }
+
+ public function getEnvironment()
+ {
+ return $this->environment;
+ }
+
+ public function setEnvironment($value)
+ {
+ $this->environment = $value;
+ return $this;
+ }
+
+ private function getDefaultPrefixes()
+ {
+ $value = get_include_path();
+ return explode(':', $value);
+ }
+
+ private function _convertPath($value)
+ {
+ $path = @realpath($value);
+ if ($path === false) {
+ $path = $value;
+ }
+ // we need app_path to have a trailing slash otherwise
+ // base path detection becomes complex if the same
+ // prefix is matched
+ if (substr($path, 0, 1) === '/' && substr($path, -1, 1) !== '/') {
+ $path = $path . '/';
+ }
+ return $path;
+ }
+
+ public function getAppPath()
+ {
+ return $this->app_path;
+ }
+
+ public function setAppPath($value)
+ {
+ if ($value) {
+ $this->app_path = $this->_convertPath($value);
+ } else {
+ $this->app_path = null;
+ }
+ return $this;
+ }
+
+ public function getExcludedAppPaths()
+ {
+ return $this->excluded_app_paths;
+ }
+
+ public function setExcludedAppPaths($value)
+ {
+ if ($value) {
+ $this->excluded_app_paths = $value ? array_map(array($this, '_convertPath'), $value) : $value;
+ } else {
+ $this->excluded_app_paths = null;
+ }
+ return $this;
+ }
+ public function getPrefixes()
+ {
+ return $this->prefixes;
+ }
+
+ public function setPrefixes($value)
+ {
+ $this->prefixes = $value ? array_map(array($this, '_convertPath'), $value) : $value;
+ return $this;
+ }
+
+ public function getSendCallback()
+ {
+ return $this->send_callback;
+ }
+
+ public function setSendCallback($value)
+ {
+ $this->send_callback = $value;
+ return $this;
+ }
+
+ public function getTransport()
+ {
+ return $this->transport;
+ }
+
+ public function getServerEndpoint($value)
+ {
+ return $this->server;
+ }
+
+ public function getUserAgent()
+ {
+ return 'sentry-php/' . self::VERSION;
+ }
+
+ /**
+ * Set a custom transport to override how Sentry events are sent upstream.
+ *
+ * The bound function will be called with ``$client`` and ``$data`` arguments
+ * and is responsible for encoding the data, authenticating, and sending
+ * the data to the upstream Sentry server.
+ *
+ * @param function $value Function to be called
+ */
+ public function setTransport($value)
+ {
+ $this->transport = $value;
+ return $this;
}
public static function getDefaultProcessors()
@@ -208,8 +373,12 @@ public function exception($exception)
/**
* Log a message to sentry
+ *
+ * @param string $message The message (primary description) for the event.
+ * @param array $params params to use when formatting the message.
+ * @param array $data Additional attributes to pass with this event (see Sentry docs).
*/
- public function captureMessage($message, $params=array(), $level_or_options=array(),
+ public function captureMessage($message, $params=array(), $data=array(),
$stack=false, $vars = null)
{
// Gracefully handle messages which contain formatting characters, but were not
@@ -220,20 +389,20 @@ public function captureMessage($message, $params=array(), $level_or_options=arra
$formatted_message = $message;
}
- if ($level_or_options === null) {
+ if ($data === null) {
$data = array();
- } elseif (!is_array($level_or_options)) {
+ // support legacy method of passing in a level name as the third arg
+ } elseif (!is_array($data)) {
$data = array(
- 'level' => $level_or_options,
+ 'level' => $data,
);
- } else {
- $data = $level_or_options;
}
$data['message'] = $formatted_message;
$data['sentry.interfaces.Message'] = array(
'message' => $message,
'params' => $params,
+ 'formatted' => $formatted_message,
);
return $this->capture($data, $stack, $vars);
@@ -241,8 +410,11 @@ public function captureMessage($message, $params=array(), $level_or_options=arra
/**
* Log an exception to sentry
+ *
+ * @param Exception $exception The Exception object.
+ * @param array $data Additional attributes to pass with this event (see Sentry docs).
*/
- public function captureException($exception, $culprit_or_options=null, $logger=null, $vars=null)
+ public function captureException($exception, $data=null, $logger=null, $vars=null)
{
$has_chained_exceptions = version_compare(PHP_VERSION, '5.3.0', '>=');
@@ -250,27 +422,15 @@ public function captureException($exception, $culprit_or_options=null, $logger=n
return null;
}
- if (!is_array($culprit_or_options)) {
+ if ($data === null) {
$data = array();
- if ($culprit_or_options !== null) {
- $data['culprit'] = $culprit_or_options;
- }
- } else {
- $data = $culprit_or_options;
- }
-
- // TODO(dcramer): DRY this up
- $message = $exception->getMessage();
- if (empty($message)) {
- $message = get_class($exception);
}
$exc = $exception;
do {
$exc_data = array(
- 'value' => $exc->getMessage(),
+ 'value' => $this->serializer->serialize($exc->getMessage()),
'type' => get_class($exc),
- 'module' => $exc->getFile() .':'. $exc->getLine(),
);
/**'exception'
@@ -292,15 +452,14 @@ public function captureException($exception, $culprit_or_options=null, $logger=n
$exc_data['stacktrace'] = array(
'frames' => Raven_Stacktrace::get_stack_info(
- $trace, $this->trace, $this->shift_vars, $vars, $this->message_limit, $this->prefixes,
- $this->app_path
+ $trace, $this->trace, $vars, $this->message_limit, $this->prefixes,
+ $this->app_path, $this->excluded_app_paths, $this->serializer, $this->reprSerializer
),
);
$exceptions[] = $exc_data;
} while ($has_chained_exceptions && $exc = $exc->getPrevious());
- $data['message'] = $message;
$data['exception'] = array(
'values' => array_reverse($exceptions),
);
@@ -319,6 +478,24 @@ public function captureException($exception, $culprit_or_options=null, $logger=n
return $this->capture($data, $trace, $vars);
}
+
+ /**
+ * Capture the most recent error (obtained with ``error_get_last``).
+ */
+ public function captureLastError()
+ {
+ if (null === $error = error_get_last()) {
+ return;
+ }
+
+ $e = new ErrorException(
+ @$error['message'], 0, @$error['type'],
+ @$error['file'], @$error['line']
+ );
+
+ return $this->captureException($e);
+ }
+
/**
* Log an query to sentry
*/
@@ -346,6 +523,12 @@ public function getLastEventID()
return $this->_last_event_id;
}
+ protected function registerDefaultBreadcrumbHandlers()
+ {
+ $handler = new Raven_Breadcrumbs_ErrorHandler($this);
+ $handler->install();
+ }
+
protected function is_http_request()
{
return isset($_SERVER['REQUEST_METHOD']) && PHP_SAPI !== 'cli';
@@ -353,15 +536,13 @@ protected function is_http_request()
protected function get_http_data()
{
- $env = $headers = array();
+ $headers = array();
foreach ($_SERVER as $key => $value) {
if (0 === strpos($key, 'HTTP_')) {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))))] = $value;
} elseif (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH')) && $value !== '') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))))] = $value;
- } else {
- $env[$key] = $value;
}
}
@@ -382,9 +563,6 @@ protected function get_http_data()
if (!empty($headers)) {
$result['headers'] = $headers;
}
- if (!empty($env)) {
- $result['env'] = $env;
- }
return array(
'request' => $result,
@@ -395,7 +573,7 @@ protected function get_user_data()
{
$user = $this->context->user;
if ($user === null) {
- if (!session_id()) {
+ if (!function_exists('session_id') || !session_id()) {
return array();
}
$user = array(
@@ -425,6 +603,7 @@ public function get_default_data()
'tags' => $this->tags,
'platform' => 'php',
'sdk' => $this->sdk,
+ 'culprit' => $this->transaction->peek(),
);
}
@@ -477,20 +656,15 @@ public function capture($data, $stack = null, $vars = null)
if (empty($data['extra'])) {
unset($data['extra']);
- } else {
- $data['extra'] = $data['extra'];
}
-
if (empty($data['tags'])) {
unset($data['tags']);
- } else {
- $data['tags'] = $data['tags'];
}
- if (!empty($data['user'])) {
- $data['user'] = $data['user'];
+ if (empty($data['user'])) {
+ unset($data['user']);
}
- if (!empty($data['request'])) {
- $data['request'] = $data['request'];
+ if (empty($data['request'])) {
+ unset($data['request']);
}
if (!$this->breadcrumbs->is_empty()) {
@@ -513,8 +687,8 @@ public function capture($data, $stack = null, $vars = null)
if (!isset($data['stacktrace']) && !isset($data['exception'])) {
$data['stacktrace'] = array(
'frames' => Raven_Stacktrace::get_stack_info(
- $stack, $this->trace, $this->shift_vars, $vars, $this->message_limit,
- $this->prefixes, $this->app_path
+ $stack, $this->trace, $vars, $this->message_limit, $this->prefixes,
+ $this->app_path, $this->excluded_app_paths, $this->serializer, $this->reprSerializer
),
);
}
@@ -526,10 +700,7 @@ public function capture($data, $stack = null, $vars = null)
if (!$this->store_errors_for_bulk_send) {
$this->send($data);
} else {
- if (empty($this->error_data)) {
- $this->error_data = array();
- }
- $this->error_data[] = $data;
+ $this->_pending_events[] = $data;
}
$this->_last_event_id = $data['event_id'];
@@ -539,6 +710,24 @@ public function capture($data, $stack = null, $vars = null)
public function sanitize(&$data)
{
+ // attempt to sanitize any user provided data
+ if (!empty($data['request'])) {
+ $data['request'] = $this->serializer->serialize($data['request']);
+ }
+ if (!empty($data['user'])) {
+ $data['user'] = $this->serializer->serialize($data['user'], 3);
+ }
+ if (!empty($data['extra'])) {
+ $data['extra'] = $this->serializer->serialize($data['extra']);
+ }
+ if (!empty($data['tags'])) {
+ foreach ($data['tags'] as $key => $value) {
+ $data['tags'][$key] = @(string)$value;
+ }
+ }
+ if (!empty($data['contexts'])) {
+ $data['contexts'] = $this->serializer->serialize($data['contexts'], 5);
+ }
}
/**
@@ -555,27 +744,47 @@ public function process(&$data)
public function sendUnsentErrors()
{
- if (!empty($this->error_data)) {
- foreach ($this->error_data as $data) {
- $this->send($data);
- }
- unset($this->error_data);
+ foreach ($this->_pending_events as $data) {
+ $this->send($data);
}
+ $this->_pending_events = array();
if ($this->store_errors_for_bulk_send) {
//in case an error occurs after this is called, on shutdown, send any new errors.
$this->store_errors_for_bulk_send = !defined('RAVEN_CLIENT_END_REACHED');
}
}
+ public function encode(&$data)
+ {
+ $message = Raven_Compat::json_encode($data);
+ if ($message === false) {
+ if (function_exists('json_last_error_msg')) {
+ $this->_lasterror = json_last_error_msg();
+ } else {
+ $this->_lasterror = json_last_error();
+ }
+ return false;
+ }
+
+ if (function_exists("gzcompress")) {
+ $message = gzcompress($message);
+ }
+
+ // PHP's builtin curl_* function are happy without this, but the exec method requires it
+ $message = base64_encode($message);
+
+ return $message;
+ }
+
/**
* Wrapper to handle encoding and sending data to the Sentry API server.
*
* @param array $data Associative array of data to log
*/
- public function send($data)
+ public function send(&$data)
{
- if (is_callable($this->send_callback) && !call_user_func($this->send_callback, $data)) {
- // if send_callback returns falsely, end native send
+ if (is_callable($this->send_callback) && call_user_func_array($this->send_callback, array(&$data)) === false) {
+ // if send_callback returns false, end native send
return;
}
@@ -583,20 +792,15 @@ public function send($data)
return;
}
- $message = Raven_Compat::json_encode($data);
-
- if (function_exists("gzcompress")) {
- $message = gzcompress($message);
+ if ($this->transport) {
+ return call_user_func($this->transport, $this, $data);
}
- $message = base64_encode($message); // PHP's builtin curl_* function are happy without this, but the exec method requires it
- $client_string = 'sentry-php/' . self::VERSION;
- $timestamp = microtime(true);
+ $message = $this->encode($data);
+
$headers = array(
- 'User-Agent' => $client_string,
- 'X-Sentry-Auth' => $this->get_auth_header(
- $timestamp, $client_string, $this->public_key,
- $this->secret_key),
+ 'User-Agent' => $this->getUserAgent(),
+ 'X-Sentry-Auth' => $this->getAuthHeader(),
'Content-Type' => 'application/octet-stream'
);
@@ -679,31 +883,35 @@ private function send_http($url, $data, $headers=array())
}
}
- /**
- * Send the cURL to Sentry asynchronously. No errors will be returned from cURL
- *
- * @param string $url URL of the Sentry instance to log to
- * @param array $data Associative array of data to log
- * @param array $headers Associative array of headers
- * @return bool
- */
- private function send_http_asynchronous_curl_exec($url, $data, $headers)
+ protected function buildCurlCommand($url, $data, $headers)
{
// TODO(dcramer): support ca_cert
$cmd = $this->curl_path.' -X POST ';
foreach ($headers as $key => $value) {
- $cmd .= '-H \''. $key. ': '. $value. '\' ';
+ $cmd .= '-H ' . escapeshellarg($key.': '.$value). ' ';
}
- $cmd .= '-d \''. $data .'\' ';
- $cmd .= '\''. $url .'\' ';
+ $cmd .= '-d ' . escapeshellarg($data) . ' ';
+ $cmd .= escapeshellarg($url) . ' ';
$cmd .= '-m 5 '; // 5 second timeout for the whole process (connect + send)
if (!$this->verify_ssl) {
$cmd .= '-k ';
}
$cmd .= '> /dev/null 2>&1 &'; // ensure exec returns immediately while curl runs in the background
- exec($cmd);
+ return $cmd;
+ }
+ /**
+ * Send the cURL to Sentry asynchronously. No errors will be returned from cURL
+ *
+ * @param string $url URL of the Sentry instance to log to
+ * @param array $data Associative array of data to log
+ * @param array $headers Associative array of headers
+ * @return bool
+ */
+ private function send_http_asynchronous_curl_exec($url, $data, $headers)
+ {
+ exec($this->buildCurlCommand($url, $data, $headers));
return true; // The exec method is just fire and forget, so just assume it always works
}
@@ -786,6 +994,12 @@ protected function get_auth_header($timestamp, $client, $api_key, $secret_key)
return sprintf('Sentry %s', implode(', ', $header));
}
+ public function getAuthHeader()
+ {
+ $timestamp = microtime(true);
+ return $this->get_auth_header($timestamp, $this->getUserAgent(), $this->public_key, $this->secret_key);
+ }
+
/**
* Generate an uuid4 value
*
@@ -925,6 +1139,7 @@ public function registerSeverityMap($map)
/**
* Convenience function for setting a user's ID and Email
*
+ * @deprecated
* @param string $id User's ID
* @param string|null $email User's email
* @param array $data Additional user data
@@ -938,14 +1153,34 @@ public function set_user_data($id, $email=null, $data=array())
$this->user_context(array_merge($user, $data));
}
+ public function onShutdown()
+ {
+ if (!defined('RAVEN_CLIENT_END_REACHED')) {
+ define('RAVEN_CLIENT_END_REACHED', true);
+ }
+ $this->sendUnsentErrors();
+ if ($this->curl_method == 'async') {
+ $this->_curl_handler->join();
+ }
+ }
+
/**
* Sets user context.
*
* @param array $data Associative array of user data
+ * @param bool $merge Merge existing context with new context
*/
- public function user_context($data)
+ public function user_context($data, $merge=true)
{
- $this->context->user = $data;
+ if ($merge && $this->context->user !== null) {
+ // bail if data is null
+ if (!$data) {
+ return;
+ }
+ $this->context->user = array_merge($this->context->user, $data);
+ } else {
+ $this->context->user = $data;
+ }
}
/**
diff --git a/raven/lib/Raven/Compat.php b/raven/lib/Raven/Compat.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/Context.php b/raven/lib/Raven/Context.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/CurlHandler.php b/raven/lib/Raven/CurlHandler.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/ErrorHandler.php b/raven/lib/Raven/ErrorHandler.php
old mode 100644
new mode 100755
index 79bb5f2..98223f9
--- a/raven/lib/Raven/ErrorHandler.php
+++ b/raven/lib/Raven/ErrorHandler.php
@@ -31,149 +31,126 @@ class Raven_ErrorHandler
private $old_error_handler;
private $call_existing_error_handler = false;
private $reservedMemory;
+ /** @var Raven_Client */
+ private $client;
private $send_errors_last = false;
-
- /**
- * @var array
- * Error types which should be processed by the handler.
- * A 'null' value implies "whatever error_reporting is at time of error".
- */
- private $error_types = null;
-
- /**
- * @deprecated
- * @var array
- * Error types that can be processed by the handler
- */
- private $validErrorTypes = array(
+ private $fatal_error_types = array(
E_ERROR,
- E_WARNING,
E_PARSE,
- E_NOTICE,
E_CORE_ERROR,
E_CORE_WARNING,
E_COMPILE_ERROR,
E_COMPILE_WARNING,
- E_USER_ERROR,
- E_USER_WARNING,
- E_USER_NOTICE,
E_STRICT,
- E_RECOVERABLE_ERROR,
- E_DEPRECATED,
- E_USER_DEPRECATED,
);
/**
- * @deprecated
* @var array
- * The default Error types that are always processed by the handler. Can be set during construction.
+ * Error types which should be processed by the handler.
+ * A 'null' value implies "whatever error_reporting is at time of error".
*/
- private $defaultErrorTypes = array(
- E_ERROR,
- E_PARSE,
- E_CORE_ERROR,
- E_CORE_WARNING,
- E_COMPILE_ERROR,
- E_COMPILE_WARNING,
- E_STRICT,
- );
+ private $error_types = null;
- public function __construct($client, $send_errors_last = false, $default_error_types = null,
- $error_types = null)
+ public function __construct($client, $send_errors_last = false, $error_types = null,
+ $__error_types = null)
{
- $this->client = $client;
- if ($default_error_types !== null) {
- $this->defaultErrorTypes = $default_error_types;
+ // support legacy fourth argument for error types
+ if ($error_types === null) {
+ $error_types = $__error_types;
}
+
+ $this->client = $client;
$this->error_types = $error_types;
- register_shutdown_function(array($this, 'detectShutdown'));
+ $this->fatal_error_types = array_reduce($this->fatal_error_types, array($this, 'bitwiseOr'));
if ($send_errors_last) {
$this->send_errors_last = true;
$this->client->store_errors_for_bulk_send = true;
- register_shutdown_function(array($this->client, 'sendUnsentErrors'));
}
}
+ public function bitwiseOr($a, $b)
+ {
+ return $a | $b;
+ }
+
public function handleException($e, $isError = false, $vars = null)
{
- $e->event_id = $this->client->getIdent($this->client->captureException($e, null, null, $vars));
+ $e->event_id = $this->client->captureException($e, null, null, $vars);
if (!$isError && $this->call_existing_exception_handler && $this->old_exception_handler) {
call_user_func($this->old_exception_handler, $e);
}
}
- public function handleError($code, $message, $file = '', $line = 0, $context=array())
+ public function handleError($type, $message, $file = '', $line = 0, $context = array())
{
+ // http://php.net/set_error_handler
+ // The following error types cannot be handled with a user defined function: E_ERROR,
+ // E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and
+ // most of E_STRICT raised in the file where set_error_handler() is called.
+
if (error_reporting() !== 0) {
$error_types = $this->error_types;
if ($error_types === null) {
$error_types = error_reporting();
}
- if ($error_types & $code) {
- $e = new ErrorException($message, 0, $code, $file, $line);
+ if ($error_types & $type) {
+ $e = new ErrorException($message, 0, $type, $file, $line);
$this->handleException($e, true, $context);
}
}
+
if ($this->call_existing_error_handler) {
if ($this->old_error_handler !== null) {
- return call_user_func($this->old_error_handler, $code, $message, $file, $line, $context);
+ return call_user_func(
+ $this->old_error_handler,
+ $type,
+ $message,
+ $file,
+ $line,
+ $context
+ );
} else {
return false;
}
}
- }
-
- /**
- * Nothing by default, use it in child classes for catching other types of errors
- * Only constants from $this->validErrorTypes can be used
- *
- * @deprecated
- * @return array
- */
-
- protected function getAdditionalErrorTypesToProcess()
- {
- return array();
- }
-
- /**
- * @deprecated
- * @return array
- */
- private function getErrorTypesToProcess()
- {
- $additionalErrorTypes = array_intersect($this->getAdditionalErrorTypesToProcess(), $this->validErrorTypes);
- // array_unique so bitwise "or" operation wouldn't fail if some error type gets repeated
- return array_unique(array_merge($this->defaultErrorTypes, $additionalErrorTypes));
+ return true;
}
public function handleFatalError()
{
- if (null === $lastError = error_get_last()) {
- return;
- }
-
unset($this->reservedMemory);
- $errors = 0;
- foreach ($this->getErrorTypesToProcess() as $errorType) {
- $errors |= $errorType;
+ if (null === $error = error_get_last()) {
+ return;
}
- if ($lastError['type'] & $errors) {
+ if ($this->shouldCaptureFatalError($error['type'])) {
$e = new ErrorException(
- @$lastError['message'], @$lastError['type'], @$lastError['type'],
- @$lastError['file'], @$lastError['line']
+ @$error['message'], 0, @$error['type'],
+ @$error['file'], @$error['line']
);
$this->handleException($e, true);
}
}
- public function registerExceptionHandler($call_existing_exception_handler = true)
+ public function shouldCaptureFatalError($type)
+ {
+ return $type & $this->fatal_error_types;
+ }
+
+ /**
+ * Register a handler which will intercept unhnalded exceptions and report them to the
+ * associated Sentry client.
+ *
+ * @param bool $call_existing Call any existing exception handlers after processing
+ * this instance.
+ * @return $this
+ */
+ public function registerExceptionHandler($call_existing = true)
{
$this->old_exception_handler = set_exception_handler(array($this, 'handleException'));
- $this->call_existing_exception_handler = $call_existing_exception_handler;
+ $this->call_existing_exception_handler = $call_existing;
return $this;
}
@@ -181,19 +158,29 @@ public function registerExceptionHandler($call_existing_exception_handler = true
* Register a handler which will intercept standard PHP errors and report them to the
* associated Sentry client.
*
- * @return array
+ * @param bool $call_existing Call any existing errors handlers after processing
+ * this instance.
+ * @param array $error_types All error types that should be sent.
+ * @return $this
*/
- //
- public function registerErrorHandler($call_existing_error_handler = true, $error_types = null)
+ public function registerErrorHandler($call_existing = true, $error_types = null)
{
if ($error_types !== null) {
$this->error_types = $error_types;
}
$this->old_error_handler = set_error_handler(array($this, 'handleError'), E_ALL);
- $this->call_existing_error_handler = $call_existing_error_handler;
+ $this->call_existing_error_handler = $call_existing;
return $this;
}
+ /**
+ * Register a fatal error handler, which will attempt to capture errors which
+ * shutdown the PHP process. These are commonly things like OOM or timeouts.
+ *
+ * @param int $reservedMemorySize Number of kilobytes memory space to reserve,
+ * which is utilized when handling fatal errors.
+ * @return $this
+ */
public function registerShutdownFunction($reservedMemorySize = 10)
{
register_shutdown_function(array($this, 'handleFatalError'));
@@ -201,11 +188,4 @@ public function registerShutdownFunction($reservedMemorySize = 10)
$this->reservedMemory = str_repeat('x', 1024 * $reservedMemorySize);
return $this;
}
-
- public function detectShutdown()
- {
- if (!defined('RAVEN_CLIENT_END_REACHED')) {
- define('RAVEN_CLIENT_END_REACHED', true);
- }
- }
}
diff --git a/raven/lib/Raven/Exception.php b/raven/lib/Raven/Exception.php
new file mode 100755
index 0000000..a6199f4
--- /dev/null
+++ b/raven/lib/Raven/Exception.php
@@ -0,0 +1,4 @@
+serializeString($value);
}
}
}
diff --git a/raven/lib/Raven/SanitizeDataProcessor.php b/raven/lib/Raven/SanitizeDataProcessor.php
old mode 100644
new mode 100755
index 97c7c15..72d52c5
--- a/raven/lib/Raven/SanitizeDataProcessor.php
+++ b/raven/lib/Raven/SanitizeDataProcessor.php
@@ -64,26 +64,51 @@ public function sanitize(&$item, $key)
}
}
- public function sanitizeHttp(&$data)
+ public function sanitizeException(&$data)
{
- if (empty($data['request'])) {
- return;
+ foreach ($data['exception']['values'] as &$value) {
+ return $this->sanitizeStacktrace($value['stacktrace']);
}
+ }
+
+ public function sanitizeHttp(&$data)
+ {
$http = &$data['request'];
- if (empty($http['cookies'])) {
- return;
+ if (!empty($http['cookies'])) {
+ $cookies = &$http['cookies'];
+ if (!empty($cookies[$this->session_cookie_name])) {
+ $cookies[$this->session_cookie_name] = self::MASK;
+ }
}
+ if (!empty($http['data']) && is_array($http['data'])) {
+ array_walk_recursive($http['data'], array($this, 'sanitize'));
+ }
+ }
- $cookies = &$http['cookies'];
- if (!empty($cookies[$this->session_cookie_name])) {
- $cookies[$this->session_cookie_name] = self::MASK;
+ public function sanitizeStacktrace(&$data)
+ {
+ foreach ($data['frames'] as &$frame) {
+ if (empty($frame['vars'])) {
+ continue;
+ }
+ array_walk_recursive($frame['vars'], array($this, 'sanitize'));
}
}
public function process(&$data)
{
- array_walk_recursive($data, array($this, 'sanitize'));
- $this->sanitizeHttp($data);
+ if (!empty($data['exception'])) {
+ $this->sanitizeException($data);
+ }
+ if (!empty($data['stacktrace'])) {
+ $this->sanitizeStacktrace($data['stacktrace']);
+ }
+ if (!empty($data['request'])) {
+ $this->sanitizeHttp($data);
+ }
+ if (!empty($data['extra'])) {
+ array_walk_recursive($data['extra'], array($this, 'sanitize'));
+ }
}
/**
diff --git a/raven/lib/Raven/Serializer.php b/raven/lib/Raven/Serializer.php
old mode 100644
new mode 100755
index c60ee85..43401ef
--- a/raven/lib/Raven/Serializer.php
+++ b/raven/lib/Raven/Serializer.php
@@ -26,24 +26,72 @@
*/
class Raven_Serializer
{
+ /*
+ * The default mb detect order
+ *
+ * @see http://php.net/manual/en/function.mb-detect-encoding.php
+ */
+ const DEFAULT_MB_DETECT_ORDER = 'auto';
+
+ /*
+ * Suggested detect order for western countries
+ */
+ const WESTERN_MB_DETECT_ORDER = 'UTF-8, ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, Windows-1251, Windows-1252, Windows-1254';
+
+ /**
+ * This is the default mb detect order for the detection of encoding
+ *
+ * @var string
+ */
+ private $mb_detect_order= self::DEFAULT_MB_DETECT_ORDER;
+
+ /**
+ * @param null|string $mb_detect_order
+ */
+ public function __construct($mb_detect_order = null)
+ {
+ if ($mb_detect_order != null) {
+ $this->mb_detect_order = $mb_detect_order;
+ }
+ }
/**
* Serialize an object (recursively) into something safe for data
* sanitization and encoding.
*/
public function serialize($value, $max_depth=3, $_depth=0)
{
- if (is_object($value) || is_resource($value)) {
- return $this->serializeValue($value);
- } elseif ($_depth < $max_depth && is_array($value)) {
+ $className = is_object($value) ? get_class($value) : null;
+ $toArray = is_array($value) || $className === 'stdClass';
+ if ($toArray && $_depth < $max_depth) {
$new = array();
foreach ($value as $k => $v) {
$new[$this->serializeValue($k)] = $this->serialize($v, $max_depth, $_depth + 1);
}
return $new;
- } else {
- return $this->serializeValue($value);
}
+ return $this->serializeValue($value);
+ }
+
+ protected function serializeString($value)
+ {
+ $value = (string) $value;
+ if (function_exists('mb_detect_encoding')
+ && function_exists('mb_convert_encoding')
+ ) {
+ // we always guarantee this is coerced, even if we can't detect encoding
+ if ($currentEncoding = mb_detect_encoding($value, $this->mb_detect_order)) {
+ $value = mb_convert_encoding($value, 'UTF-8', $currentEncoding);
+ } else {
+ $value = mb_convert_encoding($value, 'UTF-8');
+ }
+ }
+
+ if (strlen($value) > 1024) {
+ $value = substr($value, 0, 1014) . ' {clipped}';
+ }
+
+ return $value;
}
protected function serializeValue($value)
@@ -57,13 +105,28 @@ protected function serializeValue($value)
} elseif (is_array($value)) {
return 'Array of length ' . count($value);
} else {
- $value = (string) $value;
+ return $this->serializeString($value);
+ }
+ }
- if (function_exists('mb_convert_encoding')) {
- $value = mb_convert_encoding($value, 'UTF-8', 'auto');
- }
- return $value;
- }
+ /**
+ * @return string
+ */
+ public function getMbDetectOrder()
+ {
+ return $this->mb_detect_order;
+ }
+
+ /**
+ * @param string $mb_detect_order
+ *
+ * @return Raven_Serializer
+ */
+ public function setMbDetectOrder($mb_detect_order)
+ {
+ $this->mb_detect_order = $mb_detect_order;
+
+ return $this;
}
}
diff --git a/raven/lib/Raven/Stacktrace.php b/raven/lib/Raven/Stacktrace.php
old mode 100644
new mode 100755
index df9ecfa..c3c3398
--- a/raven/lib/Raven/Stacktrace.php
+++ b/raven/lib/Raven/Stacktrace.php
@@ -13,44 +13,43 @@ class Raven_Stacktrace
'require_once',
);
- public static function get_stack_info($frames, $trace = false, $shiftvars = true, $errcontext = null,
- $frame_var_limit = Raven_Client::MESSAGE_LIMIT, $strip_prefixes = null,
- $app_path = null)
+ public static function get_stack_info($frames,
+ $trace = false,
+ $errcontext = null,
+ $frame_var_limit = Raven_Client::MESSAGE_LIMIT,
+ $strip_prefixes = null,
+ $app_path = null,
+ $excluded_app_paths = null,
+ Raven_Serializer $serializer = null,
+ Raven_ReprSerializer $reprSerializer = null)
{
+ $serializer = $serializer ?: new Raven_Serializer();
+ $reprSerializer = $reprSerializer ?: new Raven_ReprSerializer();
+
/**
- * PHP's way of storing backstacks seems bass-ackwards to me
- * 'function' is not the function you're in; it's any function being
- * called, so we have to shift 'function' down by 1. Ugh.
+ * PHP stores calls in the stacktrace, rather than executing context. Sentry
+ * wants to know "when Im calling this code, where am I", and PHP says "I'm
+ * calling this function" not "I'm in this function". Due to that, we shift
+ * the context for a frame up one, meaning the variables (which are the calling
+ * args) come from the previous frame.
*/
$result = array();
for ($i = 0; $i < count($frames); $i++) {
- $frame = $frames[$i];
+ $frame = isset($frames[$i]) ? $frames[$i] : null;
$nextframe = isset($frames[$i + 1]) ? $frames[$i + 1] : null;
if (!array_key_exists('file', $frame)) {
- // XXX: Disable capturing of anonymous functions until we can implement a better grouping mechanism.
- // In our examples these generally didn't help with debugging as the information was found elsewhere
- // within the exception or the stacktrace
- continue;
- // if (isset($frame['args'])) {
- // $args = is_string($frame['args']) ? $frame['args'] : @json_encode($frame['args']);
- // }
- // else {
- // $args = array();
- // }
- // if (!empty($nextframe['class'])) {
- // $context['line'] = sprintf('%s%s%s(%s)',
- // $nextframe['class'], $nextframe['type'], $nextframe['function'],
- // $args);
- // }
- // else {
- // $context['line'] = sprintf('%s(%s)', $nextframe['function'], $args);
- // }
- // $abs_path = '';
- // $context['prefix'] = '';
- // $context['suffix'] = '';
- // $context['filename'] = $filename = '[Anonymous function]';
- // $context['lineno'] = 0;
+ if (!empty($frame['class'])) {
+ $context['line'] = sprintf('%s%s%s',
+ $frame['class'], $frame['type'], $frame['function']);
+ } else {
+ $context['line'] = sprintf('%s(anonymous)', $frame['function']);
+ }
+ $abs_path = '';
+ $context['prefix'] = '';
+ $context['suffix'] = '';
+ $context['filename'] = $filename = '[Anonymous function]';
+ $context['lineno'] = 0;
} else {
$context = self::read_source_file($frame['file'], $frame['line']);
$abs_path = $frame['file'];
@@ -58,56 +57,50 @@ public static function get_stack_info($frames, $trace = false, $shiftvars = true
// strip base path if present
$context['filename'] = self::strip_prefixes($context['filename'], $strip_prefixes);
-
- $module = basename($abs_path);
- if (isset($nextframe['class'])) {
- $module .= ':' . $nextframe['class'];
- }
-
- if (empty($result) && isset($errcontext)) {
+ if ($i === 0 && isset($errcontext)) {
// If we've been given an error context that can be used as the vars for the first frame.
$vars = $errcontext;
} else {
if ($trace) {
- if ($shiftvars) {
- $vars = self::get_frame_context($nextframe, $frame_var_limit);
- } else {
- $vars = self::get_caller_frame_context($frame);
- }
+ $vars = self::get_frame_context($nextframe, $frame_var_limit);
} else {
$vars = array();
}
}
$data = array(
- // abs_path isn't overly useful, wastes space, and exposes
- // filesystem internals
- // 'abs_path' => $abs_path,
'filename' => $context['filename'],
'lineno' => (int) $context['lineno'],
- 'module' => $module,
- 'function' => $nextframe['function'],
- 'pre_context' => $context['prefix'],
- 'context_line' => $context['line'],
- 'post_context' => $context['suffix'],
+ 'function' => isset($nextframe['function']) ? $nextframe['function'] : null,
+ 'pre_context' => $serializer->serialize($context['prefix']),
+ 'context_line' => $serializer->serialize($context['line']),
+ 'post_context' => $serializer->serialize($context['suffix']),
);
// detect in_app based on app path
if ($app_path) {
- $data['in_app'] = (bool)(substr($abs_path, 0, strlen($app_path)) === $app_path);
+ $in_app = (bool)(substr($abs_path, 0, strlen($app_path)) === $app_path);
+ if ($in_app && $excluded_app_paths) {
+ foreach ($excluded_app_paths as $path) {
+ if (substr($abs_path, 0, strlen($path)) === $path) {
+ $in_app = false;
+ break;
+ }
+ }
+ }
+ $data['in_app'] = $in_app;
}
// dont set this as an empty array as PHP will treat it as a numeric array
// instead of a mapping which goes against the defined Sentry spec
if (!empty($vars)) {
- $serializer = new Raven_ReprSerializer();
$cleanVars = array();
foreach ($vars as $key => $value) {
- $value = $serializer->serialize($value);
+ $value = $reprSerializer->serialize($value);
if (is_string($value) || is_numeric($value)) {
- $cleanVars[$key] = substr($value, 0, $frame_var_limit);
+ $cleanVars[(string)$key] = substr($value, 0, $frame_var_limit);
} else {
- $cleanVars[$key] = $value;
+ $cleanVars[(string)$key] = $value;
}
}
$data['vars'] = $cleanVars;
@@ -119,7 +112,7 @@ public static function get_stack_info($frames, $trace = false, $shiftvars = true
return array_reverse($result);
}
- public static function get_caller_frame_context($frame)
+ public static function get_default_context($frame, $frame_arg_limit = Raven_Client::MESSAGE_LIMIT)
{
if (!isset($frame['args'])) {
return array();
@@ -128,6 +121,9 @@ public static function get_caller_frame_context($frame)
$i = 1;
$args = array();
foreach ($frame['args'] as $arg) {
+ if (is_string($arg) || is_numeric($arg)) {
+ $arg = substr($arg, 0, $frame_arg_limit);
+ }
$args['param'.$i] = $arg;
$i++;
}
@@ -136,24 +132,23 @@ public static function get_caller_frame_context($frame)
public static function get_frame_context($frame, $frame_arg_limit = Raven_Client::MESSAGE_LIMIT)
{
- // The reflection API seems more appropriate if we associate it with the frame
- // where the function is actually called (since we're treating them as function context)
- if (!isset($frame['function'])) {
- return array();
- }
-
if (!isset($frame['args'])) {
return array();
}
+ // The reflection API seems more appropriate if we associate it with the frame
+ // where the function is actually called (since we're treating them as function context)
+ if (!isset($frame['function'])) {
+ return self::get_default_context($frame, $frame_arg_limit);
+ }
if (strpos($frame['function'], '__lambda_func') !== false) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (isset($frame['class']) && $frame['class'] == 'Closure') {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (strpos($frame['function'], '{closure}') !== false) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (in_array($frame['function'], self::$statements)) {
if (empty($frame['args'])) {
@@ -161,7 +156,7 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
return array();
} else {
// Sanitize the file path
- return array($frame['args'][0]);
+ return array('param1' => $frame['args'][0]);
}
}
try {
@@ -177,7 +172,7 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
$reflection = new ReflectionFunction($frame['function']);
}
} catch (ReflectionException $e) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
$params = $reflection->getParameters();
@@ -195,9 +190,7 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
}
$args[$params[$i]->name] = $arg;
} else {
- // TODO: Sentry thinks of these as context locals, so they must be named
- // Assign the argument by number
- // $args[$i] = $arg;
+ $args['param'.$i] = $arg;
}
}
@@ -207,11 +200,11 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
private static function strip_prefixes($filename, $prefixes)
{
if ($prefixes === null) {
- return;
+ return $filename;
}
foreach ($prefixes as $prefix) {
if (substr($filename, 0, strlen($prefix)) === $prefix) {
- return substr($filename, strlen($prefix) + 1);
+ return substr($filename, strlen($prefix));
}
}
return $filename;
diff --git a/raven/lib/Raven/TransactionStack.php b/raven/lib/Raven/TransactionStack.php
new file mode 100755
index 0000000..5d428c7
--- /dev/null
+++ b/raven/lib/Raven/TransactionStack.php
@@ -0,0 +1,48 @@
+stack = array();
+ }
+
+ public function clear()
+ {
+ $this->stack = array();
+ }
+
+ public function peek()
+ {
+ $len = count($this->stack);
+ if ($len === 0) {
+ return null;
+ }
+ return $this->stack[$len - 1];
+ }
+
+ public function push($context)
+ {
+ $this->stack[] = $context;
+ }
+
+ public function pop($context=null)
+ {
+ if (!$context) {
+ return array_pop($this->stack);
+ }
+ while (!empty($this->stack)) {
+ if (array_pop($this->stack) === $context) {
+ return $context;
+ }
+ }
+ }
+}
diff --git a/raven/lib/Raven/Util.php b/raven/lib/Raven/Util.php
old mode 100644
new mode 100755
diff --git a/raven/lib/Raven/data/cacert.pem b/raven/lib/Raven/data/cacert.pem
old mode 100644
new mode 100755
diff --git a/raven/phpunit.xml b/raven/phpunit.xml
old mode 100644
new mode 100755
diff --git a/raven/test/Raven/Tests/Breadcrumbs/MonologTest.php b/raven/test/Raven/Tests/Breadcrumbs/MonologTest.php
deleted file mode 100644
index f536985..0000000
--- a/raven/test/Raven/Tests/Breadcrumbs/MonologTest.php
+++ /dev/null
@@ -1,68 +0,0 @@
-run(Object(Illuminate\Http\Request))
-#3 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(5053): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
-#4 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(715): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
-#5 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(696): Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request))
-#6 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(7825): Illuminate\Foundation\Application->handle(Object(Illuminate\Http\Request), 1, true)
-#7 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(8432): Illuminate\Session\Middleware->handle(Object(Illuminate\Http\Request), 1, true)
-#8 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(8379): Illuminate\Cookie\Queue->handle(Object(Illuminate\Http\Request), 1, true)
-#9 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(11123): Illuminate\Cookie\Guard->handle(Object(Illuminate\Http\Request), 1, true)
-#10 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(657): Stack\StackedHttpKernel->handle(Object(Illuminate\Http\Request))
-#11 /sentry-laravel/examples/laravel-4.2/public/index.php(49): Illuminate\Foundation\Application->run()
-#12 /sentry-laravel/examples/laravel-4.2/server.php(19): require_once('/Users/dcramer/...')
-#13 {main}
-EOF;
- }
-
- public function testSimple()
- {
- $client = new \Raven_Client();
- $handler = new \Raven_Breadcrumbs_MonologHandler($client);
-
- $logger = new Monolog\Logger('sentry');
- $logger->pushHandler($handler);
- $logger->addWarning('Foo');
-
- $crumbs = $client->breadcrumbs->fetch();
- $this->assertEquals(count($crumbs), 1);
- $this->assertEquals($crumbs[0]['message'], 'Foo');
- $this->assertEquals($crumbs[0]['category'], 'sentry');
- $this->assertEquals($crumbs[0]['level'], 'warning');
- }
-
- public function testErrorInMessage()
- {
- $client = new \Raven_Client();
- $handler = new \Raven_Breadcrumbs_MonologHandler($client);
-
- $logger = new Monolog\Logger('sentry');
- $logger->pushHandler($handler);
- $logger->addError($this->getSampleErrorMessage());
-
- $crumbs = $client->breadcrumbs->fetch();
- $this->assertEquals(count($crumbs), 1);
- $this->assertEquals($crumbs[0]['data']['type'], 'Exception');
- $this->assertEquals($crumbs[0]['data']['value'], 'An unhandled exception');
- $this->assertEquals($crumbs[0]['category'], 'sentry');
- $this->assertEquals($crumbs[0]['level'], 'error');
- }
-}
diff --git a/raven/test/Raven/Tests/BreadcrumbsTest.php b/raven/test/Raven/Tests/BreadcrumbsTest.php
deleted file mode 100644
index 5046459..0000000
--- a/raven/test/Raven/Tests/BreadcrumbsTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-record(array('message' => $i));
- }
-
- $results = $breadcrumbs->fetch();
-
- $this->assertEquals(count($results), 10);
- for ($i = 1; $i <= 10; $i++) {
- $this->assertEquals($results[$i - 1]['message'], $i);
- }
- }
-
- public function testJson()
- {
- $breadcrumbs = new Raven_Breadcrumbs(1);
- $breadcrumbs->record(array('message' => 'test'));
- $json = $breadcrumbs->to_json();
-
- $this->assertEquals(count($json['values']), 1);
- $this->assertEquals($json['values'][0]['message'], 'test');
- }
-}
diff --git a/raven/test/Raven/Tests/ClientTest.php b/raven/test/Raven/Tests/ClientTest.php
deleted file mode 100644
index 6a8dde8..0000000
--- a/raven/test/Raven/Tests/ClientTest.php
+++ /dev/null
@@ -1,768 +0,0 @@
-__sent_events;
- }
- public function send($data)
- {
- if (is_callable($this->send_callback) && !call_user_func($this->send_callback, $data)) {
- // if send_callback returns falsely, end native send
- return;
- }
- $this->__sent_events[] = $data;
- }
- public function is_http_request()
- {
- return true;
- }
- public function get_auth_header($timestamp, $client, $api_key, $secret_key)
- {
- return parent::get_auth_header($timestamp, $client, $api_key, $secret_key);
- }
- public function get_http_data()
- {
- return parent::get_http_data();
- }
- public function get_user_data()
- {
- return parent::get_user_data();
- }
-
- /**
- * Expose the current url method to test it
- *
- * @return string
- */
- public function test_get_current_url()
- {
- return $this->get_current_url();
- }
-}
-
-class Raven_Tests_ClientTest extends PHPUnit_Framework_TestCase
-{
- private function create_exception()
- {
- try {
- throw new Exception('Foo bar');
- } catch (Exception $ex) {
- return $ex;
- }
- }
-
- private function create_chained_exception()
- {
- try {
- throw new Exception('Foo bar');
- } catch (Exception $ex) {
- try {
- throw new Exception('Child exc', 0, $ex);
- } catch (Exception $ex2) {
- return $ex2;
- }
- }
- }
-
- public function testParseDsnHttp()
- {
- $result = Raven_Client::parseDsn('http://public:secret@example.com/1');
-
- $this->assertEquals($result['project'], 1);
- $this->assertEquals($result['server'], 'http://example.com/api/1/store/');
- $this->assertEquals($result['public_key'], 'public');
- $this->assertEquals($result['secret_key'], 'secret');
- }
-
- public function testParseDsnHttps()
- {
- $result = Raven_Client::parseDsn('https://public:secret@example.com/1');
-
- $this->assertEquals($result['project'], 1);
- $this->assertEquals($result['server'], 'https://example.com/api/1/store/');
- $this->assertEquals($result['public_key'], 'public');
- $this->assertEquals($result['secret_key'], 'secret');
- }
-
- public function testParseDsnPath()
- {
- $result = Raven_Client::parseDsn('http://public:secret@example.com/app/1');
-
- $this->assertEquals($result['project'], 1);
- $this->assertEquals($result['server'], 'http://example.com/app/api/1/store/');
- $this->assertEquals($result['public_key'], 'public');
- $this->assertEquals($result['secret_key'], 'secret');
- }
-
- public function testParseDsnPort()
- {
- $result = Raven_Client::parseDsn('http://public:secret@example.com:9000/app/1');
-
- $this->assertEquals($result['project'], 1);
- $this->assertEquals($result['server'], 'http://example.com:9000/app/api/1/store/');
- $this->assertEquals($result['public_key'], 'public');
- $this->assertEquals($result['secret_key'], 'secret');
- }
-
- public function testParseDsnInvalidScheme()
- {
- try {
- Raven_Client::parseDsn('gopher://public:secret@/1');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- public function testParseDsnMissingNetloc()
- {
- try {
- Raven_Client::parseDsn('http://public:secret@/1');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- public function testParseDsnMissingProject()
- {
- try {
- Raven_Client::parseDsn('http://public:secret@example.com');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testParseDsnMissingPublicKey()
- {
- Raven_Client::parseDsn('http://:secret@example.com/1');
- }
- /**
- * @expectedException InvalidArgumentException
- */
- public function testParseDsnMissingSecretKey()
- {
- Raven_Client::parseDsn('http://public@example.com/1');
- }
-
- public function testDsnFirstArgument()
- {
- $client = new Raven_Client('http://public:secret@example.com/1');
-
- $this->assertEquals($client->project, 1);
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->public_key, 'public');
- $this->assertEquals($client->secret_key, 'secret');
- }
-
- public function testDsnFirstArgumentWithOptions()
- {
- $client = new Raven_Client('http://public:secret@example.com/1', array(
- 'site' => 'foo',
- ));
-
- $this->assertEquals($client->project, 1);
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->public_key, 'public');
- $this->assertEquals($client->secret_key, 'secret');
- $this->assertEquals($client->site, 'foo');
- }
-
- public function testOptionsFirstArgument()
- {
- $client = new Raven_Client(array(
- 'server' => 'http://example.com/api/1/store/',
- 'project' => 1,
- ));
-
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- }
-
-
- public function testDsnInOptionsFirstArg()
- {
- $client = new Raven_Client(array(
- 'dsn' => 'http://public:secret@example.com/1',
- ));
-
- $this->assertEquals($client->project, 1);
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->public_key, 'public');
- $this->assertEquals($client->secret_key, 'secret');
- }
-
- public function testDsnInOptionsSecondArg()
- {
- $client = new Raven_Client(null, array(
- 'dsn' => 'http://public:secret@example.com/1',
- ));
-
- $this->assertEquals($client->project, 1);
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->public_key, 'public');
- $this->assertEquals($client->secret_key, 'secret');
- }
-
- public function testOptionsFirstArgumentWithOptions()
- {
- $client = new Raven_Client(array(
- 'server' => 'http://example.com/api/1/store/',
- 'project' => 1,
- ), array(
- 'site' => 'foo',
- ));
-
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->site, 'foo');
- }
-
- public function testOptionsExtraData()
- {
- $client = new Dummy_Raven_Client(array('extra' => array('foo' => 'bar')));
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['extra']['foo'], 'bar');
- }
-
- public function testEmptyExtraData()
- {
- $client = new Dummy_Raven_Client(array('extra' => array()));
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals(array_key_exists('extra', $event), false);
- }
-
- public function testCaptureMessageDoesHandleUninterpolatedMessage()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['message'], 'Test Message %s');
- }
-
- public function testCaptureMessageDoesHandleInterpolatedMessage()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['message'], 'Test Message foo');
- }
-
- public function testCaptureMessageSetsInterface()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['sentry.interfaces.Message'], array(
- 'message' => 'Test Message %s',
- 'params' => array('foo'),
- ));
- }
-
- public function testCaptureMessageHandlesOptionsAsThirdArg()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'), array(
- 'level' => Dummy_Raven_Client::WARNING,
- 'extra' => array('foo' => 'bar')
- ));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- $this->assertEquals($event['extra']['foo'], 'bar');
- }
-
- public function testCaptureMessageHandlesLevelAsThirdArg()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'), Dummy_Raven_Client::WARNING);
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- }
-
- public function testCaptureExceptionSetsInterfaces()
- {
- # TODO: it'd be nice if we could mock the stacktrace extraction function here
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex);
-
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
-
- $exc = $event['exception'];
- $this->assertEquals(count($exc['values']), 1);
- $this->assertEquals($exc['values'][0]['value'], 'Foo bar');
- $this->assertEquals($exc['values'][0]['type'], 'Exception');
- $this->assertFalse(empty($exc['values'][0]['module']));
-
- $this->assertFalse(empty($exc['values'][0]['stacktrace']['frames']));
- $frames = $exc['values'][0]['stacktrace']['frames'];
- $frame = $frames[count($frames) - 1];
- $this->assertTrue($frame['lineno'] > 0);
- $this->assertEquals($frame['module'], 'ClientTest.php:Raven_Tests_ClientTest');
- $this->assertEquals($frame['function'], 'create_exception');
- $this->assertFalse(isset($frame['vars']));
- $this->assertEquals($frame['context_line'], ' throw new Exception(\'Foo bar\');');
- $this->assertFalse(empty($frame['pre_context']));
- $this->assertFalse(empty($frame['post_context']));
- }
-
- public function testCaptureExceptionChainedException()
- {
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
- }
-
- # TODO: it'd be nice if we could mock the stacktrace extraction function here
- $client = new Dummy_Raven_Client();
- $ex = $this->create_chained_exception();
- $client->captureException($ex);
-
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
-
- $exc = $event['exception'];
- $this->assertEquals(count($exc['values']), 2);
- $this->assertEquals($exc['values'][0]['value'], 'Foo bar');
- $this->assertEquals($exc['values'][1]['value'], 'Child exc');
- }
-
- public function testCaptureExceptionDifferentLevelsInChainedExceptionsBug()
- {
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
- }
-
- $client = new Dummy_Raven_Client();
- $e1 = new ErrorException('First', 0, E_DEPRECATED);
- $e2 = new ErrorException('Second', 0, E_NOTICE, __FILE__, __LINE__, $e1);
- $e3 = new ErrorException('Third', 0, E_ERROR, __FILE__, __LINE__, $e2);
-
- $client->captureException($e1);
- $client->captureException($e2);
- $client->captureException($e3);
- $events = $client->getSentEvents();
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::ERROR);
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::INFO);
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- }
-
- public function testCaptureExceptionHandlesOptionsAsSecondArg()
- {
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex, array('culprit' => 'test'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['culprit'], 'test');
- }
-
- public function testCaptureExceptionHandlesCulpritAsSecondArg()
- {
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex, 'test');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['culprit'], 'test');
- }
-
- public function testCaptureExceptionHandlesExcludeOption()
- {
- $client = new Dummy_Raven_Client(array(
- 'exclude' => array('Exception'),
- ));
- $ex = $this->create_exception();
- $client->captureException($ex, 'test');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 0);
- }
-
- public function testDoesRegisterProcessors()
- {
- $client = new Dummy_Raven_Client(array(
- 'processors' => array('Raven_SanitizeDataProcessor'),
- ));
- $this->assertEquals(count($client->processors), 1);
- $this->assertTrue($client->processors[0] instanceof Raven_SanitizeDataProcessor);
- }
-
- public function testProcessDoesCallProcessors()
- {
- $data = array("key"=>"value");
-
- $processor = $this->getMock('Processor', array('process'));
- $processor->expects($this->once())
- ->method('process')
- ->with($data);
-
- $client = new Dummy_Raven_Client();
- $client->processors[] = $processor;
- $client->process($data);
- }
-
- public function testDefaultProcessorsAreUsed()
- {
- $client = new Dummy_Raven_Client();
- $defaults = Dummy_Raven_Client::getDefaultProcessors();
-
- $this->assertEquals(count($client->processors), count($defaults));
- }
-
- public function testDefaultProcessorsContainSanitizeDataProcessor()
- {
- $defaults = Dummy_Raven_Client::getDefaultProcessors();
-
- $this->assertTrue(in_array('Raven_SanitizeDataProcessor', $defaults));
- }
-
- public function testGetDefaultData()
- {
- $client = new Dummy_Raven_Client();
- $expected = array(
- 'platform' => 'php',
- 'project' => $client->project,
- 'server_name' => $client->name,
- 'site' => $client->site,
- 'logger' => $client->logger,
- 'tags' => $client->tags,
- 'sdk' => array(
- 'name' => 'sentry-php',
- 'version' => $client::VERSION,
- ),
- );
- $this->assertEquals($expected, $client->get_default_data());
- }
-
- /**
- * @backupGlobals
- */
- public function testGetHttpData()
- {
- $_SERVER = array(
- 'REDIRECT_STATUS' => '200',
- 'CONTENT_TYPE' => 'text/xml',
- 'CONTENT_LENGTH' => '99',
- 'HTTP_HOST' => 'getsentry.com',
- 'HTTP_ACCEPT' => 'text/html',
- 'HTTP_ACCEPT_CHARSET' => 'utf-8',
- 'HTTP_COOKIE' => 'cupcake: strawberry',
- 'SERVER_PORT' => '443',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'PATCH',
- 'QUERY_STRING' => 'q=bitch&l=en',
- 'REQUEST_URI' => '/welcome/',
- 'SCRIPT_NAME' => '/index.php',
- );
- $_POST = array(
- 'stamp' => '1c',
- );
- $_COOKIE = array(
- 'donut' => 'chocolat',
- );
-
- $expected = array(
- 'request' => array(
- 'method' => 'PATCH',
- 'url' => 'https://getsentry.com/welcome/',
- 'query_string' => 'q=bitch&l=en',
- 'data' => array(
- 'stamp' => '1c',
- ),
- 'cookies' => array(
- 'donut' => 'chocolat',
- ),
- 'headers' => array(
- 'Host' => 'getsentry.com',
- 'Accept' => 'text/html',
- 'Accept-Charset' => 'utf-8',
- 'Cookie' => 'cupcake: strawberry',
- 'Content-Type' => 'text/xml',
- 'Content-Length' => '99',
- ),
- 'env' => array(
- 'REDIRECT_STATUS' => '200',
- 'SERVER_PORT' => '443',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'PATCH',
- 'QUERY_STRING' => 'q=bitch&l=en',
- 'REQUEST_URI' => '/welcome/',
- 'SCRIPT_NAME' => '/index.php',
- ),
- )
- );
-
- $client = new Dummy_Raven_Client();
- $this->assertEquals($expected, $client->get_http_data());
- }
-
- public function testGetUserDataWithSetUser()
- {
- $client = new Dummy_Raven_Client();
-
- $id = 'unique_id';
- $email = 'foo@example.com';
-
- $user = array(
- 'username' => 'my_user',
- );
-
- $client->set_user_data($id, $email, $user);
-
- $expected = array(
- 'user' => array(
- 'id' => 'unique_id',
- 'username' => 'my_user',
- 'email' => 'foo@example.com',
- )
- );
-
- $this->assertEquals($expected, $client->get_user_data());
- }
-
- public function testGetUserDataWithNoUser()
- {
- $client = new Dummy_Raven_Client();
-
- $expected = array(
- 'user' => array(
- 'id' => session_id(),
- )
- );
- $this->assertEquals($expected, $client->get_user_data());
- }
-
- public function testGetAuthHeader()
- {
- $client = new Dummy_Raven_Client();
-
- $clientstring = 'sentry-php/test';
- $timestamp = '1234341324.340000';
-
- $expected = "Sentry sentry_timestamp={$timestamp}, sentry_client={$clientstring}, " .
- "sentry_version=" . Dummy_Raven_Client::PROTOCOL . ", " .
- "sentry_key=publickey, sentry_secret=secretkey";
-
- $this->assertEquals($expected, $client->get_auth_header($timestamp, 'sentry-php/test', 'publickey', 'secretkey'));
- }
-
- public function testCaptureMessageWithUserContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->user_context(array('email' => 'foo@example.com'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'email' => 'foo@example.com',
- ), $event['user']);
- }
-
- public function testCaptureMessageWithTagsContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->tags_context(array('foo' => 'bar'));
- $client->tags_context(array('biz' => 'boz'));
- $client->tags_context(array('biz' => 'baz'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'foo' => 'bar',
- 'biz' => 'baz',
- ), $event['tags']);
- }
-
- public function testCaptureMessageWithExtraContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->extra_context(array('foo' => 'bar'));
- $client->extra_context(array('biz' => 'boz'));
- $client->extra_context(array('biz' => 'baz'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'foo' => 'bar',
- 'biz' => 'baz',
- ), $event['extra']);
- }
-
- public function testGetLastEventID()
- {
- $client = new Dummy_Raven_Client();
- $client->capture(array('message' => 'test', 'event_id' => 'abc'));
- $this->assertEquals($client->getLastEventID(), 'abc');
- }
-
- public function cb1($data)
- {
- $this->assertEquals('test', $data['message']);
- return false;
- }
-
- public function cb2($data)
- {
- $this->assertEquals('test', $data['message']);
- return true;
- }
-
- public function testSendCallback()
- {
- $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb1')));
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(0, count($events));
-
- $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb2')));
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- }
-
- /**
- * Set the server array to the test values, check the current url
- *
- * @dataProvider currentUrlProvider
- * @param array $serverData
- * @param array $options
- * @param string $expected - the url expected
- * @param string $message - fail message
- */
- public function testCurrentUrl($serverVars, $options, $expected, $message)
- {
- $_SERVER = $serverVars;
-
- $client = new Dummy_Raven_Client($options);
- $result = $client->test_get_current_url();
-
- $this->assertSame($expected, $result, $message);
- }
-
- /**
- * Arrays of:
- * $_SERVER data
- * config
- * expected url
- * Fail message
- *
- * @return array
- */
- public function currentUrlProvider()
- {
- return array(
- array(
- array(),
- array(),
- null,
- 'No url expected for empty REQUEST_URI'
- ),
- array(
- array(
- 'REQUEST_URI' => '/',
- 'HTTP_HOST' => 'example.com',
- ),
- array(),
- 'http://example.com/',
- 'The url is expected to be http with the request uri'
- ),
- array(
- array(
- 'REQUEST_URI' => '/',
- 'HTTP_HOST' => 'example.com',
- 'HTTPS' => 'on'
- ),
- array(),
- 'https://example.com/',
- 'The url is expected to be https because of HTTPS on'
- ),
- array(
- array(
- 'REQUEST_URI' => '/',
- 'HTTP_HOST' => 'example.com',
- 'SERVER_PORT' => '443'
- ),
- array(),
- 'https://example.com/',
- 'The url is expected to be https because of the server port'
- ),
- array(
- array(
- 'REQUEST_URI' => '/',
- 'HTTP_HOST' => 'example.com',
- 'X-FORWARDED-PROTO' => 'https'
- ),
- array(),
- 'http://example.com/',
- 'The url is expected to be http because the X-Forwarded header is ignored'
- ),
- array(
- array(
- 'REQUEST_URI' => '/',
- 'HTTP_HOST' => 'example.com',
- 'X-FORWARDED-PROTO' => 'https'
- ),
- array('trust_x_forwarded_proto' => true),
- 'https://example.com/',
- 'The url is expected to be https because the X-Forwarded header is trusted'
- )
- );
- }
-}
diff --git a/raven/test/Raven/Tests/CompatTest.php b/raven/test/Raven/Tests/CompatTest.php
deleted file mode 100644
index 93f7c41..0000000
--- a/raven/test/Raven/Tests/CompatTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-assertEquals(Raven_Compat::gethostname(), Raven_Compat::_gethostname());
- $this->assertTrue(strlen(Raven_Compat::_gethostname()) > 0);
- }
-
- public function test_hash_hmac()
- {
- $result = Raven_Compat::hash_hmac('sha1', 'foo', 'bar');
- $this->assertEquals('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
-
- $result = Raven_Compat::_hash_hmac('sha1', 'foo', 'bar');
- $this->assertEquals('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
- }
-
- public function test_json_encode()
- {
- $result = Raven_Compat::json_encode(array('foo' => array('bar' => 1)));
- $this->assertEquals('{"foo":{"bar":1}}', $result);
-
- $result = Raven_Compat::_json_encode(array('foo' => array('bar' => 1)));
- $this->assertEquals('{"foo":{"bar":1}}', $result);
-
- $result = Raven_Compat::_json_encode(array(1, 2, 3, 4, 'foo', 'bar'));
- $this->assertEquals('[1,2,3,4,"foo","bar"]', $result);
-
- $result = Raven_Compat::_json_encode(array(1, 'foo', 'foobar' => 'bar'));
- $this->assertEquals('{0:1,1:"foo","foobar":"bar"}', $result);
-
- $result = Raven_Compat::_json_encode(array(array()));
- $this->assertEquals('[[]]', $result);
- }
-}
diff --git a/raven/test/Raven/Tests/ErrorHandlerTest.php b/raven/test/Raven/Tests/ErrorHandlerTest.php
deleted file mode 100644
index fb6b224..0000000
--- a/raven/test/Raven/Tests/ErrorHandlerTest.php
+++ /dev/null
@@ -1,147 +0,0 @@
-errorLevel = error_reporting();
- $this->errorHandlerCalled = false;
- $this->existingErrorHandler = set_error_handler(array($this, 'errorHandler'), -1);
- }
-
- public function errorHandler()
- {
- $this->errorHandlerCalled = true;
- }
-
- public function tearDown()
- {
- // XXX(dcramer): this isn't great as it doesnt restore the old error reporting level
- set_error_handler(array($this, 'errorHandler'), error_reporting());
- error_reporting($this->errorLevel);
- }
-
- public function testErrorsAreLoggedAsExceptions()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent', 'sendUnsentErrors'));
- $client->expects($this->once())
- ->method('captureException')
- ->with($this->isInstanceOf('ErrorException'));
-
- $handler = new Raven_ErrorHandler($client, E_ALL);
- $handler->handleError(E_WARNING, 'message');
- }
-
- public function testExceptionsAreLogged()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->once())
- ->method('captureException')
- ->with($this->isInstanceOf('ErrorException'));
-
- $e = new ErrorException('message', 0, E_WARNING, '', 0);
-
- $handler = new Raven_ErrorHandler($client);
- $handler->handleException($e);
- }
-
- public function testErrorHandlerPassErrorReportingPass()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->once())
- ->method('captureException');
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false, -1);
-
- error_reporting(E_USER_WARNING);
- trigger_error('Warning', E_USER_WARNING);
- }
-
- public function testErrorHandlerPropagates()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->never())
- ->method('captureException');
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(true, E_DEPRECATED);
-
- error_reporting(E_USER_WARNING);
- trigger_error('Warning', E_USER_WARNING);
-
- $this->assertEquals($this->errorHandlerCalled, 1);
- }
-
- public function testErrorHandlerRespectsErrorReportingDefault()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->once())
- ->method('captureException');
-
- error_reporting(E_DEPRECATED);
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(true);
-
- error_reporting(E_ALL);
- trigger_error('Warning', E_USER_WARNING);
-
- $this->assertEquals($this->errorHandlerCalled, 1);
- }
-
- // Because we cannot **know** that a user silenced an error, we always
- // defer to respecting the error reporting settings.
- public function testSilentErrorsAreReported()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->never())
- ->method('captureException');
-
- error_reporting(E_USER_WARNING);
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false);
-
- @trigger_error('Silent', E_USER_WARNING);
- }
-
- public function testErrorHandlerDefaultsErrorReporting()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->never())
- ->method('captureException');
-
- error_reporting(E_USER_ERROR);
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false);
-
- trigger_error('Warning', E_USER_WARNING);
- }
-
- public function testFluidInterface()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $handler = new Raven_ErrorHandler($client);
- $result = $handler->registerErrorHandler();
- $this->assertEquals($result, $handler);
- $result = $handler->registerExceptionHandler();
- $this->assertEquals($result, $handler);
- // TODO(dcramer): cant find a great way to test resetting the shutdown
- // handler
- // $result = $handler->registerShutdownHandler();
- // $this->assertEquals($result, $handler);
- }
-}
diff --git a/raven/test/Raven/Tests/ReprSerializerTest.php b/raven/test/Raven/Tests/ReprSerializerTest.php
deleted file mode 100644
index dc8ed52..0000000
--- a/raven/test/Raven/Tests/ReprSerializerTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-serialize($input);
- $this->assertEquals(array('1', '2', '3'), $result);
- }
-
- public function testObjectsAreStrings()
- {
- $serializer = new Raven_ReprSerializer();
- $input = new Raven_StacktraceTestObject();
- $result = $serializer->serialize($input);
- $this->assertEquals('Object Raven_StacktraceTestObject', $result);
- }
-
- public function testIntsAreInts()
- {
- $serializer = new Raven_ReprSerializer();
- $input = 1;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_string($result));
- $this->assertEquals(1, $result);
- }
-
- public function testFloats()
- {
- $serializer = new Raven_ReprSerializer();
- $input = 1.5;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_string($result));
- $this->assertEquals('1.5', $result);
- }
-
- public function testBooleans()
- {
- $serializer = new Raven_ReprSerializer();
- $input = true;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_string($result));
- $this->assertEquals('true', $result);
-
- $input = false;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_string($result));
- $this->assertEquals('false', $result);
- }
-
- public function testNull()
- {
- $serializer = new Raven_ReprSerializer();
- $input = null;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_string($result));
- $this->assertEquals('null', $result);
- }
-
- public function testRecursionMaxDepth()
- {
- $serializer = new Raven_ReprSerializer();
- $input = array();
- $input[] = &$input;
- $result = $serializer->serialize($input, 3);
- $this->assertEquals(array(array(array('Array of length 1'))), $result);
- }
-}
diff --git a/raven/test/Raven/Tests/SanitizeDataProcessorTest.php b/raven/test/Raven/Tests/SanitizeDataProcessorTest.php
deleted file mode 100644
index 40c6aa6..0000000
--- a/raven/test/Raven/Tests/SanitizeDataProcessorTest.php
+++ /dev/null
@@ -1,198 +0,0 @@
- array(
- 'data' => array(
- 'foo' => 'bar',
- 'password' => 'hello',
- 'the_secret' => 'hello',
- 'a_password_here' => 'hello',
- 'mypasswd' => 'hello',
- 'authorization' => 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=',
- 'card_number' => array(
- '1111',
- '2222',
- '3333',
- '4444'
- )
- ),
- )
- );
-
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
- $processor->process($data);
-
- $vars = $data['request']['data'];
- $this->assertEquals($vars['foo'], 'bar');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['password']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['the_secret']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['a_password_here']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['mypasswd']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['authorization']);
-
- $this->markTestIncomplete('Array scrubbing has not been implemented yet.');
-
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['card_number']['0']);
- }
-
- public function testDoesFilterSessionId()
- {
- $data = array(
- 'request' => array(
- 'cookies' => array(
- ini_get('session.name') => 'abc',
- ),
- )
- );
-
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
- $processor->process($data);
-
- $cookies = $data['request']['cookies'];
- $this->assertEquals($cookies[ini_get('session.name')], Raven_SanitizeDataProcessor::MASK);
- }
-
- public function testDoesFilterCreditCard()
- {
- $data = array(
- 'ccnumba' => '4242424242424242'
- );
-
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
- $processor->process($data);
-
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $data['ccnumba']);
- }
-
- /**
- * @covers setProcessorOptions
- *
- */
- public function testSettingProcessorOptions()
- {
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
-
- $this->assertEquals($processor->getFieldsRe(), '/(authorization|password|passwd|secret|password_confirmation|card_number|auth_pw)/i', 'got default fields');
- $this->assertEquals($processor->getValuesRe(), '/^(?:\d[ -]*?){13,16}$/', 'got default values');
-
- $options = array(
- 'fields_re' => '/(api_token)/i',
- 'values_re' => '/^(?:\d[ -]*?){15,16}$/'
- );
-
- $processor->setProcessorOptions($options);
-
- $this->assertEquals($processor->getFieldsRe(), '/(api_token)/i', 'overwrote fields');
- $this->assertEquals($processor->getValuesRe(), '/^(?:\d[ -]*?){15,16}$/', 'overwrote values');
- }
-
- /**
- * @dataProvider overrideDataProvider
- *
- * @param $processorOptions
- * @param $client_options
- * @param $dsn
- */
- public function testOverrideOptions($processorOptions, $client_options, $dsn)
- {
- $client = new Raven_Client($dsn, $client_options);
- $processor = $client->processors[0];
-
- $this->assertInstanceOf('Raven_SanitizeDataProcessor', $processor);
- $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
- $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_SanitizeDataProcessor']['values_re'], 'overwrote values');
- }
-
- /**
- * @depends testOverrideOptions
- * @dataProvider overrideDataProvider
- *
- * @param $processorOptions
- * @param $client_options
- * @param $dsn
- */
- public function testOverridenSanitize($processorOptions, $client_options, $dsn)
- {
- $data = array(
- 'request' => array(
- 'data' => array(
- 'foo' => 'bar',
- 'password' => 'hello',
- 'the_secret' => 'hello',
- 'a_password_here' => 'hello',
- 'mypasswd' => 'hello',
- 'api_token' => 'nioenio3nrio3jfny89nby9bhr#RML#R',
- 'authorization' => 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=',
- 'card_number' => array(
- '1111111111111111',
- '2222',
- )
- ),
- )
- );
-
- $client = new Raven_Client($dsn, $client_options);
- $processor = $client->processors[0];
-
- $this->assertInstanceOf('Raven_SanitizeDataProcessor', $processor);
- $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
- $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_SanitizeDataProcessor']['values_re'], 'overwrote values');
-
- $processor->process($data);
-
- $vars = $data['request']['data'];
- $this->assertEquals($vars['foo'], 'bar', 'did not alter foo');
- $this->assertEquals($vars['password'], 'hello', 'did not alter password');
- $this->assertEquals($vars['the_secret'], 'hello', 'did not alter the_secret');
- $this->assertEquals($vars['a_password_here'], 'hello', 'did not alter a_password_here');
- $this->assertEquals($vars['mypasswd'], 'hello', 'did not alter mypasswd');
- $this->assertEquals($vars['authorization'], 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=', 'did not alter authorization');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['api_token'], 'masked api_token');
-
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['card_number']['0'], 'masked card_number[0]');
- $this->assertEquals($vars['card_number']['1'], $vars['card_number']['1'], 'did not alter card_number[1]');
- }
-
- /**
- * Provides data for testing overriding the processor options
- *
- * @return array
- */
- public static function overrideDataProvider()
- {
- $processorOptions = array(
- 'Raven_SanitizeDataProcessor' => array(
- 'fields_re' => '/(api_token)/i',
- 'values_re' => '/^(?:\d[ -]*?){15,16}$/'
- )
- );
-
- $client_options = array(
- 'processors' => array('Raven_SanitizeDataProcessor'),
- 'processorOptions' => $processorOptions
- );
-
- $dsn = 'http://9aaa31f9a05b4e72aaa06aa8157a827a:9aa7aa82a9694a08a1a7589a2a035a9a@sentry.domain.tld/1';
-
- return array(
- array($processorOptions, $client_options, $dsn)
- );
- }
-}
diff --git a/raven/test/Raven/Tests/SerializerTest.php b/raven/test/Raven/Tests/SerializerTest.php
deleted file mode 100644
index 0bc43a2..0000000
--- a/raven/test/Raven/Tests/SerializerTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-serialize($input);
- $this->assertEquals(array('1', '2', '3'), $result);
- }
-
- public function testObjectsAreStrings()
- {
- $serializer = new Raven_Serializer();
- $input = new Raven_StacktraceTestObject();
- $result = $serializer->serialize($input);
- $this->assertEquals('Object Raven_StacktraceTestObject', $result);
- }
-
- public function testIntsAreInts()
- {
- $serializer = new Raven_Serializer();
- $input = 1;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_integer($result));
- $this->assertEquals(1, $result);
- }
-
- public function testFloats()
- {
- $serializer = new Raven_Serializer();
- $input = 1.5;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_float($result));
- $this->assertEquals(1.5, $result);
- }
-
- public function testBooleans()
- {
- $serializer = new Raven_Serializer();
- $input = true;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_bool($result));
- $this->assertEquals(true, $result);
-
- $input = false;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_bool($result));
- $this->assertEquals(false, $result);
- }
-
- public function testNull()
- {
- $serializer = new Raven_Serializer();
- $input = null;
- $result = $serializer->serialize($input);
- $this->assertTrue(is_null($result));
- $this->assertEquals(null, $result);
- }
-
- public function testRecursionMaxDepth()
- {
- $serializer = new Raven_Serializer();
- $input = array();
- $input[] = &$input;
- $result = $serializer->serialize($input, 3);
- $this->assertEquals(array(array(array('Array of length 1'))), $result);
- }
-}
diff --git a/raven/test/Raven/Tests/StacktraceTest.php b/raven/test/Raven/Tests/StacktraceTest.php
deleted file mode 100644
index b9269c7..0000000
--- a/raven/test/Raven/Tests/StacktraceTest.php
+++ /dev/null
@@ -1,304 +0,0 @@
- 0) {
- return call_user_func('raven_test_recurse', $times, $callback);
- }
-
- return call_user_func($callback);
-}
-
-function raven_test_create_stacktrace($args=null, $times=3)
-{
- return raven_test_recurse($times, 'debug_backtrace');
-}
-
-class Raven_Tests_StacktraceTest extends PHPUnit_Framework_TestCase
-{
- public function testCanTraceParamContext()
- {
- $stack = raven_test_create_stacktrace(array('biz', 'baz'), 0);
-
- $frame = $stack[2];
- $params = Raven_Stacktrace::get_frame_context($frame);
- $this->assertEquals($params['args'], array('biz', 'baz'));
- $this->assertEquals($params['times'], 0);
- }
-
- public function testSimpleTrace()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testSimpleUnshiftedTrace()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, false);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals('/tmp/a.php', $frame['vars']['param1']);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('friend', $frame['vars']['param1']);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testShiftedCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $vars = array(
- "foo" => "bar",
- "baz" => "zoom"
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, true, $vars);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $this->assertFalse(isset($frame['vars']));
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- $this->assertEquals($vars, $frame['vars']);
- }
-
- public function testDoesNotModifyCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- // PHP's errcontext as passed to the error handler contains REFERENCES to any vars that were in the global scope.
- // Modification of these would be really bad, since if control is returned (non-fatal error) we'll have altered the state of things!
- $originalFoo = "bloopblarp";
- $iAmFoo = $originalFoo;
- $vars = array(
- "foo" => &$iAmFoo
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, true, $vars, 5);
-
- // Check we haven't modified our vars.
- $this->assertEquals($originalFoo, $vars["foo"]);
-
- $frame = $frames[1];
- // Check that we did truncate the variable in our output
- $this->assertEquals(5, strlen($frame['vars']['foo']));
- }
-
- public function testUnshiftedCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $vars = array(
- "foo" => "bar",
- "baz" => "zoom"
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, false, $vars);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals(array('param1' => '/tmp/a.php'), $frame['vars']);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals($vars, $frame['vars']);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testDoesFixFrameInfo()
- {
- /**
- * PHP's way of storing backstacks seems bass-ackwards to me
- * 'function' is not the function you're in; it's any function being
- * called, so we have to shift 'function' down by 1. Ugh.
- */
- $stack = raven_test_create_stacktrace();
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true);
- // just grab the last few frames
- $frames = array_slice($frames, -5);
- $frame = $frames[0];
- $this->assertEquals('StacktraceTest.php:Raven_Tests_StacktraceTest', $frame['module']);
- $this->assertEquals('testDoesFixFrameInfo', $frame['function']);
- $frame = $frames[1];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_create_stacktrace', $frame['function']);
- $frame = $frames[2];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- $frame = $frames[3];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- $frame = $frames[4];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- }
-
- public function testInApp()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, null, null, 0, null, dirname(__FILE__));
-
- $this->assertEquals($frames[0]['in_app'], true);
- $this->assertEquals($frames[1]['in_app'], true);
- }
-
- public function testBasePath()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, null, null, 0, array(dirname(__FILE__)));
-
- $this->assertEquals($frames[0]['filename'], 'resources/b.php');
- $this->assertEquals($frames[1]['filename'], 'resources/a.php');
- }
-}
diff --git a/raven/test/Raven/Tests/UtilTest.php b/raven/test/Raven/Tests/UtilTest.php
deleted file mode 100644
index 856b770..0000000
--- a/raven/test/Raven/Tests/UtilTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
- 'bar');
- $result = Raven_Util::get($input, 'baz', 'foo');
- $this->assertEquals('foo', $result);
- }
-
- public function testGetReturnsPresentValuesEvenWhenEmpty()
- {
- $input = array('foo' => '');
- $result = Raven_Util::get($input, 'foo', 'bar');
- $this->assertEquals('', $result);
- }
-}
diff --git a/raven/test/Raven/Tests/resources/a.php b/raven/test/Raven/Tests/resources/a.php
deleted file mode 100644
index 78ae29c..0000000
--- a/raven/test/Raven/Tests/resources/a.php
+++ /dev/null
@@ -1,11 +0,0 @@
-