From 314a30adfa6c562bbbc943cfc2ce8b363530553f Mon Sep 17 00:00:00 2001 From: Vitalii Shtykhno Date: Wed, 6 Nov 2024 13:47:43 +0100 Subject: [PATCH 1/2] fix: add escaping special symbols for response which could broke xml --- src/qtism/data/storage/xml/Utils.php | 65 ++++++++++++++++++- .../data/storage/xml/XmlUtilsTest.php | 47 +++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/qtism/data/storage/xml/Utils.php b/src/qtism/data/storage/xml/Utils.php index 8930aa811..8f70cae2a 100644 --- a/src/qtism/data/storage/xml/Utils.php +++ b/src/qtism/data/storage/xml/Utils.php @@ -1,5 +1,7 @@ = 0x20 && $char <= 0xDF77 + || $char >= 0xE000 && $char <= 0xFFFD + || $char >= 0x10000 && $char <= 0x10FFFF; + } + + public static function xmlSpecialChars(string $value): string + { + $result = ''; + + $last = 0; + $length = strlen($value); + $i = 0; + + while ($i < $length) { + $r = mb_substr(substr($value, $i), 0, 1); + $width = strlen($r); + $i += $width; + switch ($r) { + case '"': + $esc = '"'; + break; + case "'": + $esc = '''; + break; + case '&': + $esc = '&'; + break; + case '<': + $esc = '<'; + break; + case '>': + $esc = '>'; + break; + case "\t": + $esc = ' '; + break; + case "\n": + $esc = ' '; + break; + case "\r": + $esc = ' '; + break; + default: + if (!self::isInCharacterRange(mb_ord($r)) || (mb_ord($r) === 0xFFFD && $width === 1)) { + $esc = "\u{FFFD}"; + break; + } + + continue 2; + } + $result .= substr($value, $last, $i - $last - $width) . $esc; + $last = $i; + } + return $result . substr($value, $last); + } + /** * Get the child elements of a given element by tag name. This method does * not behave like DOMElement::getElementsByTagName. It only returns the direct diff --git a/test/qtismtest/data/storage/xml/XmlUtilsTest.php b/test/qtismtest/data/storage/xml/XmlUtilsTest.php index 3e81f84cf..e0d891698 100644 --- a/test/qtismtest/data/storage/xml/XmlUtilsTest.php +++ b/test/qtismtest/data/storage/xml/XmlUtilsTest.php @@ -1,5 +1,7 @@ 'http://www.imsglobal.org/xsd/imsqtiv2p2_html5_v1p0'], + ['qh5' => 'http://www.imsglobal.org/xsd/imsqtiv2p2_html5_v1p0'], Utils::findExternalNamespaces($xml) ); } + public function testValueAsStringReplaceSpecialSymbols(): void + { + $this->assertEquals("160\u{FFFD}", Utils::valueAsString("160\u{0008}")); + } + + public function testProcessSpecialCharsetWithoutError(): void + { + $xml = (' + + + + + + 1 + + + + + PT22S + + + + completed + + + 0 + + + 1 + + + + %s + + + + +'); + $this->assertNotNull(Utils::findExternalNamespaces(sprintf($xml, Utils::valueAsString("160\u{0008}")))); + } + public function testremoveAllButFirstOccurrence(): void { $subject = 'abc 12 abc 345abc678abc'; From c0bafdaa80a88d1bc2cd09326fbe6dbf243f9088 Mon Sep 17 00:00:00 2001 From: Vitalii Shtykhno Date: Wed, 6 Nov 2024 13:49:56 +0100 Subject: [PATCH 2/2] chore: indent continue block --- src/qtism/data/storage/xml/Utils.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qtism/data/storage/xml/Utils.php b/src/qtism/data/storage/xml/Utils.php index 8f70cae2a..87bbfca84 100644 --- a/src/qtism/data/storage/xml/Utils.php +++ b/src/qtism/data/storage/xml/Utils.php @@ -412,8 +412,7 @@ public static function xmlSpecialChars(string $value): string $esc = "\u{FFFD}"; break; } - - continue 2; + continue 2; } $result .= substr($value, $last, $i - $last - $width) . $esc; $last = $i;