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

azjezz / psl / 12713643030

10 Jan 2025 04:47PM UTC coverage: 98.483% (-0.2%) from 98.691%
12713643030

push

github

web-flow
chore: switch to mago (#501)

* chore: switch from php-cs-fixer and phpcs to mago

Signed-off-by: azjezz <azjezz@protonmail.com>

682 of 699 new or added lines in 176 files covered. (97.57%)

3 existing lines in 2 files now uncovered.

5322 of 5404 relevant lines covered (98.48%)

50.89 hits per line

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

95.18
/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
use Psl\Str;
10

11
use function pack;
12
use function unpack;
13

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

41
        for ($i = 0; ($i + 3) <= $binary_length; $i += 3) {
1,016✔
42
            /** @var array<int, int> $chunk */
43
            $chunk = unpack('C*', Str\slice($binary, $i, 3, encoding: Str\Encoding::Ascii8bit));
1,000✔
44
            $byte0 = $chunk[1];
1,000✔
45
            $byte1 = $chunk[2];
1,000✔
46
            $byte2 = $chunk[3];
1,000✔
47
            $dest .=
1,000✔
48
                static::encode6Bits($byte0 >> 2) .
1,000✔
49
                static::encode6Bits((($byte0 << 4) | ($byte1 >> 4)) & 63) .
1,000✔
50
                static::encode6Bits((($byte1 << 2) | ($byte2 >> 6)) & 63) .
1,000✔
51
                static::encode6Bits($byte2 & 63);
1,000✔
52
        }
53
        if ($i < $binary_length) {
1,016✔
54
            /**
55
             * @psalm-suppress InvalidArgument
56
             *
57
             * @var array<int, int> $chunk
58
             */
59
            $chunk = unpack('C*', Str\slice($binary, $i, $binary_length - $i, encoding: Str\Encoding::Ascii8bit));
680✔
60
            $byte0 = $chunk[1];
680✔
61
            if (($i + 1) < $binary_length) {
680✔
62
                $byte1 = $chunk[2];
336✔
63
                $dest .=
336✔
64
                    static::encode6Bits($byte0 >> 2) .
336✔
65
                    static::encode6Bits((($byte0 << 4) | ($byte1 >> 4)) & 63) .
336✔
66
                    static::encode6Bits(($byte1 << 2) & 63);
336✔
67
                if ($padding) {
336✔
68
                    $dest .= '=';
168✔
69
                }
70
            } else {
71
                $dest .= static::encode6Bits($byte0 >> 2) . static::encode6Bits(($byte0 << 4) & 63);
344✔
72
                if ($padding) {
344✔
73
                    $dest .= '==';
172✔
74
                }
75
            }
76
        }
77

78
        return $dest;
1,016✔
79
    }
80

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

101
        static::checkRange($base64);
1,024✔
102

103
        if ($explicit_padding && ($base64_length % 4) !== 0) {
1,020✔
104
            throw new Exception\IncorrectPaddingException('The given base64 string has incorrect padding.');
4✔
105
        }
106

107
        /** @psalm-suppress MissingThrowsDocblock */
108
        $base64 = Str\trim_right($base64, '=');
1,016✔
109
        $base64_length = Str\length($base64, encoding: Str\Encoding::Ascii8bit);
1,016✔
110

111
        $err = 0;
1,016✔
112
        $dest = '';
1,016✔
113
        for ($i = 0; ($i + 4) <= $base64_length; $i += 4) {
1,016✔
114
            /** @var array<int, int> $chunk */
115
            $chunk = unpack('C*', Str\slice($base64, $i, 4, encoding: Str\Encoding::Ascii8bit));
1,000✔
116
            $char0 = static::decode6Bits($chunk[1]);
1,000✔
117
            $char1 = static::decode6Bits($chunk[2]);
1,000✔
118
            $char2 = static::decode6Bits($chunk[3]);
1,000✔
119
            $char3 = static::decode6Bits($chunk[4]);
1,000✔
120
            $dest .= pack(
1,000✔
121
                'CCC',
1,000✔
122
                (($char0 << 2) | ($char1 >> 4)) & 0xff,
1,000✔
123
                (($char1 << 4) | ($char2 >> 2)) & 0xff,
1,000✔
124
                (($char2 << 6) | $char3) & 0xff,
1,000✔
125
            );
1,000✔
126
            $err |= ($char0 | $char1 | $char2 | $char3) >> 8;
1,000✔
127
        }
128
        if ($i < $base64_length) {
1,016✔
129
            /**
130
             * @psalm-suppress InvalidArgument
131
             *
132
             * @var array<int, int> $chunk
133
             */
134
            $chunk = unpack('C*', Str\slice($base64, $i, $base64_length - $i, encoding: Str\Encoding::Ascii8bit));
680✔
135
            $char0 = static::decode6Bits($chunk[1]);
680✔
136
            if (($i + 2) < $base64_length) {
680✔
137
                $char1 = static::decode6Bits($chunk[2]);
336✔
138
                $char2 = static::decode6Bits($chunk[3]);
336✔
139
                $dest .= pack('CC', (($char0 << 2) | ($char1 >> 4)) & 0xff, (($char1 << 4) | ($char2 >> 2)) & 0xff);
336✔
140
                $err |= ($char0 | $char1 | $char2) >> 8;
336✔
141
            } elseif (($i + 1) < $base64_length) {
344✔
142
                $char1 = static::decode6Bits($chunk[2]);
344✔
143
                $dest .= pack('C', (($char0 << 2) | ($char1 >> 4)) & 0xff);
344✔
144
                $err |= ($char0 | $char1) >> 8;
344✔
145
            } elseif ($explicit_padding) {
×
146
                $err |= 1;
×
147
            }
148
        }
149
        $check = $err === 0;
1,016✔
150
        if (!$check) {
1,016✔
NEW
151
            throw new Exception\RangeException('Expected characters in the correct base64 alphabet');
×
152
        }
153

154
        return $dest;
1,016✔
155
    }
156

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

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

189
        return pack('C', $bin + $diff);
254✔
190
    }
191

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

212
        return $ret;
254✔
213
    }
214
}
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

© 2025 Coveralls, Inc