Base62x   F
last analyzed

Complexity

Total Complexity 79

Size/Duplication

Total Lines 483
Duplicated Lines 0 %

Importance

Changes 5
Bugs 4 Features 0
Metric Value
wmc 79
eloc 362
c 5
b 4
f 0
dl 0
loc 483
rs 2.08

7 Methods

Rating   Name   Duplication   Size   Complexity  
C decode() 0 91 14
B dec2xx() 0 58 11
A fillRb62x() 0 12 4
B xx2dec() 0 51 10
C setAscii() 0 43 15
F encode() 0 145 21
A _decodeByLength() 0 27 4

How to fix   Complexity   

Complex Class

Complex classes like Base62x often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Base62x, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Mfonte\Base62x\Encoding;
4
5
// source: https://github.com/wadelau/Base62x/blob/master/Base62x.class.php
6
7
/*
8
 * -Base62x in -PHP
9
 * [email protected]
10
 * Refers to
11
    http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=6020065
12
    -GitHub-Wadelau , base62x.c
13
    https://github.com/wadelau/Base62x
14
    https://ufqi.com/dev/base62x/?_via=-naturedns
15
 * Tue Aug  9 21:18:14 CST 2016
16
 * bugfix, 13:39 13 September 2016
17
 * bugfix, Thu Sep 29 04:06:26 UTC 2016
18
 * imprvs on numeric conversion, Fri Oct  7 03:42:59 UTC 2016
19
 * bugifx by _decodeByLength, 20:40 28 November 2016
20
 * imprvs on decode, Mon Mar 11 03:07:37 GMT 2019
21
 */
