Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\Uid;
13
 
14
/**
15
 * @internal
16
 *
17
 * @author Nicolas Grekas <p@tchwork.com>
18
 */
19
class BinaryUtil
20
{
21
    public const BASE10 = [
22
        '' => '0123456789',
23
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
24
    ];
25
 
26
    public const BASE58 = [
27
        '' => '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
28
        1 => 0, 1, 2, 3, 4, 5, 6, 7, 8, 'A' => 9,
29
        'B' => 10, 'C' => 11, 'D' => 12, 'E' => 13, 'F' => 14, 'G' => 15,
30
        'H' => 16, 'J' => 17, 'K' => 18, 'L' => 19, 'M' => 20, 'N' => 21,
31
        'P' => 22, 'Q' => 23, 'R' => 24, 'S' => 25, 'T' => 26, 'U' => 27,
32
        'V' => 28, 'W' => 29, 'X' => 30, 'Y' => 31, 'Z' => 32, 'a' => 33,
33
        'b' => 34, 'c' => 35, 'd' => 36, 'e' => 37, 'f' => 38, 'g' => 39,
34
        'h' => 40, 'i' => 41, 'j' => 42, 'k' => 43, 'm' => 44, 'n' => 45,
35
        'o' => 46, 'p' => 47, 'q' => 48, 'r' => 49, 's' => 50, 't' => 51,
36
        'u' => 52, 'v' => 53, 'w' => 54, 'x' => 55, 'y' => 56, 'z' => 57,
37
    ];
38
 
39
    // https://tools.ietf.org/html/rfc4122#section-4.1.4
40
    // 0x01b21dd213814000 is the number of 100-ns intervals between the
41
    // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
42
    private const TIME_OFFSET_INT = 0x01B21DD213814000;
43
    private const TIME_OFFSET_BIN = "\x01\xb2\x1d\xd2\x13\x81\x40\x00";
44
    private const TIME_OFFSET_COM1 = "\xfe\x4d\xe2\x2d\xec\x7e\xbf\xff";
45
    private const TIME_OFFSET_COM2 = "\xfe\x4d\xe2\x2d\xec\x7e\xc0\x00";
46
 
47
    public static function toBase(string $bytes, array $map): string
48
    {
49
        $base = \strlen($alphabet = $map['']);
50
        $bytes = array_values(unpack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', $bytes));
51
        $digits = '';
52
 
53
        while ($count = \count($bytes)) {
54
            $quotient = [];
55
            $remainder = 0;
56
 
57
            for ($i = 0; $i !== $count; ++$i) {
58
                $carry = $bytes[$i] + ($remainder << (\PHP_INT_SIZE >= 8 ? 16 : 8));
59
                $digit = intdiv($carry, $base);
60
                $remainder = $carry % $base;
61
 
62
                if ($digit || $quotient) {
63
                    $quotient[] = $digit;
64
                }
65
            }
66
 
67
            $digits = $alphabet[$remainder].$digits;
68
            $bytes = $quotient;
69
        }
70
 
71
        return $digits;
72
    }
73
 
74
    public static function fromBase(string $digits, array $map): string
75
    {
76
        $base = \strlen($map['']);
77
        $count = \strlen($digits);
78
        $bytes = [];
79
 
80
        while ($count) {
81
            $quotient = [];
82
            $remainder = 0;
83
 
84
            for ($i = 0; $i !== $count; ++$i) {
85
                $carry = ($bytes ? $digits[$i] : $map[$digits[$i]]) + $remainder * $base;
86
 
87
                if (\PHP_INT_SIZE >= 8) {
88
                    $digit = $carry >> 16;
89
                    $remainder = $carry & 0xFFFF;
90
                } else {
91
                    $digit = $carry >> 8;
92
                    $remainder = $carry & 0xFF;
93
                }
94
 
95
                if ($digit || $quotient) {
96
                    $quotient[] = $digit;
97
                }
98
            }
99
 
100
            $bytes[] = $remainder;
101
            $count = \count($digits = $quotient);
102
        }
103
 
104
        return pack(\PHP_INT_SIZE >= 8 ? 'n*' : 'C*', ...array_reverse($bytes));
105
    }
106
 
107
    public static function add(string $a, string $b): string
108
    {
109
        $carry = 0;
110
        for ($i = 7; 0 <= $i; --$i) {
111
            $carry += \ord($a[$i]) + \ord($b[$i]);
112
            $a[$i] = \chr($carry & 0xFF);
113
            $carry >>= 8;
114
        }
115
 
116
        return $a;
117
    }
118
 
119
    /**
120
     * @param string $time Count of 100-nanosecond intervals since the UUID epoch 1582-10-15 00:00:00 in hexadecimal
121
     */
122
    public static function hexToDateTime(string $time): \DateTimeImmutable
123
    {
124
        if (\PHP_INT_SIZE >= 8) {
125
            $time = (string) (hexdec($time) - self::TIME_OFFSET_INT);
126
        } else {
127
            $time = str_pad(hex2bin($time), 8, "\0", \STR_PAD_LEFT);
128
 
129
            if (self::TIME_OFFSET_BIN <= $time) {
130
                $time = self::add($time, self::TIME_OFFSET_COM2);
131
                $time[0] = $time[0] & "\x7F";
132
                $time = self::toBase($time, self::BASE10);
133
            } else {
134
                $time = self::add($time, self::TIME_OFFSET_COM1);
135
                $time = '-'.self::toBase($time ^ "\xff\xff\xff\xff\xff\xff\xff\xff", self::BASE10);
136
            }
137
        }
138
 
139
        if (9 > \strlen($time)) {
140
            $time = '-' === $time[0] ? '-'.str_pad(substr($time, 1), 8, '0', \STR_PAD_LEFT) : str_pad($time, 8, '0', \STR_PAD_LEFT);
141
        }
142
 
143
        return \DateTimeImmutable::createFromFormat('U.u?', substr_replace($time, '.', -7, 0));
144
    }
145
 
146
    /**
147
     * @return string Count of 100-nanosecond intervals since the UUID epoch 1582-10-15 00:00:00 in hexadecimal
148
     */
149
    public static function dateTimeToHex(\DateTimeInterface $time): string
150
    {
151
        if (\PHP_INT_SIZE >= 8) {
152
            if (-self::TIME_OFFSET_INT > $time = (int) $time->format('Uu0')) {
153
                throw new \InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
154
            }
155
 
156
            return str_pad(dechex(self::TIME_OFFSET_INT + $time), 16, '0', \STR_PAD_LEFT);
157
        }
158
 
159
        $time = $time->format('Uu0');
160
        $negative = '-' === $time[0];
161
        if ($negative && self::TIME_OFFSET_INT < $time = substr($time, 1)) {
162
            throw new \InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
163
        }
164
        $time = self::fromBase($time, self::BASE10);
165
        $time = str_pad($time, 8, "\0", \STR_PAD_LEFT);
166
 
167
        if ($negative) {
168
            $time = self::add($time, self::TIME_OFFSET_COM1) ^ "\xff\xff\xff\xff\xff\xff\xff\xff";
169
        } else {
170
            $time = self::add($time, self::TIME_OFFSET_BIN);
171
        }
172
 
173
        return bin2hex($time);
174
    }
175
}