Encoder   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 52
c 2
b 0
f 0
dl 0
loc 117
ccs 50
cts 50
cp 1
rs 10
wmc 11

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A encode() 0 31 4
A decode() 0 36 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Afonso\Base24;
6
7
/**
8
 * An encoder/decoder that uses the Base 24 binary-to-text encoding scheme.
9
 */
10
class Encoder
11
{
12
    /**
13
     * The alphabet used by this encoder.
14
     *
15
     * @var string
16
     */
17
    const ALPHABET = 'ZAC2B3EF4GH5TK67P8RS9WXY';
18
19
    /**
20
     * The length of the alphabet used by this encoder.
21
     *
22
     * @var int
23
     */
24
    const ALPHABET_LENGTH = 24;
25
26
    private $encodeMap = [];
27
    private $decodeMap = [];
28
29 105
    public function __construct()
30
    {
31 105
        for ($i = 0; $i < strlen(self::ALPHABET); $i++) {
32 105
            $this->decodeMap[self::ALPHABET[$i]] = $i;
33 105
            $this->decodeMap[strtolower(self::ALPHABET[$i])] = $i;
34 105
            $this->encodeMap[$i] = self::ALPHABET[$i];
35
        }
36 105
    }
37
38
    /**
39
     * Convert the given array of bytes into a Base 24-encoded string.
40
     *
41
     * The length of the input array must be a multiple of 4, otherwise this
42
     * method will throw an exception.
43
     *
44
     * @param int[] $input
45
     * @return string
46
     * @throws \InvalidArgumentException
47
     */
48 51
    public function encode(array $input): string
49
    {
50 51
        $dataLength = count($input);
51
52 51
        if ($dataLength % 4 !== 0) {
53 3
            throw new \InvalidArgumentException('Input to encode must have a length multiple of 4');
54
        }
55
56 48
        $result = '';
57 48
        for ($i = 0; $i < $dataLength / 4; $i++) {
58 48
            $j = $i * 4;
59 48
            $mask = 0xFF;
60
61 48
            $b3 = $input[$j] & $mask;
62 48
            $b2 = $input[$j + 1] & $mask;
63 48
            $b1 = $input[$j + 2] & $mask;
64 48
            $b0 = $input[$j + 3] & $mask;
65
66
            $value = 0xFFFFFFFF &
67 48
                (($b3 << 24) | ($b2 << 16) | ($b1 << 8) | $b0);
68
69 48
            $subResult = '';
70 48
            for ($k = 0; $k < 7; $k++) {
71 48
                $idx = $value % 24;
72 48
                $value = $value / self::ALPHABET_LENGTH;
73 48
                $subResult = $this->encodeMap[$idx] . $subResult;
74
            }
75
76 48
            $result .= $subResult;
77
        }
78 48
        return $result;
79
    }
80
81
    /**
82
     * Convert the given Base 24-encoded string into an array of bytes.
83
     *
84
     * The length of the input string must be a multiple of 7, otherwise this
85
     * method will throw an exception.
86
     *
87
     * @param string $input
88
     * @return int[]
89
     * @throws \InvalidArgumentException
90
     */
91 54
    public function decode(string $input): array
92
    {
93 54
        $dataLength = strlen($input);
94
95 54
        if ($dataLength % 7 !== 0) {
96 3
            throw new \InvalidArgumentException('Input to decode must have a length multiple of 7');
97
        }
98
99 51
        $bytes = [];
100 51
        for ($i = 0; $i < $dataLength / 7; $i++) {
101 51
            $j = $i * 7;
102 51
            $subData = substr($input, $j, 7);
103 51
            $value = 0;
104
105 51
            foreach (str_split($subData) as $s) {
106 51
                if (array_key_exists($s, $this->decodeMap) === false) {
107 3
                    throw new \InvalidArgumentException('Input to decode contains an invalid character');
108
                }
109
110 51
                $idx = $this->decodeMap[$s];
111 51
                $value = self::ALPHABET_LENGTH * $value + $idx;
112
            }
113
114 48
            $mask = 0xFF;
115 48
            $b0 = ($value & ($mask << 24)) >> 24;
116 48
            $b1 = ($value & ($mask << 16)) >> 16;
117 48
            $b2 = ($value & ($mask << 8)) >> 8;
118 48
            $b3 = $value & $mask;
119
120 48
            $bytes[] = $b0;
121 48
            $bytes[] = $b1;
122 48
            $bytes[] = $b2;
123 48
            $bytes[] = $b3;
124
        }
125
126 48
        return $bytes;
127
    }
128
}
129