QRcode   D
last analyzed

Complexity

Total Complexity 389

Size/Duplication

Total Lines 2563
Duplicated Lines 5.74 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 147
loc 2563
rs 4.4102
c 0
b 0
f 0
wmc 389
lcom 1
cbo 0

98 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 32 12
A getBarcodeArray() 0 3 1
A binarize() 0 10 4
A encodeString() 0 11 3
B encodeMask() 0 55 9
A setFrameAt() 0 3 1
A getFrameAt() 0 3 1
C getNextPosition() 0 46 11
B init() 26 46 5
A getCode() 0 18 4
C writeFormatInformation() 30 35 7
A mask0() 0 3 1
A mask1() 0 3 1
A mask2() 0 3 1
A mask3() 0 3 1
A mask4() 0 3 1
A mask5() 0 3 1
A mask6() 0 3 1
A mask7() 0 3 1
B generateMaskNo() 0 14 5
B makeMaskNo() 0 18 5
A makeMask() 0 6 1
C calcN1N3() 0 24 15
C evaluateSymbol() 16 54 17
B mask() 0 31 5
A isdigitat() 0 6 3
A isalnumat() 0 6 2
B identifyMode() 0 20 10
B eatNum() 16 27 6
C eatAn() 0 34 7
A eatKanji() 0 8 2
D eat8() 0 44 9
D splitString() 0 37 9
B toUpper() 0 16 5
A newInputItem() 0 15 3
B encodeModeNum() 0 22 4
A encodeModeAn() 0 16 3
A encodeMode8() 0 9 2
A encodeModeKanji() 0 17 3
A encodeModeStructure() 0 8 1
C encodeBitStream() 0 40 7
A appendNewInputItem() 0 4 1
A insertStructuredAppendHeader() 0 12 4
A calcParity() 0 11 4
A checkModeNum() 0 8 4
A estimateBitsModeNum() 0 18 3
A lookAnTable() 0 3 2
A checkModeAn() 0 8 3
A estimateBitsModeAn() 0 8 2
A estimateBitsMode8() 0 3 1
A estimateBitsModeKanji() 0 3 1
B checkModeKanji() 0 12 7
C check() 0 26 7
C estimateBitStreamSize() 0 37 8
A estimateVersion() 0 13 3
C lengthOfCode() 0 49 11
A createBitStream() 0 9 2
B convertData() 0 23 6
B appendPaddingBit() 0 24 6
A mergeBitStream() 0 8 2
A getBitStream() 0 4 1
A getByteStream() 0 4 1
A allocate() 0 3 1
A newFromNum() 8 13 3
A newFromBytes() 9 17 4
A appendBitstream() 0 9 4
A appendNum() 0 7 2
A appendBytes() 0 7 2
B bitstreamToByte() 10 28 6
A qrstrset() 0 4 3
A getDataLength() 0 3 1
A getECCLength() 0 3 1
A getWidth() 0 3 1
A getRemainder() 0 3 1
A getMinimumVersion() 0 9 3
A lengthIndicator() 7 13 4
B maximumWords() 7 18 5
A getEccSpec() 0 23 3
A putAlignmentMarker() 3 15 2
C putAlignmentPattern() 0 34 7
A getVersionPattern() 0 6 3
B getFormatInfo() 0 9 5
A putFinderPattern() 3 15 2
C createFrame() 12 59 9
B newFrame() 0 12 5
A rsBlockNum() 0 3 1
A rsBlockNum1() 0 3 1
A rsDataCodes1() 0 3 1
A rsEccCodes1() 0 3 1
A rsBlockNum2() 0 3 1
A rsDataCodes2() 0 3 1
A rsEccCodes2() 0 3 1
A rsDataLength() 0 3 1
A rsEccLength() 0 3 1
B init_rs() 0 12 8
A modnn() 0 7 2
C init_rs_char() 0 78 19
B encode_rs_char() 0 34 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like QRcode 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 QRcode, and based on these observations, apply Extract Interface, too.

1
<?php
2
//============================================================+
3
// File name   : qrcode.php
4
// Begin       : 2010-03-22
5
// Last Update : 2010-03-30
6
// Version     : 1.0.003
7
// License     : GNU LGPL v.3 (http://www.gnu.org/copyleft/lesser.html)
8
// 	----------------------------------------------------------------------------
9
//
10
// 	This library is free software; you can redistribute it and/or
11
// 	modify it under the terms of the GNU Lesser General Public
12
// 	License as published by the Free Software Foundation; either
13
// 	version 3 of the License, or any later version.
14
//
15
// 	This library is distributed in the hope that it will be useful,
16
// 	but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
// 	Lesser General Public License for more details.
19
//
20
// 	You should have received a copy of the GNU Lesser General Public
21
// 	License along with this library; if not, write to the Free Software
22
// 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
//  or browse http://www.gnu.org/copyleft/lesser.html
24
//
25
//  ----------------------------------------------------------------------------
26
//
27
// DESCRIPTION :
28
//
29
// Class to create QR-code arrays for TCPDF class.
30
// QR Code symbol is a 2D barcode that can be scanned by
31
// handy terminals such as a mobile phone with CCD.
32
// The capacity of QR Code is up to 7000 digits or 4000
33
// characters, and has high robustness.
34
// This class supports QR Code model 2, described in
35
// JIS (Japanese Industrial Standards) X0510:2004
36
// or ISO/IEC 18004.
37
// Currently the following features are not supported:
38
// ECI and FNC1 mode, Micro QR Code, QR Code model 1,
39
// Structured mode.
40
//
41
// This class is derived from the following projects:
42
// ---------------------------------------------------------
43
// "PHP QR Code encoder"
44
// License: GNU-LGPLv3
45
// Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
46
// http://phpqrcode.sourceforge.net/
47
// https://sourceforge.net/projects/phpqrcode/
48
//
49
// The "PHP QR Code encoder" is based on
50
// "C libqrencode library" (ver. 3.1.1)
51
// License: GNU-LGPL 2.1
52
// Copyright (C) 2006-2010 by Kentaro Fukuchi
53
// http://megaui.net/fukuchi/works/qrencode/index.en.html
54
//
55
// Reed-Solomon code encoder is written by Phil Karn, KA9Q.
56
// Copyright (C) 2002-2006 Phil Karn, KA9Q
57
//
58
// QR Code is registered trademark of DENSO WAVE INCORPORATED
59
// http://www.denso-wave.com/qrcode/index-e.html
60
// ---------------------------------------------------------
61
//
62
// Author: Nicola Asuni
63
//
64
// (c) Copyright 2010:
65
//               Nicola Asuni
66
//               Tecnick.com S.r.l.
67
//               Via della Pace, 11
68
//               09044 Quartucciu (CA)
69
//               ITALY
70
//               www.tecnick.com
71
//               [email protected]
72
//============================================================+
73
74
/**
75
 * Class to create QR-code arrays for TCPDF class.
76
 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
77
 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
78
 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
79
 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
80
 *
81
 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
82
 * Please read comments on this class source file for full copyright and license information.
83
 *
84
 * @package com.tecnick.tcpdf
85
 * @abstract Class for generating QR-code array for TCPDF.
86
 * @author Nicola Asuni
87
 * @copyright 2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - [email protected]
88
 * @link http://www.tcpdf.org
89
 * @license http://www.gnu.org/copyleft/lesser.html LGPL
90
 * @version 1.0.003
91
 */
