[Form] fix parsing invalid floating point numbers

This commit is contained in:
Christian Flothmann 2017-10-06 13:28:39 +02:00
parent dd490af864
commit 042eac4624
2 changed files with 98 additions and 5 deletions

View File

@ -116,6 +116,7 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
return;
}
$position = 0;
$formatter = $this->getNumberFormatter();
$groupSep = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
$decSep = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
@ -129,18 +130,44 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface
$value = str_replace(',', $decSep, $value);
}
if (false !== strpos($value, $decSep)) {
$type = \NumberFormatter::TYPE_DOUBLE;
} else {
$type = \PHP_INT_SIZE === 8 ? \NumberFormatter::TYPE_INT64 : \NumberFormatter::TYPE_INT32;
}
// replace normal spaces so that the formatter can read them
$value = $formatter->parse(str_replace(' ', "\xc2\xa0", $value));
$result = $formatter->parse(str_replace(' ', "\xc2\xa0", $value), $type, $position);
if (intl_is_failure($formatter->getErrorCode())) {
throw new TransformationFailedException($formatter->getErrorMessage());
}
if (self::FRACTIONAL == $this->type) {
$value /= 100;
$result /= 100;
}
return $value;
if (\function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value, null, true)) {
$length = mb_strlen($value, $encoding);
$remainder = mb_substr($value, $position, $length, $encoding);
} else {
$length = \strlen($value);
$remainder = substr($value, $position, $length);
}
// After parsing, position holds the index of the character where the
// parsing stopped
if ($position < $length) {
// Check if there are unrecognized characters at the end of the
// number (excluding whitespace characters)
$remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0");
if ('' !== $remainder) {
throw new TransformationFailedException(sprintf('The number contains unrecognized characters: "%s"', $remainder));
}
}
return $result;
}
/**

View File

@ -141,10 +141,10 @@ class PercentToLocalizedStringTransformerTest extends TestCase
*/
public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
{
// Since we test against "de_AT", we need the full implementation
// Since we test against "de_DE", we need the full implementation
IntlTestHelper::requireFullIntl($this, '4.8.1.1');
\Locale::setDefault('de_AT');
\Locale::setDefault('de_DE');
$transformer = new PercentToLocalizedStringTransformer(1, 'integer');
@ -236,4 +236,70 @@ class PercentToLocalizedStringTransformerTest extends TestCase
$this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
$this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransformDisallowsLeadingExtraCharacters()
{
$transformer = new PercentToLocalizedStringTransformer();
$transformer->reverseTransform('foo123');
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo3"
*/
public function testReverseTransformDisallowsCenteredExtraCharacters()
{
$transformer = new PercentToLocalizedStringTransformer();
$transformer->reverseTransform('12foo3');
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo8"
* @requires extension mbstring
*/
public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
{
// Since we test against other locales, we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
\Locale::setDefault('ru');
$transformer = new PercentToLocalizedStringTransformer();
$transformer->reverseTransform("12\xc2\xa0345,67foo8");
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
*/
public function testReverseTransformDisallowsTrailingExtraCharacters()
{
$transformer = new PercentToLocalizedStringTransformer();
$transformer->reverseTransform('123foo');
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
* @requires extension mbstring
*/
public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
{
// Since we test against other locales, we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
\Locale::setDefault('ru');
$transformer = new PercentToLocalizedStringTransformer();
$transformer->reverseTransform("12\xc2\xa0345,678foo");
}
}