Browse Source

Fixes php8 non-backward compatible changes (#1568)

* Utils method added to resolve PCRE error messages properly
Juan Morales 4 years ago
parent
commit
82ab6a5f4f

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

@@ -111,7 +111,8 @@ class LineFormatter extends NormalizerFormatter
         if (false !== strpos($output, '%')) {
             $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
             if (null === $output) {
-                throw new \RuntimeException('Failed to run preg_replace: ' . preg_last_error() . ' / ' . preg_last_error_msg());
+                $pcreErrorCode = preg_last_error();
+                throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
             }
         }
 

+ 2 - 1
src/Monolog/Handler/BrowserConsoleHandler.php

@@ -212,7 +212,8 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
         }, $style);
 
         if (null === $style) {
-            throw new \RuntimeException('Failed to run preg_replace_callback: ' . preg_last_error() . ' / ' . preg_last_error_msg());
+            $pcreErrorCode = preg_last_error();
+            throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
         }
 
         return $style;

+ 3 - 1
src/Monolog/Handler/ErrorLogHandler.php

@@ -14,6 +14,7 @@ namespace Monolog\Handler;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Logger;
+use Monolog\Utils;
 
 /**
  * Stores to PHP error_log() handler.
@@ -80,7 +81,8 @@ class ErrorLogHandler extends AbstractProcessingHandler
 
         $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
         if ($lines === false) {
-            throw new \RuntimeException('Failed to preg_split formatted string: '.preg_last_error().' / '.preg_last_error_msg());
+            $pcreErrorCode = preg_last_error();
+            throw new \RuntimeException('Failed to preg_split formatted string: ' . $pcreErrorCode . ' / '. Utils::pcreLastErrorMessage($pcreErrorCode));
         }
         foreach ($lines as $line) {
             error_log($line, $this->messageType);

+ 3 - 1
src/Monolog/Handler/SyslogUdpHandler.php

@@ -14,6 +14,7 @@ namespace Monolog\Handler;
 use DateTimeInterface;
 use Monolog\Logger;
 use Monolog\Handler\SyslogUdp\UdpSocket;
+use Monolog\Utils;
 
 /**
  * A Handler for logging to a remote syslogd server.
@@ -89,7 +90,8 @@ class SyslogUdpHandler extends AbstractSyslogHandler
 
         $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY);
         if (false === $lines) {
-            throw new \RuntimeException('Could not preg_split: '.preg_last_error().' / '.preg_last_error_msg());
+            $pcreErrorCode = preg_last_error();
+            throw new \RuntimeException('Could not preg_split: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
         }
 
         return $lines;

+ 21 - 1
src/Monolog/Utils.php

@@ -140,6 +140,25 @@ final class Utils
         return $json;
     }
 
+    /**
+     * @internal
+     */
+    public static function pcreLastErrorMessage(int $code): string
+    {
+        if (PHP_VERSION_ID >= 80000) {
+            return preg_last_error_msg();
+        }
+
+        $constants = (get_defined_constants(true))['pcre'];
+        $constants = array_filter($constants, function ($key) {
+            return substr($key, -6) == '_ERROR';
+        }, ARRAY_FILTER_USE_KEY);
+
+        $constants = array_flip($constants);
+
+        return $constants[$code] ?? 'UNDEFINED_ERROR';
+    }
+
     /**
      * Throws an exception according to a given code with a customized message
      *
@@ -197,7 +216,8 @@ final class Utils
                 $data
             );
             if (!is_string($data)) {
-                throw new \RuntimeException('Failed to preg_replace_callback: '.preg_last_error().' / '.preg_last_error_msg());
+                $pcreErrorCode = preg_last_error();
+                throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode));
             }
             $data = str_replace(
                 ['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'],

+ 32 - 0
tests/Monolog/UtilsTest.php

@@ -109,4 +109,36 @@ class UtilsTest extends \PHPUnit_Framework_TestCase
             'object' => [$obj, $obj],
         ];
     }
+
+    /**
+     * @dataProvider providesPcreLastErrorMessage
+     * @param int $code
+     * @param string $msg
+     */
+    public function testPcreLastErrorMessage($code, $msg)
+    {
+        if (PHP_VERSION_ID >= 80000) {
+            $this->assertSame('No error', Utils::pcreLastErrorMessage($code));
+            return;
+        }
+
+        $this->assertEquals($msg, Utils::pcreLastErrorMessage($code));
+    }
+
+    /**
+     * @return array[]
+     */
+    public function providesPcreLastErrorMessage()
+    {
+        return [
+            [0, 'PREG_NO_ERROR'],
+            [1, 'PREG_INTERNAL_ERROR'],
+            [2, 'PREG_BACKTRACK_LIMIT_ERROR'],
+            [3, 'PREG_RECURSION_LIMIT_ERROR'],
+            [4, 'PREG_BAD_UTF8_ERROR'],
+            [5, 'PREG_BAD_UTF8_OFFSET_ERROR'],
+            [6, 'PREG_JIT_STACKLIMIT_ERROR'],
+            [-1, 'UNDEFINED_ERROR'],
+        ];
+    }
 }