Uuid5::calculateComponents()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 13
rs 9.4286
cc 1
eloc 9
nc 1
nop 1
1
<?php
2
/**
3
 * Author: Nil Portugués Calderó <[email protected]>
4
 * Date: 2/14/15
5
 * Time: 11:04 AM
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace NilPortugues\Uuid\Versions;
12
13
use NilPortugues\Uuid\UuidInterface;
14
15
/**
16
 * Class Uuid5
17
 * @package NilPortugues\Uuid\Versions
18
 */
19
class Uuid5 extends AbstractUuid implements UuidInterface
20
{
21
    /**
22
     * The nil UUID is special form of UUID that is specified to have all 128 bits set to zero.
23
     * @link http://tools.ietf.org/html/rfc4122#section-4.1.7
24
     */
25
    const NIL = '00000000-0000-0000-0000-000000000000';
26
27
    /**
28
     * Regular expression pattern for matching a valid UUID of any variant.
29
     */
30
    const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$';
31
32
    /**
33
     * @param string|null $namespace
34
     * @param string|null $name
35
     *
36
     * @return string
37
     */
38
    public static function create($namespace = null, $name = null)
39
    {
40
        $fields = [
41
            self::TIME_LOW                  => '00000000',
42
            self::TIME_MID                  => '0000',
43
            self::TIME_HI_AND_VERSION       => '0000',
44
            self::CLOCK_SEQ_HI_AND_RESERVED => '00',
45
            self::CLOCK_SEQ_LOW             => '00',
46
            self::NODE                      => '000000000000',
47
        ];
48
49
        if (!($namespace instanceof Uuid5)) {
50
            $fields = self::fromString($namespace);
51
        }
52
53
        $hash = \sha1(self::getBytes($fields) . $name);
54
55
        return self::toString(self::uuidFromHashedName($hash, 5));
56
    }
57
58
    /**
59
     * Creates a UUID from the string standard representation as described
60
     * in the toString() method.
61
     *
62
     * @param string $name A string that specifies a UUID
63
     *
64
     * @return array
65
     * @throws \InvalidArgumentException If the $name isn't a valid UUID
66
     */
67
    private static function fromString($name)
68
    {
69
        $components = self::calculateComponents($name);
70
71
        $nameParsed = \implode('-', $components);
72
        if (!self::isValid($nameParsed)) {
73
            throw new \InvalidArgumentException('Invalid UUID string: ' . $name);
74
        }
75
76
        return [
77
            self::TIME_LOW                  => \sprintf('%08s', $components[0]),
78
            self::TIME_MID                  => \sprintf('%04s', $components[1]),
79
            self::TIME_HI_AND_VERSION       => \sprintf('%04s', $components[2]),
80
            self::CLOCK_SEQ_HI_AND_RESERVED => \sprintf('%02s', \substr($components[3], 0, 2)),
81
            self::CLOCK_SEQ_LOW             => \sprintf('%02s', \substr($components[3], 2)),
82
            self::NODE                      => \sprintf('%012s', $components[4]),
83
        ];
84
    }
85
86
    /**
87
     * We have stripped out the dashes and are breaking up the string using
88
     * \substr(). In this way, we can accept a full hex value that doesn't
89
     * contain dashes.
90
     * @param $name
91
     *
92
     * @return array
93
     */
94
    private static function calculateComponents($name)
95
    {
96
        $nameParsed = \str_replace(['urn:', 'uuid:', '{', '}', '-'], '', $name);
97
98
        $components = [
99
            \substr($nameParsed, 0, 8),
100
            \substr($nameParsed, 8, 4),
101
            \substr($nameParsed, 12, 4),
102
            \substr($nameParsed, 16, 4),
103
            \substr($nameParsed, 20),
104
        ];
105
        return $components;
106
    }
107
108
    /**
109
     * Check if a string is a valid uuid
110
     *
111
     * @param string $uuid The uuid to test
112
     *
113
     * @return boolean
114
     */
115
    private static function isValid($uuid)
116
    {
117
        $uuid = \str_replace(['urn:', 'uuid:', '{', '}'], '', $uuid);
118
119
        if (0 == \preg_match('/' . self::VALID_PATTERN . '/', $uuid)) {
120
            return false;
121
        }
122
123
        return true;
124
    }
125
126
    /**
127
     * Returns the UUID as a 16-byte string (containing the six integer fields
128
     * in big-endian byte order)
129
     *
130
     * @param array $fields
131
     *
132
     * @return string
133
     */
134
    private static function getBytes(array $fields)
135
    {
136
        $bytes = '';
137
        foreach (\range(-2, -32, 2) as $step) {
138
            $bytes = \chr(\hexdec(\substr(self::getHex($fields), $step, 2))) . $bytes;
139
        }
140
141
        return $bytes;
142
    }
143
144
    /**
145
     * Returns the hexadecimal value of the UUID
146
     *
147
     * @param array $fields
148
     *
149
     * @return string
150
     */
151
    private static function getHex(array $fields)
152
    {
153
        return \str_replace('-', '', static::toString($fields));
154
    }
155
}
156