• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

azjezz / psl / 23101178730

15 Mar 2026 02:02AM UTC coverage: 95.57%. Remained the same
23101178730

push

github

web-flow
bc: use $camelCase variable naming everywhere (#631)

930 of 1013 new or added lines in 219 files covered. (91.81%)

10 existing lines in 8 files now uncovered.

10462 of 10947 relevant lines covered (95.57%)

32.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.29
/src/Psl/Encoding/Base64/Internal/Base64.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Psl\Encoding\Base64\Internal;
6

7
use Psl\Encoding\Exception;
8
use Psl\Regex;
9

10
use function pack;
11
use function rtrim;
12
use function strlen;
13
use function substr;
14
use function unpack;
15

16
/**
17
 * The following class was derived from code of Paragon Initiative Enterprises.
18
 *
19
 * https://github.com/paragonie/constant_time_encoding/blob/198317fa6db951dd791be0740915dae878f34b3a/src/Base64.php
20
 *
21
 * Code subject to MIT License (https://github.com/paragonie/constant_time_encoding/blob/198317fa6db951dd791be0740915dae878f34b3a/LICENSE.txt)
22
 *
23
 * Copyright (c) 2016 - 2022 Paragon Initiative Enterprises
24
 *
25
 * @internal
26
 */
27
abstract class Base64
28
{
29
    /**
30
     * Convert a binary string into a base64-encoded string.
31
     *
32
     * Base64 character set:
33
     *  [A-Z]      [a-z]      [0-9]      +     /
34
     *  0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
35
     *
36
     * @pure
37
     */
38
    public static function encode(string $binary, bool $padding = true): string
39
    {
40
        $dest = '';
1,026✔
41
        $binaryLength = strlen($binary);
1,026✔
42

43
        for ($i = 0; ($i + 3) <= $binaryLength; $i += 3) {
1,026✔
44
            /** @var array<int, int> $chunk */
45
            $chunk = unpack('C*', substr($binary, $i, 3));
1,009✔
46
            $byte0 = $chunk[1];
1,009✔
47
            $byte1 = $chunk[2];
1,009✔
48
            $byte2 = $chunk[3];
1,009✔
49
            $dest .=
1,009✔
50
                static::encode6Bits($byte0 >> 2)
1,009✔
51
                . static::encode6Bits((($byte0 << 4) | ($byte1 >> 4)) & 63)
1,009✔
52
                . static::encode6Bits((($byte1 << 2) | ($byte2 >> 6)) & 63)
1,009✔
53
                . static::encode6Bits($byte2 & 63);
1,009✔
54
        }
55

56
        $chunkSize = $binaryLength - $i;
1,026✔
57

58
        if ($chunkSize > 0) {
1,026✔
59
            /**
60
             * @var array<int, int> $chunk
61
             */
62
            $chunk = unpack('C*', substr($binary, $i, $chunkSize));
689✔
63
            $byte0 = $chunk[1];
689✔
64
            if (($i + 1) < $binaryLength) {
689✔
65
                $byte1 = $chunk[2];
340✔
66
                $dest .=
340✔
67
                    static::encode6Bits($byte0 >> 2)
340✔
68
                    . static::encode6Bits((($byte0 << 4) | ($byte1 >> 4)) & 63)
340✔
69
                    . static::encode6Bits(($byte1 << 2) & 63);
340✔
70
                if ($padding) {
340✔
71
                    $dest .= '=';
172✔
72
                }
73
            } else {
74
                $dest .= static::encode6Bits($byte0 >> 2) . static::encode6Bits(($byte0 << 4) & 63);
349✔
75
                if ($padding) {
349✔
76
                    $dest .= '==';
177✔
77
                }
78
            }
79
        }
80

81
        return $dest;
1,026✔
82
    }
83

84
    /**
85
     * Decode a base64-encoded string into raw binary.
86
     *
87
     * Base64 character set:
88
     *  [A-Z]      [a-z]      [0-9]      +     /
89
     *  0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
90
     *
91
     * @pure
92
     *
93
     * @throws Exception\RangeException If the encoded string contains characters outside
94
     *                                  the base64 characters range.
95
     * @throws Exception\IncorrectPaddingException If the encoded string has an incorrect padding.
96
     */
97
    public static function decode(string $base64, bool $explicitPadding = true): string
98
    {
99
        $base64Length = strlen($base64);
1,043✔
100
        if (0 === $base64Length) {
1,043✔
UNCOV
101
            return '';
×
102
        }
103

104
        static::checkRange($base64);
1,043✔
105

106
        if ($explicitPadding && ($base64Length % 4) !== 0) {
1,037✔
107
            throw new Exception\IncorrectPaddingException('The given base64 string has incorrect padding.');
4✔
108
        }
109

110
        $base64 = rtrim($base64, '=');
1,033✔
111
        $base64Length = strlen($base64);
1,033✔
112

113
        $err = 0;
1,033✔
114
        $dest = '';
1,033✔
115
        for ($i = 0; ($i + 4) <= $base64Length; $i += 4) {
1,033✔
116
            /** @var array<int, int> $chunk */
117
            $chunk = unpack('C*', substr($base64, $i, 4));
1,017✔
118
            $char0 = static::decode6Bits($chunk[1]);
1,017✔
119
            $char1 = static::decode6Bits($chunk[2]);
1,017✔
120
            $char2 = static::decode6Bits($chunk[3]);
1,017✔
121
            $char3 = static::decode6Bits($chunk[4]);
1,017✔
122
            $dest .= pack(
1,017✔
123
                'CCC',
1,017✔
124
                (($char0 << 2) | ($char1 >> 4)) & 0xff,
1,017✔
125
                (($char1 << 4) | ($char2 >> 2)) & 0xff,
1,017✔
126
                (($char2 << 6) | $char3) & 0xff,
1,017✔
127
            );
1,017✔
128
            $err |= ($char0 | $char1 | $char2 | $char3) >> 8;
1,017✔
129
        }
130

131
        $chunkSize = $base64Length - $i;
1,033✔
132
        if ($chunkSize > 0) {
1,033✔
133
            /**
134
             * @var array<int, int> $chunk
135
             */
136
            $chunk = unpack('C*', substr($base64, $i, $chunkSize));
692✔
137
            $char0 = static::decode6Bits($chunk[1]);
692✔
138
            if (($i + 2) < $base64Length) {
692✔
139
                $char1 = static::decode6Bits($chunk[2]);
341✔
140
                $char2 = static::decode6Bits($chunk[3]);
341✔
141
                $dest .= pack('CC', (($char0 << 2) | ($char1 >> 4)) & 0xff, (($char1 << 4) | ($char2 >> 2)) & 0xff);
341✔
142
                $err |= ($char0 | $char1 | $char2) >> 8;
341✔
143
            } elseif (($i + 1) < $base64Length) {
351✔
144
                $char1 = static::decode6Bits($chunk[2]);
351✔
145
                $dest .= pack('C', (($char0 << 2) | ($char1 >> 4)) & 0xff);
351✔
146
                $err |= ($char0 | $char1) >> 8;
351✔
NEW
147
            } elseif ($explicitPadding) {
×
148
                $err |= 1;
×
149
            }
150
        }
151

152
        $check = 0 === $err;
1,033✔
153
        if (!$check) {
1,033✔
154
            throw new Exception\RangeException('Expected characters in the correct base64 alphabet');
×
155
        }
156

157
        return $dest;
1,033✔
158
    }
159

160
    /**
161
     * @throws Exception\RangeException If the encoded string contains characters outside
162
     *                                  the base64 characters range.
163
     *
164
     * @pure
165
     */
166
    protected static function checkRange(string $base64): void
167
    {
168
        if (!Regex\matches($base64, '%^[a-zA-Z0-9/+]*={0,2}$%')) {
275✔
169
            throw new Exception\RangeException('The given base64 string contains characters outside the base64 range.');
3✔
170
        }
171
    }
172

173
    /**
174
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
175
     * into 6-bit integers.
176
     *
177
     * @pure
178
     */
179
    protected static function encode6Bits(int $bin): string
180
    {
181
        $diff = 0x41;
264✔
182
        // if ($bin > 25) $diff += 0x61 - 0x41 - 26; // 6
183
        $diff += ((25 - $bin) >> 8) & 6;
264✔
184
        // if ($bin > 51) $diff += 0x30 - 0x61 - 26; // -75
185
        $diff -= ((51 - $bin) >> 8) & 75;
264✔
186
        // if ($bin > 61) $diff += 0x2b - 0x30 - 10; // -15
187
        $diff -= ((61 - $bin) >> 8) & 15;
264✔
188
        // if ($bin > 62) $diff += 0x2f - 0x2b - 1; // 3
189
        $diff += ((62 - $bin) >> 8) & 3;
264✔
190
        return pack('C', $bin + $diff);
264✔
191
    }
192

193
    /**
194
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
195
     * into 8-bit integers.
196
     *
197
     * @pure
198
     */
199
    protected static function decode6Bits(int $base64): int
200
    {
201
        $ret = -1;
271✔
202
        // if ($base64 > 0x40 && $base64 < 0x5b) $ret += $base64 - 0x41 + 1; // -64
203
        $ret += (((0x40 - $base64) & ($base64 - 0x5b)) >> 8) & ($base64 - 64);
271✔
204
        // if ($base64 > 0x60 && $base64 < 0x7b) $ret += $base64 - 0x61 + 26 + 1; // -70
205
        $ret += (((0x60 - $base64) & ($base64 - 0x7b)) >> 8) & ($base64 - 70);
271✔
206
        // if ($base64 > 0x2f && $base64 < 0x3a) $ret += $base64 - 0x30 + 52 + 1; // 5
207
        $ret += (((0x2f - $base64) & ($base64 - 0x3a)) >> 8) & ($base64 + 5);
271✔
208
        // if ($base64 == 0x2b) $ret += 62 + 1;
209
        $ret += (((0x2a - $base64) & ($base64 - 0x2c)) >> 8) & 63;
271✔
210
        // if ($base64 == 0x2f) ret += 63 + 1;
211
        $ret += (((0x2e - $base64) & ($base64 - 0x30)) >> 8) & 64;
271✔
212

213
        return $ret;
271✔
214
    }
215
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc