Jacek Kowalski
4 hours ago 6b9278a5d57091fce636dbb640b380cfb990db6c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?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);
    }
}