Completed
Push — master ( 9de2ae...02afd8 )
by Ronan
06:45
created

Isin::validate()   C

Complexity

Conditions 9
Paths 73

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 50
rs 6
cc 9
eloc 33
nc 73
nop 1
1
<?php
2
3
namespace IsoCodes;
4
5
/**
6
 * Class Isin.
7
 */
8
class Isin implements IsoCodeInterface
9
{
10
    /**
11
     * Validate an ISIN (International Securities Identification Number, ISO 6166).
12
     *
13
     * @param string $isin ISIN to be validated
14
     *
15
     * @see https://en.wikipedia.org/wiki/International_Securities_Identification_Number#Examples
16
     *
17
     * @return bool true if ISIN is valid
18
     */
19
    public static function validate($isin)
20
    {
21
        $isin = strtoupper($isin);
22
        if (!preg_match('/^[A-Z]{2}[A-Z0-9]{9}[0-9]$/i', $isin)) {
23
            return false;
24
        }
25
26
        $base10 = $rightmost = '';
27
        $left = $right = [];
28
29
        $payload = substr($isin, 0, 11);
30
        $length = strlen($payload);
31
32
        // Converting letters to digits
33
        for ($i = 0; $i < $length; ++$i) {
34
            $digit = substr($payload, $i, 1);
35
            $base10 .= (string) base_convert($digit, 36, 10);
36
        }
37
        $checksum = substr($isin, 11, 1);
38
        $base10 = strrev($base10);
39
        $length = strlen($base10);
40
41
        // distinguishing leftmost from rightmost
42
        for ($i = $length - 1; $i >= 0; --$i) {
43
            $digit = substr($base10, $i, 1);
44
            $rightmost = 'left';
45
            if ((($length - $i) % 2) == 0) {
46
                $left[] = $digit;
47
            } else {
48
                $right[] = $digit;
49
                $rightmost = 'right';
50
            }
51
        }
52
53
        // Multiply the group containing the rightmost character
54
        $simple = ('left' === $rightmost) ? $right : $left;
55
        $doubled = ('left' === $rightmost) ? $left : $right;
56
        $doubledCount = count($doubled);
57
        for ($i = 0; $i < $doubledCount; ++$i) {
58
            $digit = $doubled[$i] * 2;
59
            if ($digit > 9) {
60
                $digit = array_sum(str_split($digit));
61
            }
62
            $doubled[$i] = $digit;
63
        }
64
        $tot = array_sum($simple) + array_sum($doubled);
65
        $moduled = 10 - ($tot % 10);
66
67
        return (int) $moduled === (int) $checksum;
68
    }
69
}
70