22
23
class Base62x
24
{
25
    // variables
26
27
    public $isdebug = false;
28
    public $i = 0;
29
    public $codetype = 0; // 0:encode, 1:decode
30
    public const XTAG = 'x';
31
    public const ENCD = '-enc';
32
    public const DECD = '-dec';
33
    public const DEBG = '-v';
34
    public const CVTN = '-n';
35
    public const b62x = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
36
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
37
        'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
38
        'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
39
        'q', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', '1', '2', '3', 'x', ];
40
    public const bpos = 60; // 0-60 chars
41
    public const xpos = 64; // b62x[64] = 'x'
42
    public static $rb62x = [];
43
    public const ascmax = 127;
44
    public const asclist = ['4', '5', '6', '7', '8', '9', '0',
45
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
46
        'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
47
        'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
48
        'q', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', ]; // 58
49
    public $ascidx = [];
50
    public $ascrlist = [];
51
    public const max_safe_base = 36;
52
    public const base59 = 59; // static $rb62xyz = array(); static $b62xyz = array();
53
    public static $ver = 0.9;
54
55
    // methods
56
57
    // encode, ibase=2,8,10,16,32...
58
    public static function encode($input, $ibase = null)
59
    {
60
        $output = null;
61
        if ($input == null || $input == '') {
62
            return $input;
63
        }
64
65
        $codetype = 0;
66
        $xtag = self::XTAG;
67
        $b62x = self::b62x;
68
        $asclist = self::asclist;
69
        $bpos = self::bpos;
70
        $xpos = self::xpos;
71
        $ascmax = self::ascmax;
72
        //$max_safe_base = self::max_safe_base;
73
74
        $rb62x = self::fillRb62x($b62x, $bpos, $xpos);
75
        $isNum = false;
76
        if ($ibase > 0) {
77
            $isNum = true;
78
        }
79
        if ($isNum) {
80
            $num_input = self::xx2dec($input, $ibase, $rb62x);
81
            $obase = $xpos;
82
            $output = self::dec2xx($num_input, $obase, $b62x);
83
        // why a mediate number format is needed?
84
        } else {
85
            // string
86
            $ascidx = [];
87
            $ascrlist = [];
88
            $inputArr = mb_str_split($input);
89
            $inputlen = \count($inputArr);
90
            //if(!isset($ascidx)){ $ascidx = array(); }
91
            //if(!isset($ascrlist)){ $ascrlist = array(); }
92
            $setResult = self::setAscii($codetype, $inputArr, $ascidx, $ascmax, $asclist, $ascrlist);
93
            $asctype = $setResult['asctype'];
94
            $ascidx = $setResult['ascidx'];
95
            $ascrlist = $setResult['ascrlist'];
0 ignored issues
show
Unused Code introduced by
The assignment to $ascrlist is dead and can be removed.
Loading history...
96
97
            $op = [];
98
            $i = 0;
99
            $m = 0;
100
            if ($asctype == 1) {
101
                $ixtag = \ord($xtag);
102
                do {
103
                    $inputArr[$i] = \ord($inputArr[$i]);
104
                    if ($ascidx[$inputArr[$i]] > -1) {
105
                        $op[$m] = $xtag;
106
                        $op[++$m] = $ascidx[$inputArr[$i]];
107
                    } elseif ($inputArr[$i] == $ixtag) {
108
                        $op[$m] = $xtag;
109
                        $op[++$m] = $xtag;
110
                    } else {
111
                        $op[$m] = \chr((int) ($inputArr[$i]));
112
                    }
113
                    ++$m;
114
                } while (++$i < $inputlen);
115
                $op[$m] = $xtag; // asctype=1 has a tag 'x' appended
116
            } else {
117
                $c0 = 0;
118
                $c1 = 0;
119
                $c2 = 0;
120
                $c3 = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $c3 is dead and can be removed.
Loading history...
121
                do {
122
                    $remaini = $inputlen - $i;
123
                    $inputArr[$i] = \ord($inputArr[$i]);
124
                    if ($remaini > 2) {
125
                        $inputArr[$i + 1] = \ord($inputArr[$i + 1]);
126
                        $inputArr[$i + 2] = \ord($inputArr[$i + 2]);
127
                        $c0 = $inputArr[$i] >> 2;
128
                        $c1 = ((($inputArr[$i] << 6) & 0xFF) >> 2) | ($inputArr[$i + 1] >> 4);
129
                        $c2 = ((($inputArr[$i + 1] << 4) & 0xFF) >> 2) | ($inputArr[$i + 2] >> 6);
130
                        $c3 = (($inputArr[$i + 2] << 2) & 0xFF) >> 2;
131
                        if ($c0 > $bpos) {
132
                            $op[$m] = $xtag;
133
                            $op[++$m] = $b62x[$c0];
134
                        } else {
135
                            $op[$m] = $b62x[$c0];
136
                        }
137
                        if ($c1 > $bpos) {
138
                            $op[++$m] = $xtag;
139
                            $op[++$m] = $b62x[$c1];
140
                        } else {
141
                            $op[++$m] = $b62x[$c1];
142
                        }
143
                        if ($c2 > $bpos) {
144
                            $op[++$m] = $xtag;
145
                            $op[++$m] = $b62x[$c2];
146
                        } else {
147
                            $op[++$m] = $b62x[$c2];
148
                        }
149
                        if ($c3 > $bpos) {
150
                            $op[++$m] = $xtag;
151
                            $op[++$m] = $b62x[$c3];
152
                        } else {
153
                            $op[++$m] = $b62x[$c3];
154
                        }
155
                        $i += 2;
156
                    } elseif ($remaini == 2) {
157
                        $inputArr[$i + 1] = \ord($inputArr[$i + 1]);
158
                        $c0 = $inputArr[$i] >> 2;
159
                        $c1 = ((($inputArr[$i] << 6) & 0xFF) >> 2) | ($inputArr[$i + 1] >> 4);
160
                        $c2 = (($inputArr[$i + 1] << 4) & 0xFF) >> 4;
161
                        if ($c0 > $bpos) {
162
                            $op[$m] = $xtag;
163
                            $op[++$m] = $b62x[$c0];
164
                        } else {
165
                            $op[$m] = $b62x[$c0];
166
                        }
167
                        if ($c1 > $bpos) {
168
                            $op[++$m] = $xtag;
169
                            $op[++$m] = $b62x[$c1];
170
                        } else {
171
                            $op[++$m] = $b62x[$c1];
172
                        }
173
                        if ($c2 > $bpos) {
174
                            $op[++$m] = $xtag;
175
                            $op[++$m] = $b62x[$c2];
176
                        } else {
177
                            $op[++$m] = $b62x[$c2];
178
                        }
179
                        ++$i;
180
                    } else { // == 1
181
                        $c0 = $inputArr[$i] >> 2;
182
                        $c1 = (($inputArr[$i] << 6) & 0xFF) >> 6;
183
                        if ($c0 > $bpos) {
184
                            $op[$m] = $xtag;
185
                            $op[++$m] = $b62x[$c0];
186
                        } else {
187
                            $op[$m] = $b62x[$c0];
188
                        }
189
                        if ($c1 > $bpos) {
190
                            $op[++$m] = $xtag;
191
                            $op[++$m] = $b62x[$c1];
192
                        } else {
193
                            $op[++$m] = $b62x[$c1];
194
                        }
195
                    }
196
                    ++$m;
197
                } while (++$i < $inputlen);
198
            }
199
            $output = implode('', $op);
200
        }
201
202
        return $output;
203
    }
204
205
    // decode, obase=2,8,10,16,32...
206
    public static function decode($input, $obase = null)
207
    {
208
        $output = '';
209
        if ($input == null || $input == '') {
210
            return $input;
211
        }
212
213
        $codetype = 1;
214
        $xtag = self::XTAG;
215
        $b62x = self::b62x;
216
        $asclist = self::asclist;
217
        $bpos = self::bpos;
218
        $xpos = self::xpos;
219
        $ascmax = self::ascmax;
220
        $rb62x = self::fillRb62x($b62x, $bpos, $xpos);
221
        //$max_safe_base = self::max_safe_base;
222
223
        $isNum = false;
224
        if ($obase > 0) {
225
            $isNum = true;
226
        }
227
        if ($isNum) {
228
            $output = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $output is dead and can be removed.
Loading history...
229
            $ibase = $xpos;
230
            $num_input = self::xx2dec($input, $ibase, $rb62x);
231
            $output = self::dec2xx($num_input, $obase, $b62x);
232
        // why a mediate number format is needed?
233
        } else {
234
            // string
235
            $ascidx = [];
236
            $ascrlist = [];
237
            $inputArr = mb_str_split($input);
238
            $inputlen = \count($inputArr);
239
            $setResult = self::setAscii($codetype, $inputArr, $ascidx, $ascmax, $asclist, $ascrlist);
240
            $asctype = $setResult['asctype'];
241
            $ascidx = $setResult['ascidx'];
0 ignored issues
show
Unused Code introduced by
The assignment to $ascidx is dead and can be removed.
Loading history...
242
            $ascrlist = $setResult['ascrlist'];
243
244
            $op = [];
245
            $i = 0;
246
            $m = 0;
247
            if ($asctype == 1) {
248
                --$inputlen;
249
                do {
250
                    if ($inputArr[$i] == $xtag) {
251
                        if ($inputArr[$i + 1] == $xtag) {
252
                            $op[$m] = $xtag;
253
                            ++$i;
254
                        } else {
255
                            $op[$m] = \chr($ascrlist[$inputArr[++$i]]);
256
                        }
257
                    } else {
258
                        $op[$m] = $inputArr[$i];
259
                    }
260
                    ++$m;
261
                } while (++$i < $inputlen);
262
            } else {
263
                $tmpArr = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $tmpArr is dead and can be removed.
Loading history...
264
                $bint = ['1' => 1, '2' => 2, '3' => 3];
265
                do {
266
                    $tmpArr = [null, null, null, null];
267
                    $remaini = $inputlen - $i;
268
                    $j = 0;
269
                    if ($remaini > 1) {
270
                        $j = 0;
271
                        do {
272
                            if ($inputArr[$i] == $xtag) {
273
                                ++$i;
274
                                $tmpArr[$j] = $bpos + $bint[$inputArr[$i]];
275
                            } else {
276
                                $tmpArr[$j] = $rb62x[$inputArr[$i]];
277
                            }
278
                            ++$i;
279
                            ++$j;
280
                        } while ($j < 4 && $i < $inputlen);
281
282
                        $arr = self::_decodeByLength($tmpArr, $op, $m);
283
                        $op = $arr[0];
284
                        $m = $arr[1]; //- deprecated
285
                    } else {
286
                        error_log(__FILE__.': found illegal base62x input:['.$inputArr[$i].']. 1608091042.');
287
                        ++$i;
288
                        continue;
289
                    }
290
                    ++$m;
291
                } while ($i < $inputlen);
292
            }
293
            $output = implode('', $op);
294
        }
295
296
        return $output;
297
    }
298
299
    // xx2dec
300
    public static function xx2dec($inum, $ibase, $ridx)
301
    {
302
        $onum = 0;
303
        $obase = 10;
304
        $xtag = self::XTAG;
305
        $bpos = self::bpos;
306
        $safebase = self::max_safe_base;
307
        $base59 = self::base59;
308
        $xpos = self::xpos;
309
        if ($ibase <= $safebase) {
310
            $onum = base_convert($inum, $ibase, $obase);
311
        } else {
312
            if ($ibase > $base59 && $ibase < $xpos) {
313
                // base 60, 61, 62 or sth, reset ridx table
314
                //$ridx = $self->rb62xyz;
315
                $ridx_in = [];
316
                foreach ($ridx as $rk => $rv) {
317
                    $ridx_in[$rk] = $rv;
318
                }
319
                $ridx_in['x'] = 59;
320
                $ridx_in['y'] = 60;
321
                $ridx_in['z'] = 61;
322
                $ridx = $ridx_in;
323
            }
324
            $iArr = mb_str_split($inum);
325
            $iArr = array_reverse($iArr);
326
            $arrLen = \count($iArr);
327
            $xnum = 0;
328
            $isBase62x = ($ibase == $xpos);
329
            for ($i = 0; $i < $arrLen; ++$i) {
330
                if ($isBase62x && $iArr[$i + 1] == $xtag) {
331
                    $tmpi = $bpos + $ridx[$iArr[$i]];
332
                    ++$xnum;
333
                    ++$i;
334
                } else {
335
                    $tmpi = $ridx[$iArr[$i]];
336
                }
337
                if ($tmpi >= $ibase) {
338
                    error_log(__FILE__.": xxdec found out of radix:$tmpi for base:$ibase.\n");
339
                    $tmpi = $ibase - 1;
340
                }
341
                $onum = $onum + $tmpi * $ibase ** ($i - $xnum);
342
                //error_log("\t".__FILE__.": xx2dec ibase:$ibase i:$i c:".$iArr[$i]." tmpi:$tmpi onum:$onum xnum:$xnum");
343
            }
344
            if (mb_strpos($onum, 'E') !== false) {
345
                error_log(__FILE__.": Base62x::xx2dec: lost precision due to too large number:[$onum]. consider using bc math. 1610072145.");
346
                $onum = number_format($onum);
347
            }
348
        }
349
        //error_log(__FILE__.": xx2dec: in:$inum ibase:$ibase outindec:".$onum);
350
        return $onum;
351
    }
352
353
    // dec2xx
354
    public static function dec2xx($inum, $obase, $idx)
355
    {
356
        $onum = 0;
357
        $ibase = 10;
358
        $xtag = self::XTAG;
359
        $bpos = self::bpos;
360
        $safebase = self::max_safe_base;
361
        $base59 = self::base59;
362
        $xpos = self::xpos;
363
        if ($obase <= $safebase) {
364
            $onum = base_convert($inum, $ibase, $obase);
365
        } else {
366
            $isBase62x = false;
367
            if ($obase > $base59 && $obase < $xpos) {
368
                //$idx = self::b62xyz;
369
                $idx_in = [];
370
                foreach ($idx as $ik => $iv) {
371
                    $idx_in[$ik] = $iv;
372
                }
373
                $idx_in[59] = 'x';
374
                $idx_in[60] = 'y';
375
                $idx_in[61] = 'z';
376
                $idx = $idx_in;
377
            } elseif ($obase == $xpos) {
378
                $isBase62x = true;
379
            }
380
            $maxPos = $bpos;
381
            if (!$isBase62x) {
382
                $maxPos = $bpos + 1;
383
            } // cover all 0-61 chars
384
            $i = 0;
385
            $b = 0;
386
            $oArr = [];
387
            while ($inum >= $obase) {
388
                $b = $inum % $obase;
389
                $inum = floor($inum / $obase);
390
                if ($b <= $maxPos) {
391
                    $oArr[$i++] = $idx[$b];
392
                } else {
393
                    $oArr[$i++] = $idx[$b - $bpos];
394
                    $oArr[$i++] = $xtag;
395
                }
396
            }
397
            $b = $inum;
398
            if ($b > 0) {
399
                if ($b <= $maxPos) {
400
                    $oArr[$i++] = $idx[$b];
401
                } else {
402
                    $oArr[$i++] = $idx[$b - $bpos];
403
                    $oArr[$i++] = $xtag;
404
                }
405
            }
406
            $oArr = array_reverse($oArr);
407
            //print_r($oArr);
408
            $onum = implode('', $oArr);
409
        }
410
        //error_log(__FILE__.": dec2xx: inindec:$inum obase:$obase out:".($onum));
411
        return $onum;
412
    }
413
414
    // inner faciliates
415
416
    // fill reverse b62x
417
    private static function fillRb62x($b62x, $bpos, $xpos)
418
    {
419
        $rb62x = [];
420
        for ($i = 0; $i <= $xpos; ++$i) {
421
            if ($i > $bpos && $i < $xpos) {
422
                // omit x1, x2, x3
423
            } else {
424
                $rb62x[$b62x[$i]] = $i;
425
            }
426
        }
427
428
        return $rb62x;
429
    }
430
431
    // set ascii type
432
    private static function setAscii($codetype, $inputArr, $ascidx, $ascmax, $asclist, $ascrlist)
433
    {
434
        $ret = [];
435
436
        $asctype = 0;
437
        $xtag = self::XTAG;
438
        $inputlen = \count($inputArr);
439
        if ($codetype == 0 && \ord($inputArr[0]) <= $ascmax) {
440
            $asctype = 1;
441
            for ($i = 1; $i < $inputlen; ++$i) {
442
                $tmpi = \ord($inputArr[$i]);
443
                if ($tmpi > $ascmax
444
                    || ($tmpi > 16 && $tmpi < 21) // DC1-4
445
                    || ($tmpi > 27 && $tmpi < 32)) { // FC, GS, RS, US
446
                    $asctype = 0;
447
                    break;
448
                }
449
            }
450
        } elseif ($codetype == 1 && $inputArr[$inputlen - 1] == $xtag) {
451
            $asctype = 1;
452
        }
453
        $ret['asctype'] = $asctype;
454
455
        if ($asctype == 1) {
456
            for ($i = 0; $i <= $ascmax; ++$i) {
457
                $ascidx[$i] = -1;
458
            }
459
            $idxi = 0;
460
            $bgnArr = [0, 21, 32, 58, 91, 123];
461
            $endArr = [17, 28, 48, 65, 97, $ascmax + 1];
462
            foreach ($bgnArr as $k => $v) {
463
                for ($i = $v; $i < $endArr[$k]; ++$i) {
464
                    $ascidx[$i] = $asclist[$idxi];
465
                    $ascrlist[$asclist[$idxi]] = $i;
466
                    ++$idxi;
467
                }
468
            }
469
        }
470
471
        $ret['ascidx'] = $ascidx;
472
        $ret['ascrlist'] = $ascrlist;
473
474
        return $ret;
475
    }
476
477
    //- decode with x1, x2, x3
478
    //- Mon Nov 28 17:47:45 CST 2016
479
    private static function _decodeByLength($tmpArr, $op, $m)
480
    {
481
        $rtn = $op;
0 ignored issues
show
Unused Code introduced by
The assignment to $rtn is dead and can be removed.
Loading history...
482
        $c0 = 0;
483
        $c1 = 0;
484
        $c2 = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $c2 is dead and can be removed.
Loading history...
485
        if ($tmpArr[3] !== null) {
486
            $c0 = $tmpArr[0] << 2 | $tmpArr[1] >> 4;
487
            $c1 = (($tmpArr[1] << 4) & 0xF0) | ($tmpArr[2] >> 2);
488
            $c2 = (($tmpArr[2] << 6) & 0xFF) | $tmpArr[3];
489
            $op[$m] = \chr($c0);
490
            $op[++$m] = \chr($c1);
491
            $op[++$m] = \chr($c2);
492
        } elseif ($tmpArr[2] !== null) {
493
            $c0 = $tmpArr[0] << 2 | $tmpArr[1] >> 4;
494
            $c1 = (($tmpArr[1] << 4) & 0xF0) | $tmpArr[2];
495
            $op[$m] = \chr($c0);
496
            $op[++$m] = \chr($c1);
497
        } elseif ($tmpArr[1] !== null) {
498
            $c0 = $tmpArr[0] << 2 | $tmpArr[1];
499
            $op[$m] = \chr($c0);
500
        } else {
501
            $c0 = $tmpArr[0];
502
            $op[$m] = \chr($c0);
503
        }
504
505
        return [$rtn = $op, $m];
506
    }
507
}
508