diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index 0f969c7adb9b9..e8c10e700613d 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -34,7 +34,7 @@ public function __clone() } /** - * Escapes "<" special char in given text. + * Escapes "<" and ">" special chars in given text. * * @param string $text Text to escape * @@ -42,7 +42,7 @@ public function __clone() */ public static function escape($text) { - $text = preg_replace('/([^\\\\]?)])/', '$1\\\\$2', $text); return self::escapeTrailingBackslash($text); } @@ -144,9 +144,10 @@ public function formatAndWrap(string $message, int $width) { $offset = 0; $output = ''; - $tagRegex = '[a-z][^<>]*+'; + $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; + $closeTagRegex = '[a-z][^<>]*+'; $currentLineLength = 0; - preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); + preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; $text = $match[0]; @@ -180,11 +181,7 @@ public function formatAndWrap(string $message, int $width) $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength); - if (str_contains($output, "\0")) { - return strtr($output, ["\0" => '\\', '\\<' => '<']); - } - - return str_replace('\\<', '<', $output); + return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); } /** @@ -218,7 +215,8 @@ private function createStyleFromString(string $string): ?OutputFormatterStyleInt } elseif ('bg' == $match[0]) { $style->setBackground(strtolower($match[1])); } elseif ('href' === $match[0]) { - $style->setHref($match[1]); + $url = preg_replace('{\\\\([<>])}', '$1', $match[1]); + $style->setHref($url); } elseif ('options' === $match[0]) { preg_match_all('([^,;]+)', strtolower($match[1]), $options); $options = array_shift($options); diff --git a/src/Symfony/Component/Console/Tests/Fixtures/command_2.txt b/src/Symfony/Component/Console/Tests/Fixtures/command_2.txt index 45e7bec4d9d7e..fcab77a29e19a 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/command_2.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/command_2.txt @@ -2,9 +2,9 @@ command 2 description Usage: - descriptor:command2 [options] [--] \ - descriptor:command2 -o|--option_name \ - descriptor:command2 \ + descriptor:command2 [options] [--] \ + descriptor:command2 -o|--option_name \ + descriptor:command2 \ Arguments: argument_name diff --git a/src/Symfony/Component/Console/Tests/Fixtures/command_mbstring.txt b/src/Symfony/Component/Console/Tests/Fixtures/command_mbstring.txt index 2fd51d057cf62..1fa4e3135fa23 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/command_mbstring.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/command_mbstring.txt @@ -2,9 +2,9 @@ command åèä description Usage: - descriptor:åèä [options] [--] \ - descriptor:åèä -o|--option_name \ - descriptor:åèä \ + descriptor:åèä [options] [--] \ + descriptor:åèä -o|--option_name \ + descriptor:åèä \ Arguments: argument_åèä diff --git a/src/Symfony/Component/Console/Tests/Fixtures/input_argument_with_style.txt b/src/Symfony/Component/Console/Tests/Fixtures/input_argument_with_style.txt index 35384a6be87e7..79149ca69866a 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/input_argument_with_style.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/input_argument_with_style.txt @@ -1 +1 @@ - argument_name argument description [default: "\style\"] + argument_name argument description [default: "\style\"] diff --git a/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style.txt b/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style.txt index 880a53518e214..4bd30a662f4c3 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style.txt @@ -1 +1 @@ - -o, --option_name=OPTION_NAME option description [default: "\style\"] + -o, --option_name=OPTION_NAME option description [default: "\style\"] diff --git a/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style_array.txt b/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style_array.txt index 265c18c5a45d2..1fbb05b8a9ec7 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style_array.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/input_option_with_style_array.txt @@ -1 +1 @@ - -o, --option_name=OPTION_NAME option description [default: ["\Hello\","\world\"]] (multiple values allowed) + -o, --option_name=OPTION_NAME option description [default: ["\Hello\","\world\"]] (multiple values allowed) diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 1bd2b5d57bdf2..f418f446fc703 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -32,7 +32,10 @@ public function testLGCharEscaping() $this->assertEquals('foo << bar \\', $formatter->format('foo << bar \\')); $this->assertEquals("foo << \033[32mbar \\ baz\033[39m \\", $formatter->format('foo << bar \\ baz \\')); $this->assertEquals('some info', $formatter->format('\\some info\\')); - $this->assertEquals('\\some info\\', OutputFormatter::escape('some info')); + $this->assertEquals('\\some info\\', OutputFormatter::escape('some info')); + // every < and > gets escaped if not already escaped, but already escaped ones do not get escaped again + // and escaped backslashes remain as such, same with backslashes escaping non-special characters + $this->assertEquals('foo \\< bar \\< baz \\\\< foo \\> bar \\> baz \\\\> \\x', OutputFormatter::escape('foo < bar \\< baz \\\\< foo > bar \\> baz \\\\> \\x')); $this->assertEquals( "\033[33mSymfony\\Component\\Console does work very well!\033[39m", @@ -259,6 +262,7 @@ public function provideDecoratedAndNonDecoratedOutput() ['some question', 'some question', "\033[30;46msome question\033[39;49m"], ['some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"], ['some URL', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"], + ['>some URL with \', 'some URL with ', "\033]8;;https://example.com/\033\\some URL with \033]8;;\033\\"], ['some URL', 'some URL', 'some URL', 'JetBrains-JediTerm'], ]; } diff --git a/src/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php index 934e11ac1b0a3..c9a3c5e001d7a 100644 --- a/src/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php @@ -83,9 +83,9 @@ public function testFormatBlockLGEscaping() $formatter = new FormatterHelper(); $this->assertEquals( - ' '."\n". - ' \some info\ '."\n". - ' ', + ' '."\n". + ' \some info\ '."\n". + ' ', $formatter->formatBlock('some info', 'error', true), '::formatBlock() escapes \'<\' chars' ); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy