Issues (1270)

lib/phpqrcode/qrencode.php (11 issues)

1
<?php
2
/*
3
 * PHP QR Code encoder
4
 *
5
 * Main encoder classes.
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
 
28
    class QRrsblock {
29
        public $dataLength;
30
        public $data = array();
31
        public $eccLength;
32
        public $ecc = array();
33
        
34
        public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
35
        {
36
            $rs->encode_rs_char($data, $ecc);
37
        
38
            $this->dataLength = $dl;
39
            $this->data = $data;
40
            $this->eccLength = $el;
41
            $this->ecc = $ecc;
42
        }
43
    };
44
    
45
    //##########################################################################
46
47
    class QRrawcode {
48
        public $version;
49
        public $datacode = array();
50
        public $ecccode = array();
51
        public $blocks;
52
        public $rsblocks = array(); //of RSblock
53
        public $count;
54
        public $dataLength;
55
        public $eccLength;
56
        public $b1;
57
        
58
        //----------------------------------------------------------------------
59
        public function __construct(QRinput $input)
60
        {
61
            $spec = array(0, 0, 0, 0, 0);
62
            
63
            $this->datacode = $input->getByteStream();
0 ignored issues
show
Are you sure the assignment to $this->datacode is correct as $input->getByteStream() targeting QRinput::getByteStream() 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...
64
            if (is_null($this->datacode)) {
0 ignored issues
show
The condition is_null($this->datacode) is always true.
Loading history...
65
                throw new Exception('null imput string');
66
            }
67
68
            QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
69
70
            $this->version = $input->getVersion();
71
            $this->b1 = QRspec::rsBlockNum1($spec);
72
            $this->dataLength = QRspec::rsDataLength($spec);
73
            $this->eccLength = QRspec::rsEccLength($spec);
74
            $this->ecccode = array_fill(0, $this->eccLength, 0);
75
            $this->blocks = QRspec::rsBlockNum($spec);
76
            
77
            $ret = $this->init($spec);
78
            if ($ret < 0) {
79
                throw new Exception('block alloc error');
80
                return null;
0 ignored issues
show
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...
81
            }
82
83
            $this->count = 0;
84
        }
85
        
86
        //----------------------------------------------------------------------
87
        public function init(array $spec)
88
        {
89
            $dl = QRspec::rsDataCodes1($spec);
90
            $el = QRspec::rsEccCodes1($spec);
91
            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
92
            
93
94
            $blockNo = 0;
95
            $dataPos = 0;
96
            $eccPos = 0;
97
            for ($i = 0; $i < QRspec::rsBlockNum1($spec); $i++) {
98
                $ecc = array_slice($this->ecccode, $eccPos);
99
                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
0 ignored issues
show
It seems like $rs can also be of type null; however, parameter $rs of QRrsblock::__construct() does only seem to accept QRrsItem, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, /** @scrutinizer ignore-type */ $rs);
Loading history...
100
                $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
101
                
102
                $dataPos += $dl;
103
                $eccPos += $el;
104
                $blockNo++;
105
            }
106
107
            if (QRspec::rsBlockNum2($spec) == 0) {
108
                            return 0;
109
            }
110
111
            $dl = QRspec::rsDataCodes2($spec);
112
            $el = QRspec::rsEccCodes2($spec);
113
            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
114
            
115
            if ($rs == null) {
116
                return -1;
117
            }
118
            
119
            for ($i = 0; $i < QRspec::rsBlockNum2($spec); $i++) {
120
                $ecc = array_slice($this->ecccode, $eccPos);
121
                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
122
                $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
123
                
124
                $dataPos += $dl;
125
                $eccPos += $el;
126
                $blockNo++;
127
            }
128
129
            return 0;
130
        }
131
        
132
        //----------------------------------------------------------------------
133
        public function getCode()
134
        {
135
            $ret = 0;
136
137
            if ($this->count < $this->dataLength) {
138
                $row = $this->count % $this->blocks;
139
                $col = $this->count / $this->blocks;
140
                if ($col >= $this->rsblocks[0]->dataLength) {
141
                    $row += $this->b1;
142
                }
143
                $ret = $this->rsblocks[$row]->data[$col];
144
            } else if ($this->count < $this->dataLength + $this->eccLength) {
145
                $row = ($this->count - $this->dataLength) % $this->blocks;
146
                $col = ($this->count - $this->dataLength) / $this->blocks;
147
                $ret = $this->rsblocks[$row]->ecc[$col];
148
            } else {
149
                return 0;
150
            }
151
            $this->count++;
152
            
153
            return $ret;
154
        }
155
    }
156
157
    //##########################################################################
158
    
