diff --git a/modules/cms/classes/CodeParser.php b/modules/cms/classes/CodeParser.php index 5bb672133a..3d022ad7a8 100644 --- a/modules/cms/classes/CodeParser.php +++ b/modules/cms/classes/CodeParser.php @@ -153,12 +153,16 @@ protected function rebuild($path) $fileContents .= trim($body).PHP_EOL; $fileContents .= '}'.PHP_EOL; - $this->validate($fileContents); - $this->makeDirectorySafe(dirname($path)); $this->writeContentSafe($path, $fileContents); + // Attempt to load the generated code file to ensure any errors are thrown + // before the file is cached + if (!class_exists($className)) { + require_once $path; + } + return $className; } @@ -289,15 +293,6 @@ protected function getCachedFileInfo() // Helpers // - /** - * Evaluates PHP content in order to detect syntax errors. - * The method handles PHP errors and throws exceptions. - */ - protected function validate($php) - { - eval('?>'.$php); - } - /** * Extracts the class name from a cache file * @return string diff --git a/modules/system/assets/js/eventlogs/exception-beautifier.links.js b/modules/system/assets/js/eventlogs/exception-beautifier.links.js index 3f948ad869..d24907223d 100644 --- a/modules/system/assets/js/eventlogs/exception-beautifier.links.js +++ b/modules/system/assets/js/eventlogs/exception-beautifier.links.js @@ -7,10 +7,11 @@ var ExceptionBeautifier = $.fn.exceptionBeautifier.Constructor ExceptionBeautifier.EDITORS = { + vscode: {scheme: 'vscode://file/%file:%line', name: 'VS Code (vscode://)'}, + phpstorm: {scheme: 'phpstorm://open?file=%file&line=%line', name: 'PhpStorm (phpstorm://)'}, subl: {scheme: 'subl://open?url=file://%file&line=%line', name: 'Sublime (subl://)'}, txmt: {scheme: 'txmt://open/?url=file://%file&line=%line', name: 'TextMate (txmt://)'}, mvim: {scheme: 'mvim://open/?url=file://%file&line=%line', name: 'MacVim (mvim://)'}, - phpstorm: {scheme: 'phpstorm://open?file=%file&line=%line', name: 'PhpStorm (phpstorm://)'}, editor: {scheme: 'editor://open/?file=%file&line=%line', name: 'Custom (editor://)'} } diff --git a/modules/system/controllers/eventlogs/_field_details.php b/modules/system/controllers/eventlogs/_field_details.php new file mode 100644 index 0000000000..1b26ddd2df --- /dev/null +++ b/modules/system/controllers/eventlogs/_field_details.php @@ -0,0 +1,515 @@ + '/\b(for|foreach|while|class |extends|yield from|yield|echo|fn|implements|try|catch|finally|throw|new|instanceof|parent|function|return|unset|static|public|protected|private|count|global|if|else|else if|intval|int|array)\b/', + 'bool' => '/(\bnull\b|\btrue\b|\bfalse\b)/', + 'string' => [ + 'pattern' => '/(\221[^\221]*\221|\222[^\222]*\222)/', + 'before' => fn ($s) => str_replace(''', "\221", str_replace('"', "\222", $s)), + 'after' => fn ($s) => str_replace("\221", ''', str_replace("\222", '"', $s)), + ], + 'number' => [ + 'pattern' => '/(=\(\s)?(\d+)(?=(\s|;|,|\)|=))/', + 'replace' => '$2', + 'before' => fn ($s) => str_replace(''', '\'', $s), + 'after' => fn ($s) => str_replace('\'', ''', $s), + ], + 'bracket' => '/(\(|\)|\[|\]|\{|\})/', + 'variable' => '/(\$[a-z]\w*)/', + ]; + + if (preg_match('/(^\s*?\*|^\s*?\*\/|^\s*?\/\*|^\s*?\/\/|^\s*?#)/', $str)) { + return sprintf('%s', $str); + } + + foreach ($regexes as $label => $regex) { + if (is_string($regex)) { + $str = preg_replace($regex, '$1', $str); + continue; + } + + $str = preg_replace( + $regex['pattern'], + sprintf('%s', $label, $regex['replace'] ?? '$1'), + isset($regex['before']) ? $regex['before']($str) : $str + ); + + $str = isset($regex['after']) ? $regex['after']($str) : $str; + } + + return $str; +} + +/** + * Converts an array of lines into a html snippet of code + * + * @param array $snippet + * @param int|null $highlight + * @return string + */ +function makeSnippet(array $snippet, string $file, ?int $highlight = null): string +{ + return implode( + "\n", + array_reduce( + array_keys($snippet), + function (array $carry, $key) use ($snippet, $file, $highlight) { + $carry[] = sprintf( + '
%3$d: %4$s
', + ($key + 1 === $highlight ? ' highlight' : ''), + urlencode(str_replace('\\', '/', $file)), + $key + 1, + phpSyntaxHighlight(e($snippet[$key], true)) + ); + return $carry; + }, + [] + ) + ); +} + +/** + * Gets all exceptions in the stack and returns them bottom up + * + * @param array $value + * @return array + */ +function getOrderedExceptionList(array $value): array +{ + $exceptions = [$value]; + $current = $value; + while (isset($current['previous']) && ($current = $current['previous'])) { + $exceptions[] = $current; + } + + return array_reverse($exceptions); +} +?> + +
+
+
+ + + + + + + + + + + + + + + + + + + + +
HTTP Method
Url + + + +
User Agent
Client IP
+ + +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+
+ $exception): ?> +
+

+

+ +
+
+ + +
+
+ + +
+
+ +
+
+
+ + at line +
+ +
+
+ +
+
+ +
+
+ +
+ Stack Trace ( frames) +
+ $frame): ?> +
+
+ # + in + at line + + with argument 1 ? 's' : '' ?>: (, ', $frame['arguments']) ?>) + + + In App + +
+ +
+
+ +
+
+ +
+ +
+
+
+ +
+
+ +
+ + diff --git a/modules/system/controllers/eventlogs/preview.php b/modules/system/controllers/eventlogs/preview.php index 37200b5db7..316229e37b 100644 --- a/modules/system/controllers/eventlogs/preview.php +++ b/modules/system/controllers/eventlogs/preview.php @@ -24,8 +24,14 @@ -
+
formRenderPreview() ?> + +

+ + + +

@@ -33,9 +39,3 @@

fatalError)) ?>

- -

- - - -

diff --git a/modules/system/models/eventlog/fields.yaml b/modules/system/models/eventlog/fields.yaml index 1a9c11ee9a..b9f8d1fea1 100644 --- a/modules/system/models/eventlog/fields.yaml +++ b/modules/system/models/eventlog/fields.yaml @@ -9,3 +9,7 @@ fields: path: field_message containerAttributes: data-plugin: exception-beautifier + + details: + type: partial + path: field_details