fix: strip invalid XML characters from responses

This commit is contained in:
fromme committed 2026-11-03 15:07:47 +01:00
1 parent b047465339
commit e9766dbdce
3 files changed
+147 -1

No files matched your search

@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace App\Tests\BusProNet\Utility;
use App\BusProNet\Utility\XmlCharacterFilter;
use App\BusProNet\XmlCrawlerFactory;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class XmlCharacterFilterTest extends TestCase
{
public function testNulPaddedFieldNoLongerBreaksTheResponse(): void
{
// Shape of a real KUNDENKONTO/Adressdaten response with a NUL-padded Geburtsort.
$xml = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="KUNDENKONTO"></satz>'
.'<idperson>11297</idperson><adressdaten><name>Muster</name>'
.'<geburtsort>'.str_repeat('&#x0;', 40).'</geburtsort><beruf></beruf></adressdaten></ergebnis>';
$this->assertCount(0, XmlCrawlerFactory::create($xml));
$filtered = XmlCharacterFilter::strip($xml, $count);
$this->assertSame(40, $count);
$crawler = XmlCrawlerFactory::create($filtered);
$this->assertSame('Muster', $crawler->filterXPath('//adressdaten/name')->text());
$this->assertSame('', $crawler->filterXPath('//adressdaten/geburtsort')->text());
}
/** @return iterable<string, array{string}> */
public static function invalidProvider(): iterable
{
yield 'hex NUL' => ['&#x0;'];
yield 'hex NUL, padded and upper case' => ['&#X0000;'];
yield 'decimal NUL' => ['&#0;'];
yield 'vertical tab' => ['&#x0B;'];
yield 'decimal 31' => ['&#31;'];
yield 'surrogate' => ['&#xD800;'];
yield 'noncharacter FFFE' => ['&#xFFFE;'];
yield 'beyond Unicode' => ['&#x110000;'];
yield 'raw NUL byte' => ["\x00"];
yield 'raw escape byte' => ["\x1B"];
}
#[DataProvider('invalidProvider')]
public function testRemovesInvalidCharacters(string $invalid): void
{
$this->assertSame('<a>xy</a>', XmlCharacterFilter::strip('<a>x'.$invalid.'y</a>', $count));
$this->assertSame(1, $count);
}
/** @return iterable<string, array{string}> */
public static function validProvider(): iterable
{
yield 'tab' => ['&#x9;'];
yield 'line feed' => ['&#10;'];
yield 'carriage return' => ['&#xD;'];
yield 'space' => ['&#32;'];
yield 'umlaut' => ['&#xFC;'];
yield 'emoji' => ['&#x1F600;'];
yield 'named entity' => ['&amp;'];
yield 'raw tab and newline' => ["\t\r\n"];
yield 'raw UTF-8' => ['Grüße 😀'];
}
#[DataProvider('validProvider')]
public function testKeepsAllowedCharacters(string $valid): void
{
$xml = '<a>x'.$valid.'y</a>';
$this->assertSame($xml, XmlCharacterFilter::strip($xml, $count));
$this->assertSame(0, $count);
}
}