8000 [Validator] Fixed and simplified IsbnValidator · symfony/symfony@224e70f · GitHub
[go: up one dir, main page]

Skip to content

Commit 224e70f

Browse files
committed
[Validator] Fixed and simplified IsbnValidator
1 parent fd58870 commit 224e70f

File tree

3 files changed

+71
-41
lines changed

3 files changed

+71
-41
lines changed

src/Symfony/Component/Validator/Constraints/Isbn.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,8 @@ public function __construct($options = null)
4242
if (null === $this->isbn10 && null === $this->isbn13) {
4343
throw new MissingOptionsException(sprintf('Either option "isbn10" or "isbn13" must be given for constraint "%s".', __CLASS__), array('isbn10', 'isbn13'));
4444
}
45+
46+
$this->isbn10 = (bool) $this->isbn10;
47+
$this->isbn13 = (bool) $this->isbn13;
4548
}
4649
}

src/Symfony/Component/Validator/Constraints/IsbnValidator.php

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Validates whether the value is a valid ISBN-10 or ISBN-13.
2020
*
2121
* @author The Whole Life To Learn <thewholelifetolearn@gmail.com>
22+
* @author Bernhard Schussek <bschussek@gmail.com>
2223
*
2324
* @see https://en.wikipedia.org/wiki/Isbn
2425
*/
@@ -37,53 +38,71 @@ public function validate($value, Constraint $constraint)
3738
throw new UnexpectedTypeException($value, 'string');
3839
}
3940

40-
if (!is_numeric($value)) {
41-
$value = str_replace('-', '', $value);
42-
}
41+
$value = (string) $value;
42+
$canonical = strtoupper(str_replace('-', '', $value));
4343

44-
$validation = 0;
45-
$value = strtoupper($value);
46-
$valueLength = strlen($value);
47-
48-
if (10 === $valueLength && null !== $constraint->isbn10) {
49-
for ($i = 0; $i < 10; $i++) {
50-
if ($value[$i] == 'X') {
51-
$validation += 10 * intval(10 - $i);
52-
} else {
53-
$validation += intval($value[$i]) * intval(10 - $i);
54-
}
55-
}
44+
if ($constraint->isbn10 && $this->isValidIsbn10($canonical)) {
45+
return;
46+
}
5647

57-
if ($validation % 11 != 0) {
58-
if (null !== $constraint->isbn13) {
59-
$this->context->addViolation($constraint->bothIsbnMessage);
60-
} else {
61-
$this->context->addViolation($constraint->isbn10Message);
62-
}
63-
}
64-
} elseif (13 === $valueLength && null !== $constraint->isbn13) {
65-
for ($i = 0; $i < 13; $i += 2) {
66-
$validation += intval($value[$i]);
67-
}
68-
for ($i = 1; $i < 12; $i += 2) {
69-
$validation += intval($value[$i]) * 3;
70-
}
48+
if ($constraint->isbn13 && $this->isValidIsbn13($canonical)) {
49+
return;
50+
}
7151

72-
if ($validation % 10 != 0) {
73-
if (null !== $constraint->isbn10) {
74-
$this->context->addViolation($constraint->bothIsbnMessage);
75-
} else {
76-
$this->context->addViolation($constraint->isbn13Message);
77-
}
78-
}
52+
if ($constraint->isbn10 && $constraint->isbn13) {
53+
$this->context->addViolation($constraint->bothIsbnMessage, array(
54+
'{{ value }}' => $value,
55+
));
56+
} elseif ($constraint->isbn10) {
57+
$this->context->addViolation($constraint->isbn10Message, array(
58+
'{{ value }}' => $value,
59+
));
7960
} else {
80-
if (null !== $constraint->isbn10 && null !== $constraint->isbn13) {
81-
$this->context->addViolation($constraint->bothIsbnMessage);
82-
} elseif (null !== $constraint->isbn10) {
83-
$this->context->addViolation($constraint->isbn10Message);
61+
$this->context->addViolation($constraint->isbn13Message, array(
62+
'{{ value }}' => $value,
63+
));
64+
}
65+
}
66+
67+
private function isValidIsbn10($isbn)
68+
{
69+
if (10 !== strlen($isbn)) {
70+
return false;
71+
}
72+
73+
$checkSum = 0;
74+
75+
for ($i = 0; $i < 10; ++$i) {
76+
if ('X' === $isbn{$i}) {
77+
$digit = 10;
78+
} elseif (ctype_digit($isbn{$i})) {
79+
$digit = $isbn{$i};
8480
} else {
85-
$this->context->addViolation($constraint->isbn13Message);
81+
return false;
8682
}
83+
84+
$checkSum += $digit * intval(10 - $i);
85+
}
86+
87+
return 0 === $checkSum % 11;
88+
}
89+
90+
private function isValidIsbn13($isbn)
91+
{
92+
if (13 !== strlen($isbn) || !ctype_digit($isbn)) {
93+
return false;
94+
}
95+
96+
$checkSum = 0;
97+
98+
for ($i = 0; $i < 13; $i += 2) {
99+
$checkSum += $isbn{$i};
87100
}
101+
102+
for ($i = 1; $i < 12; $i += 2) {
103+
$checkSum += $isbn{$i} * 3;
104+
}
105+
106+
return 0 === $checkSum % 10;
88107
}
89108
}

src/Symfony/Component/Validator/Tests/Constraints/IsbnValidatorTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ public function getInvalidIsbn10()
5858
array('0-4X19-92611'),
5959
array('0_45122_5244'),
6060
array('2870#971#648'),
61+
array('1A34567890'),
62+
// chr(1) evaluates to 0
63+
// 2070546810 is valid
64+
array('2'.chr(1).'70546810'),
6165
);
6266
}
6367

@@ -92,6 +96,10 @@ public function getInvalidIsbn13()
9296
array('980-0474292319'),
9397
array('978_0451225245'),
9498
array('978#0471292319'),
99+
array('978-272C442282'),
100+
// chr(1) evaluates to 0
101+
// 978-2070546817 is valid
102+
array('978-2'.chr(1).'70546817'),
95103
);
96104
}
97105

0 commit comments

Comments
 (0)
0