From d5c6fa79afc41738edbbbb4a371439a12dfe3f25 Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 9 Feb 2018 09:59:11 +0100 Subject: [PATCH 01/20] Fix gzipCompress function name PHP doesn't have `gzipCompress` function, use `gzcompress` instead http://php.net/manual/en/function.gzcompress.php (cherry picked from commit d391712) --- docs/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.rst b/docs/config.rst index b97e8de53..9c56f7f86 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -171,7 +171,7 @@ The following settings are available for the client: 'User-Agent' => $client->getUserAgent(), 'X-Sentry-Auth' => $client->getAuthHeader(), ), - 'body' => gzipCompress(jsonEncode($data)), + 'body' => gzcompress(jsonEncode($data)), )) }, From 8d15022e66ed72edbb7991eec876f563d339b6a0 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Thu, 3 May 2018 16:28:32 +0200 Subject: [PATCH 02/20] Fix notice during tests --- tests/Context/ContextTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Context/ContextTest.php b/tests/Context/ContextTest.php index 2aeffdbf2..ceba26e67 100644 --- a/tests/Context/ContextTest.php +++ b/tests/Context/ContextTest.php @@ -106,7 +106,7 @@ public function testArrayLikeBehaviour() // Accessing a key that does not exists in the data object should behave // like accessing a non-existent key of an array - $context['foo']; + @$context['foo']; $error = error_get_last(); From e33e200c1205d4d12a7a3c5e04d809194ee68953 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Thu, 3 May 2018 16:54:58 +0200 Subject: [PATCH 03/20] Handle application/json data input (port of #546 to 2.x) --- .../Middleware/RequestInterfaceMiddleware.php | 5 + .../RequestInterfaceMiddlewareTest.php | 99 ++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/lib/Raven/Middleware/RequestInterfaceMiddleware.php b/lib/Raven/Middleware/RequestInterfaceMiddleware.php index a82091bcc..b656acb7a 100644 --- a/lib/Raven/Middleware/RequestInterfaceMiddleware.php +++ b/lib/Raven/Middleware/RequestInterfaceMiddleware.php @@ -53,6 +53,11 @@ public function __invoke(Event $event, callable $next, ServerRequestInterface $r if ($request->hasHeader('REMOTE_ADDR')) { $requestData['env']['REMOTE_ADDR'] = $request->getHeaderLine('REMOTE_ADDR'); } + + if (in_array('application/json', $request->getHeader('Content-Type'))) { + $inputData = file_get_contents('php://input'); + $requestData['data'] = json_decode($inputData, true); + } $event = $event->withRequest($requestData); diff --git a/tests/Middleware/RequestInterfaceMiddlewareTest.php b/tests/Middleware/RequestInterfaceMiddlewareTest.php index a4e74875a..864f00a02 100644 --- a/tests/Middleware/RequestInterfaceMiddlewareTest.php +++ b/tests/Middleware/RequestInterfaceMiddlewareTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Raven\Tests\Breadcrumbs; +namespace Raven\Tests\Middleware; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; @@ -21,6 +21,8 @@ class RequestInterfaceMiddlewareTest extends TestCase { + private static $inputData; + public function testInvokeWithNoRequest() { $configuration = new Configuration(); @@ -42,7 +44,7 @@ public function testInvokeWithNoRequest() /** * @dataProvider invokeDataProvider */ - public function testInvoke($requestData, $expectedValue) + public function testInvoke(array $requestData, array $expectedValue, $inputData = null) { $configuration = new Configuration(); $event = new Event($configuration); @@ -65,6 +67,10 @@ public function testInvoke($requestData, $expectedValue) }; $middleware = new RequestInterfaceMiddleware(); + if ($inputData) { + $this->mockReadFromPhpInput($inputData); + } + $middleware($event, $callback, $request); $this->assertEquals(1, $invokationCount); @@ -72,6 +78,9 @@ public function testInvoke($requestData, $expectedValue) public function invokeDataProvider() { + $validData = ['json_test' => 'json_data']; + $invalidData = '{"binary_json":"' . pack('NA3CC', 3, 'aBc', 0x0D, 0x0A) . '"}'; + return [ [ [ @@ -117,6 +126,92 @@ public function invokeDataProvider() ], ], ], + [ + [ + 'uri' => 'http://www.example.com/foo', + 'method' => 'POST', + 'cookies' => [], + 'headers' => [ + 'Content-Type' => ['application/json'], + 'Host' => ['www.example.com'], + 'REMOTE_ADDR' => ['127.0.0.1'], + ], + ], + [ + 'url' => 'http://www.example.com/foo', + 'method' => 'POST', + 'cookies' => [], + 'data' => $validData, + 'headers' => [ + 'Content-Type' => ['application/json'], + 'Host' => ['www.example.com'], + 'REMOTE_ADDR' => ['127.0.0.1'], + ], + 'env' => [ + 'REMOTE_ADDR' => '127.0.0.1', + ], + ], + json_encode($validData), + ], + [ + [ + 'uri' => 'http://www.example.com/foo', + 'method' => 'POST', + 'cookies' => [], + 'headers' => [ + 'Content-Type' => ['application/json'], + 'Host' => ['www.example.com'], + 'REMOTE_ADDR' => ['127.0.0.1'], + ], + ], + [ + 'url' => 'http://www.example.com/foo', + 'method' => 'POST', + 'cookies' => [], + 'data' => null, + 'headers' => [ + 'Content-Type' => ['application/json'], + 'Host' => ['www.example.com'], + 'REMOTE_ADDR' => ['127.0.0.1'], + ], + 'env' => [ + 'REMOTE_ADDR' => '127.0.0.1', + ], + ], + $invalidData, + ], ]; } + + /** + * @return string + */ + public static function getInputData() + { + return self::$inputData; + } + + /** + * @param string $inputData + */ + private function mockReadFromPhpInput($inputData) + { + self::$inputData = $inputData; + if (function_exists('Raven\Middleware\file_get_contents')) { + return; + } + + $self = \get_class($this); + + eval(<< Date: Fri, 4 May 2018 09:45:43 +0200 Subject: [PATCH 04/20] Fix Client PHPDoc tag (port of #548 to 2.x) --- lib/Raven/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Raven/Client.php b/lib/Raven/Client.php index ec45568c8..7fd458682 100644 --- a/lib/Raven/Client.php +++ b/lib/Raven/Client.php @@ -33,7 +33,7 @@ /** * Raven PHP Client. * - * @doc https://docs.sentry.io/clients/php/config/ + * @see https://docs.sentry.io/clients/php/config/ */ class Client { From 25755e666c3239407d76d1f773a5c4d685b32451 Mon Sep 17 00:00:00 2001 From: Elias Ojala Date: Sat, 17 Feb 2018 16:01:12 +0100 Subject: [PATCH 05/20] Added syntax highlighting to README.md (#551) (cherry picked from commit 4dd0a3e) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cec8d54cd..e13f69929 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ $ git checkout -b releases/1.9.x 3. Update the hardcoded version tag in ``Client.php``: -``` +```php class Raven_Client { const VERSION = '1.9.0'; @@ -170,7 +170,7 @@ git checkout master 9. Update the version in ``Client.php``: -``` +```php class Raven_Client { const VERSION = '1.10.x-dev'; @@ -179,7 +179,7 @@ class Raven_Client 10. Lastly, update the composer version in ``composer.json``: -``` +```json "extra": { "branch-alias": { "dev-master": "1.10.x-dev" From 228cad49628fb6eb2e18b05844a7be978efbbdfd Mon Sep 17 00:00:00 2001 From: ismaail Date: Thu, 22 Feb 2018 20:27:11 +0100 Subject: [PATCH 06/20] Add use statement for HttpException class (cherry picked from commit 389c3ac, port of #556 to 2.x) --- docs/integrations/laravel.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/integrations/laravel.rst b/docs/integrations/laravel.rst index acd72a337..60b3ba167 100644 --- a/docs/integrations/laravel.rst +++ b/docs/integrations/laravel.rst @@ -64,6 +64,8 @@ step is not required anymore an you can skip ahead to the next one: Date: Mon, 26 Feb 2018 10:35:59 +0100 Subject: [PATCH 07/20] Change badge with badge poser. (cherry picked from commit 47ce095, port of #557 to 2.x) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e13f69929..ebaba4866 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ # Sentry for PHP [![Build Status](https://secure.travis-ci.org/getsentry/sentry-php.png?branch=master)](http://travis-ci.org/getsentry/sentry-php) -[![Total Downloads](https://img.shields.io/packagist/dt/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry) -[![Downloads per month](https://img.shields.io/packagist/dm/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry) -[![Latest stable version](https://img.shields.io/packagist/v/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry) -[![License](http://img.shields.io/packagist/l/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry) +[![Total Downloads](https://poser.pugx.org/sentry/sentry/downloads)](https://packagist.org/packages/sentry/sentry) +[![Monthly Downloads](https://poser.pugx.org/sentry/sentry/d/monthly)](https://packagist.org/packages/sentry/sentry) +[![Latest Stable Version](https://poser.pugx.org/sentry/sentry/v/stable)](https://packagist.org/packages/sentry/sentry) +[![License](https://poser.pugx.org/sentry/sentry/license)](https://packagist.org/packages/sentry/sentry) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/getsentry/sentry-php/master.svg)](https://scrutinizer-ci.com/g/getsentry/sentry-php/) [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/getsentry/sentry-php/master.svg)](https://scrutinizer-ci.com/g/getsentry/sentry-php/) From b5bf725a70f7b6489d165e0d52db7e6c7c8bfe8f Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Sun, 18 Mar 2018 16:40:46 +0100 Subject: [PATCH 08/20] Update docs config (cherry picked from commit f9c90cf) --- docs/sentry-doc-config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sentry-doc-config.json b/docs/sentry-doc-config.json index fe0854355..972fa207d 100644 --- a/docs/sentry-doc-config.json +++ b/docs/sentry-doc-config.json @@ -16,8 +16,9 @@ "type": "framework", "doc_link": "integrations/laravel/", "wizard": [ - "index#installation", - "integrations/laravel#laravel-5-x" + "integrations/laravel#laravel-5-x", + "integrations/laravel#laravel-4-x", + "integrations/laravel#lumen-5-x" ] }, "php.monolog": { @@ -34,7 +35,6 @@ "type": "framework", "doc_link": "integrations/symfony2/", "wizard": [ - "index#installation", "integrations/symfony2#symfony-2" ] } From 354ef903e2ebe8dd73ab00e6e6491b5f0dc4d8a7 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 10:41:08 +0200 Subject: [PATCH 09/20] Add test to handle non default port in host (port of #572 to 2.x) --- .../RequestInterfaceMiddlewareTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Middleware/RequestInterfaceMiddlewareTest.php b/tests/Middleware/RequestInterfaceMiddlewareTest.php index 864f00a02..73e8b9a61 100644 --- a/tests/Middleware/RequestInterfaceMiddlewareTest.php +++ b/tests/Middleware/RequestInterfaceMiddlewareTest.php @@ -102,6 +102,22 @@ public function invokeDataProvider() ], ], ], + [ + [ + 'uri' => 'http://www.example.com:123/foo', + 'method' => 'GET', + 'cookies' => [], + 'headers' => [], + ], + [ + 'url' => 'http://www.example.com:123/foo', + 'method' => 'GET', + 'cookies' => [], + 'headers' => [ + 'Host' => ['www.example.com:123'], + ], + ], + ], [ [ 'uri' => 'http://www.example.com/foo?foo=bar&bar=baz', From 9ec6d84dca1359ea339be88b7798e7a4586ef9ad Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 10:43:21 +0200 Subject: [PATCH 10/20] Update changelog with 1.8.4 info (port of #573 to 2.x) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11c6ca486..a930b861f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ - ... +## 1.8.4 (2018-03-20) + +- Revert ignoring fatal errors on PHP 7+ (#571) +- Add PHP runtime information (#564) +- Cleanup the `site` value if it's empty (#555) +- Add `application/json` input handling (#546) + ## 1.8.3 (2018-02-07) - Serialize breadcrumbs to prevent issues with binary data (#538) From da97fce9c98aff15200a487de9f75b481c67ff69 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 11:11:05 +0200 Subject: [PATCH 11/20] Allow serialization 5 levels deep (port of #554 to 2.x) --- lib/Raven/Client.php | 2 +- tests/ClientTest.php | 69 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/lib/Raven/Client.php b/lib/Raven/Client.php index 7fd458682..2f5e89d32 100644 --- a/lib/Raven/Client.php +++ b/lib/Raven/Client.php @@ -471,7 +471,7 @@ public function sanitize(Event $event) $tagsContext = $event->getTagsContext(); if (!empty($request)) { - $event = $event->withRequest($this->serializer->serialize($request)); + $event = $event->withRequest($this->serializer->serialize($request, 5)); } if (!empty($userContext)) { $event = $event->withUserContext($this->serializer->serialize($userContext, 3)); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 72b6e0e05..23de3103a 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -503,32 +503,79 @@ public function testSanitizeUser() $this->assertEquals(['email' => 'foo@example.com'], $event->getUserContext()); } - public function testSanitizeRequest() + /** + * @dataProvider deepRequestProvider + */ + public function testSanitizeRequest(array $postData, array $expectedData) { $client = ClientBuilder::create()->getClient(); $event = new Event($client->getConfig()); $event = $event->withRequest([ - 'context' => [ - 'line' => 1216, - 'stack' => [ - 1, [2], 3, - ], + 'method' => 'POST', + 'url' => 'https://example.com/something', + 'query_string' => '', + 'data' => [ + '_method' => 'POST', + 'data' => $postData, ], ]); $event = $client->sanitize($event); $this->assertArraySubset([ - 'context' => [ - 'line' => 1216, - 'stack' => [ - 1, 'Array of length 1', 3, - ], + 'method' => 'POST', + 'url' => 'https://example.com/something', + 'query_string' => '', + 'data' => [ + '_method' => 'POST', + 'data' => $expectedData, ], ], $event->getRequest()); } + public function deepRequestProvider() + { + return [ + [ + [ + 'MyModel' => [ + 'flatField' => 'my value', + 'nestedField' => [ + 'key' => 'my other value', + ], + ], + ], + [ + 'MyModel' => [ + 'flatField' => 'my value', + 'nestedField' => [ + 'key' => 'my other value', + ], + ], + ] + ], + [ + [ + 'Level 1' => [ + 'Level 2' => [ + 'Level 3' => [ + 'Level 4' => 'something', + ], + ], + ], + ], + [ + 'Level 1' => [ + 'Level 2' => [ + 'Level 3' => 'Array of length 1', + ], + ], + ], + ], + ]; + } + private function assertMixedValueAndArray($expected_value, $actual_value) { if (null === $expected_value) { From f869efb75c3970fd78a5f4c769381ad53cf99ff0 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 11:29:17 +0200 Subject: [PATCH 12/20] Make Serializer string limit customizable (port of #559 to 2.x) --- lib/Raven/Serializer.php | 32 +++++++++++++++++++++++++++++--- tests/SerializerAbstractTest.php | 31 +++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/lib/Raven/Serializer.php b/lib/Raven/Serializer.php index 7d8cdadca..ae744538c 100644 --- a/lib/Raven/Serializer.php +++ b/lib/Raven/Serializer.php @@ -50,14 +50,24 @@ class Serializer */ protected $_all_object_serialize = false; + /** + * The default maximum message lengths. Longer strings will be truncated + * + * @var int + */ + protected $messageLimit; + /** * @param null|string $mb_detect_order + * @param null|int $messageLimit */ - public function __construct($mb_detect_order = null) + public function __construct($mb_detect_order = null, $messageLimit = Client::MESSAGE_LIMIT) { if (null != $mb_detect_order) { $this->mb_detect_order = $mb_detect_order; } + + $this->messageLimit = (int) $messageLimit; } /** @@ -133,8 +143,8 @@ protected function serializeString($value) } } - if (strlen($value) > 1024) { - $value = substr($value, 0, 1014) . ' {clipped}'; + if (strlen($value) > $this->messageLimit) { + $value = substr($value, 0, $this->messageLimit - 10) . ' {clipped}'; } return $value; @@ -197,4 +207,20 @@ public function getAllObjectSerialize() { return $this->_all_object_serialize; } + + /** + * @return int + */ + public function getMessageLimit() + { + return $this->messageLimit; + } + + /** + * @param int $messageLimit + */ + public function setMessageLimit($messageLimit) + { + $this->messageLimit = $messageLimit; + } } diff --git a/tests/SerializerAbstractTest.php b/tests/SerializerAbstractTest.php index 4b2d904e5..baa462732 100644 --- a/tests/SerializerAbstractTest.php +++ b/tests/SerializerAbstractTest.php @@ -366,16 +366,27 @@ public function testLongString($serialize_all_objects) if ($serialize_all_objects) { $serializer->setAllObjectSerialize(true); } - for ($i = 0; $i < 100; ++$i) { - foreach ([100, 1000, 1010, 1024, 1050, 1100, 10000] as $length) { - $input = ''; - for ($i = 0; $i < $length; ++$i) { - $input .= chr(mt_rand(0, 255)); - } - $result = $serializer->serialize($input); - $this->assertInternalType('string', $result); - $this->assertLessThanOrEqual(1024, strlen($result)); - } + + foreach ([100, 1000, 1010, 1024, 1050, 1100, 10000] as $length) { + $input = str_repeat('x', $length); + $result = $serializer->serialize($input); + $this->assertInternalType('string', $result); + $this->assertLessThanOrEqual(1024, strlen($result)); + } + } + + public function testLongStringWithOverwrittenMessageLength() + { + $class_name = static::get_test_class(); + /** @var \Raven\Serializer $serializer */ + $serializer = new $class_name(); + $serializer->setMessageLimit(500); + + foreach (array(100, 490, 499, 500, 501, 1000, 10000) as $length) { + $input = str_repeat('x', $length); + $result = $serializer->serialize($input); + $this->assertInternalType('string', $result); + $this->assertLessThanOrEqual(500, strlen($result)); } } From b1ed2008745fc5d664461229c52a058d4a7856b9 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 11:52:08 +0200 Subject: [PATCH 13/20] Avoid looping when exception throws exception (port of #587 to 2.x) --- tests/ClientTest.php | 20 ++++++++++++++++++++ tests/Fixtures/classes/CarelessException.php | 13 +++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/Fixtures/classes/CarelessException.php diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 23de3103a..a72a9cac2 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -27,6 +27,7 @@ use Raven\Processor\ProcessorInterface; use Raven\Processor\ProcessorRegistry; use Raven\Serializer; +use Raven\Tests\Fixtures\classes\CarelessException; use Raven\Transport\TransportInterface; // XXX: Is there a better way to stub the client? @@ -842,4 +843,23 @@ public function testSetReprSerializer() $this->assertSame($serializer, $client->getReprSerializer()); } + + public function testHandlingExceptionThrowingAnException() + { + $client = ClientBuilder::create()->getClient(); + $client->captureException($this->createCarelessExceptionWithStacktrace()); + $event = $client->getLastEvent(); + // Make sure the exception is of the careless exception and not the exception thrown inside + // the __set method of that exception caused by setting the event_id on the exception instance + $this->assertSame(CarelessException::class, $event->getException()['values'][0]['type']); + } + + private function createCarelessExceptionWithStacktrace() + { + try { + throw new CarelessException('Foo bar'); + } catch (\Exception $ex) { + return $ex; + } + } } diff --git a/tests/Fixtures/classes/CarelessException.php b/tests/Fixtures/classes/CarelessException.php new file mode 100644 index 000000000..f1776c0fa --- /dev/null +++ b/tests/Fixtures/classes/CarelessException.php @@ -0,0 +1,13 @@ + Date: Fri, 4 May 2018 12:16:02 +0200 Subject: [PATCH 14/20] Fix monolog handler not accepting Throwable (port of #586 to 2.x) --- lib/Raven/Breadcrumbs/MonologHandler.php | 10 ++- tests/Breadcrumbs/MonologHandlerTest.php | 105 +++++++++++++++++------ 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/lib/Raven/Breadcrumbs/MonologHandler.php b/lib/Raven/Breadcrumbs/MonologHandler.php index 6e19bb32a..43a6fbc1f 100644 --- a/lib/Raven/Breadcrumbs/MonologHandler.php +++ b/lib/Raven/Breadcrumbs/MonologHandler.php @@ -65,9 +65,15 @@ protected function write(array $record) return; } - if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + if ( + isset($record['context']['exception']) + && ( + $record['context']['exception'] instanceof \Exception + || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable) + ) + ) { /** - * @var \Exception + * @var \Exception|\Throwable $exc */ $exc = $record['context']['exception']; diff --git a/tests/Breadcrumbs/MonologHandlerTest.php b/tests/Breadcrumbs/MonologHandlerTest.php index b2e42c888..b602d2411 100644 --- a/tests/Breadcrumbs/MonologHandlerTest.php +++ b/tests/Breadcrumbs/MonologHandlerTest.php @@ -12,6 +12,7 @@ namespace Raven\Tests\Breadcrumbs; use Monolog\Logger; +use ParseError; use PHPUnit\Framework\TestCase; use Raven\Breadcrumbs\Breadcrumb; use Raven\Breadcrumbs\MonologHandler; @@ -44,52 +45,106 @@ protected function getSampleErrorMessage() public function testSimple() { - $client = $client = ClientBuilder::create([ - 'install_default_breadcrumb_handlers' => false, - ])->getClient(); - - $handler = new MonologHandler($client); + $client = $this->createClient(); + $logger = $this->createLoggerWithHandler($client); - $logger = new Logger('sentry'); - $logger->pushHandler($handler); $logger->addWarning('foo'); - $breadcrumbsRecorder = $this->getObjectAttribute($client, 'breadcrumbRecorder'); + $breadcrumbs = $this->getBreadcrumbs($client); + $this->assertCount(1, $breadcrumbs); + $this->assertEquals('foo', $breadcrumbs[0]->getMessage()); + $this->assertEquals(Client::LEVEL_WARNING, $breadcrumbs[0]->getLevel()); + $this->assertEquals('sentry', $breadcrumbs[0]->getCategory()); + } - /** @var \Raven\Breadcrumbs\Breadcrumb[] $breadcrumbs */ - $breadcrumbs = iterator_to_array($breadcrumbsRecorder); + public function testErrorInMessage() + { + $client = $this->createClient(); + $logger = $this->createLoggerWithHandler($client); + + $logger->addError($this->getSampleErrorMessage()); + $breadcrumbs = $this->getBreadcrumbs($client); $this->assertCount(1, $breadcrumbs); + $this->assertEquals(Breadcrumb::TYPE_ERROR, $breadcrumbs[0]->getType()); + $this->assertEquals(Client::LEVEL_ERROR, $breadcrumbs[0]->getLevel()); + $this->assertEquals('sentry', $breadcrumbs[0]->getCategory()); + $this->assertEquals('An unhandled exception', $breadcrumbs[0]->getMetadata()['value']); + } + + public function testExceptionBeingParsed() + { + $client = $this->createClient(); + $logger = $this->createLoggerWithHandler($client); - $this->assertEquals($breadcrumbs[0]->getMessage(), 'foo'); - $this->assertEquals($breadcrumbs[0]->getLevel(), Client::LEVEL_WARNING); - $this->assertEquals($breadcrumbs[0]->getCategory(), 'sentry'); + $logger->addError('A message', ['exception' => new \Exception('Foo bar')]); + + $breadcrumbs = $this->getBreadcrumbs($client); + $this->assertCount(1, $breadcrumbs); + $this->assertEquals(Breadcrumb::TYPE_ERROR, $breadcrumbs[0]->getType()); + $this->assertEquals('Foo bar', $breadcrumbs[0]->getMetadata()['value']); + $this->assertEquals('sentry', $breadcrumbs[0]->getCategory()); + $this->assertEquals(Client::LEVEL_ERROR, $breadcrumbs[0]->getLevel()); + $this->assertNull($breadcrumbs[0]->getMessage()); } - public function testErrorInMessage() + public function testThrowableBeingParsedAsException() + { + if (PHP_VERSION_ID <= 70000) { + $this->markTestSkipped('PHP 7.0 introduced Throwable'); + } + + $client = $this->createClient(); + $logger = $this->createLoggerWithHandler($client); + $throwable = new ParseError('Foo bar'); + + $logger->addError('This is a throwable', ['exception' => $throwable]); + + $breadcrumbs = $this->getBreadcrumbs($client); + $this->assertCount(1, $breadcrumbs); + $this->assertEquals(Breadcrumb::TYPE_ERROR, $breadcrumbs[0]->getType()); + $this->assertEquals('Foo bar', $breadcrumbs[0]->getMetadata()['value']); + $this->assertEquals('sentry', $breadcrumbs[0]->getCategory()); + $this->assertEquals(Client::LEVEL_ERROR, $breadcrumbs[0]->getLevel()); + $this->assertNull($breadcrumbs[0]->getMessage()); + } + + /** + * @return Client + */ + private function createClient() { $client = $client = ClientBuilder::create([ 'install_default_breadcrumb_handlers' => false, ])->getClient(); - $handler = new MonologHandler($client); + return $client; + } + /** + * @param Client $client + * @return Logger + */ + private function createLoggerWithHandler(Client $client) + { + $handler = new MonologHandler($client); $logger = new Logger('sentry'); $logger->pushHandler($handler); - $logger->addError($this->getSampleErrorMessage()); + return $logger; + } + + /** + * @param Client $client + * @return Breadcrumb[] + */ + private function getBreadcrumbs(Client $client) + { $breadcrumbsRecorder = $this->getObjectAttribute($client, 'breadcrumbRecorder'); - /** @var \Raven\Breadcrumbs\Breadcrumb[] $breadcrumbs */ $breadcrumbs = iterator_to_array($breadcrumbsRecorder); + $this->assertContainsOnlyInstancesOf(Breadcrumb::class, $breadcrumbs); - $this->assertCount(1, $breadcrumbs); - - $metaData = $breadcrumbs[0]->getMetadata(); - - $this->assertEquals($breadcrumbs[0]->getType(), Breadcrumb::TYPE_ERROR); - $this->assertEquals($breadcrumbs[0]->getLevel(), Client::LEVEL_ERROR); - $this->assertEquals($breadcrumbs[0]->getCategory(), 'sentry'); - $this->assertEquals($metaData['value'], 'An unhandled exception'); + return $breadcrumbs; } } From 477d0c94b75b5dae30e89a243340308941d1f18c Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 12:26:43 +0200 Subject: [PATCH 15/20] Fix serializer to account for non-UTF-8 chars (port of #553 to 2.x) --- lib/Raven/Serializer.php | 15 +++++++++------ tests/SerializerAbstractTest.php | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/Raven/Serializer.php b/lib/Raven/Serializer.php index ae744538c..00e92930a 100644 --- a/lib/Raven/Serializer.php +++ b/lib/Raven/Serializer.php @@ -132,19 +132,22 @@ public function serializeObject($object, $max_depth = 3, $_depth = 0, $hashes = protected function serializeString($value) { $value = (string) $value; - if (function_exists('mb_detect_encoding') - && function_exists('mb_convert_encoding') - ) { + + if (extension_loaded('mbstring')) { // 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) > $this->messageLimit) { - $value = substr($value, 0, $this->messageLimit - 10) . ' {clipped}'; + if (mb_strlen($value) > $this->messageLimit) { + $value = mb_substr($value, 0, $this->messageLimit - 10, 'UTF-8') . ' {clipped}'; + } + } else { + if (strlen($value) > $this->messageLimit) { + $value = substr($value, 0, $this->messageLimit - 10) . ' {clipped}'; + } } return $value; diff --git a/tests/SerializerAbstractTest.php b/tests/SerializerAbstractTest.php index baa462732..690f55d65 100644 --- a/tests/SerializerAbstractTest.php +++ b/tests/SerializerAbstractTest.php @@ -420,6 +420,24 @@ public function testSetAllObjectSerialize() $serializer->setAllObjectSerialize(false); $this->assertFalse($serializer->getAllObjectSerialize()); } + + public function testClippingUTF8Characters() + { + if (!extension_loaded('mbstring')) { + $this->markTestSkipped('mbstring extension is not enabled.'); + } + + $testString = 'Прекратите надеяться, что ваши пользователи будут сообщать об ошибках'; + $class_name = static::get_test_class(); + /** @var \Raven\Serializer $serializer */ + $serializer = new $class_name(null, 19); + + $clipped = $serializer->serialize($testString); + + $this->assertEquals('Прекратит {clipped}', $clipped); + $this->assertNotNull(json_encode($clipped)); + $this->assertSame(JSON_ERROR_NONE, json_last_error()); + } } /** From 1b452ba90bcf85549d6d9f794c6e0b639d51ccb9 Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Thu, 3 May 2018 09:25:13 +0200 Subject: [PATCH 16/20] Add 1.9.0 changelog entries (cherry picked from commit 01171cf) --- CHANGELOG.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a930b861f..9ca5951e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,17 @@ # CHANGELOG -## Unreleased - -- ... +## 1.9.0 (2018-05-03) + +- Fixed undefined variable (#588) +- Fix for exceptions throwing exceptions when setting event id (#587) +- Fix monolog handler not accepting Throwable (#586) +- Add `excluded_exceptions` option to exclude exceptions and their extending exceptions (#583) +- Fix `HTTP_X_FORWARDED_PROTO` header detection (#578) +- Fix sending events async in PHP 5 (#576) +- Avoid double reporting due to `ErrorException`s (#574) +- Make it possible to overwrite serializer message limit of 1024 (#559) +- Allow request data to be nested up to 5 levels deep (#554) +- Update serializer to handle UTF-8 characters correctly (#553) ## 1.8.4 (2018-03-20) From 48a45e608b9fe521435d99cdea1bebcb7b0a185c Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Thu, 3 May 2018 09:31:06 +0200 Subject: [PATCH 17/20] Add timeout and excluded_options config docs (cherry picked from commit 6860a3e) --- docs/config.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index 9c56f7f86..6e193db0d 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -241,6 +241,26 @@ The following settings are available for the client: ) ) +.. describe:: timeout + + The timeout for sending requests to the Sentry server in seconds, default is 2 seconds. + + .. code-block:: php + + 'timeout' => 2, + +.. describe:: excluded_exceptions + + Exception that should not be reported, exceptions extending exceptions in this list will also + be excluded, default is an empty array. + + In the example below, when you exclude ``LogicException`` you will also exclude ``BadFunctionCallException`` + since it extends ``LogicException``. + + .. code-block:: php + + 'excluded_exceptions' => array('LogicException'), + .. _sentry-php-request-context: Providing Request Context From 1415b1e7b8a4c2ca9b47c368ebef90628f4c2cc3 Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Thu, 3 May 2018 10:23:14 +0200 Subject: [PATCH 18/20] Add back unrelease heading to changelog (cherry picked from commit 3f52e6f) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca5951e2..30dcb6105 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## Unreleased + +- ... + ## 1.9.0 (2018-05-03) - Fixed undefined variable (#588) From 9a6987a6b5c8a2beb5d3c28c21b8144de2e2eb11 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 12:36:00 +0200 Subject: [PATCH 19/20] Fix CS --- lib/Raven/Breadcrumbs/MonologHandler.php | 6 +++--- lib/Raven/Middleware/RequestInterfaceMiddleware.php | 2 +- lib/Raven/Serializer.php | 4 ++-- tests/Breadcrumbs/MonologHandlerTest.php | 2 ++ tests/ClientTest.php | 2 +- tests/Fixtures/classes/CarelessException.php | 2 +- tests/SerializerAbstractTest.php | 2 +- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/Raven/Breadcrumbs/MonologHandler.php b/lib/Raven/Breadcrumbs/MonologHandler.php index 43a6fbc1f..4583e3785 100644 --- a/lib/Raven/Breadcrumbs/MonologHandler.php +++ b/lib/Raven/Breadcrumbs/MonologHandler.php @@ -66,14 +66,14 @@ protected function write(array $record) } if ( - isset($record['context']['exception']) + isset($record['context']['exception']) && ( - $record['context']['exception'] instanceof \Exception + $record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable) ) ) { /** - * @var \Exception|\Throwable $exc + * @var \Exception|\Throwable */ $exc = $record['context']['exception']; diff --git a/lib/Raven/Middleware/RequestInterfaceMiddleware.php b/lib/Raven/Middleware/RequestInterfaceMiddleware.php index b656acb7a..e91a1a434 100644 --- a/lib/Raven/Middleware/RequestInterfaceMiddleware.php +++ b/lib/Raven/Middleware/RequestInterfaceMiddleware.php @@ -53,7 +53,7 @@ public function __invoke(Event $event, callable $next, ServerRequestInterface $r if ($request->hasHeader('REMOTE_ADDR')) { $requestData['env']['REMOTE_ADDR'] = $request->getHeaderLine('REMOTE_ADDR'); } - + if (in_array('application/json', $request->getHeader('Content-Type'))) { $inputData = file_get_contents('php://input'); $requestData['data'] = json_decode($inputData, true); diff --git a/lib/Raven/Serializer.php b/lib/Raven/Serializer.php index 00e92930a..8cc4d443f 100644 --- a/lib/Raven/Serializer.php +++ b/lib/Raven/Serializer.php @@ -51,8 +51,8 @@ class Serializer protected $_all_object_serialize = false; /** - * The default maximum message lengths. Longer strings will be truncated - * + * The default maximum message lengths. Longer strings will be truncated. + * * @var int */ protected $messageLimit; diff --git a/tests/Breadcrumbs/MonologHandlerTest.php b/tests/Breadcrumbs/MonologHandlerTest.php index b602d2411..129b11496 100644 --- a/tests/Breadcrumbs/MonologHandlerTest.php +++ b/tests/Breadcrumbs/MonologHandlerTest.php @@ -123,6 +123,7 @@ private function createClient() /** * @param Client $client + * * @return Logger */ private function createLoggerWithHandler(Client $client) @@ -136,6 +137,7 @@ private function createLoggerWithHandler(Client $client) /** * @param Client $client + * * @return Breadcrumb[] */ private function getBreadcrumbs(Client $client) diff --git a/tests/ClientTest.php b/tests/ClientTest.php index a72a9cac2..d13e15e46 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -554,7 +554,7 @@ public function deepRequestProvider() 'key' => 'my other value', ], ], - ] + ], ], [ [ diff --git a/tests/Fixtures/classes/CarelessException.php b/tests/Fixtures/classes/CarelessException.php index f1776c0fa..aa8e94223 100644 --- a/tests/Fixtures/classes/CarelessException.php +++ b/tests/Fixtures/classes/CarelessException.php @@ -6,7 +6,7 @@ class CarelessException extends \Exception { public function __set($var, $value) { - if ($var === 'event_id') { + if ('event_id' === $var) { throw new \RuntimeException('I am carelessly throwing an exception here!'); } } diff --git a/tests/SerializerAbstractTest.php b/tests/SerializerAbstractTest.php index 690f55d65..8d87f81a7 100644 --- a/tests/SerializerAbstractTest.php +++ b/tests/SerializerAbstractTest.php @@ -382,7 +382,7 @@ public function testLongStringWithOverwrittenMessageLength() $serializer = new $class_name(); $serializer->setMessageLimit(500); - foreach (array(100, 490, 499, 500, 501, 1000, 10000) as $length) { + foreach ([100, 490, 499, 500, 501, 1000, 10000] as $length) { $input = str_repeat('x', $length); $result = $serializer->serialize($input); $this->assertInternalType('string', $result); From dd16f8939eec6d841381c40da5c811454c72703f Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Fri, 4 May 2018 22:09:08 +0200 Subject: [PATCH 20/20] Revert "Handle application/json data input (port of #546 to 2.x)" This reverts commit e33e200 --- .../Middleware/RequestInterfaceMiddleware.php | 5 - .../RequestInterfaceMiddlewareTest.php | 99 +------------------ 2 files changed, 2 insertions(+), 102 deletions(-) diff --git a/lib/Raven/Middleware/RequestInterfaceMiddleware.php b/lib/Raven/Middleware/RequestInterfaceMiddleware.php index e91a1a434..a82091bcc 100644 --- a/lib/Raven/Middleware/RequestInterfaceMiddleware.php +++ b/lib/Raven/Middleware/RequestInterfaceMiddleware.php @@ -54,11 +54,6 @@ public function __invoke(Event $event, callable $next, ServerRequestInterface $r $requestData['env']['REMOTE_ADDR'] = $request->getHeaderLine('REMOTE_ADDR'); } - if (in_array('application/json', $request->getHeader('Content-Type'))) { - $inputData = file_get_contents('php://input'); - $requestData['data'] = json_decode($inputData, true); - } - $event = $event->withRequest($requestData); return $next($event, $request, $exception, $payload); diff --git a/tests/Middleware/RequestInterfaceMiddlewareTest.php b/tests/Middleware/RequestInterfaceMiddlewareTest.php index 73e8b9a61..258688e28 100644 --- a/tests/Middleware/RequestInterfaceMiddlewareTest.php +++ b/tests/Middleware/RequestInterfaceMiddlewareTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Raven\Tests\Middleware; +namespace Raven\Tests\Breadcrumbs; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; @@ -21,8 +21,6 @@ class RequestInterfaceMiddlewareTest extends TestCase { - private static $inputData; - public function testInvokeWithNoRequest() { $configuration = new Configuration(); @@ -44,7 +42,7 @@ public function testInvokeWithNoRequest() /** * @dataProvider invokeDataProvider */ - public function testInvoke(array $requestData, array $expectedValue, $inputData = null) + public function testInvoke($requestData, $expectedValue) { $configuration = new Configuration(); $event = new Event($configuration); @@ -67,10 +65,6 @@ public function testInvoke(array $requestData, array $expectedValue, $inputData }; $middleware = new RequestInterfaceMiddleware(); - if ($inputData) { - $this->mockReadFromPhpInput($inputData); - } - $middleware($event, $callback, $request); $this->assertEquals(1, $invokationCount); @@ -78,9 +72,6 @@ public function testInvoke(array $requestData, array $expectedValue, $inputData public function invokeDataProvider() { - $validData = ['json_test' => 'json_data']; - $invalidData = '{"binary_json":"' . pack('NA3CC', 3, 'aBc', 0x0D, 0x0A) . '"}'; - return [ [ [ @@ -142,92 +133,6 @@ public function invokeDataProvider() ], ], ], - [ - [ - 'uri' => 'http://www.example.com/foo', - 'method' => 'POST', - 'cookies' => [], - 'headers' => [ - 'Content-Type' => ['application/json'], - 'Host' => ['www.example.com'], - 'REMOTE_ADDR' => ['127.0.0.1'], - ], - ], - [ - 'url' => 'http://www.example.com/foo', - 'method' => 'POST', - 'cookies' => [], - 'data' => $validData, - 'headers' => [ - 'Content-Type' => ['application/json'], - 'Host' => ['www.example.com'], - 'REMOTE_ADDR' => ['127.0.0.1'], - ], - 'env' => [ - 'REMOTE_ADDR' => '127.0.0.1', - ], - ], - json_encode($validData), - ], - [ - [ - 'uri' => 'http://www.example.com/foo', - 'method' => 'POST', - 'cookies' => [], - 'headers' => [ - 'Content-Type' => ['application/json'], - 'Host' => ['www.example.com'], - 'REMOTE_ADDR' => ['127.0.0.1'], - ], - ], - [ - 'url' => 'http://www.example.com/foo', - 'method' => 'POST', - 'cookies' => [], - 'data' => null, - 'headers' => [ - 'Content-Type' => ['application/json'], - 'Host' => ['www.example.com'], - 'REMOTE_ADDR' => ['127.0.0.1'], - ], - 'env' => [ - 'REMOTE_ADDR' => '127.0.0.1', - ], - ], - $invalidData, - ], ]; } - - /** - * @return string - */ - public static function getInputData() - { - return self::$inputData; - } - - /** - * @param string $inputData - */ - private function mockReadFromPhpInput($inputData) - { - self::$inputData = $inputData; - if (function_exists('Raven\Middleware\file_get_contents')) { - return; - } - - $self = \get_class($this); - - eval(<<