92
93
// definitions
94
if ( ! defined('QRCODEDEFS')) {
95
96
	/**
97
	 * Indicate that definitions for this class are set
98
	 */
99
	define('QRCODEDEFS', true);
100
101
	// -----------------------------------------------------
102
103
	// Encoding modes (characters which can be encoded in QRcode)
104
105
	/**
106
	 * Encoding mode
107
	 */
108
	define('QR_MODE_NL', -1);
109
110
	/**
111
	 * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
112
	 */
113
	define('QR_MODE_NM', 0);
114
115
	/**
116
	 * Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode.
117
	 */
118
	define('QR_MODE_AN', 1);
119
120
	/**
121
	 * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
122
	 */
123
	define('QR_MODE_8B', 2);
124
125
	/**
126
	 * Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode.
127
	 */
128
	define('QR_MODE_KJ', 3);
129
130
	/**
131
	 * Encoding mode STRUCTURED (currently unsupported)
132
	 */
133
	define('QR_MODE_ST', 4);
134
135
	// -----------------------------------------------------
136
137
	// Levels of error correction.
138
	// QRcode has a function of an error correcting for miss reading that white is black.
139
	// Error correcting is defined in 4 level as below.
140
141
	/**
142
	 * Error correction level L : About 7% or less errors can be corrected.
143
	 */
144
	define('QR_ECLEVEL_L', 0);
145
146
	/**
147
	 * Error correction level M : About 15% or less errors can be corrected.
148
	 */
149
	define('QR_ECLEVEL_M', 1);
150
151
	/**
152
	 * Error correction level Q : About 25% or less errors can be corrected.
153
	 */
154
	define('QR_ECLEVEL_Q', 2);
155
156
	/**
157
	 * Error correction level H : About 30% or less errors can be corrected.
158
	 */
159
	define('QR_ECLEVEL_H', 3);
160
161
	// -----------------------------------------------------
162
163
	// Version. Size of QRcode is defined as version.
164
	// Version is from 1 to 40.
165
	// Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
166
	// So version 40 is 177*177 matrix.
167
168
	/**
169
	 * Maximum QR Code version.
170
	 */
171
	define('QRSPEC_VERSION_MAX', 40);
172
173
	/**
174
	 * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
175
	 */
176
	define('QRSPEC_WIDTH_MAX', 177);
177
178
	// -----------------------------------------------------
179
180
	/**
181
	 * Matrix index to get width from $capacity array.
182
	 */
183
	define('QRCAP_WIDTH',    0);
184
185
	/**
186
	 * Matrix index to get number of words from $capacity array.
187
	 */
188
	define('QRCAP_WORDS',    1);
189
190
	/**
191
	 * Matrix index to get remainder from $capacity array.
192
	 */
193
	define('QRCAP_REMINDER', 2);
194
195
	/**
196
	 * Matrix index to get error correction level from $capacity array.
197
	 */
198
	define('QRCAP_EC',       3);
199
200
	// -----------------------------------------------------
201
202
	// Structure (currently usupported)
203
204
	/**
205
	 * Number of header bits for structured mode
206
	 */
207
	define('STRUCTURE_HEADER_BITS',  20);
208
209
	/**
210
	 * Max number of symbols for structured mode
211
	 */
212
	define('MAX_STRUCTURED_SYMBOLS', 16);
213
214
	// -----------------------------------------------------
215
216
	// Masks
217
218
	/**
219
	 * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
220
	 */
221
	define('N1',  3);
222
223
	/**
224
	 * Down point base value for case 2 mask pattern (module block of same color)
225
	 */
226
	define('N2',  3);
227
228
	/**
229
	 * Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column)
230
	 */
231
	define('N3', 40);
232
233
	/**
234
	 * Down point base value for case 4 mask pattern (ration of dark modules in whole)
235
	 */
236
	define('N4', 10);
237
238
	// -----------------------------------------------------
239
240
	// Optimization settings
241
242
	/**
243
	 * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
244
	 */
245
	define('QR_FIND_BEST_MASK', true);
246
247
	/**
248
	 * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
249
	 */
250
	define('QR_FIND_FROM_RANDOM', 2);
251
252
	/**
253
	 * when QR_FIND_BEST_MASK === false
254
	 */
255
	define('QR_DEFAULT_MASK', 2);
256
257
	// -----------------------------------------------------
258
259
} // end of definitions
260
261
// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
262
263
if (!class_exists('QRcode', false)) {
264
265
	// for compaibility with PHP4
266
	if (!function_exists('str_split')) {
267
    	/**
268
    	 * Convert a string to an array (needed for PHP4 compatibility)
269
    	 * @param string $string The input string.
270
    	 * @param int $split_length Maximum length of the chunk.
271
    	 * @return  string[] the optional split_length  parameter is specified, the returned array will be broken down into chunks with each being split_length  in length, otherwise each chunk will be one character in length. FALSE is returned if split_length is less than 1. If the split_length length exceeds the length of string , the entire string is returned as the first (and only) array element.
272
    	 */
273
		function str_split($string, $split_length=1) {
274
			if ((strlen($string) > $split_length) OR (!$split_length)) {
275
				do {
276
					$c = strlen($string);
277
					$parts[] = substr($string, 0, $split_length);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$parts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $parts = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
278
					$string = substr($string, $split_length);
279
				} while ($string !== false);
280
			} else {
281
				$parts = array($string);
282
			}
283
			return $parts;
284
		}
285
	}
286
287
	// #####################################################
288
289
	/**
290
	 * Class to create QR-code arrays for TCPDF class.
291
	 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
292
	 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
293
	 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
294
	 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
295
	 *
296
	 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
297
	 * Please read comments on this class source file for full copyright and license information.
298
	 *
299
	 * @name QRcode
300
	 * @package com.tecnick.tcpdf
301
	 * @abstract Class for generating QR-code array for TCPDF.
302
	 * @author Nicola Asuni
303
	 * @copyright 2010 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - [email protected]
304
	 * @link http://www.tcpdf.org
305
	 * @license http://www.gnu.org/copyleft/lesser.html LGPL
306
	 * @version 1.0.002
307
	 */
308
	class QRcode {
309
310
		/**
311
		 * @var barcode array to be returned which is readable by TCPDF
312
		 * @access protected
313
		 */
314
		protected $barcode_array = array();
315
316
		/**
317
		 * @var QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
318
		 * @access protected
319
		 */
320
		protected $version = 0;
321
322
		/**
323
		 * @var Levels of error correction. See definitions for possible values.
324
		 * @access protected
325
		 */
326
		protected $level = QR_ECLEVEL_L;
327
328
		/**
329
		 * @var Encoding mode
330
		 * @access protected
331
		 */
332
		protected $hint = QR_MODE_8B;
333
334
		/**
335
		 * @var if true the input string will be converted to uppercase
336
		 * @access protected
337
		 */
338
		protected $casesensitive = true;
339
340
		/**
341
		 * @var structured QR code (not supported yet)
342
		 * @access protected
343
		 */
344
		protected $structured = 0;
345
346
		/**
347
		 * @var mask data
348
		 * @access protected
349
		 */
350
		protected $data;
351
352
		// FrameFiller
353
354
		/**
355
		 * @var width
356
		 * @access protected
357
		 */
358
		protected $width;
359
360
		/**
361
		 * @var frame
362
		 * @access protected
363
		 */
364
		protected $frame;
365
366
		/**
367
		 * @var X position of bit
368
		 * @access protected
369
		 */
370
		protected $x;
371
372
		/**
373
		 * @var Y position of bit
374
		 * @access protected
375
		 */
376
		protected $y;
377
378
		/**
379
		 * @var direction
380
		 * @access protected
381
		 */
382
		protected $dir;
383
384
		/**
385
		 * @var single bit
386
		 * @access protected
387
		 */
388
		protected $bit;
389
390
		// ---- QRrawcode ----
391
392
		/**
393
		 * @var data code
394
		 * @access protected
395
		 */
396
		protected $datacode = array();
397
398
		/**
399
		 * @var error correction code
400
		 * @access protected
401
		 */
402
		protected $ecccode = array();
403
404
		/**
405
		 * @var blocks
406
		 * @access protected
407
		 */
408
		protected $blocks;
409
410
		/**
411
		 * @var Reed-Solomon blocks
412
		 * @access protected
413
		 */
414
		protected $rsblocks = array(); //of RSblock
415
416
		/**
417
		 * @var counter
418
		 * @access protected
419
		 */
420
		protected $count;
421
422
		/**
423
		 * @var data length
424
		 * @access protected
425
		 */
426
		protected $dataLength;
427
428
		/**
429
		 * @var error correction length
430
		 * @access protected
431
		 */
432
		protected $eccLength;
433
434
		/**
435
		 * @var b1
436
		 * @access protected
437
		 */
438
		protected $b1;
439
440
		// ---- QRmask ----
441
442
		/**
443
		 * @var run length
444
		 * @access protected
445
		 */
446
		protected $runLength = array();
447
448
		// ---- QRsplit ----
449
450
		/**
451
		 * @var input data string
452
		 * @access protected
453
		 */
454
		protected $dataStr = '';
455
456
		/**
457
		 * @var input items
458
		 * @access protected
459
		 */
460
		protected $items;
461
462
		// Reed-Solomon items
463
464
		/**
465
		 * @var Reed-Solomon items
466
		 * @access protected
467
		 */
468
		protected $rsitems = array();
469
470
		/**
471
		 * @var array of frames
472
		 * @access protected
473
		 */
474
		protected $frames = array();
475
476
		/**
477
		 * @var alphabet-numeric convesion table
478
		 * @access protected
479
		 */
480
		protected $anTable = array(
481
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
482
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
483
			36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
484
			 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, //
485
			-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
486
			25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
487
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
488
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  //
489
			);
490
491
		/**
492
		 * @var array Table of the capacity of symbols
493
		 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
494
		 * @access protected
495
		 */
496
		protected $capacity = array(
497
			array(0, 0, 0, array(0, 0, 0, 0)), //
498
			array(21, 26, 0, array(7, 10, 13, 17)), //  1
499
			array(25, 44, 7, array(10, 16, 22, 28)), //
500
			array(29, 70, 7, array(15, 26, 36, 44)), //
501
			array(33, 100, 7, array(20, 36, 52, 64)), //
502
			array(37, 134, 7, array(26, 48, 72, 88)), //  5
503
			array(41, 172, 7, array(36, 64, 96, 112)), //
504
			array(45, 196, 0, array(40, 72, 108, 130)), //
505
			array(49, 242, 0, array(48, 88, 132, 156)), //
506
			array(53, 292, 0, array(60, 110, 160, 192)), //
507
			array(57, 346, 0, array(72, 130, 192, 224)), // 10
508
			array(61, 404, 0, array(80, 150, 224, 264)), //
509
			array(65, 466, 0, array(96, 176, 260, 308)), //
510
			array(69, 532, 0, array(104, 198, 288, 352)), //
511
			array(73, 581, 3, array(120, 216, 320, 384)), //
512
			array(77, 655, 3, array(132, 240, 360, 432)), // 15
513
			array(81, 733, 3, array(144, 280, 408, 480)), //
514
			array(85, 815, 3, array(168, 308, 448, 532)), //
515
			array(89, 901, 3, array(180, 338, 504, 588)), //
516
			array(93, 991, 3, array(196, 364, 546, 650)), //
517
			array(97, 1085, 3, array(224, 416, 600, 700)), // 20
518
			array(101, 1156, 4, array(224, 442, 644, 750)), //
519
			array(105, 1258, 4, array(252, 476, 690, 816)), //
520
			array(109, 1364, 4, array(270, 504, 750, 900)), //
521
			array(113, 1474, 4, array(300, 560, 810, 960)), //
522
			array(117, 1588, 4, array(312, 588, 870, 1050)), // 25
523
			array(121, 1706, 4, array(336, 644, 952, 1110)), //
524
			array(125, 1828, 4, array(360, 700, 1020, 1200)), //
525
			array(129, 1921, 3, array(390, 728, 1050, 1260)), //
526
			array(133, 2051, 3, array(420, 784, 1140, 1350)), //
527
			array(137, 2185, 3, array(450, 812, 1200, 1440)), // 30
528
			array(141, 2323, 3, array(480, 868, 1290, 1530)), //
529
			array(145, 2465, 3, array(510, 924, 1350, 1620)), //
530
			array(149, 2611, 3, array(540, 980, 1440, 1710)), //
531
			array(153, 2761, 3, array(570, 1036, 1530, 1800)), //
532
			array(157, 2876, 0, array(570, 1064, 1590, 1890)), // 35
533
			array(161, 3034, 0, array(600, 1120, 1680, 1980)), //
534
			array(165, 3196, 0, array(630, 1204, 1770, 2100)), //
535
			array(169, 3362, 0, array(660, 1260, 1860, 2220)), //
536
			array(173, 3532, 0, array(720, 1316, 1950, 2310)), //
537
			array(177, 3706, 0, array(750, 1372, 2040, 2430))  // 40
538
		);
539
540
		/**
541
		 * @var array Length indicator
542
		 * @access protected
543
		 */
544
		protected $lengthTableBits = array(
545
			array(10, 12, 14),
546
			array(9, 11, 13),
547
			array(8, 16, 16),
548
			array(8, 10, 12)
549
		);
550
551
		/**
552
		 * @var array Table of the error correction code (Reed-Solomon block)
553
		 * See Table 12-16 (pp.30-36), JIS X0510:2004.
554
		 * @access protected
555
		 */
556
		protected $eccTable = array(
557
			array(array(0, 0), array(0, 0), array(0, 0), array(0, 0)), //
558
			array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), //  1
559
			array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), //
560
			array(array(1, 0), array(1, 0), array(2, 0), array(2, 0)), //
561
			array(array(1, 0), array(2, 0), array(2, 0), array(4, 0)), //
562
			array(array(1, 0), array(2, 0), array(2, 2), array(2, 2)), //  5
563
			array(array(2, 0), array(4, 0), array(4, 0), array(4, 0)), //
564
			array(array(2, 0), array(4, 0), array(2, 4), array(4, 1)), //
565
			array(array(2, 0), array(2, 2), array(4, 2), array(4, 2)), //
566
			array(array(2, 0), array(3, 2), array(4, 4), array(4, 4)), //
567
			array(array(2, 2), array(4, 1), array(6, 2), array(6, 2)), // 10
568
			array(array(4, 0), array(1, 4), array(4, 4), array(3, 8)), //
569
			array(array(2, 2), array(6, 2), array(4, 6), array(7, 4)), //
570
			array(array(4, 0), array(8, 1), array(8, 4), array(12, 4)), //
571
			array(array(3, 1), array(4, 5), array(11, 5), array(11, 5)), //
572
			array(array(5, 1), array(5, 5), array(5, 7), array(11, 7)), // 15
573
			array(array(5, 1), array(7, 3), array(15, 2), array(3, 13)), //
574
			array(array(1, 5), array(10, 1), array(1, 15), array(2, 17)), //
575
			array(array(5, 1), array(9, 4), array(17, 1), array(2, 19)), //
576
			array(array(3, 4), array(3, 11), array(17, 4), array(9, 16)), //
577
			array(array(3, 5), array(3, 13), array(15, 5), array(15, 10)), // 20
578
			array(array(4, 4), array(17, 0), array(17, 6), array(19, 6)), //
579
			array(array(2, 7), array(17, 0), array(7, 16), array(34, 0)), //
580
			array(array(4, 5), array(4, 14), array(11, 14), array(16, 14)), //
581
			array(array(6, 4), array(6, 14), array(11, 16), array(30, 2)), //
582
			array(array(8, 4), array(8, 13), array(7, 22), array(22, 13)), // 25
583
			array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), //
584
			array(array(8, 4), array(22, 3), array(8, 26), array(12, 28)), //
585
			array(array(3, 10), array(3, 23), array(4, 31), array(11, 31)), //
586
			array(array(7, 7), array(21, 7), array(1, 37), array(19, 26)), //
587
			array(array(5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
588
			array(array(13, 3), array(2, 29), array(42, 1), array(23, 28)), //
589
			array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), //
590
			array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), //
591
			array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), //
592
			array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35
593
			array(array(6, 14), array(6, 34), array(46, 10), array(2, 64)), //
594
			array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), //
595
			array(array(4, 18), array(13, 32), array(48, 14), array(42, 32)), //
596
			array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), //
597
			array(array(19, 6), array(18, 31), array(34, 34), array(20, 61))  // 40
598
		);
599
600
		/**
601
		 * @var array Positions of alignment patterns.
602
		 * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them.
603
		 * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
604
		 * @access protected
605
		 */
606
		protected $alignmentPattern = array(
607
			array(0, 0),
608
			array(0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), //  1- 5
609
			array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), //  6-10
610
			array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
611
			array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
612
			array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
613
			array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
614
			array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
615
			array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58)  // 35-40
616
		);
617
618
		/**
619
		 * @var array Version information pattern (BCH coded).
620
		 * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
621
		 * size: [QRSPEC_VERSION_MAX - 6]
622
		 * @access protected
623
		 */
624
		protected $versionPattern = array(
625
			0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
626
			0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
627
			0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
628
			0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
629
			0x27541, 0x28c69
630
		);
631
632
		/**
633
		 * @var array Format information
634
		 * @access protected
635
		 */
636
		protected $formatInfo = array(
637
			array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
638
			array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
639
			array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
640
			array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)  //
641
		);
642
643
644
		// -------------------------------------------------
645
		// -------------------------------------------------
646
647
648
		/**
649
		 * This is the class constructor.
650
		 * Creates a QRcode object
651
		 * @param string $code code to represent using QRcode
652
		 * @param string $eclevel error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
653
		 * @access public
654
		 * @since 1.0.000
655
		 */
656
		public function __construct($code, $eclevel = 'L') {
657
			$barcode_array = array();
658
			if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
659
				return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
660
			}
661
			// set error correction level
662
			$this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
0 ignored issues
show
Documentation Bug introduced by
It seems like array_search($eclevel, array('L', 'M', 'Q', 'H')) of type false or integer is incompatible with the declared type object<Levels> of property $level.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
663
			if ($this->level === false) {
664
				$this->level = QR_ECLEVEL_L;
0 ignored issues
show
Documentation Bug introduced by
It seems like QR_ECLEVEL_L of type integer is incompatible with the declared type object<Levels> of property $level.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
665
			}
666
			if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
667
				return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
668
			}
669
			if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
670
				return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
671
			}
672
			$this->items = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type object<input> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
673
			$this->encodeString($code);
674
			$qrTab = $this->binarize($this->data);
675
			$size = count($qrTab);
676
			$barcode_array['num_rows'] = $size;
677
			$barcode_array['num_cols'] = $size;
678
			$barcode_array['bcode'] = array();
679
			foreach ($qrTab as $line) {
680
				$arrAdd = array();
681
				foreach (str_split($line) as $char) {
682
					$arrAdd[] = ($char == '1') ? 1 : 0;
683
				}
684
				$barcode_array['bcode'][] = $arrAdd;
685
			}
686
			$this->barcode_array = $barcode_array;
