diff --git a/CHANGELOG.md b/CHANGELOG.md index a865083..6b55f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip - Fixed a line of only `=` or `-` after a line break not being escaped, which made a heading out of the line before it, such as in `

Foo
=

` (#226). Lines of `-` were already escaped inside of paragraphs, but not inside of list items, blockquotes or headings. - Fixed emphasis next to an empty one of the same kind losing one of its delimiters, such as ` hello` becoming ` hello**` (#252). Emphasis next to one of the same kind which is removed with `remove_nodes` also lost one. +- Fixed `</body>` or `</html>` in code or comments causing the document's own closing tags to be output after it, and everything from `<!DOCTYPE ` in code up to the next `>` being removed, which could be the rest of the document (#254) ## [5.2.3] - 2026-10-19 diff --git a/src/HtmlConverter.php b/src/HtmlConverter.php index 8c29ac8..66bcbe1 100644 --- a/src/HtmlConverter.php +++ b/src/HtmlConverter.php @@ -651,7 +651,8 @@ private function endsOnBlankLine(ElementInterface $element, ConverterInterface $ protected function sanitize(string $markdown): string { $markdown = \html_entity_decode($markdown, ENT_QUOTES, 'UTF-8'); - $markdown = \preg_replace('/]+>/', '', $markdown); // Strip doctype declaration + // Only the declaration itself, which comes first, as code could contain the same text once decoded + $markdown = \preg_replace('/^]+>/', '', $markdown); \assert($markdown !== null); $markdown = \trim($markdown); // Remove blank spaces at the beggining of the html @@ -668,8 +669,8 @@ protected function sanitize(string $markdown): string $markdown = \substr($markdown, \strlen($tag)); } } else { - // Closing tags - if (\strpos($markdown, $tag) === \strlen($markdown) - \strlen($tag)) { + // Closing tags, which code before them could also contain once decoded + if (\substr($markdown, -\strlen($tag)) === $tag) { $markdown = \substr($markdown, 0, -\strlen($tag)); } } diff --git a/tests/HtmlConverterTest.php b/tests/HtmlConverterTest.php index f97810d..b2eaa11 100644 --- a/tests/HtmlConverterTest.php +++ b/tests/HtmlConverterTest.php @@ -393,6 +393,22 @@ public function testCodeContainingTextWhichLooksLikeItsOwnTags(): void $this->assertHtmlGivesMarkdown('

x

', '`x`'); } + /** + * @see https://github.com/thephpleague/html-to-markdown/issues/254 + */ + public function testCodeContainingTextWhichLooksLikeDocumentTags(): void + { + $this->assertHtmlGivesMarkdown('
</body>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('
</html>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('
</head></body></html>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('
<html><body>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('

a </body></html>

', 'a ``'); + $this->assertHtmlGivesMarkdown('
<!DOCTYPE html>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('
<!DOCTYPE html></html>
', "```\n\n```"); + $this->assertHtmlGivesMarkdown('

Use <!DOCTYPE html first.

a > b

', "Use `assertHtmlGivesMarkdown('

x

', "x\n\n", ['preserve_comments' => true]); + } + public function testNestedCode(): void { $this->assertHtmlGivesMarkdown('
a
', "```\na\n```");