[Validator] reject ill-formed strings

This commit is contained in:
Nicolas Grekas 2015-01-26 21:06:31 +01:00
parent faaa4fe3e6
commit 3a9058a7d7
5 changed files with 83 additions and 42 deletions

View File

@ -27,6 +27,7 @@ class Length extends Constraint
public $maxMessage = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.';
public $minMessage = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.';
public $exactMessage = 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.';
public $charsetMessage = 'This value does not match the expected {{ charset }} charset.';
public $max;
public $min;
public $charset = 'UTF-8';

View File

@ -34,23 +34,40 @@ class LengthValidator extends ConstraintValidator
}
$stringValue = (string) $value;
$invalidCharset = false;
if ('UTF8' === $charset = strtoupper($constraint->charset)) {
$charset = 'UTF-8';
}
if (function_exists('iconv_strlen')) {
$length = iconv_strlen($stringValue, $constraint->charset);
$length = @iconv_strlen($stringValue, $constraint->charset);
$invalidCharset = false === $length;
} elseif (function_exists('mb_strlen')) {
$length = mb_strlen($stringValue, $constraint->charset);
if (mb_check_encoding($stringValue, $constraint->charset)) {
$length = mb_strlen($stringValue, $constraint->charset);
} else {
$invalidCharset = true;
}
} elseif ('UTF-8' !== $charset) {
$length = strlen($stringValue);
} elseif (!preg_match('//u', $stringValue)) {
$invalidCharset = true;
} elseif (function_exists('utf8_decode')) {
$length = strlen(utf8_decode($stringValue));
} else {
preg_replace('/./u', '', $stringValue, -1, $length);
}
if ($invalidCharset) {
$this->context->addViolation($constraint->charsetMessage, array(
'{{ value }}' => $this->formatValue($stringValue),
'{{ charset }}' => $constraint->charset,
), $value);
return;
}
if ($constraint->min == $constraint->max && $length != $constraint->min) {
$this->context->addViolation($constraint->exactMessage, array(
'{{ value }}' => $this->formatValue($stringValue),

View File

@ -278,6 +278,10 @@
<source>This value should not be identical to {{ compared_value_type }} {{ compared_value }}.</source>
<target>This value should not be identical to {{ compared_value_type }} {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="73">
<source>This value does not match the expected {{ charset }} charset.</source>
<target>This value does not match the expected {{ charset }} charset.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -278,6 +278,10 @@
<source>This value should not be identical to {{ compared_value_type }} {{ compared_value }}.</source>
<target>Cette valeur ne doit pas être identique à {{ compared_value_type }} {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="73">
<source>This value does not match the expected {{ charset }} charset.</source>
<target>Cette valeur ne correspond pas au jeu de caractères {{ charset }} attendu.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -48,12 +48,12 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
return array(
array(12),
array('12'),
array('üü', true),
array('éé', true),
array('üü'),
array('éé'),
array(123),
array('123'),
array('üüü', true),
array('ééé', true),
array('üüü'),
array('ééé'),
);
}
@ -62,8 +62,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
return array(
array(1234),
array('1234'),
array('üüüü', true),
array('éééé', true),
array('üüüü'),
array('éééé'),
);
}
@ -80,24 +80,34 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
return array(
array(12345),
array('12345'),
array('üüüüü', true),
array('ééééé', true),
array('üüüüü'),
array('ééééé'),
array(123456),
array('123456'),
array('üüüüüü', true),
array('éééééé', true),
array('üüüüüü'),
array('éééééé'),
);
}
public function getOneCharset()
{
if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
$this->markTestSkipped('Mbstring or iconv is required for this test.');
}
return array(
array("é", "utf8", true),
array("\xE9", "CP1252", true),
array("\xE9", "XXX", false),
array("\xE9", "utf8", false),
);
}
/**
* @dataProvider getFiveOrMoreCharacters
*/
public function testValidValuesMin($value, $mbOnly = false)
public function testValidValuesMin($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(array('min' => 5));
$this->validator->validate($value, $constraint);
@ -107,12 +117,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
/**
* @dataProvider getThreeOrLessCharacters
*/
public function testValidValuesMax($value, $mbOnly = false)
public function testValidValuesMax($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(array('max' => 3));
$this->validator->validate($value, $constraint);
@ -122,12 +128,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
/**
* @dataProvider getFourCharacters
*/
public function testValidValuesExact($value, $mbOnly = false)
public function testValidValuesExact($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(4);
$this->validator->validate($value, $constraint);
@ -137,12 +139,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
/**
* @dataProvider getThreeOrLessCharacters
*/
public function testInvalidValuesMin($value, $mbOnly = false)
public function testInvalidValuesMin($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(array(
'min' => 4,
'minMessage' => 'myMessage',
@ -161,12 +159,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
/**
* @dataProvider getFiveOrMoreCharacters
*/
public function testInvalidValuesMax($value, $mbOnly = false)
public function testInvalidValuesMax($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(array(
'max' => 4,
'maxMessage' => 'myMessage',
@ -185,12 +179,8 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
/**
* @dataProvider getNotFourCharacters
*/
public function testInvalidValuesExact($value, $mbOnly = false)
public function testInvalidValuesExact($value)
{
if ($mbOnly && !function_exists('mb_strlen')) {
$this->markTestSkipped('mb_strlen does not exist');
}
$constraint = new Length(array(
'min' => 4,
'max' => 4,
@ -207,6 +197,31 @@ class LengthValidatorTest extends AbstractConstraintValidatorTest
->assertRaised();
}
/**
* @dataProvider getOneCharset
*/
public function testOneCharset($value, $charset, $isValid)
{
$constraint = new Length(array(
'min' => 1,
'max' => 1,
'charset' => $charset,
'charsetMessage' => 'myMessage',
));
$this->validator->validate($value, $constraint);
if ($isValid) {
$this->assertNoViolation();
} else {
$this->buildViolation('myMessage')
->setParameter('{{ value }}', '"'.$value.'"')
->setParameter('{{ charset }}', $charset)
->setInvalidValue($value)
->assertRaised();
}
}
public function testConstraintGetDefaultOption()
{
$constraint = new Length(5);