0 ignored issues
show
Documentation Bug introduced by
It seems like $barcode_array of type array<string,integer|array,{"bcode":"array"}> is incompatible with the declared type object<barcode> of property $barcode_array.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
687
		}
688
689
		/**
690
		 * Returns a barcode array which is readable by TCPDF
691
		 * @return array barcode array readable by TCPDF;
692
		 * @access public
693
		 */
694
		public function getBarcodeArray() {
695
			return $this->barcode_array;
696
		}
697
698
		/**
699
		 * Convert the frame in binary form
700
		 * @param array $frame array to binarize
701
		 * @return array frame in binary form
702
		 */
703
		protected function binarize($frame) {
704
			$len = count($frame);
705
			// the frame is square (width = height)
706
			foreach ($frame as &$frameLine) {
707
				for ($i = 0; $i < $len; $i++) {
708
					$frameLine[$i] = (ord($frameLine[$i]) & 1) ? '1' : '0';
709
				}
710
			}
711
			return $frame;
712
		}
713
714
		/**
715
		 * Encode the input string to QR code
716
		 * @param string $string input string to encode
717
		 */
718
		protected function encodeString($string) {
719
			$this->dataStr = $string;
0 ignored issues
show
Documentation Bug introduced by
It seems like $string of type string is incompatible with the declared type object<input> of property $dataStr.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
720
			if ( ! $this->casesensitive) {
721
				$this->toUpper();
722
			}
723
			$ret = $this->splitString();
724
			if ($ret < 0) {
725
				return NULL;
726
			}
727
			$this->encodeMask(-1);
728
		}
729
730
		/**
731
		 * Encode mask
732
		 * @param int $mask masking mode
733
		 */
734
		protected function encodeMask($mask) {
735
			$spec = array(0, 0, 0, 0, 0);
736
			$this->datacode = $this->getByteStream($this->items);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getByteStream($this->items) of type array is incompatible with the declared type object<data> of property $datacode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
737
			if (is_null($this->datacode)) {
738
				return NULL;
739
			}
740
			$spec = $this->getEccSpec($this->version, $this->level, $spec);
741
			$this->b1 = $this->rsBlockNum1($spec);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rsBlockNum1($spec) of type integer is incompatible with the declared type object<b1> of property $b1.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
742
			$this->dataLength = $this->rsDataLength($spec);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rsDataLength($spec) of type double is incompatible with the declared type object<data> of property $dataLength.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
743
			$this->eccLength = $this->rsEccLength($spec);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rsEccLength($spec) of type integer or double is incompatible with the declared type object<error> of property $eccLength.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
744
			$this->ecccode = array_fill(0, $this->eccLength, 0);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_fill(0, $this->eccLength, 0) of type array is incompatible with the declared type object<error> of property $ecccode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
745
			$this->blocks = $this->rsBlockNum($spec);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->rsBlockNum($spec) of type integer is incompatible with the declared type object<blocks> of property $blocks.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
746
			$ret = $this->init($spec);
747
			if ($ret < 0) {
748
				return NULL;
749
			}
750
			$this->count = 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like 0 of type integer is incompatible with the declared type object<counter> of property $count.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
751
			$this->width = $this->getWidth($this->version);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getWidth($this->version) of type integer is incompatible with the declared type object<width> of property $width.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
752
			$this->frame = $this->newFrame($this->version);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->newFrame($this->version) of type array is incompatible with the declared type object<frame> of property $frame.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
753
			$this->x = $this->width - 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->width - 1 of type integer is incompatible with the declared type object<X> of property $x.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
754
			$this->y = $this->width - 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->width - 1 of type integer is incompatible with the declared type object<Y> of property $y.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
755
			$this->dir = -1;
0 ignored issues
show
Documentation Bug introduced by
It seems like -1 of type integer is incompatible with the declared type object<direction> of property $dir.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
756
			$this->bit = -1;
0 ignored issues
show
Documentation Bug introduced by
It seems like -1 of type integer is incompatible with the declared type object<single> of property $bit.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
757
			// inteleaved data and ecc codes
758
			for ($i = 0; $i < ($this->dataLength + $this->eccLength); $i++) {
759
				$code = $this->getCode();
760
				$bit = 0x80;
761
				for ($j = 0; $j < 8; $j++) {
762
					$addr = $this->getNextPosition();
763
					$this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
0 ignored issues
show
Bug introduced by
It seems like $addr defined by $this->getNextPosition() on line 762 can also be of type null; however, QRcode::setFrameAt() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
764
					$bit = $bit >> 1;
765
				}
766
			}
767
			// remainder bits
768
			$j = $this->getRemainder($this->version);
769
			for ($i = 0; $i < $j; $i++) {
770
				$addr = $this->getNextPosition();
771
				$this->setFrameAt($addr, 0x02);
0 ignored issues
show
Bug introduced by
It seems like $addr defined by $this->getNextPosition() on line 770 can also be of type null; however, QRcode::setFrameAt() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
772
			}
773
			// masking
774
			$this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_fill(0, QRSPEC_WIDTH_MAX + 1, 0) of type array is incompatible with the declared type object<run> of property $runLength.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
775
			if ($mask < 0) {
776
				if (QR_FIND_BEST_MASK) {
777
					$masked = $this->mask($this->width, $this->frame, $this->level);
778
				} else {
779
					$masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
780
				}
781
			} else {
782
				$masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
783
			}
784
			if ($masked == NULL) {
785
				return NULL;
786
			}
787
			$this->data = $masked;
0 ignored issues
show
Documentation Bug introduced by
It seems like $masked of type integer or array is incompatible with the declared type object<mask> of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
788
		}
789
790
		// - - - - - - - - - - - - - - - - - - - - - - - - -
791
792
		// FrameFiller
793
794
		/**
795
		 * Set frame value at specified position
796
		 * @param array $at x,y position
797
		 * @param int $val value of the character to set
798
		 */
799
		protected function setFrameAt($at, $val) {
800
			$this->frame[$at['y']][$at['x']] = chr($val);
801
		}
802
803
		/**
804
		 * Get frame value at specified position
805
		 * @param array $at x,y position
806
		 * @return integer at specified position
807
		 */
808
		protected function getFrameAt($at) {
809
			return ord($this->frame[$at['y']][$at['x']]);
810
		}
811
812
		/**
813
		 * Return the next frame position
814
		 * @return array of x,y coordinates
815
		 */
816
		protected function getNextPosition() {
817
			do {
818
				if ($this->bit == -1) {
819
					$this->bit = 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like 0 of type integer is incompatible with the declared type object<single> of property $bit.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
820
					return array('x'=>$this->x, 'y'=>$this->y);
821
				}
822
				$x = $this->x;
823
				$y = $this->y;
824
				$w = $this->width;
825
				if ($this->bit == 0) {
826
					$x--;
827
					$this->bit++;
828
				} else {
829
					$x++;
830
					$y += $this->dir;
831
					$this->bit--;
832
				}
833
				if ($this->dir < 0) {
834
					if ($y < 0) {
835
						$y = 0;
836
						$x -= 2;
837
						$this->dir = 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like 1 of type integer is incompatible with the declared type object<direction> of property $dir.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
838
						if ($x == 6) {
839
							$x--;
840
							$y = 9;
841
						}
842
					}
843
				} else {
844
					if ($y == $w) {
845
						$y = $w - 1;
846
						$x -= 2;
847
						$this->dir = -1;
0 ignored issues
show
Documentation Bug introduced by
It seems like -1 of type integer is incompatible with the declared type object<direction> of property $dir.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
848
						if ($x == 6) {
849
							$x--;
850
							$y -= 8;
851
						}
852
					}
853
				}
854
				if (($x < 0) OR ($y < 0)) {
855
					return NULL;
856
				}
857
				$this->x = $x;
0 ignored issues
show
Documentation Bug introduced by
It seems like $x can also be of type integer or double. However, the property $x is declared as type object<X>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
858
				$this->y = $y;
859
			} while (ord($this->frame[$y][$x]) & 0x80);
860
			return array('x'=>$x, 'y'=>$y);
861
		}
862
863
		// - - - - - - - - - - - - - - - - - - - - - - - - -
864
865
		// QRrawcode
866
867
		/**
868
		 * Initialize code.
869
		 * @param array $spec array of ECC specification
870
		 * @return 0 in case of success, -1 in case of error
0 ignored issues
show
Documentation introduced by
The doc-type 0 could not be parsed: Unknown type name "0" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
871
		 */
872
		protected function init($spec) {
873
			$dl = $this->rsDataCodes1($spec);
874
			$el = $this->rsEccCodes1($spec);
875
			$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
876
			$blockNo = 0;
877
			$dataPos = 0;
878
			$eccPos = 0;
879
			$endfor = $this->rsBlockNum1($spec);
880 View Code Duplication
			for ($i = 0; $i < $endfor; ++$i) {
881
				$ecc = array_slice($this->ecccode, $eccPos);
882
				$this->rsblocks[$blockNo] = array();
883
				$this->rsblocks[$blockNo]['dataLength'] = $dl;
884
				$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
885
				$this->rsblocks[$blockNo]['eccLength'] = $el;
886
				$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
887
				$this->rsblocks[$blockNo]['ecc'] = $ecc;
888
				$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge(array_slice(...ode, 0, $eccPos), $ecc) of type array is incompatible with the declared type object<error> of property $ecccode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
889
				$dataPos += $dl;
890
				$eccPos += $el;
891
				$blockNo++;
892
			}
893
			if ($this->rsBlockNum2($spec) == 0) {
894
				return 0;
895
			}
896
			$dl = $this->rsDataCodes2($spec);
897
			$el = $this->rsEccCodes2($spec);
898
			$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
899
			if ($rs == NULL) {
900
				return -1;
901
			}
902
			$endfor = $this->rsBlockNum2($spec);
903 View Code Duplication
			for ($i = 0; $i < $endfor; ++$i) {
904
				$ecc = array_slice($this->ecccode, $eccPos);
905
				$this->rsblocks[$blockNo] = array();
906
				$this->rsblocks[$blockNo]['dataLength'] = $dl;
907
				$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
908
				$this->rsblocks[$blockNo]['eccLength'] = $el;
909
				$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
910
				$this->rsblocks[$blockNo]['ecc'] = $ecc;
911
				$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
912
				$dataPos += $dl;
913
				$eccPos += $el;
914
				$blockNo++;
915
			}
916
			return 0;
917
		}
918
919
		/**
920
		 * Return Reed-Solomon block code.
921
		 * @return array rsblocks
922
		 */
923
		protected function getCode() {
924
			if ($this->count < $this->dataLength) {
925
				$row = $this->count % $this->blocks;
926
				$col = $this->count / $this->blocks;
927
				if ($col >= $this->rsblocks[0]['dataLength']) {
928
					$row += $this->b1;
929
				}
930
				$ret = $this->rsblocks[$row]['data'][$col];
931
			} elseif ($this->count < $this->dataLength + $this->eccLength) {
932
				$row = ($this->count - $this->dataLength) % $this->blocks;
933
				$col = ($this->count - $this->dataLength) / $this->blocks;
934
				$ret = $this->rsblocks[$row]['ecc'][$col];
935
			} else {
936
				return 0;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 0; (integer) is incompatible with the return type documented by QRcode::getCode of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
937
			}
938
			$this->count++;
939
			return $ret;
940
		}
941
942
		// - - - - - - - - - - - - - - - - - - - - - - - - -
943
944
		// QRmask
945
946
		/**
947
		 * Write Format Information on frame and returns the number of black bits
948
		 * @param int $width frame width
949
		 * @param integer $frame frame
950
		 * @param integer $mask masking mode
951
		 * @param int $level error correction level
952
		 * @return int blacks
953
		 */
954
		 protected function writeFormatInformation($width, &$frame, $mask, $level) {
955
			$blacks = 0;
956
			$format = $this->getFormatInfo($mask, $level);
0 ignored issues
show
Documentation introduced by
$mask is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
957 View Code Duplication
			for ($i = 0; $i < 8; ++$i) {
958
				if ($format & 1) {
959
					$blacks += 2;
960
					$v = 0x85;
961
				} else {
962
					$v = 0x84;
963
				}
964
				$frame[8][$width - 1 - $i] = chr($v);
965
				if ($i < 6) {
966
					$frame[$i][8] = chr($v);
967
				} else {
968
					$frame[$i + 1][8] = chr($v);
969
				}
970
				$format = $format >> 1;
971
			}
972 View Code Duplication
			for ($i = 0; $i < 7; ++$i) {
973
			if ($format & 1) {
974
				$blacks += 2;
975
				$v = 0x85;
976
			} else {
977
				$v = 0x84;
978
			}
979
			$frame[$width - 7 + $i][8] = chr($v);
980
			if ($i == 0) {
981
				$frame[8][7] = chr($v);
982
			} else {
983
				$frame[8][6 - $i] = chr($v);
984
			}
985
			$format = $format >> 1;
986
			}
987
			return $blacks;
988
		}
989
990
		/**
991
		 * mask0
992
		 * @param int $x X position
993
		 * @param int $y Y position
994
		 * @return int mask
995
		 */
996
		 protected function mask0($x, $y) {
997
			return ($x + $y) & 1;
998
		}
999
1000
		/**
1001
		 * mask1
1002
		 * @param int $x X position
1003
		 * @param int $y Y position
1004
		 * @return int mask
1005
		 */
