<?php
|
declare(strict_types=1);
|
|
namespace App\Model;
|
|
class Isbn {
|
/**
|
* Returns the ISBN-13 form of a valid ISBN-10 or ISBN-13, or null if the value is neither.
|
*/
|
public static function toIsbn13(string $value): ?string {
|
$digits = strtoupper(str_replace(['-', ' '], '', $value));
|
|
if (preg_match('/^\d{9}[\dX]$/', $digits) === 1) {
|
if (!self::isValidIsbn10($digits)) {
|
return null;
|
}
|
|
$stem = '978' . substr($digits, 0, 9);
|
|
return $stem . self::isbn13CheckDigit($stem);
|
}
|
|
if (preg_match('/^97[89]\d{10}$/', $digits) === 1
|
&& $digits[12] === self::isbn13CheckDigit(substr($digits, 0, 12))) {
|
return $digits;
|
}
|
|
return null;
|
}
|
|
private static function isValidIsbn10(string $digits): bool {
|
$sum = 0;
|
foreach (str_split($digits) as $position => $digit) {
|
$sum += (10 - $position) * ($digit === 'X' ? 10 : (int)$digit);
|
}
|
|
return $sum % 11 === 0;
|
}
|
|
private static function isbn13CheckDigit(string $stem): string {
|
$sum = 0;
|
foreach (str_split($stem) as $position => $digit) {
|
$sum += (int)$digit * ($position % 2 === 0 ? 1 : 3);
|
}
|
|
return (string)((10 - $sum % 10) % 10);
|
}
|
}
|