QRinput   F
last analyzed

Complexity

Total Complexity 95

Size/Duplication

Total Lines 451
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 211
dl 0
loc 451
rs 2
c 0
b 0
f 0
wmc 95

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getErrorCorrectionLevel() 0 3 1
A append() 0 8 2
A estimateBitsModeAn() 0 10 2
A checkModeAn() 0 9 3
A getVersion() 0 3 1
A createBitStream() 0 14 3
A estimateBitsModeNum() 0 17 3
A setErrorCorrectionLevel() 0 10 2
A mergeBitStream() 0 16 4
A __construct() 0 9 4
B checkModeKanji() 0 15 7
A estimateBitStreamSize() 0 9 2
A estimateVersion() 0 14 3
B appendPaddingBit() 0 42 8
A insertStructuredAppendHeader() 0 18 5
A convertData() 0 25 6
A estimateBitsModeKanji() 0 3 1
A lookAnTable() 0 3 2
A estimateBitsMode8() 0 3 1
A setVersion() 0 10 3
B check() 0 17 7
A appendEntry() 0 3 1
A calcParity() 0 13 4
A checkModeNum() 0 9 4
A getBitStream() 0 15 3
A getByteStream() 0 8 2
B lengthOfCode() 0 40 11

How to fix   Complexity   

Complex Class

Complex classes like QRinput 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 QRinput, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
* PHP QR Code encoder
4
*
5
* Input encoding class
6
*
7
* Based on libqrencode C library distributed under LGPL 2.1
8
* Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <[email protected]>
9
*
10
* PHP QR Code is distributed under LGPL 3
11
* Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
12
*
13
* This library is free software; you can redistribute it and/or
14
* modify it under the terms of the GNU Lesser General Public
15
* License as published by the Free Software Foundation; either
16
* version 3 of the License, or any later version.
17
*
18
* This library is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
* Lesser General Public License for more details.
22
*
23
* You should have received a copy of the GNU Lesser General Public
24
* License along with this library; if not, write to the Free Software
25
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
*/
27
namespace tinymeng\code\Gateways\qrcode;
28
29
define('STRUCTURE_HEADER_BITS',  20);
30
define('MAX_STRUCTURED_SYMBOLS', 16);
31
32
class QRinput {
33
34
    public $items;
35
    
36
    private $version;
37
    private $level;
38
    
39
    //----------------------------------------------------------------------
40
    public function __construct($version = 0, $level = QR_ECLEVEL_L)
41
    {
42
        if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {
43
            throw new Exception('Invalid version no');
0 ignored issues
show
Bug introduced by
The type tinymeng\code\Gateways\qrcode\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
44
            return NULL;
0 ignored issues
show
Unused Code introduced by
return NULL is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
45
        }
46
        
47
        $this->version = $version;
48
        $this->level = $level;
49
    }
50
    
51
    //----------------------------------------------------------------------
52
    public function getVersion()
53
    {
54
        return $this->version;
55
    }
56
    
57
    //----------------------------------------------------------------------
58
    public function setVersion($version)
59
    {
60
        if($version < 0 || $version > QRSPEC_VERSION_MAX) {
61
            throw new Exception('Invalid version no');
62
            return -1;
0 ignored issues
show
Unused Code introduced by
return -1 is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
63
        }
64
65
        $this->version = $version;
66
67
        return 0;
68
    }
69
    
70
    //----------------------------------------------------------------------
71
    public function getErrorCorrectionLevel()
72
    {
73
        return $this->level;
74
    }
75
76
    //----------------------------------------------------------------------
77
    public function setErrorCorrectionLevel($level)
78
    {
79
        if($level > QR_ECLEVEL_H) {
80
            throw new Exception('Invalid ECLEVEL');
81
            return -1;
0 ignored issues
show
Unused Code introduced by
return -1 is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
82
        }
83
84
        $this->level = $level;
85
86
        return 0;
87
    }
88
    
89
    //----------------------------------------------------------------------
90
    public function appendEntry(QRinputItem $entry)
91
    {
92
        $this->items[] = $entry;
93
    }
94
    
95
    //----------------------------------------------------------------------
96
    public function append($mode, $size, $data)
97
    {
98
        try {
99
            $entry = new QRinputItem($mode, $size, $data);
100
            $this->items[] = $entry;
101
            return 0;
102
        } catch (Exception $e) {
103
            return -1;
104
        }
105
    }
106
    
107
    //----------------------------------------------------------------------
108
    
109
    public function insertStructuredAppendHeader($size, $index, $parity)
110
    {
111
        if( $size > MAX_STRUCTURED_SYMBOLS ) {
112
            throw new Exception('insertStructuredAppendHeader wrong size');
113
        }
114
        
115
        if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
116
            throw new Exception('insertStructuredAppendHeader wrong index');
117
        }
118
119
        $buf = array($size, $index, $parity);
0 ignored issues
show
Unused Code introduced by
The assignment to $buf is dead and can be removed.
Loading history...
120
        
121
        try {
122
            $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);
0 ignored issues
show
Bug introduced by
The constant tinymeng\code\Gateways\qrcode\buf was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
123
            array_unshift($this->items, $entry);
124
            return 0;
125
        } catch (Exception $e) {
126
            return -1;
127
        }