1006
		 protected function mask1($x, $y) {
0 ignored issues
show
Unused Code introduced by
The parameter $x is not used and could be removed.

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

Loading history...
1007
			return ($y & 1);
1008
		}
1009
1010
		/**
1011
		 * mask2
1012
		 * @param int $x X position
1013
		 * @param int $y Y position
1014
		 * @return int mask
1015
		 */
1016
		 protected function mask2($x, $y) {
0 ignored issues
show
Unused Code introduced by
The parameter $y is not used and could be removed.

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

Loading history...
1017
			return ($x % 3);
1018
		}
1019
1020
		/**
1021
		 * mask3
1022
		 * @param int $x X position
1023
		 * @param int $y Y position
1024
		 * @return int mask
1025
		 */
1026
		 protected function mask3($x, $y) {
1027
			return ($x + $y) % 3;
1028
		}
1029
1030
		/**
1031
		 * mask4
1032
		 * @param int $x X position
1033
		 * @param int $y Y position
1034
		 * @return int mask
1035
		 */
1036
		 protected function mask4($x, $y) {
1037
			return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1038
		}
1039
1040
		/**
1041
		 * mask5
1042
		 * @param int $x X position
1043
		 * @param int $y Y position
1044
		 * @return int mask
1045
		 */
1046
		 protected function mask5($x, $y) {
1047
			return (($x * $y) & 1) + ($x * $y) % 3;
1048
		}
1049
1050
		/**
1051
		 * mask6
1052
		 * @param int $x X position
1053
		 * @param int $y Y position
1054
		 * @return int mask
1055
		 */
1056
		 protected function mask6($x, $y) {
1057
			return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1058
		}
1059
1060
		/**
1061
		 * mask7
1062
		 * @param int $x X position
1063
		 * @param int $y Y position
1064
		 * @return int mask
1065
		 */
1066
		 protected function mask7($x, $y) {
1067
			return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1068
		}
1069
1070
		/**
1071
		 * Return bitmask
1072
		 * @param int $maskNo mask number
1073
		 * @param int $width width
1074
		 * @param integer $frame frame
1075
		 * @return array bitmask
1076
		 */
1077
		protected function generateMaskNo($maskNo, $width, $frame) {
1078
			$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1079
			for ($y = 0; $y < $width; ++$y) {
1080
				for ($x = 0; $x < $width; ++$x) {
1081
					if (ord($frame[$y][$x]) & 0x80) {
1082
						$bitMask[$y][$x] = 0;
1083
					} else {
1084
						$maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1085
						$bitMask[$y][$x] = ($maskFunc == 0) ? 1 : 0;
1086
					}
1087
				}
1088
			}
1089
			return $bitMask;
1090
		}
1091
1092
		/**
1093
		 * makeMaskNo
1094
		 * @param int $maskNo
1095
		 * @param int $width
1096
		 * @param int $s
1097
		 * @param int $d
1098
		 * @param boolean $maskGenOnly
1099
		 * @return int b
1100
		 */
1101
		 protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) {
1102
			$b = 0;
1103
			$bitMask = array();
1104
			$bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
0 ignored issues
show
Unused Code introduced by
The call to QRcode::generateMaskNo() has too many arguments starting with $d.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1105
			if ($maskGenOnly) {
1106
				return;
1107
			}
1108
			$d = $s;
1109
			for ($y = 0; $y < $width; ++$y) {
1110
				for ($x = 0; $x < $width; ++$x) {
1111
					if ($bitMask[$y][$x] == 1) {
1112
						$d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);
1113
					}
1114
					$b += (int)(ord($d[$y][$x]) & 1);
1115
				}
1116
			}
1117
			return $b;
1118
		}
1119
1120
		/**
1121
		 * makeMask
1122
		 * @param int $width
1123
		 * @param array $frame
1124
		 * @param int $maskNo
1125
		 * @param int $level
1126
		 * @return array mask
1127
		 */
1128
		 protected function makeMask($width, $frame, $maskNo, $level) {
1129
			$masked = array_fill(0, $width, str_repeat("\0", $width));
1130
			$this->makeMaskNo($maskNo, $width, $frame, $masked);
0 ignored issues
show
Documentation introduced by
$frame is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$masked is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1131
			$this->writeFormatInformation($width, $masked, $maskNo, $level);
1132
			return $masked;
1133
		}
1134
1135
		/**
1136
		 * calcN1N3
1137
		 * @param int $length
1138
		 * @return int demerit
1139
		 */
1140
		 protected function calcN1N3($length) {
1141
			$demerit = 0;
1142
			for ($i = 0; $i < $length; ++$i) {
1143
				if ($this->runLength[$i] >= 5) {
1144
					$demerit += (N1 + ($this->runLength[$i] - 5));
1145
				}
1146
				if ($i & 1) {
1147
					if (($i >= 3) AND ($i < ($length - 2)) AND ($this->runLength[$i] % 3 == 0)) {
1148
						$fact = (int)($this->runLength[$i] / 3);
1149
						if (($this->runLength[$i - 2] == $fact)
1150
							AND ($this->runLength[$i - 1] == $fact)
1151
							AND ($this->runLength[$i + 1] == $fact)
1152
							AND ($this->runLength[$i + 2] == $fact)) {
1153
							if (($this->runLength[$i - 3] < 0) OR ($this->runLength[$i - 3] >= (4 * $fact))) {
1154
								$demerit += N3;
1155
							} elseif ((($i + 3) >= $length) OR ($this->runLength[$i + 3] >= (4 * $fact))) {
1156
								$demerit += N3;
1157
							}
1158
						}
1159
					}
1160
				}
1161
			}
1162
			return $demerit;
1163
		}
1164
1165
		/**
1166
		 * evaluateSymbol
1167
		 * @param int $width
1168
		 * @param array $frame
1169
		 * @return int demerit
1170
		 */
1171
		 protected function evaluateSymbol($width, $frame) {
1172
			$head = 0;
1173
			$demerit = 0;
1174
			for ($y = 0; $y < $width; ++$y) {
1175
				$head = 0;
1176
				$this->runLength[0] = 1;
1177
				$frameY = $frame[$y];
1178
				if ($y > 0) {
1179
					$frameYM = $frame[$y - 1];
1180
				}
1181
				for ($x = 0; $x < $width; ++$x) {
1182
					if (($x > 0) AND ($y > 0)) {
1183
						$b22 = ord($frameY[$x]) & ord($frameY[$x - 1]) & ord($frameYM[$x]) & ord($frameYM[$x - 1]);
0 ignored issues
show
Bug introduced by
The variable $frameYM does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1184
						$w22 = ord($frameY[$x]) | ord($frameY[$x - 1]) | ord($frameYM[$x]) | ord($frameYM[$x - 1]);
1185
						if (($b22 | ($w22 ^ 1)) & 1) {
1186
							$demerit += N2;
1187
						}
1188
					}
1189
					if (($x == 0) AND (ord($frameY[$x]) & 1)) {
1190
						$this->runLength[0] = -1;
1191
						$head = 1;
1192
						$this->runLength[$head] = 1;
1193 View Code Duplication
					} elseif ($x > 0) {
1194
						if ((ord($frameY[$x]) ^ ord($frameY[$x - 1])) & 1) {
1195
							$head++;
1196
							$this->runLength[$head] = 1;
1197
						} else {
1198
							$this->runLength[$head]++;
1199
						}
1200
					}
1201
				}
1202
				$demerit += $this->calcN1N3($head + 1);
1203
			}
1204
			for ($x = 0; $x < $width; ++$x) {
1205
				$head = 0;
1206
				$this->runLength[0] = 1;
1207
				for ($y = 0; $y < $width; ++$y) {
1208
					if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
1209
						$this->runLength[0] = -1;
1210
						$head = 1;
1211
						$this->runLength[$head] = 1;
1212 View Code Duplication
					} elseif ($y > 0) {
1213
						if ((ord($frame[$y][$x]) ^ ord($frame[$y - 1][$x])) & 1) {
1214
							$head++;
1215
							$this->runLength[$head] = 1;
1216
						} else {
1217
							$this->runLength[$head]++;
1218
						}
1219
					}
1220
				}
1221
				$demerit += $this->calcN1N3($head + 1);
1222
			}
1223
			return $demerit;
1224
		}
1225
1226
		/**
1227
		 * mask
1228
		 * @param int $width
1229
		 * @param array $frame
1230
		 * @param int $level
1231
		 * @return array best mask
1232
		 */
1233
		 protected function mask($width, $frame, $level) {
1234
			$minDemerit = PHP_INT_MAX;
1235
			$bestMaskNum = 0;
1236
			$bestMask = array();
1237
			$checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1238
			if (QR_FIND_FROM_RANDOM !== false) {
1239
				$howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
1240
				for ($i = 0; $i < $howManuOut; ++$i) {
1241
					$remPos = rand(0, count($checked_masks) - 1);
1242
					unset($checked_masks[$remPos]);
1243
					$checked_masks = array_values($checked_masks);
1244
				}
1245
			}
1246
			$bestMask = $frame;
1247
			foreach ($checked_masks as $i) {
1248
				$mask = array_fill(0, $width, str_repeat("\0", $width));
1249
				$demerit = 0;
1250
				$blacks = 0;
1251
				$blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
0 ignored issues
show
Documentation introduced by
$frame is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$mask is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1252
				$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
1253
				$blacks  = (int)(100 * $blacks / ($width * $width));
1254
				$demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
1255
				$demerit += $this->evaluateSymbol($width, $mask);
0 ignored issues
show
Documentation introduced by
$mask is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1256
				if ($demerit < $minDemerit) {
1257
					$minDemerit = $demerit;
1258
					$bestMask = $mask;
1259
					$bestMaskNum = $i;
1260
				}
1261
			}
1262
			return $bestMask;
1263
		}
1264
1265
		// - - - - - - - - - - - - - - - - - - - - - - - - -
1266
1267
		// QRsplit
1268
1269
		/**
1270
		 * Return true if the character at specified position is a number
1271
		 * @param string $str string
1272
		 * @param int $pos characted position
1273
		 * @return boolean true of false
1274
		 */
1275
		 protected function isdigitat($str, $pos) {
1276
			if ($pos >= strlen($str)) {
1277
				return false;
1278
			}
1279
			return ((ord($str[$pos]) >= ord('0')) && (ord($str[$pos]) <= ord('9')));
1280
		}
1281
1282
		/**
1283
		 * Return true if the character at specified position is an alphanumeric character
1284
		 * @param string $str string
1285
		 * @param int $pos characted position
1286
		 * @return boolean true of false
1287
		 */
1288
		 protected function isalnumat($str, $pos) {
1289
			if ($pos >= strlen($str)) {
1290
				return false;
1291
			}
1292
			return ($this->lookAnTable(ord($str[$pos])) >= 0);
1293
		}
1294
1295
		/**
1296
		 * identifyMode
1297
		 * @param int $pos
1298
		 * @return int mode
1299
		 */
1300
		 protected function identifyMode($pos) {
1301
			if ($pos >= strlen($this->dataStr)) {
1302
				return QR_MODE_NL;
1303
			}
1304
			$c = $this->dataStr[$pos];
1305
			if ($this->isdigitat($this->dataStr, $pos)) {
1306
				return QR_MODE_NM;
1307
			} elseif ($this->isalnumat($this->dataStr, $pos)) {
1308
				return QR_MODE_AN;
1309
			} elseif ($this->hint == QR_MODE_KJ) {
1310
				if ($pos + 1 < strlen($this->dataStr)) {
1311
					$d = $this->dataStr[$pos + 1];
1312
					$word = (ord($c) << 8) | ord($d);
1313
					if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1314
						return QR_MODE_KJ;
1315
					}
1316
				}
1317
			}
1318
			return QR_MODE_8B;
1319
		}
1320
1321
		/**
1322
		 * eatNum
1323
		 * @return int run
1324
		 */
1325
		 protected function eatNum() {
1326
			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1327
			$p = 0;
1328
			while ($this->isdigitat($this->dataStr, $p)) {
1329
				$p++;
1330
			}
1331
			$run = $p;
1332
			$mode = $this->identifyMode($p);
1333 View Code Duplication
			if ($mode == QR_MODE_8B) {
1334
				$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1335
				+ $this->estimateBitsMode8(1)         // + 4 + l8
1336
				- $this->estimateBitsMode8($run + 1); // - 4 - l8
1337
				if ($dif > 0) {
1338
					return $this->eat8();
1339
				}
1340
			}
1341 View Code Duplication
			if ($mode == QR_MODE_AN) {
1342
				$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1343
				+ $this->estimateBitsModeAn(1)        // + 4 + la
1344
				- $this->estimateBitsModeAn($run + 1); // - 4 - la
1345
				if ($dif > 0) {
1346
					return $this->eatAn();
1347
				}
1348
			}
1349
			$this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->appendNewInputIte..._split($this->dataStr)) of type array<integer,null|array...stream":"array|null"}>> is incompatible with the declared type object<input> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1350
			return $run;
1351
		}
1352
1353
		/**
1354
		 * eatAn
1355
		 * @return int run
1356
		 */