159
    class QRcode {
160
    
161
        public $version;
162
        public $width;
163
        public $data; 
164
        
165
        //----------------------------------------------------------------------
166
        public function encodeMask(QRinput $input, $mask)
167
        {
168
            if ($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
169
                throw new Exception('wrong version');
170
            }
171
            if ($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
172
                throw new Exception('wrong level');
173
            }
174
175
            $raw = new QRrawcode($input);
176
            
177
            QRtools::markTime('after_raw');
178
            
179
            $version = $raw->version;
180
            $width = QRspec::getWidth($version);
181
            $frame = QRspec::newFrame($version);
182
            
183
            $filler = new FrameFiller($width, $frame);
184
            if (is_null($filler)) {
185
                return null;
186
            }
187
188
            // inteleaved data and ecc codes
189
            for ($i = 0; $i < $raw->dataLength + $raw->eccLength; $i++) {
190
                $code = $raw->getCode();
191
                $bit = 0x80;
192
                for ($j = 0; $j < 8; $j++) {
193
                    $addr = $filler->next();
194
                    $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
195
                    $bit = $bit >> 1;
196
                }
197
            }
198
            
199
            QRtools::markTime('after_filler');
200
            
201
            unset($raw);
202
            
203
            // remainder bits
204
            $j = QRspec::getRemainder($version);
205
            for ($i = 0; $i < $j; $i++) {
206
                $addr = $filler->next();
207
                $filler->setFrameAt($addr, 0x02);
208
            }
209
            
210
            $frame = $filler->frame;
211
            unset($filler);
212
            
213
            
214
            // masking
215
            $maskObj = new QRmask();
216
            if ($mask < 0) {
217
            
218
                if (QR_FIND_BEST_MASK) {
219
                    $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
220
                } else {
221
                    $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
222
                }
223
            } else {
224
                $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
225
            }
226
            
227
            if ($masked == null) {
228
                return null;
229
            }
230
            
231
            QRtools::markTime('after_mask');
232
            
233
            $this->version = $version;
234
            $this->width = $width;
235
            $this->data = $masked;
236
            
237
            return $this;
238
        }
239
    
240
        //----------------------------------------------------------------------
241
        public function encodeInput(QRinput $input)
242
        {
243
            return $this->encodeMask($input, -1);
244
        }
245
        
246
        //----------------------------------------------------------------------
247
        public function encodeString8bit($string, $version, $level)
248
        {
249
            if (string == null) {
0 ignored issues
show
The constant string was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
250
                throw new Exception('empty string!');
251
                return null;
0 ignored issues
show
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...
252
            }
253
254
            $input = new QRinput($version, $level);
255
            if ($input == null) {
256
                return null;
257
            }
258
259
            $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
0 ignored issues
show
The call to QRinput::append() has too many arguments starting with str_split($string). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

259
            /** @scrutinizer ignore-call */ $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
260
            if ($ret < 0) {
261
                unset($input);
262
                return null;
263
            }
264
            return $this->encodeInput($input);
265
        }
266
267
        //----------------------------------------------------------------------
268
        public function encodeString($string, $version, $level, $hint, $casesensitive)
269
        {
270
271
            if ($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
272
                throw new Exception('bad hint');
273
                return null;
0 ignored issues
show
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...
274
            }
275
276
            $input = new QRinput($version, $level);
277
            if ($input == null) {
278
                return null;
279
            }
280
281
            $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
282
            if ($ret < 0) {
283
                return null;
284
            }
285
286
            return $this->encodeInput($input);
287
        }
288
        
289
        //----------------------------------------------------------------------
290
        public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint = false) 
0 ignored issues
show
The parameter $saveandprint is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

290
        public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, /** @scrutinizer ignore-unused */ $saveandprint = false) 

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
291
        {
292
            $enc = QRencode::factory($level, $size, $margin);
293
            return $enc->encodePNG($text, $outfile, $saveandprint = false);
0 ignored issues
show
Are you sure the usage of $enc->encodePNG($text, $... $saveandprint = false) targeting QRencode::encodePNG() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
294
        }
295
296
        //----------------------------------------------------------------------
297
        public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
298
        {
299
            $enc = QRencode::factory($level, $size, $margin);
300
            return $enc->encode($text, $outfile);
301
        }
302
303
        //----------------------------------------------------------------------
304
        public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
305
        {
306
            $enc = QRencode::factory($level, $size, $margin);
307
            return $enc->encodeRAW($text, $outfile);
308
        }
309
    }
310
    
311
    //##########################################################################
312
    
