uploadDir = sys_get_temp_dir() . '/urlshort-svg-' . $suffix; $this->tmpDir = sys_get_temp_dir() . '/urlshort-svgtmp-' . $suffix; mkdir($this->uploadDir, 0775, true); mkdir($this->tmpDir, 0775, true); } protected function tearDown(): void { foreach ([$this->uploadDir, $this->tmpDir] as $dir) { foreach (glob($dir . '/*') ?: [] as $file) { unlink($file); } if (is_dir($dir)) { rmdir($dir); } } } private function store(string $svg): string { $path = $this->tmpDir . '/' . bin2hex(random_bytes(4)); file_put_contents($path, $svg); $store = new LogoStore($this->uploadDir); $filename = $store->store([ 'name' => 'logo.svg', 'tmp_name' => $path, 'size' => strlen($svg), 'error' => UPLOAD_ERR_OK, ], 1); return (string) file_get_contents($this->uploadDir . '/' . $filename); } /** * @return array}> */ public static function payloadProvider(): array { $open = ''; $close = ''; return [ 'Skriptblock' => [ $open . '' . $close, [' [ $open . '' . $close, ['foreignObject', ' [ $open . '' . $close, [' [ $open . '' . $close, ['alert(1)'], ], ]; } /** * @param list $forbidden * @dataProvider payloadProvider */ public function testPayloadsAreRemoved(string $svg, array $forbidden): void { $stored = $this->store($svg); foreach ($forbidden as $needle) { self::assertStringNotContainsStringIgnoringCase( $needle, $stored, sprintf('"%s" darf nach der Bereinigung nicht mehr enthalten sein.', $needle), ); } } public function testHarmlessContentSurvives(): void { $svg = '' . '' . '' . '' . '' . '' . ''; $stored = $this->store($svg); self::assertStringContainsString(''; $stored = $this->store($svg); self::assertStringContainsString('data:image/png;base64,', $stored); } public function testEncodedJavascriptHrefIsRemoved(): void { // HTML-Entities werden vor der Pruefung aufgeloest. $svg = '' . 'x'; $stored = $this->store($svg); self::assertStringNotContainsStringIgnoringCase('alert(1)', $stored); self::assertStringNotContainsStringIgnoringCase('avascript:', $stored); } }