128
    }
129
130
    //----------------------------------------------------------------------
131
    public function calcParity()
132
    {
133
        $parity = 0;
134
        
135
        foreach($this->items as $item) {
136
            if($item->mode != QR_MODE_STRUCTURE) {
137
                for($i=$item->size-1; $i>=0; $i--) {
138
                    $parity ^= $item->data[$i];
139
                }
140
            }
141
        }
142
143
        return $parity;
144
    }
145
    
146
    //----------------------------------------------------------------------
147
    public static function checkModeNum($size, $data)
148
    {
149
        for($i=0; $i<$size; $i++) {
150
            if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){
151
                return false;
152
            }
153
        }
154
155
        return true;
156
    }
157
158
    //----------------------------------------------------------------------
159
    public static function estimateBitsModeNum($size)
160
    {
161
        $w = (int)$size / 3;
162
        $bits = $w * 10;
163
        
164
        switch($size - $w * 3) {
165
            case 1:
166
                $bits += 4;
167
                break;
168
            case 2:
169
                $bits += 7;
170
                break;
171
            default:
172
                break;
173
        }
174
175
        return $bits;
176
    }
177
    
178
    //----------------------------------------------------------------------
179
    public static $anTable = array(
180
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
181
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
182
        36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,
183
         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,
184
        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
185
        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
186
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
187
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
188
    );
189
    
190
    //----------------------------------------------------------------------
191
    public static function lookAnTable($c)
192
    {
193
        return (($c > 127)?-1:self::$anTable[$c]);
194
    }
195
    
196
    //----------------------------------------------------------------------
197
    public static function checkModeAn($size, $data)
198
    {
199
        for($i=0; $i<$size; $i++) {
200
            if (self::lookAnTable(ord($data[$i])) == -1) {
201
                return false;
202
            }
203
        }
204
205
        return true;
206
    }
207
    
208
    //----------------------------------------------------------------------
209
    public static function estimateBitsModeAn($size)
210
    {
211
        $w = (int)($size / 2);
212
        $bits = $w * 11;
213
        
214
        if($size & 1) {
215
            $bits += 6;
216
        }
217
218
        return $bits;
219
    }
220
221
    //----------------------------------------------------------------------
222
    public static function estimateBitsMode8($size)
223
    {
224
        return $size * 8;
225
    }
226
    
227
    //----------------------------------------------------------------------
228
    public function estimateBitsModeKanji($size)
229
    {
230
        return (int)(($size / 2) * 13);
231
    }
232
    
233
    //----------------------------------------------------------------------
234
    public static function checkModeKanji($size, $data)
235
    {
236
        if($size & 1)
237
            return false;
238
239
        for($i=0; $i<$size; $i+=2) {
240
            $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
241
            if( $val < 0x8140 
242
            || ($val > 0x9ffc && $val < 0xe040) 
243
            || $val > 0xebbf) {
244
                return false;
245
            }
246
        }
247
248
        return true;
249
    }
250
251
    /***********************************************************************
252
     * Validation
253
     **********************************************************************/
254
255
    public static function check($mode, $size, $data)
256
    {
257
        if($size <= 0) 
258
            return false;
259
260
        switch($mode) {
261
            case QR_MODE_NUM:       return self::checkModeNum($size, $data);   break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
262
            case QR_MODE_AN:        return self::checkModeAn($size, $data);    break;
263
            case QR_MODE_KANJI:     return self::checkModeKanji($size, $data); break;
264
            case QR_MODE_8:         return true; break;
265
            case QR_MODE_STRUCTURE: return true; break;
266
            
267
            default:
268
                break;
269
        }
270
271
        return false;
272
    }
273
    
274
    
275
    //----------------------------------------------------------------------
276
    public function estimateBitStreamSize($version)
277
    {
278
        $bits = 0;
279
280
        foreach($this->items as $item) {
281
            $bits += $item->estimateBitStreamSizeOfEntry($version);
282
        }
283
284
        return $bits;
285
    }
286
    
287
    //----------------------------------------------------------------------
288
    public function estimateVersion()
289
    {
290
        $version = 0;
291
        $prev = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $prev is dead and can be removed.
Loading history...
292
        do {
293
            $prev = $version;
294
            $bits = $this->estimateBitStreamSize($prev);
295
            $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
296
            if ($version < 0) {
297
                return -1;
298
            }
299
        } while ($version > $prev);
300
301
        return $version;
302
    }
303
    
304
    //----------------------------------------------------------------------
305
    public static function lengthOfCode($mode, $version, $bits)
306
    {
307
        $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);