1357
		 protected function eatAn() {
1358
			$la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1359
			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1360
			$p = 0;
1361
			while ($this->isalnumat($this->dataStr, $p)) {
1362
				if ($this->isdigitat($this->dataStr, $p)) {
1363
					$q = $p;
1364
					while ($this->isdigitat($this->dataStr, $q)) {
1365
						$q++;
1366
					}
1367
					$dif = $this->estimateBitsModeAn($p) // + 4 + la
1368
					+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1369
					- $this->estimateBitsModeAn($q); // - 4 - la
1370
					if ($dif < 0) {
1371
						break;
1372
					} else {
1373
						$p = $q;
1374
					}
1375
				} else {
1376
					$p++;
1377
				}
1378
			}
1379
			$run = $p;
1380
			if ( ! $this->isalnumat($this->dataStr, $p)) {
1381
				$dif = $this->estimateBitsModeAn($run) + 4 + $la
1382
				+ $this->estimateBitsMode8(1) // + 4 + l8
1383
				- $this->estimateBitsMode8($run + 1); // - 4 - l8
1384
				if ($dif > 0) {
1385
					return $this->eat8();
1386
				}
1387
			}
1388
			$this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->appendNewInputIte..._split($this->dataStr)) of type array<integer,null|array...stream":"array|null"}>> is incompatible with the declared type object<input> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1389
			return $run;
1390
		}
1391
1392
		/**
1393
		 * eatKanji
1394
		 * @return int run
1395
		 */
1396
		 protected function eatKanji() {
1397
			$p = 0;
1398
			while ($this->identifyMode($p) == QR_MODE_KJ) {
1399
				$p += 2;
1400
			}
1401
			$this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->appendNewInputIte..._split($this->dataStr)) of type array<integer,null|array...stream":"array|null"}>> is incompatible with the declared type object<input> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1402
			return $run;
0 ignored issues
show
Bug introduced by
The variable $run does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1403
		}
1404
1405
		/**
1406
		 * eat8
1407
		 * @return int run
1408
		 */
1409
		 protected function eat8() {
1410
			$la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1411
			$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1412
			$p = 1;
1413
			$dataStrLen = strlen($this->dataStr);
1414
			while ($p < $dataStrLen) {
1415
				$mode = $this->identifyMode($p);
1416
				if ($mode == QR_MODE_KJ) {
1417
					break;
1418
				}
1419
				if ($mode == QR_MODE_NM) {
1420
					$q = $p;
1421
					while ($this->isdigitat($this->dataStr, $q)) {
1422
						$q++;
1423
					}
1424
					$dif = $this->estimateBitsMode8($p) // + 4 + l8
1425
					+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1426
					- $this->estimateBitsMode8($q); // - 4 - l8
1427
					if ($dif < 0) {
1428
						break;
1429
					} else {
1430
						$p = $q;
1431
					}
1432
				} elseif ($mode == QR_MODE_AN) {
1433
					$q = $p;
1434
					while ($this->isalnumat($this->dataStr, $q)) {
1435
						$q++;
1436
					}
1437
					$dif = $this->estimateBitsMode8($p)  // + 4 + l8
1438
					+ $this->estimateBitsModeAn($q - $p) + 4 + $la
1439
					- $this->estimateBitsMode8($q); // - 4 - l8
1440
					if ($dif < 0) {
1441
						break;
1442
					} else {
1443
						$p = $q;
1444
					}
1445
				} else {
1446
					$p++;
1447
				}
1448
			}
1449
			$run = $p;
1450
			$this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->appendNewInputIte..._split($this->dataStr)) of type array<integer,null|array...stream":"array|null"}>> is incompatible with the declared type object<input> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1451
			return $run;
1452
		}
1453
1454
		/**
1455
		 * splitString
1456
		 */
1457
		 protected function splitString() {
1458
			while (strlen($this->dataStr) > 0) {
1459
				if ($this->dataStr == '') {
1460
					return 0;
1461
				}
1462
				$mode = $this->identifyMode(0);
1463
				switch ($mode) {
1464
					case QR_MODE_NM: {
1465
						$length = $this->eatNum();
1466
						break;
1467
					}
1468
					case QR_MODE_AN: {
1469
						$length = $this->eatAn();
1470
						break;
1471
					}
1472
					case QR_MODE_KJ: {
1473
						if ($hint == QR_MODE_KJ) {
0 ignored issues
show
Bug introduced by
The variable $hint does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1474
							$length = $this->eatKanji();
1475
						} else {
1476
							$length = $this->eat8();
1477
						}
1478
						break;
1479
					}
1480
					default: {
1481
						$length = $this->eat8();
1482
						break;
1483
					}
1484
				}
1485
				if ($length == 0) {
1486
					return 0;
1487
				}
1488
				if ($length < 0) {
1489
					return -1;
1490
				}
1491
				$this->dataStr = substr($this->dataStr, $length);
0 ignored issues
show
Documentation Bug introduced by
It seems like substr($this->dataStr, $length) of type string is incompatible with the declared type object<input> of property $dataStr.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1492
			}
1493
		}
1494
1495
		/**
1496
		 * toUpper
1497
		 */
1498
		 protected function toUpper() {
1499
			$stringLen = strlen($this->dataStr);
1500
			$p = 0;
1501
			while ($p < $stringLen) {
1502
				$mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
0 ignored issues
show
Unused Code introduced by
The call to QRcode::identifyMode() has too many arguments starting with $this->hint.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1503
				if ($mode == QR_MODE_KJ) {
1504
					$p += 2;
1505
				} else {
1506
					if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
1507
						$this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
1508
					}
1509
					$p++;
1510
				}
1511
			}
1512
			return $this->dataStr;
1513
		}
1514
1515
		// - - - - - - - - - - - - - - - - - - - - - - - - -
1516
1517
		// QRinputItem
1518
1519
		/**
1520
		 * newInputItem
1521
		 * @param int $mode
1522
		 * @param int $size
1523
		 * @param array $data
1524
		 * @param array $bstream
1525
		 * @return array input item
1526
		 */
1527
		 protected function newInputItem($mode, $size, $data, $bstream = null) {
1528
			$setData = array_slice($data, 0, $size);
1529
			if (count($setData) < $size) {
1530
				$setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1531
			}
1532
			if ( ! $this->check($mode, $size, $setData)) {
1533
				return NULL;
1534
			}
1535
			$inputitem = array();
1536
			$inputitem['mode'] = $mode;
1537
			$inputitem['size'] = $size;
1538
			$inputitem['data'] = $setData;
1539
			$inputitem['bstream'] = $bstream;
1540
			return $inputitem;
1541
		}
1542
1543
		/**
1544
		 * encodeModeNum
1545
		 * @param array $inputitem
1546
		 * @param int $version
1547
		 * @return array input item
1548
		 */
1549
		 protected function encodeModeNum($inputitem, $version) {
1550
			$words = (int)($inputitem['size'] / 3);
1551
			$inputitem['bstream'] = array();
1552
			$val = 0x1;
1553
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1554
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1555
			for ($i = 0; $i < $words; ++$i) {
1556
				$val  = (ord($inputitem['data'][$i * 3]) - ord('0')) * 100;
1557
				$val += (ord($inputitem['data'][$i * 3 + 1]) - ord('0')) * 10;
1558
				$val += (ord($inputitem['data'][$i * 3 + 2]) - ord('0'));
1559
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1560
			}
1561
			if ($inputitem['size'] - $words * 3 == 1) {
1562
				$val = ord($inputitem['data'][$words * 3]) - ord('0');
1563
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1564
			} elseif (($inputitem['size'] - ($words * 3)) == 2) {
1565
				$val  = (ord($inputitem['data'][$words * 3]) - ord('0')) * 10;
1566
				$val += (ord($inputitem['data'][$words * 3 + 1]) - ord('0'));
1567
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
1568
			}
1569
			return $inputitem;
1570
		}
1571
1572
		/**
1573
		 * encodeModeAn
1574
		 * @param array $inputitem
1575
		 * @param int $version
1576
		 * @return array input item
1577
		 */
1578
		 protected function encodeModeAn($inputitem, $version) {
1579
			$words = (int)($inputitem['size'] / 2);
1580
			$inputitem['bstream'] = array();
1581
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
1582
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']); //DEBUG
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1583
			for ($i = 0; $i < $words; ++$i) {
1584
				$val  = (int)$this->lookAnTable(ord($inputitem['data'][$i * 2])) * 45;
1585
				$val += (int)$this->lookAnTable(ord($inputitem['data'][$i * 2 + 1]));
1586
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1587
			}
1588
			if ($inputitem['size'] & 1) {
1589
				$val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
1590
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1591
			}
1592
			return $inputitem;
1593
		}
1594
1595
		/**
1596
		 * encodeMode8
1597
		 * @param array $inputitem
1598
		 * @param int $version
1599
		 * @return array input item
1600
		 */
1601
		 protected function encodeMode8($inputitem, $version) {
1602
			$inputitem['bstream'] = array();
1603
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
1604
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1605
			for ($i = 0; $i < $inputitem['size']; ++$i) {
1606
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1607
			}
1608
			return $inputitem;
1609
		}
1610
1611
		/**
1612
		 * encodeModeKanji
1613
		 * @param array $inputitem
1614
		 * @param int $version
1615
		 * @return array input item
1616
		 */
1617
		 protected function encodeModeKanji($inputitem, $version) {
1618
			$inputitem['bstream'] = array();
1619
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
1620
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1621
			for ($i = 0; $i < $inputitem['size']; $i += 2) {
1622
				$val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i + 1]);
1623
				if ($val <= 0x9ffc) {
1624
					$val -= 0x8140;
1625
				} else {
1626
					$val -= 0xc140;
1627
				}
1628
				$h = ($val >> 8) * 0xc0;
1629
				$val = ($val & 0xff) + $h;
1630
				$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1631
			}
1632
			return $inputitem;
1633
		}
1634
1635
		/**
1636
		 * encodeModeStructure
1637
		 * @param array $inputitem
1638
		 * @return array input item
1639
		 */
1640
		 protected function encodeModeStructure($inputitem) {
1641
			$inputitem['bstream'] = array();
1642
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
1643
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1644
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1645
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
0 ignored issues
show
Bug introduced by
It seems like $inputitem['bstream'] can also be of type integer; however, QRcode::appendNum() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1646
			return $inputitem;
1647
		}
1648
1649
		/**
1650
		 * encodeBitStream
1651
		 * @param array $inputitem
1652
		 * @param int $version
1653
		 * @return array input item
1654
		 */
1655
		 protected function encodeBitStream($inputitem, $version) {
1656
			$inputitem['bstream'] = array();
1657
			$words = $this->maximumWords($inputitem['mode'], $version);
1658
			if ($inputitem['size'] > $words) {
1659
				$st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
1660
				$st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1661
				$st1 = $this->encodeBitStream($st1, $version);
0 ignored issues
show
Bug introduced by
It seems like $st1 can also be of type null; however, QRcode::encodeBitStream() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1662
				$st2 = $this->encodeBitStream($st2, $version);
0 ignored issues
show
Bug introduced by
It seems like $st2 can also be of type null; however, QRcode::encodeBitStream() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1663
				$inputitem['bstream'] = array();
1664
				$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
0 ignored issues
show
Bug introduced by
It seems like $st1['bstream'] can also be of type double or integer; however, QRcode::appendBitstream() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1665
				$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
0 ignored issues
show
Bug introduced by
It seems like $st2['bstream'] can also be of type double or integer; however, QRcode::appendBitstream() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1666
			} else {
1667
				switch ($inputitem['mode']) {
1668
					case QR_MODE_NM: {
1669
						$inputitem = $this->encodeModeNum($inputitem, $version);
1670
						break;
1671
					}
1672
					case QR_MODE_AN: {
1673
						$inputitem = $this->encodeModeAn($inputitem, $version);
1674
						break;
1675
					}
1676
					case QR_MODE_8B: {
1677
						$inputitem = $this->encodeMode8($inputitem, $version);
1678
						break;
1679
					}
1680
					case QR_MODE_KJ: {
1681
						$inputitem = $this->encodeModeKanji($inputitem, $version);
1682
						break;
1683
					}
1684
					case QR_MODE_ST: {
1685
						$inputitem = $this->encodeModeStructure($inputitem);
1686
						break;
1687
					}
1688
					default: {
1689
						break;
1690
					}
1691
				}
1692
			}
1693
			return $inputitem;
1694
		}
1695
1696
		// - - - - - - - - - - - - - - - - - - - - - - - - -
1697
1698
		// QRinput
1699
1700
		/**
1701
		 * Append data to an input object.
1702
		 * The data is copied and appended to the input object.
1703
		 * @param array items input items
1704
		 * @param int $mode encoding mode.
1705
		 * @param int $size size of data (byte).
1706
		 * @param string[] $data array of input data.
1707
		 * @return items
1708
		 *
1709
		 */
1710
		protected function appendNewInputItem($items, $mode, $size, $data) {
1711
			$items[] = $this->newInputItem($mode, $size, $data);
1712
			return $items;
1713
		}
1714
1715
		/**
1716
		 * insertStructuredAppendHeader
1717
		 * @param array $items
1718
		 * @param int $size
1719
		 * @param int $index
1720
		 * @param int $parity
1721
		 * @return array items
1722
		 */
1723
		 protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1724
			if ($size > MAX_STRUCTURED_SYMBOLS) {
1725
				return -1;
1726
			}
1727
			if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1728
				return -1;
