Completed
Pull Request — master (#1419)
by Robert
11:09 queued 01:09
created

UuidGenerator::generate()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 3
nc 1
nop 2
crap 2
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
24
/**
25
 * Generates UUIDs.
26
 *
27
 * @since       1.0
28
 */
29
class UuidGenerator extends AbstractIdGenerator
30
{
31
    /**
32
     * A unique environment value to salt each UUID with.
33
     *
34
     * @var string
35
     */
36
    protected $salt = null;
37
38
    /**
39
     * Used to set the salt that will be applied to each id
40
     *
41
     * @param string $salt The sale to use
42
     */
43 2
    public function setSalt($salt)
44
    {
45 2
        $this->salt = $salt;
46 2
    }
47
48
    /**
49
     * Returns the current salt value
50
     *
51
     * @return string $salt The current salt
52
     */
53 1
    public function getSalt()
54
    {
55 1
        return $this->salt;
56
    }
57
58
    /**
59
     * Checks that a given string is a valid uuid.
60
     *
61
     * @param string $uuid The string to check.
62
     * @return boolean
63
     */
64 2
    public function isValid($uuid)
65
    {
66 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)
67 2
            === 1;
68
    }
69
70
    /**
71
     * Generates a new UUID
72
     *
73
     * @param DocumentManager $dm Not used.
74
     * @param object $document Not used.
75
     * @return string UUID
76
     */
77 2
    public function generate(DocumentManager $dm, $document)
78
    {
79 2
        $uuid = $this->generateV4();
80 2
        return $this->generateV5($uuid, $this->salt ?: php_uname('n'));
81
    }
82
83
    /**
84
     * Generates a v4 UUID
85
     *
86
     * @return string
87
     */
88 2
    public function generateV4()
89
    {
90 2
        return sprintf(
91 2
            '%04x%04x%04x%04x%04x%04x%04x%04x',
92
            // 32 bits for "time_low"
93 2
            mt_rand(0, 0xffff),
94 2
            mt_rand(0, 0xffff),
95
            // 16 bits for "time_mid"
96 2
            mt_rand(0, 0xffff),
97
            // 16 bits for "time_hi_and_version",
98
            // four most significant bits holds version number 4
99 2
            mt_rand(0, 0x0fff) | 0x4000,
100
            // 16 bits, 8 bits for "clk_seq_hi_res",
101
            // 8 bits for "clk_seq_low",
102
            // two most significant bits holds zero and one for variant DCE1.1
103 2
            mt_rand(0, 0x3fff) | 0x8000,
104
            // 48 bits for "node"
105 2
            mt_rand(0, 0xffff),
106 2
            mt_rand(0, 0xffff),
107 2
            mt_rand(0, 0xffff)
108
        );
109
    }
110
111
    /**
112
     * Generates a v5 UUID
113
     *
114
     * @param string $namespace The UUID to seed with
115
     * @param string $salt The string to salt this new UUID with
116
     * @throws \Exception when the provided namespace is invalid
117
     * @return string
118
     */
119 2
    public function generateV5($namespace, $salt)
120
    {
121 2
        if ( ! $this->isValid($namespace)) {
122
            throw new \Exception('Provided $namespace is invalid: ' . $namespace);
123
        }
124
125
        // Get hexadecimal components of namespace
126 2
        $nhex = str_replace(array('-', '{', '}'), '', $namespace);
127
128
        // Binary Value
129 2
        $nstr = '';
130
131
        // Convert Namespace UUID to bits
132 2
        for ($i = 0; $i < strlen($nhex); $i += 2) {
133 2
            $nstr .= chr(hexdec($nhex[$i] . $nhex[$i + 1]));
134
        }
135
136
        // Calculate hash value
137 2
        $hash = sha1($nstr . $salt);
138
139 2
        return sprintf(
140 2
            '%08s%04s%04x%04x%12s',
141
            // 32 bits for "time_low"
142 2
            substr($hash, 0, 8),
143
            // 16 bits for "time_mid"
144 2
            substr($hash, 8, 4),
145
            // 16 bits for "time_hi_and_version",
146
            // four most significant bits holds version number 3
147 2
            (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
148
            // 16 bits, 8 bits for "clk_seq_hi_res",
149
            // 8 bits for "clk_seq_low",
150
            // two most significant bits holds zero and one for variant DCE1.1
151 2
            (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
152
            // 48 bits for "node"
153 2
            substr($hash, 20, 12)
154
        );
155
    }
156
}
157