Browse Source

Resolve json encoding errors issue globally, refs #137

Jordi Boggiano 13 năm trước cách đây
mục cha
commit
63e3bfdf7e

+ 3 - 2
src/Monolog/Formatter/LineFormatter.php

@@ -81,10 +81,11 @@ class LineFormatter extends NormalizerFormatter
             return (string) $data;
         }
 
+        $data = $this->normalize($data);
         if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
-            return json_encode($this->normalize($data), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+            return $this->toJson($data);
         }
 
-        return str_replace('\\/', '/', json_encode($this->normalize($data)));
+        return str_replace('\\/', '/', json_encode($data));
     }
 }

+ 11 - 2
src/Monolog/Formatter/NormalizerFormatter.php

@@ -71,7 +71,7 @@ class NormalizerFormatter implements FormatterInterface
         }
 
         if (is_object($data)) {
-            return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data));
+            return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data, true));
         }
 
         if (is_resource($data)) {
@@ -81,8 +81,17 @@ class NormalizerFormatter implements FormatterInterface
         return '[unknown('.gettype($data).')]';
     }
 
-    protected function toJson($data)
+    protected function toJson($data, $ignoreErrors = false)
     {
+        // suppress json_encode errors since it's twitchy with some inputs
+        if ($ignoreErrors) {
+            if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+                return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+            }
+
+            return @json_encode($data);
+        }
+
         if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
             return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
         }

+ 2 - 11
src/Monolog/Formatter/WildfireFormatter.php

@@ -67,13 +67,8 @@ class WildfireFormatter extends NormalizerFormatter
             $message = reset($message);
         }
 
-        // Handle json_encode recursion error
-        if ($handleError) {
-            set_error_handler(function () { });
-        }
-
         // Create JSON object describing the appearance of the message in the console
-        $json = json_encode(array(
+        $json = $this->toJson(array(
             array(
                 'Type'  => $this->logLevels[$record['level']],
                 'File'  => $file,
@@ -81,11 +76,7 @@ class WildfireFormatter extends NormalizerFormatter
                 'Label' => $record['channel'],
             ),
             $message,
-        ));
-
-        if ($handleError) {
-            restore_error_handler();
-        }
+        ), $handleError);
 
         // The message itself is a serialization of the above JSON object + it's length
         return sprintf(

+ 55 - 0
tests/Monolog/Formatter/NormalizerFormatterTest.php

@@ -89,6 +89,61 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
             ),
         ), $formatted);
     }
+
+    /**
+     * Test issue #137
+     */
+    public function testIgnoresRecursiveObjectReferences()
+    {
+        // set up the recursion
+        $foo = new \stdClass();
+        $bar = new \stdClass();
+
+        $foo->bar = $bar;
+        $bar->foo = $foo;
+
+        // set an error handler to assert that the error is not raised anymore
+        $that = $this;
+        set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
+            if (error_reporting() & $level) {
+                restore_error_handler();
+                $that->fail("$message should not be raised");
+            }
+        });
+
+        $formatter = new NormalizerFormatter();
+        $reflMethod = new \ReflectionMethod($formatter, 'toJson');
+        $reflMethod->setAccessible(true);
+        $res = $reflMethod->invoke($formatter, array($foo, $bar), true);
+
+        restore_error_handler();
+
+        $this->assertEquals(@json_encode(array($foo, $bar)), $res);
+    }
+
+    public function testIgnoresInvalidTypes()
+    {
+        // set up the recursion
+        $resource = fopen(__FILE__, 'r');
+
+        // set an error handler to assert that the error is not raised anymore
+        $that = $this;
+        set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
+            if (error_reporting() & $level) {
+                restore_error_handler();
+                $that->fail("$message should not be raised");
+            }
+        });
+
+        $formatter = new NormalizerFormatter();
+        $reflMethod = new \ReflectionMethod($formatter, 'toJson');
+        $reflMethod->setAccessible(true);
+        $res = $reflMethod->invoke($formatter, array($resource), true);
+
+        restore_error_handler();
+
+        $this->assertEquals(@json_encode(array($resource)), $res);
+    }
 }
 
 class TestFooNorm

+ 0 - 37
tests/Monolog/Formatter/WildfireFormatterTest.php

@@ -108,41 +108,4 @@ class WildfireFormatterTest extends \PHPUnit_Framework_TestCase
 
         $wildfire->formatBatch(array($record));
     }
-
-    /**
-     * Test issue #137 (https://github.com/Seldaek/monolog/pull/137)
-     */
-    public function testFormatWithObjectsInContext()
-    {
-        // Set up the recursion
-        $foo = new \stdClass();
-        $bar = new \stdClass();
-
-        $foo->bar = $bar;
-        $bar->foo = $foo;
-
-        $record = array(
-            'message'    => "foo",
-            'level'      => 300,
-            'channel'    => 'foo',
-            'context'    => array(
-                'stack'  => array(
-                    array($foo),
-                    array($bar),
-                ),
-            ),
-            'extra'      => array(),
-        );
-
-        // Set an error handler to assert that the error is not raised anymore
-        $that = $this;
-        set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
-           $that->fail("$message should not be raised anymore");
-        });
-
-        $wildfire = new WildfireFormatter();
-        $wildfire->format($record);
-
-        restore_error_handler();
-    }
 }