1729
			}
1730
			$buf = array($size, $index, $parity);
1731
			$entry = $this->newInputItem(QR_MODE_ST, 3, buf);
1732
			array_unshift($items, $entry);
1733
			return $items;
1734
		}
1735
1736
		/**
1737
		 * calcParity
1738
		 * @param array $items
1739
		 * @return int parity
1740
		 */
1741
		 protected function calcParity($items) {
1742
			$parity = 0;
1743
			foreach ($items as $item) {
1744
				if ($item['mode'] != QR_MODE_ST) {
1745
					for ($i = $item['size'] - 1; $i >= 0; --$i) {
1746
						$parity ^= $item['data'][$i];
1747
					}
1748
				}
1749
			}
1750
			return $parity;
1751
		}
1752
1753
		/**
1754
		 * checkModeNum
1755
		 * @param int $size
1756
		 * @param array $data
1757
		 * @return boolean true or false
1758
		 */
1759
		 protected function checkModeNum($size, $data) {
1760
			for ($i = 0; $i < $size; ++$i) {
1761
				if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))) {
1762
					return false;
1763
				}
1764
			}
1765
			return true;
1766
		}
1767
1768
		/**
1769
		 * estimateBitsModeNum
1770
		 * @param int $size
1771
		 * @return int number of bits
1772
		 */
1773
		 protected function estimateBitsModeNum($size) {
1774
			$w = (int)$size / 3;
1775
			$bits = $w * 10;
1776
			switch ($size - $w * 3) {
1777
				case 1: {
1778
					$bits += 4;
1779
					break;
1780
				}
1781
				case 2: {
1782
					$bits += 7;
1783
					break;
1784
				}
1785
				default: {
1786
					break;
1787
				}
1788
			}
1789
			return $bits;
1790
		}
1791
1792
		/**
1793
		 * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1794
		 * @param int $c character value
1795
		 * @return integer
1796
		 */
1797
		protected function lookAnTable($c) {
1798
			return (($c > 127) ?-1 : $this->anTable[$c]);
1799
		}
1800
1801
		/**
1802
		 * checkModeAn
1803
		 * @param int $size
1804
		 * @param array $data
1805
		 * @return boolean true or false
1806
		 */
1807
		 protected function checkModeAn($size, $data) {
1808
			for ($i = 0; $i < $size; ++$i) {
1809
				if ($this->lookAnTable(ord($data[$i])) == -1) {
1810
					return false;
1811
				}
1812
			}
1813
			return true;
1814
		}
1815
1816
		/**
1817
		 * estimateBitsModeAn
1818
		 * @param int $size
1819
		 * @return int number of bits
1820
		 */
1821
		 protected function estimateBitsModeAn($size) {
1822
			$w = (int)($size / 2);
1823
			$bits = $w * 11;
1824
			if ($size & 1) {
1825
				$bits += 6;
1826
			}
1827
			return $bits;
1828
		}
1829
1830
		/**
1831
		 * estimateBitsMode8
1832
		 * @param int $size
1833
		 * @return int number of bits
1834
		 */
1835
		 protected function estimateBitsMode8($size) {
1836
			return $size * 8;
1837
		}
1838
1839
		/**
1840
		 * estimateBitsModeKanji
1841
		 * @param int $size
1842
		 * @return int number of bits
1843
		 */
1844
		 protected function estimateBitsModeKanji($size) {
1845
			return (int)(($size / 2) * 13);
1846
		}
1847
1848
		/**
1849
		 * checkModeKanji
1850
		 * @param int $size
1851
		 * @param array $data
1852
		 * @return boolean true or false
1853
		 */
1854
		 protected function checkModeKanji($size, $data) {
1855
			if ($size & 1) {
1856
				return false;
1857
			}
1858
			for ($i = 0; $i < $size; $i += 2) {
1859
				$val = (ord($data[$i]) << 8) | ord($data[$i + 1]);
1860
				if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1861
					return false;
1862
				}
1863
			}
1864
			return true;
1865
		}
1866
1867
		/**
1868
		 * Validate the input data.
1869
		 * @param int $mode encoding mode.
1870
		 * @param int $size size of data (byte).
1871
		 * @param array data data to validate
1872
		 * @return boolean true in case of valid data, false otherwise
1873
		 */
1874
		protected function check($mode, $size, $data) {
1875
			if ($size <= 0) {
1876
				return false;
1877
			}
1878
			switch ($mode) {
1879
				case QR_MODE_NM: {
1880
					return $this->checkModeNum($size, $data);
1881
				}
1882
				case QR_MODE_AN: {
1883
					return $this->checkModeAn($size, $data);
1884
				}
1885
				case QR_MODE_KJ: {
1886
					return $this->checkModeKanji($size, $data);
1887
				}
1888
				case QR_MODE_8B: {
1889
					return true;
1890
				}
1891
				case QR_MODE_ST: {
1892
					return true;
1893
				}
1894
				default: {
1895
					break;
1896
				}
1897
			}
1898
			return false;
1899
		}
1900
1901
		/**
1902
		 * estimateBitStreamSize
1903
		 * @param array $items
1904
		 * @param int $version
1905
		 * @return int bits
1906
		 */
1907
		 protected function estimateBitStreamSize($items, $version) {
1908
			$bits = 0;
1909
			if ($version == 0) {
1910
				$version = 1;
1911
			}
1912
			foreach ($items as $item) {
1913
				switch ($item['mode']) {
1914
					case QR_MODE_NM: {
1915
						$bits = $this->estimateBitsModeNum($item['size']);
1916
						break;
1917
					}
1918
					case QR_MODE_AN: {
1919
						$bits = $this->estimateBitsModeAn($item['size']);
1920
						break;
1921
					}
1922
					case QR_MODE_8B: {
1923
						$bits = $this->estimateBitsMode8($item['size']);
1924
						break;
1925
					}
1926
					case QR_MODE_KJ: {
1927
						$bits = $this->estimateBitsModeKanji($item['size']);
1928
						break;
1929
					}
1930
					case QR_MODE_ST: {
1931
						return STRUCTURE_HEADER_BITS;
1932
					}
1933
					default: {
1934
						return 0;
1935
					}
1936
				}
1937
				$l = $this->lengthIndicator($item['mode'], $version);
1938
				$m = 1 << $l;
1939
				$num = (int)(($item['size'] + $m - 1) / $m);
1940
				$bits += $num * (4 + $l);
1941
			}
1942
			return $bits;
1943
		}
1944
1945
		/**
1946
		 * estimateVersion
1947
		 * @param array $items
1948
		 * @return int version
1949
		 */
1950
		 protected function estimateVersion($items) {
1951
			$version = 0;
1952
			$prev = 0;
1953
			do {
1954
				$prev = $version;
1955
				$bits = $this->estimateBitStreamSize($items, $prev);
1956
				$version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1957
				if ($version < 0) {
1958
					return -1;
1959
				}
1960
			} while ($version > $prev);
1961
			return $version;
1962
		}
1963
1964
		/**
1965
		 * lengthOfCode
1966
		 * @param int $mode
1967
		 * @param int $version
1968
		 * @param int $bits
1969
		 * @return int size
1970
		 */
1971
		 protected function lengthOfCode($mode, $version, $bits) {
1972
			$payload = $bits - 4 - $this->lengthIndicator($mode, $version);
1973
			switch ($mode) {
1974
				case QR_MODE_NM: {
1975
					$chunks = (int)($payload / 10);
1976
					$remain = $payload - $chunks * 10;
1977
					$size = $chunks * 3;
1978
					if ($remain >= 7) {
1979
						$size += 2;
1980
					} elseif ($remain >= 4) {
1981
						$size += 1;
1982
					}
1983
					break;
1984
				}
1985
				case QR_MODE_AN: {
1986
					$chunks = (int)($payload / 11);
1987
					$remain = $payload - $chunks * 11;
1988
					$size = $chunks * 2;
1989
					if ($remain >= 6) {
1990
						++$size;
1991
					}
1992
					break;
1993
				}
1994
				case QR_MODE_8B: {
1995
					$size = (int)($payload / 8);
1996
					break;
1997
				}
1998
				case QR_MODE_KJ: {
1999
					$size = (int)(($payload / 13) * 2);
2000
					break;
2001
				}
2002
				case QR_MODE_ST: {
2003
					$size = (int)($payload / 8);
2004
					break;
2005
				}
2006
				default: {
2007
					$size = 0;
2008
					break;
2009
				}
2010
			}
2011
			$maxsize = $this->maximumWords($mode, $version);
2012
			if ($size < 0) {
2013
				$size = 0;
2014
			}
2015
			if ($size > $maxsize) {
2016
				$size = $maxsize;
2017
			}
2018
			return $size;
2019
		}
2020
2021
		/**
2022
		 * createBitStream
2023
		 * @param array $items
2024
		 * @return array of items and total bits
2025
		 */
2026
		 protected function createBitStream($items) {
2027
			$total = 0;
2028
			foreach ($items as $key => $item) {
2029
				$items[$key] = $this->encodeBitStream($item, $this->version);
2030
				$bits = count($items[$key]['bstream']);
2031
				$total += $bits;
2032
			}
2033
			return array($items, $total);
2034
		}
2035
2036
		/**
2037
		 * convertData
2038
		 * @param array $items
2039
		 * @return array items
2040
		 */
2041
		 protected function convertData($items) {
2042
			$ver = $this->estimateVersion($items);
2043
			if ($ver > $this->version) {
2044
				$this->version = $ver;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ver of type integer is incompatible with the declared type object<QR> of property $version.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
2045
			}
2046
			for (;;) {
2047
				$cbs = $this->createBitStream($items);
2048
				$items = $cbs[0];
2049
				$bits = $cbs[1];
2050
				if ($bits < 0) {
2051
					return -1;
2052
				}
2053
				$ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
2054
				if ($ver < 0) {
2055
					return -1;
2056
				} elseif ($ver > $this->version) {
2057
					$this->version = $ver;
2058
				} else {
2059
					break;
2060
				}
2061
			}
2062
			return $items;
2063
		}
2064
2065
		/**
2066
		 * Append Padding Bit to bitstream
2067
		 * @param array $bstream
2068
		 * @return array bitstream
2069
		 */
2070
		 protected function appendPaddingBit($bstream) {
2071
			$bits = count($bstream);
2072
			$maxwords = $this->getDataLength($this->version, $this->level);
2073
			$maxbits = $maxwords * 8;
2074
			if ($maxbits == $bits) {
2075
				return 0;
2076
			}
2077
			if ($maxbits - $bits < 5) {
2078
				return $this->appendNum($bstream, $maxbits - $bits, 0);
2079
			}
2080
			$bits += 4;
2081
			$words = (int)(($bits + 7) / 8);
2082
			$padding = array();
2083
			$padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
2084
			$padlen = $maxwords - $words;
2085
			if ($padlen > 0) {
2086
				$padbuf = array();
2087
				for ($i = 0; $i < $padlen; ++$i) {
2088
					$padbuf[$i] = ($i & 1) ? 0x11 : 0xec;
2089
				}
2090
				$padding = $this->appendBytes($padding, $padlen, $padbuf);
0 ignored issues
show
Bug introduced by
It seems like $padding defined by $this->appendBytes($padding, $padlen, $padbuf) on line 2090 can also be of type integer; however, QRcode::appendBytes() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2091
			}
2092
			return $this->appendBitstream($bstream, $padding);
0 ignored issues
show
Bug introduced by
It seems like $padding can also be of type integer; however, QRcode::appendBitstream() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2093
		}
2094
2095
		/**
2096
		 * mergeBitStream
2097
		 * @param integer $items
2098
		 * @return array bitstream
2099
		 */
2100
		 protected function mergeBitStream($items) {
2101
			$items = $this->convertData($items);
0 ignored issues
show
Documentation introduced by
$items is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2102
			$bstream = array();
2103
			foreach ($items as $item) {
0 ignored issues
show
Bug introduced by
The expression $items of type integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
2104
				$bstream = $this->appendBitstream($bstream, $item['bstream']);
2105
			}
2106
			return $bstream;
2107
		}
2108
2109
		/**
2110
		 * Returns a stream of bits.
2111
		 * @param int $items
2112
		 * @return array padded merged byte stream
2113
		 */
2114
		protected function getBitStream($items) {
2115
			$bstream = $this->mergeBitStream($items);
2116
			return $this->appendPaddingBit($bstream);
2117
		}
2118
2119
		/**
2120
		 * Pack all bit streams padding bits into a byte array.
2121
		 * @param int $items
2122
		 * @return array padded merged byte stream
2123
		 */
2124
		protected function getByteStream($items) {
2125
			$bstream = $this->getBitStream($items);
2126
			return $this->bitstreamToByte($bstream);
0 ignored issues
show
Bug introduced by
It seems like $bstream defined by $this->getBitStream($items) on line 2125 can also be of type integer; however, QRcode::bitstreamToByte() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2127
		}
2128
2129
		// - - - - - - - - - - - - - - - - - - - - - - - - -
2130
2131
		// QRbitstream
2132
2133
		/**
2134
		 * Return an array with zeros
2135
		 * @param int $setLength array size
2136
		 * @return array
2137
		 */
2138
		 protected function allocate($setLength) {
2139
			return array_fill(0, $setLength, 0);
2140
		}
2141
2142
		/**
2143
		 * Return new bitstream from number
2144
		 * @param int $bits number of bits
2145
		 * @param int $num number
2146
		 * @return array bitstream
2147
		 */
2148
		 protected function newFromNum($bits, $num) {
2149
			$bstream = $this->allocate($bits);
2150
			$mask = 1 << ($bits - 1);
2151 View Code Duplication
			for ($i = 0; $i < $bits; ++$i) {
2152
				if ($num & $mask) {
2153
					$bstream[$i] = 1;
2154
				} else {
2155
					$bstream[$i] = 0;
2156
				}
2157
				$mask = $mask >> 1;
2158
			}
2159
			return $bstream;
2160
		}
2161
2162
		/**
2163
		 * Return new bitstream from bytes
2164
		 * @param int $size size
2165
		 * @param array $data bytes
2166
		 * @return array bitstream
2167
		 */
2168
		 protected function newFromBytes($size, $data) {
2169
			$bstream = $this->allocate($size * 8);
2170
			$p = 0;
2171
			for ($i = 0; $i < $size; ++$i) {
2172
				$mask = 0x80;
2173 View Code Duplication
				for ($j = 0; $j < 8; ++$j) {
2174
					if ($data[$i] & $mask) {
2175
						$bstream[$p] = 1;
2176
					} else {
2177
						$bstream[$p] = 0;
2178
					}
2179
					$p++;
2180
					$mask = $mask >> 1;
2181
				}
2182
			}
2183
			return $bstream;
2184
		}
2185
2186
		/**
2187
		 * Append one bitstream to another
2188
		 * @param array $bitstream original bitstream
2189
		 * @param array $append bitstream to append
2190
		 * @return array bitstream
2191
		 */
2192
		 protected function appendBitstream($bitstream, $append) {
2193
			if (( ! is_array($append)) OR (count($append) == 0)) {
2194
				return $bitstream;
2195
			}
2196
			if (count($bitstream) == 0) {
2197
				return $append;
2198
			}
2199
			return array_values(array_merge($bitstream, $append));
2200
		}
2201
2202
		/**
2203
		 * Append one bitstream created from number to another
2204
		 * @param array $bitstream original bitstream
2205
		 * @param int $bits number of bits
2206
		 * @param int $num number
2207
		 * @return array bitstream
2208
		 */
2209
		 protected function appendNum($bitstream, $bits, $num) {
2210
			if ($bits == 0) {
2211
				return 0;
2212
			}
2213
			$b = $this->newFromNum($bits, $num);
2214
			return $this->appendBitstream($bitstream, $b);
2215
		}
2216
2217
		/**
2218
		 * Append one bitstream created from bytes to another
2219
		 * @param array $bitstream original bitstream
2220
		 * @param int $size size
2221
		 * @param array $data bytes
2222
		 * @return array bitstream
2223
		 */
2224
		 protected function appendBytes($bitstream, $size, $data) {
2225
			if ($size == 0) {
2226
				return 0;
2227
			}
2228
			$b = $this->newFromBytes($size, $data);
2229
			return $this->appendBitstream($bitstream, $b);
2230
		}
2231
2232
		/**
2233
		 * Convert bitstream to bytes
2234
		 * @param array $bstream original bitstream
2235
		 * @return array of bytes
2236
		 */
2237
		 protected function bitstreamToByte($bstream) {
2238
			$size = count($bstream);
2239
			if ($size == 0) {
2240
				return array();
2241
			}
2242
			$data = array_fill(0, (int)(($size + 7) / 8), 0);
2243
			$bytes = (int)($size / 8);
2244
			$p = 0;
2245
			for ($i = 0; $i < $bytes; $i++) {
2246
				$v = 0;
2247 View Code Duplication
				for ($j = 0; $j < 8; $j++) {
2248
					$v = $v << 1;
2249
					$v |= $bstream[$p];
2250
					$p++;
2251
				}
2252
				$data[$i] = $v;
2253
			}
2254
			if ($size & 7) {
2255
				$v = 0;
2256 View Code Duplication
				for ($j = 0; $j < ($size & 7); $j++) {
2257
					$v = $v << 1;
2258
					$v |= $bstream[$p];
2259
					$p++;
2260
				}
2261
				$data[$bytes] = $v;
2262
			}
2263
			return $data;
2264
		}
2265
2266
		// - - - - - - - - - - - - - - - - - - - - - - - - -
2267
2268
		// QRspec
2269
2270
		/**
2271
		 * Replace a value on the array at the specified position
2272
		 * @param array $srctab
2273
		 * @param int $x X position
2274
		 * @param int $y Y position
2275
		 * @param string $repl value to replace
2276
		 * @param int $replLen length of the repl string
2277
		 * @return array srctab
2278
		 */
2279
		 protected function qrstrset($srctab, $x, $y, $repl, $replLen = false) {
2280
			$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false) ? substr($repl, 0, $replLen) : $repl, $x, ($replLen !== false) ? $replLen : strlen($repl));
2281
			return $srctab;
2282
		}
2283
2284
		/**
2285
		 * Return maximum data code length (bytes) for the version.
2286
		 * @param int $version version
2287
		 * @param int $level error correction level
2288
		 * @return int maximum size (bytes)
2289
		 */
2290
		protected function getDataLength($version, $level) {
2291
			return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
2292
		}
2293
2294
		/**
2295
		 * Return maximum error correction code length (bytes) for the version.
2296
		 * @param int $version version
2297
		 * @param int $level error correction level
2298
		 * @return int ECC size (bytes)
2299
		 */
2300
		protected function getECCLength($version, $level) {
2301
			return $this->capacity[$version][QRCAP_EC][$level];
2302
		}
2303
2304
		/**
2305
		 * Return the width of the symbol for the version.
2306
		 * @param int $version version
2307
		 * @return int width
2308
		 */
2309
		protected function getWidth($version) {
2310
			return $this->capacity[$version][QRCAP_WIDTH];
2311
		}
2312
2313
		/**
2314
		 * Return the numer of remainder bits.
2315
		 * @param int $version version
2316
		 * @return int number of remainder bits
2317
		 */
2318
		protected function getRemainder($version) {
2319
			return $this->capacity[$version][QRCAP_REMINDER];
2320
		}
2321
2322
		/**
2323
		 * Return a version number that satisfies the input code length.
2324
		 * @param int $size input code length (byte)
2325
		 * @param int $level error correction level
2326
		 * @return int version number
2327
		 */
2328
		protected function getMinimumVersion($size, $level) {
2329
			for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2330
				$words = $this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level];
2331
				if ($words >= $size) {
2332
					return $i;
2333
				}
2334
			}
2335
			return -1;
2336
		}
2337
2338
		/**
2339
		 * Return the size of length indicator for the mode and version.
2340
		 * @param int $mode encoding mode
2341
		 * @param int $version version
2342
		 * @return int the size of the appropriate length indicator (bits).
2343
		 */
2344
		protected function lengthIndicator($mode, $version) {
2345
			if ($mode == QR_MODE_ST) {
2346
				return 0;
2347
			}
2348 View Code Duplication
			if ($version <= 9) {
2349
				$l = 0;
2350
			} elseif ($version <= 26) {
2351
				$l = 1;
2352
			} else {
2353
				$l = 2;
2354
			}
2355
			return $this->lengthTableBits[$mode][$l];
2356
		}
2357
2358
		/**
2359
		 * Return the maximum length for the mode and version.
2360
		 * @param int $mode encoding mode
2361
		 * @param int $version version
2362
		 * @return int the maximum length (bytes)
2363
		 */
2364
		protected function maximumWords($mode, $version) {
2365
			if ($mode == QR_MODE_ST) {
2366
				return 3;
2367
			}
2368 View Code Duplication
			if ($version <= 9) {
2369
				$l = 0;
2370
			} else if ($version <= 26) {
2371
				$l = 1;
2372
			} else {
2373
				$l = 2;
2374
			}
2375
			$bits = $this->lengthTableBits[$mode][$l];
2376
			$words = (1 << $bits) - 1;
2377
			if ($mode == QR_MODE_KJ) {
2378
				$words *= 2; // the number of bytes is required
2379
			}
2380
			return $words;
2381
		}
2382
2383
		/**
2384
		 * Return an array of ECC specification.
2385
		 * @param int $version version
2386
		 * @param int $level error correction level
2387
		 * @param integer[] $spec an array of ECC specification contains as following: {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
2388
		 * @return array spec
2389
		 */
2390
		protected function getEccSpec($version, $level, $spec) {
2391
			if (count($spec) < 5) {
2392
				$spec = array(0, 0, 0, 0, 0);
2393
			}
2394
			$b1 = $this->eccTable[$version][$level][0];
2395
			$b2 = $this->eccTable[$version][$level][1];
2396
			$data = $this->getDataLength($version, $level);
2397
			$ecc = $this->getECCLength($version, $level);
2398
			if ($b2 == 0) {
2399
				$spec[0] = $b1;
2400
				$spec[1] = (int)($data / $b1);
2401
				$spec[2] = (int)($ecc / $b1);
2402
				$spec[3] = 0;
2403
				$spec[4] = 0;
2404
			} else {
2405
				$spec[0] = $b1;
2406
				$spec[1] = (int)($data / ($b1 + $b2));
2407
				$spec[2] = (int)($ecc / ($b1 + $b2));
2408
				$spec[3] = $b2;
2409
				$spec[4] = $spec[1] + 1;
2410
			}
2411
			return $spec;
2412
		}
2413
2414
		/**
2415
		 * Put an alignment marker.
2416
		 * @param array $frame frame
2417
		 * @param int $ox X center coordinate of the pattern
2418
		 * @param int $oy Y center coordinate of the pattern
2419
		 * @return array frame
2420
		 */
2421
		protected function putAlignmentMarker($frame, $ox, $oy) {
2422
			$finder = array(
2423
				"\xa1\xa1\xa1\xa1\xa1",
2424
				"\xa1\xa0\xa0\xa0\xa1",
2425
				"\xa1\xa0\xa1\xa0\xa1",
2426
				"\xa1\xa0\xa0\xa0\xa1",
2427
				"\xa1\xa1\xa1\xa1\xa1"
2428
				);
2429
			$yStart = $oy - 2;
2430
			$xStart = $ox - 2;
2431 View Code Duplication
			for ($y = 0; $y < 5; $y++) {
2432
				$frame = $this->qrstrset($frame, $xStart, $yStart + $y, $finder[$y]);
2433
			}
2434
			return $frame;
2435
		}
2436
2437
		/**
2438
		 * Put an alignment pattern.
2439
		 * @param int $version version
2440
		 * @param array $frame frame
2441
		 * @param int $width width
2442
		 * @return array frame
2443
		 */
2444
		 protected function putAlignmentPattern($version, $frame, $width) {
2445
			if ($version < 2) {
2446
				return $frame;
2447
			}
2448
			$d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
2449
			if ($d < 0) {
2450
				$w = 2;
2451
			} else {
2452
				$w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
2453
			}
2454
			if ($w * $w - 3 == 1) {
2455
				$x = $this->alignmentPattern[$version][0];
2456
				$y = $this->alignmentPattern[$version][0];
2457
				$frame = $this->putAlignmentMarker($frame, $x, $y);
2458
				return $frame;
2459
			}
2460
			$cx = $this->alignmentPattern[$version][0];
2461
			$wo = $w - 1;
2462
			for ($x = 1; $x < $wo; ++$x) {
2463
				$frame = $this->putAlignmentMarker($frame, 6, $cx);
2464
				$frame = $this->putAlignmentMarker($frame, $cx, 6);
2465
				$cx += $d;
2466
			}
2467
			$cy = $this->alignmentPattern[$version][0];
2468
			for ($y = 0; $y < $wo; ++$y) {
2469
				$cx = $this->alignmentPattern[$version][0];
2470
				for ($x = 0; $x < $wo; ++$x) {
2471
					$frame = $this->putAlignmentMarker($frame, $cx, $cy);
2472
					$cx += $d;
2473
				}
2474
				$cy += $d;
2475
			}
2476
			return $frame;
2477
		}
2478
2479
		/**
2480
		 * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2481
		 * @param int $version version
2482
		 * @return BCH encoded version information pattern
2483
		 */
2484
		protected function getVersionPattern($version) {
2485
			if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2486
				return 0;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 0; (integer) is incompatible with the return type documented by QRcode::getVersionPattern of type BCH.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
2487
			}
2488
			return $this->versionPattern[($version - 7)];
2489
		}
2490
2491
		/**
2492
		 * Return BCH encoded format information pattern.
2493
		 * @param array $mask
2494
		 * @param int $level error correction level
2495
		 * @return BCH encoded format information pattern
2496
		 */
2497
		protected function getFormatInfo($mask, $level) {
2498
			if (($mask < 0) OR ($mask > 7)) {
2499
				return 0;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 0; (integer) is incompatible with the return type documented by QRcode::getFormatInfo of type BCH.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
2500
			}
2501
			if (($level < 0) OR ($level > 3)) {
2502
				return 0;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 0; (integer) is incompatible with the return type documented by QRcode::getFormatInfo of type BCH.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
2503
			}
2504
			return $this->formatInfo[$level][$mask];
2505
		}
