Base36   A
last analyzed

Complexity

Total Complexity 4

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 4
c 2
b 0
f 0
lcom 0
cbo 2
dl 0
loc 121
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A explain() 0 17 1
A generateCustomPartAuto() 0 8 1
A generateRandomPart() 0 9 1
A generateTimeParts() 0 15 1
1
<?php
2
namespace Fwolf\Util\Uuid;
3
4
/**
5
 * UUID generator using base-36 characters (0-9a-z)
6
 *
7
 *
8
 * Second part: 6 chars, limit to 2038 by base36 timestamp:
9
 *      base_convert('zzzzzz', 36, 10) = 2176782335 = 2038-12-24 13:45:35
10
 *
11
 * Microsecond part: 4 chars, waste some number range (by * 1000000):
12
 *      base_convert(999999, 10, 36) = lflr
13
 *
14
 * So, For wider time range than 2038, we can start count timestamp from not
15
 * year 1970. And further, combine second and microsecond part together to use
16
 * its lflr~z{4} part. Result usable year raise to about 110 years. Detail:
17
 *
18
 *      If offset time is 2012-07-11 = 1341957600
19
 *      Lifetime start: (base36 of 10{6 + 4 - 1}) / 10^6 + offset timestamp =
20
 *          1443517557 = 2015-09-29 11:05:57
21
 *      Lifetime end: base36 of z{6 + 4} / 10^6 + offset timestamp =
22
 *          4998116040 = 2128-05-20 14:34:00
23
 *
24
 *
25
 * Group part: 2 chars
26
 *      base_convert('zz', 36, 10) = 1295, enough to group server.
27
 *
28
 *
29
 * Random part: 6 chars
30
 *      36^6 = 2176782336, about 50% of 16^8 = 4294967296,
31
 *      But microsecond is 200x of base16 UUID (10^6 vs 10^4 / 2).
32
 *
33
 *
34
 * @see         http://3v4l.org/YPTHo       Find best start date
35
 * @see         https://gist.github.com/fwolf/5f3e44343a3bebf36953
36
 * @see         http://3v4l.org/FMINm       Estimate lifetime
37
 * @see         https://gist.github.com/fwolf/b5b10173b00086d5f33c
38
 *
39
 *
40
 * @copyright   Copyright 2013-2016 Fwolf
41
 * @license     http://opensource.org/licenses/MIT MIT
42
 */
43
class Base36 extends AbstractTimeBasedUuidGenerator
44
{
45
    /**
46
     * {@inheritdoc}
47
     */
48
    const LENGTH = 25;
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    const LENGTH_SECOND = 6;
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    const LENGTH_MICROSECOND = 4;
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    const LENGTH_GROUP = 2;
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    const LENGTH_CUSTOM = 7;
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    const LENGTH_RANDOM = 6;
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    const LENGTH_CHECK_DIGIT = 0;
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    const SEPARATOR = '';
84
85
    /**
86
     * Start offset of timestamp
87
     */
88
    const TIMESTAMP_OFFSET = 1341957600;    // 2012-07-11
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
89
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function explain($uuid)
95
    {
96
        $explanation = parent::explain($uuid);
97
98
        $timeStr = $explanation->getSecond() . $explanation->getMicrosecond();
99
        $timeStr = base_convert($timeStr, 36, 10);
100
101
        $second = round($timeStr / 1000000) + static::TIMESTAMP_OFFSET;
102
        $second = date('Y-m-d H:i:s', $second);
103
104
        $microsecond = strval(round($timeStr % 1000000));
105
106
        $explanation->setSecond($second)
107
            ->setMicrosecond($microsecond);
108
109
        return $explanation;
110
    }
111
112
113
    /** @noinspection SpellCheckingInspection */
114
    /**
115
     * {@inheritdoc}
116
     *
117
     * Parent method result md5, here only need 9 digit of them.
118
     *      base_convert('f{8}', 16, 36) = 5e5fvsp
119
     *      base_convert('f{9}', 16, 36) = 2eaf24s9
120
     */
121
    protected function generateCustomPartAuto()
122
    {
123
        $seed = parent::generateCustomPartAuto();
124
        $seed = substr($seed, 0, 9);
125
126
        // In case convert result not fulfill the length
127
        return base_convert($seed, 16, 36) . '0000000';
128
    }
129
130
131
    /**
132
     * {@inheritdoc}
133
     */
134
    protected function generateRandomPart()
135
    {
136
        // base_convert('zzz', 36, 10) = 46655
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
137
        // base_convert('100', 36, 10) = 1296
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
138
        $randomPart = base_convert(mt_rand(1296, 46655), 10, 36) .
139
            base_convert(mt_rand(0, 46655), 10, 36);
140
141
        return $randomPart;
142
    }
143
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    protected function generateTimeParts()
149
    {
150
        list($microSecond, $second) = explode(' ', microtime());
151
152
        $microSecond = round($microSecond * 1000000);
153
        $microSecond = str_pad($microSecond, 6, '0', STR_PAD_LEFT);
154
155
        $timestamp = $second - static::TIMESTAMP_OFFSET . $microSecond;
156
        $timeStr = base_convert($timestamp, 10, 36);
157
158
        return [
159
            substr($timeStr, 0, static::LENGTH_SECOND),
160
            substr($timeStr, static::LENGTH_SECOND, static::LENGTH_MICROSECOND),
161
        ];
162
    }
163
}
164