308
        switch($mode) {
309
            case QR_MODE_NUM:
310
                $chunks = (int)($payload / 10);
311
                $remain = $payload - $chunks * 10;
312
                $size = $chunks * 3;
313
                if($remain >= 7) {
314
                    $size += 2;
315
                } else if($remain >= 4) {
316
                    $size += 1;
317
                }
318
                break;
319
            case QR_MODE_AN:
320
                $chunks = (int)($payload / 11);
321
                $remain = $payload - $chunks * 11;
322
                $size = $chunks * 2;
323
                if($remain >= 6) 
324
                    $size++;
325
                break;
326
            case QR_MODE_8:
327
                $size = (int)($payload / 8);
328
                break;
329
            case QR_MODE_KANJI:
330
                $size = (int)(($payload / 13) * 2);
331
                break;
332
            case QR_MODE_STRUCTURE:
333
                $size = (int)($payload / 8);
334
                break;
335
            default:
336
                $size = 0;
337
                break;
338
        }
339
        
340
        $maxsize = QRspec::maximumWords($mode, $version);
341
        if($size < 0) $size = 0;
342
        if($size > $maxsize) $size = $maxsize;
343
344
        return $size;
345
    }
346
    
347
    //----------------------------------------------------------------------
348
    public function createBitStream()
349
    {
350
        $total = 0;
351
352
        foreach($this->items as $item) {
353
            $bits = $item->encodeBitStream($this->version);
354
            
355
            if($bits < 0) 
356
                return -1;
357
                
358
            $total += $bits;
359
        }
360
361
        return $total;
362
    }
363
    
364
    //----------------------------------------------------------------------
365
    public function convertData()
366
    {
367
        $ver = $this->estimateVersion();
368
        if($ver > $this->getVersion()) {
369
            $this->setVersion($ver);
370
        }
371
372
        for(;;) {
373
            $bits = $this->createBitStream();
374
            
375
            if($bits < 0) 
376
                return -1;
377
                
378
            $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);
379
            if($ver < 0) {
380
                throw new Exception('WRONG VERSION');
381
                return -1;
0 ignored issues
show
Unused Code introduced by
return -1 is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
382
            } else if($ver > $this->getVersion()) {
383
                $this->setVersion($ver);
384
            } else {
385
                break;
386
            }
387
        }
388
389
        return 0;
390
    }
391
    
392
    //----------------------------------------------------------------------
393
    public function appendPaddingBit(&$bstream)
394
    {
395
        $bits = $bstream->size();
396
        $maxwords = QRspec::getDataLength($this->version, $this->level);
397
        $maxbits = $maxwords * 8;
398
399
        if ($maxbits == $bits) {
400
            return 0;
401
        }
402
403
        if ($maxbits - $bits < 5) {
404
            return $bstream->appendNum($maxbits - $bits, 0);
405
        }
406
407
        $bits += 4;
408
        $words = (int)(($bits + 7) / 8);
409
410
        $padding = new QRbitstream();
411
        $ret = $padding->appendNum($words * 8 - $bits + 4, 0);
412
        
413
        if($ret < 0) 
414
            return $ret;
415
416
        $padlen = $maxwords - $words;
417
        
418
        if($padlen > 0) {
419
            
420
            $padbuf = array();
421
            for($i=0; $i<$padlen; $i++) {
422
                $padbuf[$i] = ($i&1)?0x11:0xec;
423
            }
424
            
425
            $ret = $padding->appendBytes($padlen, $padbuf);
426
            
427
            if($ret < 0)
428
                return $ret;
429
            
430
        }
431
432
        $ret = $bstream->append($padding);
433
        
434
        return $ret;
435
    }
436
437
    //----------------------------------------------------------------------
438
    public function mergeBitStream()
439
    {
440
        if($this->convertData() < 0) {
441
            return null;
442
        }
443
444
        $bstream = new QRbitstream();
445
        
446
        foreach($this->items as $item) {
447
            $ret = $bstream->append($item->bstream);
448
            if($ret < 0) {
449
                return null;
450
            }
451
        }
452
453
        return $bstream;
454
    }
455
456
    //----------------------------------------------------------------------
457
    public function getBitStream()
458
    {
459
460
        $bstream = $this->mergeBitStream();
461
        
462
        if($bstream == null) {
463
            return null;
464
        }
465
        
466
        $ret = $this->appendPaddingBit($bstream);
467
        if($ret < 0) {
468
            return null;
469
        }
470
471
        return $bstream;
472
    }
473
    
474
    //----------------------------------------------------------------------
475
    public function getByteStream()
476
    {
477
        $bstream = $this->getBitStream();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $bstream is correct as $this->getBitStream() targeting tinymeng\code\Gateways\q...QRinput::getBitStream() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
478
        if($bstream == null) {
0 ignored issues
show
introduced by
The condition $bstream == null is always true.
Loading history...
479
            return null;
480
        }
481
        
482
        return $bstream->toByte();
483
    }
484
}
485
    
486
    
487