2506
2507
		/**
2508
		 * Put a finder pattern.
2509
		 * @param array $frame frame
2510
		 * @param int $ox X center coordinate of the pattern
2511
		 * @param int $oy Y center coordinate of the pattern
2512
		 * @return array frame
2513
		 */
2514
		protected function putFinderPattern($frame, $ox, $oy) {
2515
			$finder = array(
2516
			"\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2517
			"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2518
			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2519
			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2520
			"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2521
			"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2522
			"\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2523
			);
2524 View Code Duplication
			for ($y = 0; $y < 7; $y++) {
2525
				$frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2526
			}
2527
			return $frame;
2528
		}
2529
2530
		/**
2531
		 * Return a copy of initialized frame.
2532
		 * @param int $version version
2533
		 * @return Array of unsigned char.
2534
		 */
2535
		protected function createFrame($version) {
2536
			$width = $this->capacity[$version][QRCAP_WIDTH];
2537
			$frameLine = str_repeat("\0", $width);
2538
			$frame = array_fill(0, $width, $frameLine);
2539
			// Finder pattern
2540
			$frame = $this->putFinderPattern($frame, 0, 0);
2541
			$frame = $this->putFinderPattern($frame, $width - 7, 0);
2542
			$frame = $this->putFinderPattern($frame, 0, $width - 7);
2543
			// Separator
2544
			$yOffset = $width - 7;
2545
			for ($y = 0; $y < 7; ++$y) {
2546
				$frame[$y][7] = "\xc0";
2547
				$frame[$y][$width - 8] = "\xc0";
2548
				$frame[$yOffset][7] = "\xc0";
2549
				++$yOffset;
2550
			}
2551
			$setPattern = str_repeat("\xc0", 8);
2552
			$frame = $this->qrstrset($frame, 0, 7, $setPattern);
2553
			$frame = $this->qrstrset($frame, $width - 8, 7, $setPattern);
2554
			$frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
2555
			// Format info
2556
			$setPattern = str_repeat("\x84", 9);
2557
			$frame = $this->qrstrset($frame, 0, 8, $setPattern);
2558
			$frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
2559
			$yOffset = $width - 8;
2560
			for ($y = 0; $y < 8; ++$y, ++$yOffset) {
2561
				$frame[$y][8] = "\x84";
2562
				$frame[$yOffset][8] = "\x84";
2563
			}
2564
			// Timing pattern
2565
			$wo = $width - 15;
2566
			for ($i = 1; $i < $wo; ++$i) {
2567
				$frame[6][7 + $i] = chr(0x90 | ($i & 1));
2568
				$frame[7 + $i][6] = chr(0x90 | ($i & 1));
2569
			}
2570
			// Alignment pattern
2571
			$frame = $this->putAlignmentPattern($version, $frame, $width);
2572
			// Version information
2573
			if ($version >= 7) {
2574
				$vinf = $this->getVersionPattern($version);
2575
				$v = $vinf;
2576 View Code Duplication
				for ($x = 0; $x < 6; ++$x) {
2577
					for ($y = 0; $y < 3; ++$y) {
2578
						$frame[($width - 11) + $y][$x] = chr(0x88 | ($v & 1));
2579
						$v = $v >> 1;
2580
					}
2581
				}
2582
				$v = $vinf;
2583 View Code Duplication
				for ($y = 0; $y < 6; ++$y) {
2584
					for ($x = 0; $x < 3; ++$x) {
2585
						$frame[$y][$x + ($width - 11)] = chr(0x88 | ($v & 1));
2586
						$v = $v >> 1;
2587
					}
2588
				}
2589
			}
2590
			// and a little bit...
2591
			$frame[$width - 8][8] = "\x81";
2592
			return $frame;
2593
		}
2594
2595
		/**
2596
		 * Set new frame for the specified version.
2597
		 * @param int $version version
2598
		 * @return Array of unsigned char.
2599
		 */
2600
		protected function newFrame($version) {
2601
			if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2602
				return NULL;
2603
			}
2604
			if ( ! isset($this->frames[$version])) {
2605
				$this->frames[$version] = $this->createFrame($version);
2606
			}
2607
			if (is_null($this->frames[$version])) {
2608
				return NULL;
2609
			}
2610
			return $this->frames[$version];
2611
		}
2612
2613
		/**
2614
		 * Return block number 0
2615
		 * @param array $spec
2616
		 * @return int value
2617
		 */
2618
		 protected function rsBlockNum($spec) {
2619
			return ($spec[0] + $spec[3]);
2620
		}
2621
2622
		/**
2623
		 * Return block number 1
2624
		 * @param array $spec
2625
		 * @return int value
2626
		 */
2627
		 protected function rsBlockNum1($spec) {
2628
			return $spec[0];
2629
		}
2630
2631
		/**
2632
		 * Return data codes 1
2633
		 * @param array $spec
2634
		 * @return int value
2635
		 */
2636
		 protected function rsDataCodes1($spec) {
2637
			return $spec[1];
2638
		}
2639
2640
		/**
2641
		 * Return ecc codes 1
2642
		 * @param array $spec
2643
		 * @return int value
2644
		 */
2645
		 protected function rsEccCodes1($spec) {
2646
			return $spec[2];
2647
		}
2648
2649
		/**
2650
		 * Return block number 2
2651
		 * @param array $spec
2652
		 * @return int value
2653
		 */
2654
		 protected function rsBlockNum2($spec) {
2655
			return $spec[3];
2656
		}
2657
2658
		/**
2659
		 * Return data codes 2
2660
		 * @param array $spec
2661
		 * @return int value
2662
		 */
2663
		 protected function rsDataCodes2($spec) {
2664
			return $spec[4];
2665
		}
2666
2667
		/**
2668
		 * Return ecc codes 2
2669
		 * @param array $spec
2670
		 * @return int value
2671
		 */
2672
		 protected function rsEccCodes2($spec) {
2673
			return $spec[2];
2674
		}
2675
2676
		/**
2677
		 * Return data length
2678
		 * @param array $spec
2679
		 * @return double value
2680
		 */
2681
		 protected function rsDataLength($spec) {
2682
			return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2683
		}
2684
2685
		/**
2686
		 * Return ecc length
2687
		 * @param array $spec
2688
		 * @return int value
2689
		 */
2690
		 protected function rsEccLength($spec) {
2691
			return ($spec[0] + $spec[3]) * $spec[2];
2692
		}
2693
2694
		// - - - - - - - - - - - - - - - - - - - - - - - - -
2695
2696
		// QRrs
2697
2698
		/**
2699
		 * Initialize a Reed-Solomon codec and add it to existing rsitems
2700
		 * @param int $symsize symbol size, bits
2701
		 * @param int $gfpoly  Field generator polynomial coefficients
2702
		 * @param int $fcr  first root of RS code generator polynomial, index form
2703
		 * @param int $prim  primitive element to generate polynomial roots
2704
		 * @param int $nroots RS code generator polynomial degree (number of roots)
2705
		 * @param int $pad  padding bytes at front of shortened block
2706
		 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2707
		 */
2708
		 protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2709
			foreach ($this->rsitems as $rs) {
2710
				if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2711
					OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2712
					continue;
2713
				}
2714
				return $rs;
2715
			}
2716
			$rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2717
			array_unshift($this->rsitems, $rs);
2718
			return $rs;
2719
		}
2720
2721
		// - - - - - - - - - - - - - - - - - - - - - - - - -
2722
2723
		// QRrsItem
2724
2725
		/**
2726
		 * modnn
2727
		 * @param array RS values
2728
		 * @param int $x X position
2729
		 * @return int X osition
2730
		 */
2731
		 protected function modnn($rs, $x) {
2732
			while ($x >= $rs['nn']) {
2733
				$x -= $rs['nn'];
2734
				$x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2735
			}
2736
			return $x;
2737
		}
2738
2739
		/**
2740
		 * Initialize a Reed-Solomon codec and returns an array of values.
2741
		 * @param int $symsize symbol size, bits
2742
		 * @param int $gfpoly  Field generator polynomial coefficients
2743
		 * @param int $fcr  first root of RS code generator polynomial, index form
2744
		 * @param int $prim  primitive element to generate polynomial roots
2745
		 * @param int $nroots RS code generator polynomial degree (number of roots)
2746
		 * @param int $pad  padding bytes at front of shortened block
2747
		 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2748
		 */
2749
		protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2750
			// Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2751
			$rs = null;
2752
			// Check parameter ranges
2753
			if (($symsize < 0) OR ($symsize > 8)) {
2754
				return $rs;
2755
			}
2756
			if (($fcr < 0) OR ($fcr >= (1 << $symsize))) {
2757
				return $rs;
2758
			}
2759
			if (($prim <= 0) OR ($prim >= (1 << $symsize))) {
2760
				return $rs;
2761
			}
2762
			if (($nroots < 0) OR ($nroots >= (1 << $symsize))) {
2763
				return $rs;
2764
			}
2765
			if (($pad < 0) OR ($pad >= ((1 << $symsize) - 1 - $nroots))) {
2766
				return $rs;
2767
			}
2768
			$rs = array();
2769
			$rs['mm'] = $symsize;
2770
			$rs['nn'] = (1 << $symsize) - 1;
2771
			$rs['pad'] = $pad;
2772
			$rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2773
			$rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2774
			// PHP style macro replacement ;)
2775
			$NN = & $rs['nn'];
2776
			$A0 = & $NN;
2777
			// Generate Galois field lookup tables
2778
			$rs['index_of'][0] = $A0; // log(zero) = -inf
2779
			$rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2780
			$sr = 1;
2781
			for ($i = 0; $i < $rs['nn']; ++$i) {
2782
				$rs['index_of'][$sr] = $i;
2783
				$rs['alpha_to'][$i] = $sr;
2784
				$sr <<= 1;
2785
				if ($sr & (1 << $symsize)) {
2786
					$sr ^= $gfpoly;
2787
				}
2788
				$sr &= $rs['nn'];
2789
			}
2790
			if ($sr != 1) {
2791
				// field generator polynomial is not primitive!
2792
				return NULL;
2793
			}
2794
			// Form RS code generator polynomial from its roots
2795
			$rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2796
			$rs['fcr'] = $fcr;
2797
			$rs['prim'] = $prim;
2798
			$rs['nroots'] = $nroots;
2799
			$rs['gfpoly'] = $gfpoly;
2800
			// Find prim-th root of 1, used in decoding
2801
			for ($iprim = 1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2802
				; // intentional empty-body loop!
2803
			}
2804
			$rs['iprim'] = (int)($iprim / $prim);
2805
			$rs['genpoly'][0] = 1;
2806
2807
2808
			for ($i = 0, $root = $fcr * $prim; $i < $nroots; $i++, $root += $prim) {
2809
				$rs['genpoly'][$i + 1] = 1;
2810
				// Multiply rs->genpoly[] by  @**(root + x)
2811
				for ($j = $i; $j > 0; --$j) {
2812
					if ($rs['genpoly'][$j] != 0) {
2813
						$rs['genpoly'][$j] = $rs['genpoly'][$j - 1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2814
					} else {
2815
						$rs['genpoly'][$j] = $rs['genpoly'][$j - 1];
2816
					}
2817
				}
2818
				// rs->genpoly[0] can never be zero
2819
				$rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2820
			}
2821
			// convert rs->genpoly[] to index form for quicker encoding
2822
			for ($i = 0; $i <= $nroots; ++$i) {
2823
				$rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2824
			}
2825
			return $rs;
2826
		}
2827
2828
		/**
2829
		 * Encode a Reed-Solomon codec and returns the parity array
2830
		 * @param array $rs RS values
2831
		 * @param array $data data
2832
		 * @param array $parity parity
2833
		 * @return parity array
2834
		 */
2835
		 protected function encode_rs_char($rs, $data, $parity) {
0 ignored issues
show
Unused Code introduced by
The parameter $parity is not used and could be removed.

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

Loading history...
2836
			$MM       = & $rs['mm']; // bits per symbol
2837
			$NN       = & $rs['nn']; // the total number of symbols in a RS block
2838
			$ALPHA_TO = & $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
2839
			$INDEX_OF = & $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
2840
			$GENPOLY  = & $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2841
			$NROOTS   = & $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
2842
			$FCR      = & $rs['fcr']; // first consecutive root, index form
2843
			$PRIM     = & $rs['prim']; // primitive element, index form
2844
			$IPRIM    = & $rs['iprim']; // prim-th root of 1, index form
2845
			$PAD      = & $rs['pad']; // the number of pad symbols in a block
2846
			$A0       = & $NN;
2847
			$parity = array_fill(0, $NROOTS, 0);
2848
			for ($i = 0; $i < ($NN - $NROOTS - $PAD); $i++) {
2849
				$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2850
				if ($feedback != $A0) {
2851
					// feedback term is non-zero
2852
					// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2853
					// always be for the polynomials constructed by init_rs()
2854
					$feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2855
					for ($j = 1; $j < $NROOTS; ++$j) {
2856
					$parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2857
					}
2858
				}
2859
				// Shift
2860
				array_shift($parity);
2861
				if ($feedback != $A0) {
2862
					array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
2863
				} else {
2864
					array_push($parity, 0);
2865
				}
2866
			}
2867
			return $parity;
2868
		}
2869
2870
	} // end QRcode class
2871
2872
} // END OF "class_exists QRcode"
2873
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
2874