Completed
Pull Request — master (#1375)
by Bilge
32:45 queued 14:35
created

UuidGenerator::generateV5()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 37
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3.0017

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 37
ccs 16
cts 17
cp 0.9412
rs 8.8571
cc 3
eloc 15
nc 3
nop 2
crap 3.0017
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\Id;
21
22
use Doctrine\ODM\MongoDB\DocumentManager;
23
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
24
25
/**
26
 * Generates UUIDs.
27
 *
28
 * @since       1.0
29
 */
30
class UuidGenerator extends AbstractIdGenerator
31
{
32
    /**
33
     * A unique environment value to salt each UUID with.
34
     *
35
     * @var string
36
     */
37
    protected $salt = null;
38
39
    /**
40
     * Used to set the salt that will be applied to each id
41
     *
42
     * @param string $salt The sale to use
43
     */
44 2
    public function setSalt($salt)
45
    {
46 2
        $this->salt = $salt;
47 2
    }
48
49
    /**
50
     * Returns the current salt value
51
     *
52
     * @return string $salt The current salt
53
     */
54 1
    public function getSalt()
55
    {
56 1
        return $this->salt;
57
    }
58
59
    /**
60
     * Checks that a given string is a valid uuid.
61
     *
62
     * @param string $uuid The string to check.
63
     * @return boolean
64
     */
65 2
    public function isValid($uuid)
66
    {
67 2
        return preg_match('/^\{?[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{12}\}?$/i', $uuid)
68 2
            === 1;
69
    }
70
71
    /**
72
     * Generates a new UUID
73
     *
74
     * @param DocumentManager $dm Not used.
75
     * @param object $document Not used.
76
     * @return string UUID
77
     */
78 2
    public function generate(DocumentManager $dm, $document)
79
    {
80 2
        $uuid = $this->generateV4();
81 2
        return $this->generateV5($uuid, $this->salt ?: php_uname('n'));
82
    }
83
84
    /**
85
     * Generates a v4 UUID
86
     *
87
     * @return string
88
     */
89 2
    public function generateV4()
90
    {
91 2
        return sprintf(
92 2
            '%04x%04x%04x%04x%04x%04x%04x%04x',
93
            // 32 bits for "time_low"
94 2
            mt_rand(0, 0xffff),
95 2
            mt_rand(0, 0xffff),
96
            // 16 bits for "time_mid"
97 2
            mt_rand(0, 0xffff),
98
            // 16 bits for "time_hi_and_version",
99
            // four most significant bits holds version number 4
100 2
            mt_rand(0, 0x0fff) | 0x4000,
101
            // 16 bits, 8 bits for "clk_seq_hi_res",
102
            // 8 bits for "clk_seq_low",
103
            // two most significant bits holds zero and one for variant DCE1.1
104 2
            mt_rand(0, 0x3fff) | 0x8000,
105
            // 48 bits for "node"
106 2
            mt_rand(0, 0xffff),
107 2
            mt_rand(0, 0xffff),
108 2
            mt_rand(0, 0xffff)
109 2
        );
110
    }
111
112
    /**
113
     * Generates a v5 UUID
114
     *
115
     * @param string $namespace The UUID to seed with
116
     * @param string $salt The string to salt this new UUID with
117
     * @throws \Exception when the provided namespace is invalid
118
     * @return string
119
     */
120 2
    public function generateV5($namespace, $salt)
121
    {
122 2
        if ( ! $this->isValid($namespace)) {
123
            throw new \Exception('Provided $namespace is invalid: ' . $namespace);
124
        }
125
126
        // Get hexadecimal components of namespace
127 2
        $nhex = str_replace(array('-', '{', '}'), '', $namespace);
128
129
        // Binary Value
130 2
        $nstr = '';
131
132
        // Convert Namespace UUID to bits
133 2
        for ($i = 0; $i < strlen($nhex); $i += 2) {
134 2
            $nstr .= chr(hexdec($nhex[$i] . $nhex[$i + 1]));
135 2
        }
136
137
        // Calculate hash value
138 2
        $hash = sha1($nstr . $salt);
139
140 2
        return sprintf(
141 2
            '%08s%04s%04x%04x%12s',
142
            // 32 bits for "time_low"
143 2
            substr($hash, 0, 8),
144
            // 16 bits for "time_mid"
145 2
            substr($hash, 8, 4),
146
            // 16 bits for "time_hi_and_version",
147
            // four most significant bits holds version number 3
148 2
            (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
149
            // 16 bits, 8 bits for "clk_seq_hi_res",
150
            // 8 bits for "clk_seq_low",
151
            // two most significant bits holds zero and one for variant DCE1.1
152 2
            (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
153
            // 48 bits for "node"
154 2
            substr($hash, 20, 12)
155 2
        );
156
    }
157
}
158