From c1729a18b1ed523c1db95bea54d93785ba8e863a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 17 Jul 2025 09:29:40 +0200 Subject: [PATCH] [VarDumper] Fix dumping on systems that don't have a working iconv --- .../VarDumper/Dumper/AbstractDumper.php | 45 ++++++++++++++++--- src/Symfony/Component/VarDumper/composer.json | 1 - 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index 53165ba640fca..cf812be67d6b9 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -188,17 +188,48 @@ protected function utf8Encode(?string $s): ?string return $s; } - if (!\function_exists('iconv')) { - throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); + if (\function_exists('iconv')) { + if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { + return $c; + } + if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { + return $c; + } } - if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { - return $c; + $s .= $s; + $len = \strlen($s); + $mapCp1252 = false; + + for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { + if ($s[$i] < "\x80") { + $s[$j] = $s[$i]; + } elseif ($s[$i] < "\xC0") { + $s[$j] = "\xC2"; + $s[++$j] = $s[$i]; + if ($s[$i] < "\xA0") { + $mapCp1252 = true; + } + } else { + $s[$j] = "\xC3"; + $s[++$j] = \chr(\ord($s[$i]) - 64); + } } - if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { - return $c; + + $s = substr($s, 0, $j); + + if (!$mapCp1252) { + return $s; } - return iconv('CP850', 'UTF-8', $s); + return strtr($s, [ + "\xC2\x80" => '€', "\xC2\x82" => '‚', "\xC2\x83" => 'ƒ', "\xC2\x84" => '„', + "\xC2\x85" => '…', "\xC2\x86" => '†', "\xC2\x87" => '‡', "\xC2\x88" => 'ˆ', + "\xC2\x89" => '‰', "\xC2\x8A" => 'Š', "\xC2\x8B" => '‹', "\xC2\x8C" => 'Œ', + "\xC2\x8D" => 'Ž', "\xC2\x91" => '‘', "\xC2\x92" => '’', "\xC2\x93" => '“', + "\xC2\x94" => '”', "\xC2\x95" => '•', "\xC2\x96" => '–', "\xC2\x97" => '—', + "\xC2\x98" => '˜', "\xC2\x99" => '™', "\xC2\x9A" => 'š', "\xC2\x9B" => '›', + "\xC2\x9C" => 'œ', "\xC2\x9E" => 'ž', + ]); } } diff --git a/src/Symfony/Component/VarDumper/composer.json b/src/Symfony/Component/VarDumper/composer.json index e6166f86d5141..4863061c29e90 100644 --- a/src/Symfony/Component/VarDumper/composer.json +++ b/src/Symfony/Component/VarDumper/composer.json @@ -21,7 +21,6 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^5.4|^6.0|^7.0", "symfony/error-handler": "^6.3|^7.0", "symfony/http-kernel": "^5.4|^6.0|^7.0",