313
    class FrameFiller {
314
    
315
        public $width;
316
        public $frame;
317
        public $x;
318
        public $y;
319
        public $dir;
320
        public $bit;
321
        
322
        //----------------------------------------------------------------------
323
        public function __construct($width, &$frame)
324
        {
325
            $this->width = $width;
326
            $this->frame = $frame;
327
            $this->x = $width - 1;
328
            $this->y = $width - 1;
329
            $this->dir = -1;
330
            $this->bit = -1;
331
        }
332
        
333
        //----------------------------------------------------------------------
334
        public function setFrameAt($at, $val)
335
        {
336
            $this->frame[$at['y']][$at['x']] = chr($val);
337
        }
338
        
339
        //----------------------------------------------------------------------
340
        public function getFrameAt($at)
341
        {
342
            return ord($this->frame[$at['y']][$at['x']]);
343
        }
344
        
345
        //----------------------------------------------------------------------
346
        public function next()
347
        {
348
            do {
349
            
350
                if ($this->bit == -1) {
351
                    $this->bit = 0;
352
                    return array('x'=>$this->x, 'y'=>$this->y);
353
                }
354
355
                $x = $this->x;
356
                $y = $this->y;
357
                $w = $this->width;
358
359
                if ($this->bit == 0) {
360
                    $x--;
361
                    $this->bit++;
362
                } else {
363
                    $x++;
364
                    $y += $this->dir;
365
                    $this->bit--;
366
                }
367
368
                if ($this->dir < 0) {
369
                    if ($y < 0) {
370
                        $y = 0;
371
                        $x -= 2;
372
                        $this->dir = 1;
373
                        if ($x == 6) {
374
                            $x--;
375
                            $y = 9;
376
                        }
377
                    }
378
                } else {
379
                    if ($y == $w) {
380
                        $y = $w - 1;
381
                        $x -= 2;
382
                        $this->dir = -1;
383
                        if ($x == 6) {
384
                            $x--;
385
                            $y -= 8;
386
                        }
387
                    }
388
                }
389
                if ($x < 0 || $y < 0) {
390
                    return null;
391
                }
392
393
                $this->x = $x;
394
                $this->y = $y;
395
396
            } while (ord($this->frame[$y][$x]) & 0x80);
397
                        
398
            return array('x'=>$x, 'y'=>$y);
399
        }
400
        
401
    } ;
402
    
403
    //##########################################################################    
404
    
405
    class QRencode {
406
    
407
        public $casesensitive = true;
408
        public $eightbit = false;
409
        
410
        public $version = 0;
411
        public $size = 3;
412
        public $margin = 4;
413
        
414
        public $structured = 0; // not supported yet
415
        
416
        public $level = QR_ECLEVEL_L;
417
        public $hint = QR_MODE_8;
418
        
419
        //----------------------------------------------------------------------
420
        public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
421
        {
422
            $enc = new QRencode();
423
            $enc->size = $size;
424
            $enc->margin = $margin;
425
            
426
            switch ($level.'') {
427
            case '0':
428
            case '1':
429
            case '2':
430
            case '3':
431
                    $enc->level = $level;
432
                break;
433
            case 'l':
434
            case 'L':
435
                    $enc->level = QR_ECLEVEL_L;
436
                break;
437
            case 'm':
438
            case 'M':
439
                    $enc->level = QR_ECLEVEL_M;
440
                break;
441
            case 'q':
442
            case 'Q':
443
                    $enc->level = QR_ECLEVEL_Q;
444
                break;
445
            case 'h':
446
            case 'H':
447
                    $enc->level = QR_ECLEVEL_H;
448
                break;
449
            }
450
            
451
            return $enc;
452
        }
453
        
454
        //----------------------------------------------------------------------
455
        public function encodeRAW($intext, $outfile = false) 
0 ignored issues
show
The parameter $outfile is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

455
        public function encodeRAW($intext, /** @scrutinizer ignore-unused */ $outfile = false) 

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
456
        {
457
            $code = new QRcode();
458
459
            if ($this->eightbit) {
460
                $code->encodeString8bit($intext, $this->version, $this->level);
461
            } else {
462
                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
463
            }
464
            
465
            return $code->data;
466
        }
467
468
        //----------------------------------------------------------------------
469
        public function encode($intext, $outfile = false) 
470
        {
471
            $code = new QRcode();
472
473
            if ($this->eightbit) {
474
                $code->encodeString8bit($intext, $this->version, $this->level);
475
            } else {
476
                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
477
            }
478
            
479
            QRtools::markTime('after_encode');
480
            
481
            if ($outfile !== false) {
482
                file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
483
            } else {
484
                return QRtools::binarize($code->data);
485
            }
486
        }
487
        
488
        //----------------------------------------------------------------------
489
        public function encodePNG($intext, $outfile = false, $saveandprint = false) 
490
        {
491
            try {
492
            
493
                ob_start();
494
                $tab = $this->encode($intext);
495
                $err = ob_get_contents();
496
                ob_end_clean();
497
                
498
                if ($err != '') {
499
                                    QRtools::log($outfile, $err);
500
                }
501
                
502
                $maxSize = (int) (QR_PNG_MAXIMUM_SIZE / (count($tab) + 2 * $this->margin));
503
                
504
                QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin, $saveandprint);
505
            
506
            } catch (Exception $e) {
507
            
508
                QRtools::log($outfile, $e->getMessage());
509
            
510
            }
511
        }
512
    }
513