GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — 2.8 ( 651d2c...3866ce )
by Thorsten
18:13
created

QRcode::identifyMode()   B

Complexity

Conditions 10
Paths 7

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 15
nc 7
nop 1
dl 0
loc 20
rs 7.2765
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
//============================================================+
3
// File name   : qrcode.php
4
// Version     : 1.0.010
5
// Begin       : 2010-03-22
6
// Last Update : 2012-07-25
7
// Author      : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - [email protected]
8
// License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9
// -------------------------------------------------------------------
10
// Copyright (C) 2010-2012 Nicola Asuni - Tecnick.com LTD
11
//
12
// This file is part of TCPDF software library.
13
//
14
// TCPDF is free software: you can redistribute it and/or modify it
15
// under the terms of the GNU Lesser General Public License as
16
// published by the Free Software Foundation, either version 3 of the
17
// License, or (at your option) any later version.
18
//
19
// TCPDF is distributed in the hope that it will be useful, but
20
// WITHOUT ANY WARRANTY; without even the implied warranty of
21
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22
// See the GNU Lesser General Public License for more details.
23
//
24
// You should have received a copy of the GNU Lesser General Public License
25
// along with TCPDF.  If not, see <http://www.gnu.org/licenses/>.
26
//
27
// See LICENSE.TXT file for more information.
28
// -------------------------------------------------------------------
29
//
30
// DESCRIPTION :
31
//
32
// Class to create QR-code arrays for TCPDF class.
33
// QR Code symbol is a 2D barcode that can be scanned by
34
// handy terminals such as a mobile phone with CCD.
35
// The capacity of QR Code is up to 7000 digits or 4000
36
// characters, and has high robustness.
37
// This class supports QR Code model 2, described in
38
// JIS (Japanese Industrial Standards) X0510:2004
39
// or ISO/IEC 18004.
40
// Currently the following features are not supported:
41
// ECI and FNC1 mode, Micro QR Code, QR Code model 1,
42
// Structured mode.
43
//
44
// This class is derived from the following projects:
45
// ---------------------------------------------------------
46
// "PHP QR Code encoder"
47
// License: GNU-LGPLv3
48
// Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
49
// http://phpqrcode.sourceforge.net/
50
// https://sourceforge.net/projects/phpqrcode/
51
//
52
// The "PHP QR Code encoder" is based on
53
// "C libqrencode library" (ver. 3.1.1)
54
// License: GNU-LGPL 2.1
55
// Copyright (C) 2006-2010 by Kentaro Fukuchi
56
// http://megaui.net/fukuchi/works/qrencode/index.en.html
57
//
58
// Reed-Solomon code encoder is written by Phil Karn, KA9Q.
59
// Copyright (C) 2002-2006 Phil Karn, KA9Q
60
//
61
// QR Code is registered trademark of DENSO WAVE INCORPORATED
62
// http://www.denso-wave.com/qrcode/index-e.html
63
// ---------------------------------------------------------
64
//============================================================+
65
66
/**
67
 * @file
68
 * Class to create QR-code arrays for TCPDF class.
69
 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
70
 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
71
 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
72
 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
73
 *
74
 * 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).
75
 * Please read comments on this class source file for full copyright and license information.
76
 *
77
 * @package com.tecnick.tcpdf
78
 * @author Nicola Asuni
79
 * @version 1.0.010
80
 */
81
82
// definitions
83
if (!defined('QRCODEDEFS')) {
84
85
	/**
86
	 * Indicate that definitions for this class are set
87
	 */
88
	define('QRCODEDEFS', true);
89
90
	// -----------------------------------------------------
91
92
	// Encoding modes (characters which can be encoded in QRcode)
93
94
	/**
95
	 * Encoding mode
96
	 */
97
	define('QR_MODE_NL', -1);
98
99
	/**
100
	 * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
101
	 */
102
	define('QR_MODE_NM', 0);
103
104
	/**
105
	 * 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.
106
	 */
107
	define('QR_MODE_AN', 1);
108
109
	/**
110
	 * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
111
	 */
112
	define('QR_MODE_8B', 2);
113
114
	/**
115
	 * 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.
116
	 */
117
	define('QR_MODE_KJ', 3);
118
119
	/**
120
	 * Encoding mode STRUCTURED (currently unsupported)
121
	 */
122
	define('QR_MODE_ST', 4);
123
124
	// -----------------------------------------------------
125
126
	// Levels of error correction.
127
	// QRcode has a function of an error correcting for miss reading that white is black.
128
	// Error correcting is defined in 4 level as below.
129
130
	/**
131
	 * Error correction level L : About 7% or less errors can be corrected.
132
	 */
133
	define('QR_ECLEVEL_L', 0);
134
135
	/**
136
	 * Error correction level M : About 15% or less errors can be corrected.
137
	 */
138
	define('QR_ECLEVEL_M', 1);
139
140
	/**
141
	 * Error correction level Q : About 25% or less errors can be corrected.
142
	 */
143
	define('QR_ECLEVEL_Q', 2);
144
145
	/**
146
	 * Error correction level H : About 30% or less errors can be corrected.
147
	 */
148
	define('QR_ECLEVEL_H', 3);
149
150
	// -----------------------------------------------------
151
152
	// Version. Size of QRcode is defined as version.
153
	// Version is from 1 to 40.
154
	// Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
155
	// So version 40 is 177*177 matrix.
156
157
	/**
158
	 * Maximum QR Code version.
159
	 */
160
	define('QRSPEC_VERSION_MAX', 40);
161
162
	/**
163
	 * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
164
	 */
165
    define('QRSPEC_WIDTH_MAX', 177);
166
167
	// -----------------------------------------------------
168
169
	/**
170
	 * Matrix index to get width from $capacity array.
171
	 */
172
    define('QRCAP_WIDTH',    0);
173
174
    /**
175
	 * Matrix index to get number of words from $capacity array.
176
	 */
177
    define('QRCAP_WORDS',    1);
178
179
    /**
180
	 * Matrix index to get remainder from $capacity array.
181
	 */
182
    define('QRCAP_REMINDER', 2);
183
184
    /**
185
	 * Matrix index to get error correction level from $capacity array.
186
	 */
187
    define('QRCAP_EC',       3);
188
189
	// -----------------------------------------------------
190
191
	// Structure (currently usupported)
192
193
	/**
194
	 * Number of header bits for structured mode
195
	 */
196
    define('STRUCTURE_HEADER_BITS',  20);
197
198
    /**
199
	 * Max number of symbols for structured mode
200
	 */
201
    define('MAX_STRUCTURED_SYMBOLS', 16);
202
203
	// -----------------------------------------------------
204
205
    // Masks
206
207
    /**
208
	 * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
209
	 */
210
    define('N1',  3);
211
212
    /**
213
	 * Down point base value for case 2 mask pattern (module block of same color)
214
	 */
215
	define('N2',  3);
216
217
    /**
218
	 * 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)
219
	 */
220
	define('N3', 40);
221
222
    /**
223
	 * Down point base value for case 4 mask pattern (ration of dark modules in whole)
224
	 */
225
	define('N4', 10);
226
227
	// -----------------------------------------------------
228
229
	// Optimization settings
230
231
	/**
232
	 * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
233
	 */
234
	define('QR_FIND_BEST_MASK', true);
235
236
	/**
237
	 * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
238
	 */
239
	define('QR_FIND_FROM_RANDOM', 2);
240
241
	/**
242
	 * when QR_FIND_BEST_MASK === false
243
	 */
244
	define('QR_DEFAULT_MASK', 2);
245
246
	// -----------------------------------------------------
247
248
} // end of definitions
249
250
// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
251
252
// for compatibility with PHP4
253
if (!function_exists('str_split')) {
254
	/**
255
	 * Convert a string to an array (needed for PHP4 compatibility)
256
	 * @param $string (string) The input string.
257
	 * @param $split_length (int) Maximum length of the chunk.
258
	 * @return  If 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.
259
	 */
260
	function str_split($string, $split_length=1) {
261
		if ((strlen($string) > $split_length) OR (!$split_length)) {
262
			do {
263
				$c = strlen($string);
264
				$parts[] = substr($string, 0, $split_length);
265
				$string = substr($string, $split_length);
266
			} while ($string !== false);
267
		} else {
268
			$parts = array($string);
269
		}
270
		return $parts;
271
	}
272
}
273
274
// #####################################################
275
276
/**
277
 * @class QRcode
278
 * Class to create QR-code arrays for TCPDF class.
279
 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
280
 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
281
 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
282
 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
283
 *
284
 * 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).
285
 * Please read comments on this class source file for full copyright and license information.
286
 *
287
 * @package com.tecnick.tcpdf
288
 * @author Nicola Asuni
289
 * @version 1.0.010
290
 */
291
class QRcode {
292
293
	/**
294
	 * Barcode array to be returned which is readable by TCPDF.
295
	 * @protected
296
	 */
297
	protected $barcode_array = array();
298
299
	/**
300
	 * 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.
301
	 * @protected
302
	 */
303
	protected $version = 0;
304
305
	/**
306
	 * Levels of error correction. See definitions for possible values.
307
	 * @protected
308
	 */
309
	protected $level = QR_ECLEVEL_L;
310
311
	/**
312
	 * Encoding mode.
313
	 * @protected
314
	 */
315
	protected $hint = QR_MODE_8B;
316
317
	/**
318
	 * Boolean flag, if true the input string will be converted to uppercase.
319
	 * @protected
320
	 */
321
	protected $casesensitive = true;
322
323
	/**
324
	 * Structured QR code (not supported yet).
325
	 * @protected
326
	 */
327
	protected $structured = 0;
328
329
	/**
330
	 * Mask data.
331
	 * @protected
332
	 */
333
	protected $data;
334
335
	// FrameFiller
336
337
	/**
338
	 * Width.
339
	 * @protected
340
	 */
341
	protected $width;
342
343
	/**
344
	 * Frame.
345
	 * @protected
346
	 */
347
	protected $frame;
348
349
	/**
350
	 * X position of bit.
351
	 * @protected
352
	 */
353
	protected $x;
354
355
	/**
356
	 * Y position of bit.
357
	 * @protected
358
	 */
359
	protected $y;
360
361
	/**
362
	 * Direction.
363
	 * @protected
364
	 */
365
	protected $dir;
366
367
	/**
368
	 * Single bit value.
369
	 * @protected
370
	 */
371
	protected $bit;
372
373
	// ---- QRrawcode ----
374
375
	/**
376
	 * Data code.
377
	 * @protected
378
	 */
379
	protected $datacode = array();
380
381
	/**
382
	 * Error correction code.
383
	 * @protected
384
	 */
385
	protected $ecccode = array();
386
387
	/**
388
	 * Blocks.
389
	 * @protected
390
	 */
391
	protected $blocks;
392
393
	/**
394
	 * Reed-Solomon blocks.
395
	 * @protected
396
	 */
397
	protected $rsblocks = array(); //of RSblock
398
399
	/**
400
	 * Counter.
401
	 * @protected
402
	 */
403
	protected $count;
404
405
	/**
406
	 * Data length.
407
	 * @protected
408
	 */
409
	protected $dataLength;
410
411
	/**
412
	 * Error correction length.
413
	 * @protected
414
	 */
415
	protected $eccLength;
416
417
	/**
418
	 * Value b1.
419
	 * @protected
420
	 */
421
	protected $b1;
422
423
	// ---- QRmask ----
424
425
	/**
426
	 * Run length.
427
	 * @protected
428
	 */
429
	protected $runLength = array();
430
431
	// ---- QRsplit ----
432
433
	/**
434
	 * Input data string.
435
	 * @protected
436
	 */
437
	protected $dataStr = '';
438
439
	/**
440
	 * Input items.
441
	 * @protected
442
	 */
443
	protected $items;
444
445
	// Reed-Solomon items
446
447
	/**
448
	 * Reed-Solomon items.
449
	 * @protected
450
	 */
451
	protected $rsitems = array();
452
453
	/**
454
	 * Array of frames.
455
	 * @protected
456
	 */
457
	protected $frames = array();
458
459
	/**
460
	 * Alphabet-numeric convesion table.
461
	 * @protected
462
	 */
463
	protected $anTable = array(
464
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
465
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
466
		36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
467
		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1, //
468
		-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
469
		25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
470
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
471
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  //
472
		);
473
474
	/**
475
	 * Array Table of the capacity of symbols.
476
	 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
477
	 * @protected
478
	 */
479
	protected $capacity = array(
480
		array(  0,    0, 0, array(   0,    0,    0,    0)), //
481
		array( 21,   26, 0, array(   7,   10,   13,   17)), //  1
482
		array( 25,   44, 7, array(  10,   16,   22,   28)), //
483
		array( 29,   70, 7, array(  15,   26,   36,   44)), //
484
		array( 33,  100, 7, array(  20,   36,   52,   64)), //
485
		array( 37,  134, 7, array(  26,   48,   72,   88)), //  5
486
		array( 41,  172, 7, array(  36,   64,   96,  112)), //
487
		array( 45,  196, 0, array(  40,   72,  108,  130)), //
488
		array( 49,  242, 0, array(  48,   88,  132,  156)), //
489
		array( 53,  292, 0, array(  60,  110,  160,  192)), //
490
		array( 57,  346, 0, array(  72,  130,  192,  224)), // 10
491
		array( 61,  404, 0, array(  80,  150,  224,  264)), //
492
		array( 65,  466, 0, array(  96,  176,  260,  308)), //
493
		array( 69,  532, 0, array( 104,  198,  288,  352)), //
494
		array( 73,  581, 3, array( 120,  216,  320,  384)), //
495
		array( 77,  655, 3, array( 132,  240,  360,  432)), // 15
496
		array( 81,  733, 3, array( 144,  280,  408,  480)), //
497
		array( 85,  815, 3, array( 168,  308,  448,  532)), //
498
		array( 89,  901, 3, array( 180,  338,  504,  588)), //
499
		array( 93,  991, 3, array( 196,  364,  546,  650)), //
500
		array( 97, 1085, 3, array( 224,  416,  600,  700)), // 20
501
		array(101, 1156, 4, array( 224,  442,  644,  750)), //
502
		array(105, 1258, 4, array( 252,  476,  690,  816)), //
503
		array(109, 1364, 4, array( 270,  504,  750,  900)), //
504
		array(113, 1474, 4, array( 300,  560,  810,  960)), //
505
		array(117, 1588, 4, array( 312,  588,  870, 1050)), // 25
506
		array(121, 1706, 4, array( 336,  644,  952, 1110)), //
507
		array(125, 1828, 4, array( 360,  700, 1020, 1200)), //
508
		array(129, 1921, 3, array( 390,  728, 1050, 1260)), //
509
		array(133, 2051, 3, array( 420,  784, 1140, 1350)), //
510
		array(137, 2185, 3, array( 450,  812, 1200, 1440)), // 30
511
		array(141, 2323, 3, array( 480,  868, 1290, 1530)), //
512
		array(145, 2465, 3, array( 510,  924, 1350, 1620)), //
513
		array(149, 2611, 3, array( 540,  980, 1440, 1710)), //
514
		array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
515
		array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
516
		array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
517
		array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
518
		array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
519
		array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
520
		array(177, 3706, 0, array( 750, 1372, 2040, 2430))  // 40
521
	);
522
523
	/**
524
	 * Array Length indicator.
525
	 * @protected
526
	 */
527
	protected $lengthTableBits = array(
528
		array(10, 12, 14),
529
		array( 9, 11, 13),
530
		array( 8, 16, 16),
531
		array( 8, 10, 12)
532
	);
533
534
	/**
535
	 * Array Table of the error correction code (Reed-Solomon block).
536
	 * See Table 12-16 (pp.30-36), JIS X0510:2004.
537
	 * @protected
538
	 */
539
	protected $eccTable = array(
540
		array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)), //
541
		array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //  1
542
		array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), //
543
		array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)), //
544
		array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)), //
545
		array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), //  5
546
		array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)), //
547
		array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)), //
548
		array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)), //
549
		array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)), //
550
		array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), // 10
551
		array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)), //
552
		array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)), //
553
		array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)), //
554
		array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)), //
555
		array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), // 15
556
		array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)), //
557
		array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)), //
558
		array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)), //
559
		array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)), //
560
		array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), // 20
561
		array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)), //
562
		array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)), //
563
		array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)), //
564
		array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)), //
565
		array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
566
		array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)), //
567
		array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)), //
568
		array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
569
		array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)), //
570
		array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
571
		array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)), //
572
		array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)), //
573
		array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)), //
574
		array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)), //
575
		array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), // 35
576
		array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
577
		array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)), //
578
		array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
579
		array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)), //
580
		array(array(19,  6), array(18, 31), array(34, 34), array(20, 61))  // 40
581
	);
582
583
	/**
584
	 * Array Positions of alignment patterns.
585
	 * 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.
586
	 * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
587
	 * @protected
588
	 */
589
	protected $alignmentPattern = array(
590
		array( 0,  0),
591
		array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), //  1- 5
592
		array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), //  6-10
593
		array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
594
		array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
595
		array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
596
		array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
597
		array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
598
		array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58)  // 35-40
599
	);
600
601
	/**
602
	 * Array Version information pattern (BCH coded).
603
	 * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
604
	 * size: [QRSPEC_VERSION_MAX - 6]
605
	 * @protected
606
	 */
607
	protected $versionPattern = array(
608
		0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
609
		0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
610
		0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
611
		0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
612
		0x27541, 0x28c69
613
	);
614
615
	/**
616
	 * Array Format information
617
	 * @protected
618
	 */
619
	protected $formatInfo = array(
620
		array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
621
		array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
622
		array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
623
		array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)  //
624
	);
625
626
627
	// -------------------------------------------------
628
	// -------------------------------------------------
629
630
631
	/**
632
	 * This is the class constructor.
633
	 * Creates a QRcode object
634
	 * @param $code (string) code to represent using QRcode
635
	 * @param $eclevel (string) 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>
636
	 * @public
637
	 * @since 1.0.000
638
	 */
639
	public function __construct($code, $eclevel = 'L') {
640
		$barcode_array = array();
641
		if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
642
			return false;
643
		}
644
		// set error correction level
645
		$this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
646
		if ($this->level === false) {
647
			$this->level = QR_ECLEVEL_L;
648
		}
649
		if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
650
			return false;
651
		}
652
		if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
653
			return false;
654
		}
655
		$this->items = array();
656
		$this->encodeString($code);
657
		if (is_null($this->data)) {
658
			return false;
659
		}
660
		$qrTab = $this->binarize($this->data);
661
		$size = count($qrTab);
662
		$barcode_array['num_rows'] = $size;
663
		$barcode_array['num_cols'] = $size;
664
		$barcode_array['bcode'] = array();
665
		foreach ($qrTab as $line) {
666
			$arrAdd = array();
667
			foreach (str_split($line) as $char) {
668
				$arrAdd[] = ($char=='1')?1:0;
669
			}
670
			$barcode_array['bcode'][] = $arrAdd;
671
		}
672
		$this->barcode_array = $barcode_array;
673
	}
674
675
	/**
676
	 * Returns a barcode array which is readable by TCPDF
677
	 * @return array barcode array readable by TCPDF;
678
	 * @public
679
	 */
680
	public function getBarcodeArray() {
681
		return $this->barcode_array;
682
	}
683
684
	/**
685
	 * Convert the frame in binary form
686
	 * @param $frame (array) array to binarize
687
	 * @return array frame in binary form
688
	 */
689
	protected function binarize($frame) {
690
		$len = count($frame);
691
		// the frame is square (width = height)
692
		foreach ($frame as &$frameLine) {
693
			for ($i=0; $i<$len; $i++) {
694
				$frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
695
			}
696
		}
697
		return $frame;
698
	}
699
700
	/**
701
	 * Encode the input string to QR code
702
	 * @param $string (string) input string to encode
703
	 */
704
	protected function encodeString($string) {
705
		$this->dataStr = $string;
706
		if (!$this->casesensitive) {
707
			$this->toUpper();
708
		}
709
		$ret = $this->splitString();
710
		if ($ret < 0) {
711
			return NULL;
712
		}
713
		$this->encodeMask(-1);
714
	}
715
716
	/**
717
	 * Encode mask
718
	 * @param $mask (int) masking mode
719
	 */
720
	protected function encodeMask($mask) {
721
		$spec = array(0, 0, 0, 0, 0);
722
		$this->datacode = $this->getByteStream($this->items);
723
		if (is_null($this->datacode)) {
724
			return NULL;
725
		}
726
		$spec = $this->getEccSpec($this->version, $this->level, $spec);
727
		$this->b1 = $this->rsBlockNum1($spec);
728
		$this->dataLength = $this->rsDataLength($spec);
729
		$this->eccLength = $this->rsEccLength($spec);
730
		$this->ecccode = array_fill(0, $this->eccLength, 0);
731
		$this->blocks = $this->rsBlockNum($spec);
732
		$ret = $this->init($spec);
733
		if ($ret < 0) {
734
			return NULL;
735
		}
736
		$this->count = 0;
737
		$this->width = $this->getWidth($this->version);
738
		$this->frame = $this->newFrame($this->version);
739
		$this->x = $this->width - 1;
740
		$this->y = $this->width - 1;
741
		$this->dir = -1;
742
		$this->bit = -1;
743
		// inteleaved data and ecc codes
744
		for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
745
			$code = $this->getCode();
746
			$bit = 0x80;
747
			for ($j=0; $j<8; $j++) {
748
				$addr = $this->getNextPosition();
749
				$this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
750
				$bit = $bit >> 1;
751
			}
752
		}
753
		// remainder bits
754
		$j = $this->getRemainder($this->version);
755
		for ($i=0; $i<$j; $i++) {
756
			$addr = $this->getNextPosition();
757
			$this->setFrameAt($addr, 0x02);
758
		}
759
		// masking
760
		$this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
761
		if ($mask < 0) {
762
			if (QR_FIND_BEST_MASK) {
763
				$masked = $this->mask($this->width, $this->frame, $this->level);
764
			} else {
765
				$masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
766
			}
767
		} else {
768
			$masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
769
		}
770
		if ($masked == NULL) {
771
			return NULL;
772
		}
773
		$this->data = $masked;
774
	}
775
776
	// - - - - - - - - - - - - - - - - - - - - - - - - -
777
778
	// FrameFiller
779
780
	/**
781
	 * Set frame value at specified position
782
	 * @param $at (array) x,y position
783
	 * @param $val (int) value of the character to set
784
	 */
785
	protected function setFrameAt($at, $val) {
786
		$this->frame[$at['y']][$at['x']] = chr($val);
787
	}
788
789
	/**
790
	 * Get frame value at specified position
791
	 * @param $at (array) x,y position
792
	 * @return value at specified position
793
	 */
794
	protected function getFrameAt($at) {
795
		return ord($this->frame[$at['y']][$at['x']]);
796
	}
797
798
	/**
799
	 * Return the next frame position
800
	 * @return array of x,y coordinates
801
	 */
802
	protected function getNextPosition() {
803
		do {
804
			if ($this->bit == -1) {
805
				$this->bit = 0;
806
				return array('x'=>$this->x, 'y'=>$this->y);
807
			}
808
			$x = $this->x;
809
			$y = $this->y;
810
			$w = $this->width;
811
			if ($this->bit == 0) {
812
				$x--;
813
				$this->bit++;
814
			} else {
815
				$x++;
816
				$y += $this->dir;
817
				$this->bit--;
818
			}
819
			if ($this->dir < 0) {
820
				if ($y < 0) {
821
					$y = 0;
822
					$x -= 2;
823
					$this->dir = 1;
824
					if ($x == 6) {
825
						$x--;
826
						$y = 9;
827
					}
828
				}
829
			} else {
830
				if ($y == $w) {
831
					$y = $w - 1;
832
					$x -= 2;
833
					$this->dir = -1;
834
					if ($x == 6) {
835
						$x--;
836
						$y -= 8;
837
					}
838
				}
839
			}
840
			if (($x < 0) OR ($y < 0)) {
841
				return NULL;
842
			}
843
			$this->x = $x;
844
			$this->y = $y;
845
		} while(ord($this->frame[$y][$x]) & 0x80);
846
		return array('x'=>$x, 'y'=>$y);
847
	}
848
849
	// - - - - - - - - - - - - - - - - - - - - - - - - -
850
851
	// QRrawcode
852
853
	/**
854
	 * Initialize code.
855
	 * @param $spec (array) array of ECC specification
856
	 * @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...
857
	 */
858
	protected function init($spec) {
859
		$dl = $this->rsDataCodes1($spec);
860
		$el = $this->rsEccCodes1($spec);
861
		$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
862
		$blockNo = 0;
863
		$dataPos = 0;
864
		$eccPos = 0;
865
		$endfor = $this->rsBlockNum1($spec);
866 View Code Duplication
		for ($i=0; $i < $endfor; ++$i) {
867
			$ecc = array_slice($this->ecccode, $eccPos);
868
			$this->rsblocks[$blockNo] = array();
869
			$this->rsblocks[$blockNo]['dataLength'] = $dl;
870
			$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
871
			$this->rsblocks[$blockNo]['eccLength'] = $el;
872
			$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
873
			$this->rsblocks[$blockNo]['ecc'] = $ecc;
874
			$this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
875
			$dataPos += $dl;
876
			$eccPos += $el;
877
			$blockNo++;
878
		}
879
		if ($this->rsBlockNum2($spec) == 0) {
880
			return 0;
881
		}
882
		$dl = $this->rsDataCodes2($spec);
883
		$el = $this->rsEccCodes2($spec);
884
		$rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
885
		if ($rs == NULL) {
886
			return -1;
887
		}
888
		$endfor = $this->rsBlockNum2($spec);
889 View Code Duplication
		for ($i=0; $i < $endfor; ++$i) {
890
			$ecc = array_slice($this->ecccode, $eccPos);
891
			$this->rsblocks[$blockNo] = array();
892
			$this->rsblocks[$blockNo]['dataLength'] = $dl;
893
			$this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
894
			$this->rsblocks[$blockNo]['eccLength'] = $el;
895
			$ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
896
			$this->rsblocks[$blockNo]['ecc'] = $ecc;
897
			$this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
898
			$dataPos += $dl;
899
			$eccPos += $el;
900
			$blockNo++;
901
		}
902
		return 0;
903
	}
904
905
	/**
906
	 * Return Reed-Solomon block code.
907
	 * @return array rsblocks
908
	 */
909
	protected function getCode() {
910
		if ($this->count < $this->dataLength) {
911
			$row = $this->count % $this->blocks;
912
			$col = $this->count / $this->blocks;
913
			if ($col >= $this->rsblocks[0]['dataLength']) {
914
				$row += $this->b1;
915
			}
916
			$ret = $this->rsblocks[$row]['data'][$col];
917
		} elseif ($this->count < $this->dataLength + $this->eccLength) {
918
			$row = ($this->count - $this->dataLength) % $this->blocks;
919
			$col = ($this->count - $this->dataLength) / $this->blocks;
920
			$ret = $this->rsblocks[$row]['ecc'][$col];
921
		} else {
922
			return 0;
923
		}
924
		$this->count++;
925
		return $ret;
926
	}
927
928
	// - - - - - - - - - - - - - - - - - - - - - - - - -
929
930
	// QRmask
931
932
	/**
933
	 * Write Format Information on frame and returns the number of black bits
934
	 * @param $width (int) frame width
935
	 * @param $frame (array) frame
936
	 * @param $mask (array) masking mode
937
	 * @param $level (int) error correction level
938
	 * @return int blacks
939
	 */
940
	 protected function writeFormatInformation($width, &$frame, $mask, $level) {
941
		$blacks = 0;
942
		$format =  $this->getFormatInfo($mask, $level);
943 View Code Duplication
		for ($i=0; $i<8; ++$i) {
944
			if ($format & 1) {
945
				$blacks += 2;
946
				$v = 0x85;
947
			} else {
948
				$v = 0x84;
949
			}
950
			$frame[8][$width - 1 - $i] = chr($v);
951
			if ($i < 6) {
952
				$frame[$i][8] = chr($v);
953
			} else {
954
				$frame[$i + 1][8] = chr($v);
955
			}
956
			$format = $format >> 1;
957
		}
958 View Code Duplication
		for ($i=0; $i<7; ++$i) {
959
		if ($format & 1) {
960
			$blacks += 2;
961
			$v = 0x85;
962
		} else {
963
			$v = 0x84;
964
		}
965
		$frame[$width - 7 + $i][8] = chr($v);
966
		if ($i == 0) {
967
			$frame[8][7] = chr($v);
968
		} else {
969
			$frame[8][6 - $i] = chr($v);
970
		}
971
		$format = $format >> 1;
972
		}
973
		return $blacks;
974
	}
975
976
	/**
977
	 * mask0
978
	 * @param $x (int) X position
979
	 * @param $y (int) Y position
980
	 * @return int mask
981
	 */
982
	 protected function mask0($x, $y) {
983
		return ($x + $y) & 1;
984
	}
985
986
	/**
987
	 * mask1
988
	 * @param $x (int) X position
989
	 * @param $y (int) Y position
990
	 * @return int mask
991
	 */
992
	 protected function mask1($x, $y) {
993
		return ($y & 1);
994
	}
995
996
	/**
997
	 * mask2
998
	 * @param $x (int) X position
999
	 * @param $y (int) Y position
1000
	 * @return int mask
1001
	 */
1002
	 protected function mask2($x, $y) {
1003
		return ($x % 3);
1004
	}
1005
1006
	/**
1007
	 * mask3
1008
	 * @param $x (int) X position
1009
	 * @param $y (int) Y position
1010
	 * @return int mask
1011
	 */
1012
	 protected function mask3($x, $y) {
1013
		return ($x + $y) % 3;
1014
	}
1015
1016
	/**
1017
	 * mask4
1018
	 * @param $x (int) X position
1019
	 * @param $y (int) Y position
1020
	 * @return int mask
1021
	 */
1022
	 protected function mask4($x, $y) {
1023
		return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1024
	}
1025
1026
	/**
1027
	 * mask5
1028
	 * @param $x (int) X position
1029
	 * @param $y (int) Y position
1030
	 * @return int mask
1031
	 */
1032
	 protected function mask5($x, $y) {
1033
		return (($x * $y) & 1) + ($x * $y) % 3;
1034
	}
1035
1036
	/**
1037
	 * mask6
1038
	 * @param $x (int) X position
1039
	 * @param $y (int) Y position
1040
	 * @return int mask
1041
	 */
1042
	 protected function mask6($x, $y) {
1043
		return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1044
	}
1045
1046
	/**
1047
	 * mask7
1048
	 * @param $x (int) X position
1049
	 * @param $y (int) Y position
1050
	 * @return int mask
1051
	 */
1052
	 protected function mask7($x, $y) {
1053
		return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1054
	}
1055
1056
	/**
1057
	 * Return bitmask
1058
	 * @param $maskNo (int) mask number
1059
	 * @param $width (int) width
1060
	 * @param $frame (array) frame
1061
	 * @return array bitmask
1062
	 */
1063
	protected function generateMaskNo($maskNo, $width, $frame) {
1064
		$bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1065
		for ($y=0; $y<$width; ++$y) {
1066
			for ($x=0; $x<$width; ++$x) {
1067
				if (ord($frame[$y][$x]) & 0x80) {
1068
					$bitMask[$y][$x] = 0;
1069
				} else {
1070
					$maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1071
					$bitMask[$y][$x] = ($maskFunc == 0)?1:0;
1072
				}
1073
			}
1074
		}
1075
		return $bitMask;
1076
	}
1077
1078
	/**
1079
	 * makeMaskNo
1080
	 * @param $maskNo (int)
1081
	 * @param $width (int)
1082
	 * @param $s (int)
1083
	 * @param $d (int)
1084
	 * @param $maskGenOnly (boolean)
1085
	 * @return int b
1086
	 */
1087
	 protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
1088
		$b = 0;
1089
		$bitMask = array();
1090
		$bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
1091
		if ($maskGenOnly) {
1092
			return;
1093
		}
1094
		$d = $s;
1095
		for ($y=0; $y<$width; ++$y) {
1096
			for ($x=0; $x<$width; ++$x) {
1097
				if ($bitMask[$y][$x] == 1) {
1098
					$d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int)($bitMask[$y][$x])));
1099
				}
1100
				$b += (int)(ord($d[$y][$x]) & 1);
1101
			}
1102
		}
1103
		return $b;
1104
	}
1105
1106
	/**
1107
	 * makeMask
1108
	 * @param $width (int)
1109
	 * @param $frame (array)
1110
	 * @param $maskNo (int)
1111
	 * @param $level (int)
1112
	 * @return array mask
1113
	 */
1114
	 protected function makeMask($width, $frame, $maskNo, $level) {
1115
		$masked = array_fill(0, $width, str_repeat("\0", $width));
1116
		$this->makeMaskNo($maskNo, $width, $frame, $masked);
1117
		$this->writeFormatInformation($width, $masked, $maskNo, $level);
1118
		return $masked;
1119
	}
1120
1121
	/**
1122
	 * calcN1N3
1123
	 * @param $length (int)
1124
	 * @return int demerit
1125
	 */
1126
	 protected function calcN1N3($length) {
1127
		$demerit = 0;
1128
		for ($i=0; $i<$length; ++$i) {
1129
			if ($this->runLength[$i] >= 5) {
1130
				$demerit += (N1 + ($this->runLength[$i] - 5));
1131
			}
1132
			if ($i & 1) {
1133
				if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
1134
					$fact = (int)($this->runLength[$i] / 3);
1135
					if (($this->runLength[$i-2] == $fact)
1136
						AND ($this->runLength[$i-1] == $fact)
1137
						AND ($this->runLength[$i+1] == $fact)
1138
						AND ($this->runLength[$i+2] == $fact)) {
1139
						if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
1140
							$demerit += N3;
1141
						} elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
1142
							$demerit += N3;
1143
						}
1144
					}
1145
				}
1146
			}
1147
		}
1148
		return $demerit;
1149
	}
1150
1151
	/**
1152
	 * evaluateSymbol
1153
	 * @param $width (int)
1154
	 * @param $frame (array)
1155
	 * @return int demerit
1156
	 */
1157
	 protected function evaluateSymbol($width, $frame) {
1158
		$head = 0;
1159
		$demerit = 0;
1160
		for ($y=0; $y<$width; ++$y) {
1161
			$head = 0;
1162
			$this->runLength[0] = 1;
1163
			$frameY = $frame[$y];
1164
			if ($y > 0) {
1165
				$frameYM = $frame[$y-1];
1166
			}
1167
			for ($x=0; $x<$width; ++$x) {
1168
				if (($x > 0) AND ($y > 0)) {
1169
					$b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
1170
					$w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
1171
					if (($b22 | ($w22 ^ 1)) & 1) {
1172
						$demerit += N2;
1173
					}
1174
				}
1175
				if (($x == 0) AND (ord($frameY[$x]) & 1)) {
1176
					$this->runLength[0] = -1;
1177
					$head = 1;
1178
					$this->runLength[$head] = 1;
1179 View Code Duplication
				} elseif ($x > 0) {
1180
					if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
1181
						$head++;
1182
						$this->runLength[$head] = 1;
1183
					} else {
1184
						$this->runLength[$head]++;
1185
					}
1186
				}
1187
			}
1188
			$demerit += $this->calcN1N3($head+1);
1189
		}
1190
		for ($x=0; $x<$width; ++$x) {
1191
			$head = 0;
1192
			$this->runLength[0] = 1;
1193
			for ($y=0; $y<$width; ++$y) {
1194
				if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
1195
					$this->runLength[0] = -1;
1196
					$head = 1;
1197
					$this->runLength[$head] = 1;
1198 View Code Duplication
				} elseif ($y > 0) {
1199
					if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
1200
						$head++;
1201
						$this->runLength[$head] = 1;
1202
					} else {
1203
						$this->runLength[$head]++;
1204
					}
1205
				}
1206
			}
1207
			$demerit += $this->calcN1N3($head+1);
1208
		}
1209
		return $demerit;
1210
	}
1211
1212
	/**
1213
	 * mask
1214
	 * @param $width (int)
1215
	 * @param $frame (array)
1216
	 * @param $level (int)
1217
	 * @return array best mask
1218
	 */
1219
	 protected function mask($width, $frame, $level) {
1220
		$minDemerit = PHP_INT_MAX;
1221
		$bestMaskNum = 0;
1222
		$bestMask = array();
1223
		$checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1224
		if (QR_FIND_FROM_RANDOM !== false) {
1225
			$howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
1226
			for ($i = 0; $i <  $howManuOut; ++$i) {
1227
				$remPos = rand (0, count($checked_masks)-1);
1228
				unset($checked_masks[$remPos]);
1229
				$checked_masks = array_values($checked_masks);
1230
			}
1231
		}
1232
		$bestMask = $frame;
1233
		foreach ($checked_masks as $i) {
1234
			$mask = array_fill(0, $width, str_repeat("\0", $width));
1235
			$demerit = 0;
1236
			$blacks = 0;
1237
			$blacks  = $this->makeMaskNo($i, $width, $frame, $mask);
1238
			$blacks += $this->writeFormatInformation($width, $mask, $i, $level);
1239
			$blacks  = (int)(100 * $blacks / ($width * $width));
1240
			$demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
1241
			$demerit += $this->evaluateSymbol($width, $mask);
1242
			if ($demerit < $minDemerit) {
1243
				$minDemerit = $demerit;
1244
				$bestMask = $mask;
1245
				$bestMaskNum = $i;
1246
			}
1247
		}
1248
		return $bestMask;
1249
	}
1250
1251
	// - - - - - - - - - - - - - - - - - - - - - - - - -
1252
1253
	// QRsplit
1254
1255
	/**
1256
	 * Return true if the character at specified position is a number
1257
	 * @param $str (string) string
1258
	 * @param $pos (int) characted position
1259
	 * @return boolean true of false
1260
	 */
1261
	 protected function isdigitat($str, $pos) {
1262
		if ($pos >= strlen($str)) {
1263
			return false;
1264
		}
1265
		return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
1266
	}
1267
1268
	/**
1269
	 * Return true if the character at specified position is an alphanumeric character
1270
	 * @param $str (string) string
1271
	 * @param $pos (int) characted position
1272
	 * @return boolean true of false
1273
	 */
1274
	 protected function isalnumat($str, $pos) {
1275
		if ($pos >= strlen($str)) {
1276
			return false;
1277
		}
1278
		return ($this->lookAnTable(ord($str[$pos])) >= 0);
1279
	}
1280
1281
	/**
1282
	 * identifyMode
1283
	 * @param $pos (int)
1284
	 * @return int mode
1285
	 */
1286
	 protected function identifyMode($pos) {
1287
		if ($pos >= strlen($this->dataStr)) {
1288
			return QR_MODE_NL;
1289
		}
1290
		$c = $this->dataStr[$pos];
1291
		if ($this->isdigitat($this->dataStr, $pos)) {
1292
			return QR_MODE_NM;
1293
		} elseif ($this->isalnumat($this->dataStr, $pos)) {
1294
			return QR_MODE_AN;
1295
		} elseif ($this->hint == QR_MODE_KJ) {
1296
			if ($pos+1 < strlen($this->dataStr)) {
1297
				$d = $this->dataStr[$pos+1];
1298
				$word = (ord($c) << 8) | ord($d);
1299
				if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1300
					return QR_MODE_KJ;
1301
				}
1302
			}
1303
		}
1304
		return QR_MODE_8B;
1305
	}
1306
1307
	/**
1308
	 * eatNum
1309
	 * @return int run
1310
	 */
1311
	 protected function eatNum() {
1312
		$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1313
		$p = 0;
1314
		while($this->isdigitat($this->dataStr, $p)) {
1315
			$p++;
1316
		}
1317
		$run = $p;
1318
		$mode = $this->identifyMode($p);
1319 View Code Duplication
		if ($mode == QR_MODE_8B) {
1320
			$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1321
			+ $this->estimateBitsMode8(1)         // + 4 + l8
1322
			- $this->estimateBitsMode8($run + 1); // - 4 - l8
1323
			if ($dif > 0) {
1324
				return $this->eat8();
1325
			}
1326
		}
1327 View Code Duplication
		if ($mode == QR_MODE_AN) {
1328
			$dif = $this->estimateBitsModeNum($run) + 4 + $ln
1329
			+ $this->estimateBitsModeAn(1)        // + 4 + la
1330
			- $this->estimateBitsModeAn($run + 1);// - 4 - la
1331
			if ($dif > 0) {
1332
				return $this->eatAn();
1333
			}
1334
		}
1335
		$this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
1336
		return $run;
1337
	}
1338
1339
	/**
1340
	 * eatAn
1341
	 * @return int run
1342
	 */
1343
	 protected function eatAn() {
1344
		$la = $this->lengthIndicator(QR_MODE_AN,  $this->version);
1345
		$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1346
		$p =1 ;
1347
		while($this->isalnumat($this->dataStr, $p)) {
1348
			if ($this->isdigitat($this->dataStr, $p)) {
1349
				$q = $p;
1350
				while($this->isdigitat($this->dataStr, $q)) {
1351
					$q++;
1352
				}
1353
				$dif = $this->estimateBitsModeAn($p) // + 4 + la
1354
				+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1355
				- $this->estimateBitsModeAn($q); // - 4 - la
1356
				if ($dif < 0) {
1357
					break;
1358
				} else {
1359
					$p = $q;
1360
				}
1361
			} else {
1362
				$p++;
1363
			}
1364
		}
1365
		$run = $p;
1366
		if (!$this->isalnumat($this->dataStr, $p)) {
1367
			$dif = $this->estimateBitsModeAn($run) + 4 + $la
1368
			+ $this->estimateBitsMode8(1) // + 4 + l8
1369
			- $this->estimateBitsMode8($run + 1); // - 4 - l8
1370
			if ($dif > 0) {
1371
				return $this->eat8();
1372
			}
1373
		}
1374
		$this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
1375
		return $run;
1376
	}
1377
1378
	/**
1379
	 * eatKanji
1380
	 * @return int run
1381
	 */
1382
	 protected function eatKanji() {
1383
		$p = 0;
1384
		while($this->identifyMode($p) == QR_MODE_KJ) {
1385
			$p += 2;
1386
		}
1387
		$this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
1388
		return $run;
1389
	}
1390
1391
	/**
1392
	 * eat8
1393
	 * @return int run
1394
	 */
1395
	 protected function eat8() {
1396
		$la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1397
		$ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1398
		$p = 1;
1399
		$dataStrLen = strlen($this->dataStr);
1400
		while($p < $dataStrLen) {
1401
			$mode = $this->identifyMode($p);
1402
			if ($mode == QR_MODE_KJ) {
1403
				break;
1404
			}
1405
			if ($mode == QR_MODE_NM) {
1406
				$q = $p;
1407
				while($this->isdigitat($this->dataStr, $q)) {
1408
					$q++;
1409
				}
1410
				$dif = $this->estimateBitsMode8($p) // + 4 + l8
1411
				+ $this->estimateBitsModeNum($q - $p) + 4 + $ln
1412
				- $this->estimateBitsMode8($q); // - 4 - l8
1413
				if ($dif < 0) {
1414
					break;
1415
				} else {
1416
					$p = $q;
1417
				}
1418
			} elseif ($mode == QR_MODE_AN) {
1419
				$q = $p;
1420
				while($this->isalnumat($this->dataStr, $q)) {
1421
					$q++;
1422
				}
1423
				$dif = $this->estimateBitsMode8($p)  // + 4 + l8
1424
				+ $this->estimateBitsModeAn($q - $p) + 4 + $la
1425
				- $this->estimateBitsMode8($q); // - 4 - l8
1426
				if ($dif < 0) {
1427
					break;
1428
				} else {
1429
					$p = $q;
1430
				}
1431
			} else {
1432
				$p++;
1433
			}
1434
		}
1435
		$run = $p;
1436
		$this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
1437
		return $run;
1438
	}
1439
1440
	/**
1441
	 * splitString
1442
	 * @return (int)
1443
	 */
1444
	 protected function splitString() {
1445
		while (strlen($this->dataStr) > 0) {
1446
			$mode = $this->identifyMode(0);
1447
			switch ($mode) {
1448
				case QR_MODE_NM: {
1449
					$length = $this->eatNum();
1450
					break;
1451
				}
1452
				case QR_MODE_AN: {
1453
					$length = $this->eatAn();
1454
					break;
1455
				}
1456
				case QR_MODE_KJ: {
1457
					if ($hint == QR_MODE_KJ) {
1458
						$length = $this->eatKanji();
1459
					} else {
1460
						$length = $this->eat8();
1461
					}
1462
					break;
1463
				}
1464
				default: {
1465
					$length = $this->eat8();
1466
					break;
1467
				}
1468
			}
1469
			if ($length == 0) {
1470
				return 0;
1471
			}
1472
			if ($length < 0) {
1473
				return -1;
1474
			}
1475
			$this->dataStr = substr($this->dataStr, $length);
1476
		}
1477
		return 0;
1478
	}
1479
1480
	/**
1481
	 * toUpper
1482
	 */
1483
	 protected function toUpper() {
1484
		$stringLen = strlen($this->dataStr);
1485
		$p = 0;
1486
		while ($p < $stringLen) {
1487
			$mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
1488
			if ($mode == QR_MODE_KJ) {
1489
				$p += 2;
1490
			} else {
1491
				if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
1492
					$this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
1493
				}
1494
				$p++;
1495
			}
1496
		}
1497
		return $this->dataStr;
1498
	}
1499
1500
	// - - - - - - - - - - - - - - - - - - - - - - - - -
1501
1502
	// QRinputItem
1503
1504
	/**
1505
	 * newInputItem
1506
	 * @param $mode (int)
1507
	 * @param $size (int)
1508
	 * @param $data (array)
1509
	 * @param $bstream (array)
1510
	 * @return array input item
1511
	 */
1512
	 protected function newInputItem($mode, $size, $data, $bstream=null) {
1513
		$setData = array_slice($data, 0, $size);
1514
		if (count($setData) < $size) {
1515
			$setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1516
		}
1517
		if (!$this->check($mode, $size, $setData)) {
1518
			return NULL;
1519
		}
1520
		$inputitem = array();
1521
		$inputitem['mode'] = $mode;
1522
		$inputitem['size'] = $size;
1523
		$inputitem['data'] = $setData;
1524
		$inputitem['bstream'] = $bstream;
1525
		return $inputitem;
1526
	}
1527
1528
	/**
1529
	 * encodeModeNum
1530
	 * @param $inputitem (array)
1531
	 * @param $version (int)
1532
	 * @return array input item
1533
	 */
1534
	 protected function encodeModeNum($inputitem, $version) {
1535
		$words = (int)($inputitem['size'] / 3);
1536
		$inputitem['bstream'] = array();
1537
		$val = 0x1;
1538
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1539
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
1540
		for ($i=0; $i < $words; ++$i) {
1541
			$val  = (ord($inputitem['data'][$i*3  ]) - ord('0')) * 100;
1542
			$val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
1543
			$val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
1544
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
1545
		}
1546
		if ($inputitem['size'] - $words * 3 == 1) {
1547
			$val = ord($inputitem['data'][$words*3]) - ord('0');
1548
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1549
		} elseif (($inputitem['size'] - ($words * 3)) == 2) {
1550
			$val  = (ord($inputitem['data'][$words*3  ]) - ord('0')) * 10;
1551
			$val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
1552
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
1553
		}
1554
		return $inputitem;
1555
	}
1556
1557
	/**
1558
	 * encodeModeAn
1559
	 * @param $inputitem (array)
1560
	 * @param $version (int)
1561
	 * @return array input item
1562
	 */
1563
	 protected function encodeModeAn($inputitem, $version) {
1564
		$words = (int)($inputitem['size'] / 2);
1565
		$inputitem['bstream'] = array();
1566
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
1567
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
1568
		for ($i=0; $i < $words; ++$i) {
1569
			$val  = (int)($this->lookAnTable(ord($inputitem['data'][$i*2])) * 45);
1570
			$val += (int)($this->lookAnTable(ord($inputitem['data'][($i*2)+1])));
1571
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
1572
		}
1573
		if ($inputitem['size'] & 1) {
1574
			$val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
1575
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
1576
		}
1577
		return $inputitem;
1578
	}
1579
1580
	/**
1581
	 * encodeMode8
1582
	 * @param $inputitem (array)
1583
	 * @param $version (int)
1584
	 * @return array input item
1585
	 */
1586
	 protected function encodeMode8($inputitem, $version) {
1587
		$inputitem['bstream'] = array();
1588
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
1589
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
1590
		for ($i=0; $i < $inputitem['size']; ++$i) {
1591
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
1592
		}
1593
		return $inputitem;
1594
	}
1595
1596
	/**
1597
	 * encodeModeKanji
1598
	 * @param $inputitem (array)
1599
	 * @param $version (int)
1600
	 * @return array input item
1601
	 */
1602
	 protected function encodeModeKanji($inputitem, $version) {
1603
		$inputitem['bstream'] = array();
1604
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
1605
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
1606
		for ($i=0; $i<$inputitem['size']; $i+=2) {
1607
			$val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
1608
			if ($val <= 0x9ffc) {
1609
				$val -= 0x8140;
1610
			} else {
1611
				$val -= 0xc140;
1612
			}
1613
			$h = ($val >> 8) * 0xc0;
1614
			$val = ($val & 0xff) + $h;
1615
			$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
1616
		}
1617
		return $inputitem;
1618
	}
1619
1620
	/**
1621
	 * encodeModeStructure
1622
	 * @param $inputitem (array)
1623
	 * @return array input item
1624
	 */
1625
	 protected function encodeModeStructure($inputitem) {
1626
		$inputitem['bstream'] = array();
1627
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
1628
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
1629
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
1630
		$inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
1631
		return $inputitem;
1632
	}
1633
1634
	/**
1635
	 * encodeBitStream
1636
	 * @param $inputitem (array)
1637
	 * @param $version (int)
1638
	 * @return array input item
1639
	 */
1640
	 protected function encodeBitStream($inputitem, $version) {
1641
		$inputitem['bstream'] = array();
1642
		$words = $this->maximumWords($inputitem['mode'], $version);
1643
		if ($inputitem['size'] > $words) {
1644
			$st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
1645
			$st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1646
			$st1 = $this->encodeBitStream($st1, $version);
1647
			$st2 = $this->encodeBitStream($st2, $version);
1648
			$inputitem['bstream'] = array();
1649
			$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
1650
			$inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
1651
		} else {
1652
			switch($inputitem['mode']) {
1653
				case QR_MODE_NM: {
1654
					$inputitem = $this->encodeModeNum($inputitem, $version);
1655
					break;
1656
				}
1657
				case QR_MODE_AN: {
1658
					$inputitem = $this->encodeModeAn($inputitem, $version);
1659
					break;
1660
				}
1661
				case QR_MODE_8B: {
1662
					$inputitem = $this->encodeMode8($inputitem, $version);
1663
					break;
1664
				}
1665
				case QR_MODE_KJ: {
1666
					$inputitem = $this->encodeModeKanji($inputitem, $version);
1667
					break;
1668
				}
1669
				case QR_MODE_ST: {
1670
					$inputitem = $this->encodeModeStructure($inputitem);
1671
					break;
1672
				}
1673
				default: {
1674
					break;
1675
				}
1676
			}
1677
		}
1678
		return $inputitem;
1679
	}
1680
1681
	// - - - - - - - - - - - - - - - - - - - - - - - - -
1682
1683
	// QRinput
1684
1685
	/**
1686
	 * Append data to an input object.
1687
	 * The data is copied and appended to the input object.
1688
	 * @param $items (arrray) input items
1689
	 * @param $mode (int) encoding mode.
1690
	 * @param $size (int) size of data (byte).
1691
	 * @param $data (array) array of input data.
1692
	 * @return items
1693
	 *
1694
	 */
1695
	protected function appendNewInputItem($items, $mode, $size, $data) {
1696
		$newitem = $this->newInputItem($mode, $size, $data);
1697
		if (!empty($newitem)) {
1698
			$items[] = $newitem;
1699
		}
1700
		return $items;
1701
	}
1702
1703
	/**
1704
	 * insertStructuredAppendHeader
1705
	 * @param $items (array)
1706
	 * @param $size (int)
1707
	 * @param $index (int)
1708
	 * @param $parity (int)
1709
	 * @return array items
1710
	 */
1711
	 protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1712
		if ($size > MAX_STRUCTURED_SYMBOLS) {
1713
			return -1;
1714
		}
1715
		if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1716
			return -1;
1717
		}
1718
		$buf = array($size, $index, $parity);
1719
		$entry = $this->newInputItem(QR_MODE_ST, 3, buf);
1720
		array_unshift($items, $entry);
1721
		return $items;
1722
	}
1723
1724
	/**
1725
	 * calcParity
1726
	 * @param $items (array)
1727
	 * @return int parity
1728
	 */
1729
	 protected function calcParity($items) {
1730
		$parity = 0;
1731
		foreach ($items as $item) {
1732
			if ($item['mode'] != QR_MODE_ST) {
1733
				for ($i=$item['size']-1; $i>=0; --$i) {
1734
					$parity ^= $item['data'][$i];
1735
				}
1736
			}
1737
		}
1738
		return $parity;
1739
	}
1740
1741
	/**
1742
	 * checkModeNum
1743
	 * @param $size (int)
1744
	 * @param $data (array)
1745
	 * @return boolean true or false
1746
	 */
1747
	 protected function checkModeNum($size, $data) {
1748
		for ($i=0; $i<$size; ++$i) {
1749
			if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
1750
				return false;
1751
			}
1752
		}
1753
		return true;
1754
	}
1755
1756
	/**
1757
	 * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1758
	 * @param $c (int) character value
1759
	 * @return value
1760
	 */
1761
	protected function lookAnTable($c) {
1762
		return (($c > 127)?-1:$this->anTable[$c]);
1763
	}
1764
1765
	/**
1766
	 * checkModeAn
1767
	 * @param $size (int)
1768
	 * @param $data (array)
1769
	 * @return boolean true or false
1770
	 */
1771
	 protected function checkModeAn($size, $data) {
1772
		for ($i=0; $i<$size; ++$i) {
1773
			if ($this->lookAnTable(ord($data[$i])) == -1) {
1774
				return false;
1775
			}
1776
		}
1777
		return true;
1778
	}
1779
1780
	/**
1781
	 * estimateBitsModeNum
1782
	 * @param $size (int)
1783
	 * @return int number of bits
1784
	 */
1785
	 protected function estimateBitsModeNum($size) {
1786
		$w = (int)($size / 3);
1787
		$bits = ($w * 10);
1788
		switch($size - ($w * 3)) {
1789
			case 1: {
1790
				$bits += 4;
1791
				break;
1792
			}
1793
			case 2: {
1794
				$bits += 7;
1795
				break;
1796
			}
1797
		}
1798
		return $bits;
1799
	}
1800
1801
	/**
1802
	 * estimateBitsModeAn
1803
	 * @param $size (int)
1804
	 * @return int number of bits
1805
	 */
1806
	 protected function estimateBitsModeAn($size) {
1807
		$bits = (int)($size * 5.5); // (size / 2 ) * 11
1808
		if ($size & 1) {
1809
			$bits += 6;
1810
		}
1811
		return $bits;
1812
	}
1813
1814
	/**
1815
	 * estimateBitsMode8
1816
	 * @param $size (int)
1817
	 * @return int number of bits
1818
	 */
1819
	 protected function estimateBitsMode8($size) {
1820
		return (int)($size * 8);
1821
	}
1822
1823
	/**
1824
	 * estimateBitsModeKanji
1825
	 * @param $size (int)
1826
	 * @return int number of bits
1827
	 */
1828
	 protected function estimateBitsModeKanji($size) {
1829
		return (int)($size * 6.5); // (size / 2 ) * 13
1830
	}
1831
1832
	/**
1833
	 * checkModeKanji
1834
	 * @param $size (int)
1835
	 * @param $data (array)
1836
	 * @return boolean true or false
1837
	 */
1838
	 protected function checkModeKanji($size, $data) {
1839
		if ($size & 1) {
1840
			return false;
1841
		}
1842
		for ($i=0; $i<$size; $i+=2) {
1843
			$val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1844
			if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1845
				return false;
1846
			}
1847
		}
1848
		return true;
1849
	}
1850
1851
	/**
1852
	 * Validate the input data.
1853
	 * @param $mode (int) encoding mode.
1854
	 * @param $size (int) size of data (byte).
1855
	 * @param $data (array) data to validate
1856
	 * @return boolean true in case of valid data, false otherwise
1857
	 */
1858
	protected function check($mode, $size, $data) {
1859
		if ($size <= 0) {
1860
			return false;
1861
		}
1862
		switch($mode) {
1863
			case QR_MODE_NM: {
1864
				return $this->checkModeNum($size, $data);
1865
			}
1866
			case QR_MODE_AN: {
1867
				return $this->checkModeAn($size, $data);
1868
			}
1869
			case QR_MODE_KJ: {
1870
				return $this->checkModeKanji($size, $data);
1871
			}
1872
			case QR_MODE_8B: {
1873
				return true;
1874
			}
1875
			case QR_MODE_ST: {
1876
				return true;
1877
			}
1878
			default: {
1879
				break;
1880
			}
1881
		}
1882
		return false;
1883
	}
1884
1885
	/**
1886
	 * estimateBitStreamSize
1887
	 * @param $items (array)
1888
	 * @param $version (int)
1889
	 * @return int bits
1890
	 */
1891
	 protected function estimateBitStreamSize($items, $version) {
1892
		$bits = 0;
1893
		if ($version == 0) {
1894
			$version = 1;
1895
		}
1896
		foreach ($items as $item) {
1897
			switch($item['mode']) {
1898
				case QR_MODE_NM: {
1899
					$bits = $this->estimateBitsModeNum($item['size']);
1900
					break;
1901
				}
1902
				case QR_MODE_AN: {
1903
					$bits = $this->estimateBitsModeAn($item['size']);
1904
					break;
1905
				}
1906
				case QR_MODE_8B: {
1907
					$bits = $this->estimateBitsMode8($item['size']);
1908
					break;
1909
				}
1910
				case QR_MODE_KJ: {
1911
					$bits = $this->estimateBitsModeKanji($item['size']);
1912
					break;
1913
				}
1914
				case QR_MODE_ST: {
1915
					return STRUCTURE_HEADER_BITS;
1916
				}
1917
				default: {
1918
					return 0;
1919
				}
1920
			}
1921
			$l = $this->lengthIndicator($item['mode'], $version);
1922
			$m = 1 << $l;
1923
			$num = (int)(($item['size'] + $m - 1) / $m);
1924
			$bits += $num * (4 + $l);
1925
		}
1926
		return $bits;
1927
	}
1928
1929
	/**
1930
	 * estimateVersion
1931
	 * @param $items (array)
1932
	 * @return int version
1933
	 */
1934
	 protected function estimateVersion($items) {
1935
		$version = 0;
1936
		$prev = 0;
1937
		do {
1938
			$prev = $version;
1939
			$bits = $this->estimateBitStreamSize($items, $prev);
1940
			$version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1941
			if ($version < 0) {
1942
				return -1;
1943
			}
1944
		} while ($version > $prev);
1945
		return $version;
1946
	}
1947
1948
	/**
1949
	 * lengthOfCode
1950
	 * @param $mode (int)
1951
	 * @param $version (int)
1952
	 * @param $bits (int)
1953
	 * @return int size
1954
	 */
1955
	 protected function lengthOfCode($mode, $version, $bits) {
1956
		$payload = $bits - 4 - $this->lengthIndicator($mode, $version);
1957
		switch($mode) {
1958
			case QR_MODE_NM: {
1959
				$chunks = (int)($payload / 10);
1960
				$remain = $payload - $chunks * 10;
1961
				$size = $chunks * 3;
1962
				if ($remain >= 7) {
1963
					$size += 2;
1964
				} elseif ($remain >= 4) {
1965
					$size += 1;
1966
				}
1967
				break;
1968
			}
1969
			case QR_MODE_AN: {
1970
				$chunks = (int)($payload / 11);
1971
				$remain = $payload - $chunks * 11;
1972
				$size = $chunks * 2;
1973
				if ($remain >= 6) {
1974
					++$size;
1975
				}
1976
				break;
1977
			}
1978
			case QR_MODE_8B: {
1979
				$size = (int)($payload / 8);
1980
				break;
1981
			}
1982
			case QR_MODE_KJ: {
1983
				$size = (int)(($payload / 13) * 2);
1984
				break;
1985
			}
1986
			case QR_MODE_ST: {
1987
				$size = (int)($payload / 8);
1988
				break;
1989
			}
1990
			default: {
1991
				$size = 0;
1992
				break;
1993
			}
1994
		}
1995
		$maxsize = $this->maximumWords($mode, $version);
1996
		if ($size < 0) {
1997
			$size = 0;
1998
		}
1999
		if ($size > $maxsize) {
2000
			$size = $maxsize;
2001
		}
2002
		return $size;
2003
	}
2004
2005
	/**
2006
	 * createBitStream
2007
	 * @param $items (array)
2008
	 * @return array of items and total bits
2009
	 */
2010
	 protected function createBitStream($items) {
2011
		$total = 0;
2012
		foreach ($items as $key => $item) {
2013
			$items[$key] = $this->encodeBitStream($item, $this->version);
2014
			$bits = count($items[$key]['bstream']);
2015
			$total += $bits;
2016
		}
2017
		return array($items, $total);
2018
	}
2019
2020
	/**
2021
	 * convertData
2022
	 * @param $items (array)
2023
	 * @return array items
2024
	 */
2025
	 protected function convertData($items) {
2026
		$ver = $this->estimateVersion($items);
2027
		if ($ver > $this->version) {
2028
			$this->version = $ver;
2029
		}
2030
		while (true) {
2031
			$cbs = $this->createBitStream($items);
2032
			$items = $cbs[0];
2033
			$bits = $cbs[1];
2034
			if ($bits < 0) {
2035
				return -1;
2036
			}
2037
			$ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
2038
			if ($ver < 0) {
2039
				return -1;
2040
			} elseif ($ver > $this->version) {
2041
				$this->version = $ver;
2042
			} else {
2043
				break;
2044
			}
2045
		}
2046
		return $items;
2047
	}
2048
2049
	/**
2050
	 * Append Padding Bit to bitstream
2051
	 * @param $bstream (array)
2052
	 * @return array bitstream
2053
	 */
2054
	 protected function appendPaddingBit($bstream) {
2055
	 	if (is_null($bstream)) {
2056
	 		return null;
2057
	 	}
2058
		$bits = count($bstream);
2059
		$maxwords = $this->getDataLength($this->version, $this->level);
2060
		$maxbits = $maxwords * 8;
2061
		if ($maxbits == $bits) {
2062
			return $bstream;
2063
		}
2064
		if ($maxbits - $bits < 5) {
2065
			return $this->appendNum($bstream, $maxbits - $bits, 0);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->appendNum($bstream, $maxbits - $bits, 0); of type integer|array adds the type integer to the return on line 2065 which is incompatible with the return type documented by QRcode::appendPaddingBit of type array.
Loading history...
2066
		}
2067
		$bits += 4;
2068
		$words = (int)(($bits + 7) / 8);
2069
		$padding = array();
2070
		$padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
2071
		$padlen = $maxwords - $words;
2072
		if ($padlen > 0) {
2073
			$padbuf = array();
2074
			for ($i=0; $i<$padlen; ++$i) {
2075
				$padbuf[$i] = ($i&1)?0x11:0xec;
2076
			}
2077
			$padding = $this->appendBytes($padding, $padlen, $padbuf);
2078
		}
2079
		return $this->appendBitstream($bstream, $padding);
2080
	}
2081
2082
	/**
2083
	 * mergeBitStream
2084
	 * @param $items (array) items
2085
	 * @return array bitstream
2086
	 */
2087
	 protected function mergeBitStream($items) {
2088
		$items = $this->convertData($items);
2089
		if (!is_array($items)) {
2090
			return null;
2091
		}
2092
		$bstream = array();
2093
		foreach ($items as $item) {
2094
			$bstream = $this->appendBitstream($bstream, $item['bstream']);
2095
		}
2096
		return $bstream;
2097
	}
2098
2099
	/**
2100
	 * Returns a stream of bits.
2101
	 * @param $items (int)
2102
	 * @return array padded merged byte stream
2103
	 */
2104
	protected function getBitStream($items) {
2105
		$bstream = $this->mergeBitStream($items);
2106
		return $this->appendPaddingBit($bstream);
2107
	}
2108
2109
	/**
2110
	 * Pack all bit streams padding bits into a byte array.
2111
	 * @param $items (int)
2112
	 * @return array padded merged byte stream
2113
	 */
2114
	protected function getByteStream($items) {
2115
		$bstream = $this->getBitStream($items);
2116
		return $this->bitstreamToByte($bstream);
2117
	}
2118
2119
	// - - - - - - - - - - - - - - - - - - - - - - - - -
2120
2121
	// QRbitstream
2122
2123
	/**
2124
	 * Return an array with zeros
2125
	 * @param $setLength (int) array size
2126
	 * @return array
2127
	 */
2128
	 protected function allocate($setLength) {
2129
		return array_fill(0, $setLength, 0);
2130
	}
2131
2132
	/**
2133
	 * Return new bitstream from number
2134
	 * @param $bits (int) number of bits
2135
	 * @param $num (int) number
2136
	 * @return array bitstream
2137
	 */
2138
	 protected function newFromNum($bits, $num) {
2139
		$bstream = $this->allocate($bits);
2140
		$mask = 1 << ($bits - 1);
2141 View Code Duplication
		for ($i=0; $i<$bits; ++$i) {
2142
			if ($num & $mask) {
2143
				$bstream[$i] = 1;
2144
			} else {
2145
				$bstream[$i] = 0;
2146
			}
2147
			$mask = $mask >> 1;
2148
		}
2149
		return $bstream;
2150
	}
2151
2152
	/**
2153
	 * Return new bitstream from bytes
2154
	 * @param $size (int) size
2155
	 * @param $data (array) bytes
2156
	 * @return array bitstream
2157
	 */
2158
	 protected function newFromBytes($size, $data) {
2159
		$bstream = $this->allocate($size * 8);
2160
		$p=0;
2161
		for ($i=0; $i<$size; ++$i) {
2162
			$mask = 0x80;
2163 View Code Duplication
			for ($j=0; $j<8; ++$j) {
2164
				if ($data[$i] & $mask) {
2165
					$bstream[$p] = 1;
2166
				} else {
2167
					$bstream[$p] = 0;
2168
				}
2169
				$p++;
2170
				$mask = $mask >> 1;
2171
			}
2172
		}
2173
		return $bstream;
2174
	}
2175
2176
	/**
2177
	 * Append one bitstream to another
2178
	 * @param $bitstream (array) original bitstream
2179
	 * @param $append (array) bitstream to append
2180
	 * @return array bitstream
2181
	 */
2182
	 protected function appendBitstream($bitstream, $append) {
2183
		if ((!is_array($append)) OR (count($append) == 0)) {
2184
			return $bitstream;
2185
		}
2186
		if (count($bitstream) == 0) {
2187
			return $append;
2188
		}
2189
		return array_values(array_merge($bitstream, $append));
2190
	}
2191
2192
	/**
2193
	 * Append one bitstream created from number to another
2194
	 * @param $bitstream (array) original bitstream
2195
	 * @param $bits (int) number of bits
2196
	 * @param $num (int) number
2197
	 * @return array bitstream
2198
	 */
2199
	 protected function appendNum($bitstream, $bits, $num) {
2200
		if ($bits == 0) {
2201
			return 0;
2202
		}
2203
		$b = $this->newFromNum($bits, $num);
2204
		return $this->appendBitstream($bitstream, $b);
2205
	}
2206
2207
	/**
2208
	 * Append one bitstream created from bytes to another
2209
	 * @param $bitstream (array) original bitstream
2210
	 * @param $size (int) size
2211
	 * @param $data (array) bytes
2212
	 * @return array bitstream
2213
	 */
2214
	 protected function appendBytes($bitstream, $size, $data) {
2215
		if ($size == 0) {
2216
			return 0;
2217
		}
2218
		$b = $this->newFromBytes($size, $data);
2219
		return $this->appendBitstream($bitstream, $b);
2220
	}
2221
2222
	/**
2223
	 * Convert bitstream to bytes
2224
	 * @param $bstream (array) original bitstream
2225
	 * @return array of bytes
2226
	 */
2227
	 protected function bitstreamToByte($bstream) {
2228
		if (is_null($bstream)) {
2229
	 		return null;
2230
	 	}
2231
		$size = count($bstream);
2232
		if ($size == 0) {
2233
			return array();
2234
		}
2235
		$data = array_fill(0, (int)(($size + 7) / 8), 0);
2236
		$bytes = (int)($size / 8);
2237
		$p = 0;
2238
		for ($i=0; $i<$bytes; $i++) {
2239
			$v = 0;
2240 View Code Duplication
			for ($j=0; $j<8; $j++) {
2241
				$v = $v << 1;
2242
				$v |= $bstream[$p];
2243
				$p++;
2244
			}
2245
			$data[$i] = $v;
2246
		}
2247
		if ($size & 7) {
2248
			$v = 0;
2249 View Code Duplication
			for ($j=0; $j<($size & 7); $j++) {
2250
				$v = $v << 1;
2251
				$v |= $bstream[$p];
2252
				$p++;
2253
			}
2254
			$data[$bytes] = $v;
2255
		}
2256
		return $data;
2257
	}
2258
2259
	// - - - - - - - - - - - - - - - - - - - - - - - - -
2260
2261
	// QRspec
2262
2263
	/**
2264
	 * Replace a value on the array at the specified position
2265
	 * @param $srctab (array)
2266
	 * @param $x (int) X position
2267
	 * @param $y (int) Y position
2268
	 * @param $repl (string) value to replace
2269
	 * @param $replLen (int) length of the repl string
2270
	 * @return array srctab
2271
	 */
2272
	 protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
2273
		$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
2274
		return $srctab;
2275
	}
2276
2277
	/**
2278
	 * Return maximum data code length (bytes) for the version.
2279
	 * @param $version (int) version
2280
	 * @param $level (int) error correction level
2281
	 * @return int maximum size (bytes)
2282
	 */
2283
	protected function getDataLength($version, $level) {
2284
		return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
2285
	}
2286
2287
	/**
2288
	 * Return maximum error correction code length (bytes) for the version.
2289
	 * @param $version (int) version
2290
	 * @param $level (int) error correction level
2291
	 * @return int ECC size (bytes)
2292
	 */
2293
	protected function getECCLength($version, $level){
2294
		return $this->capacity[$version][QRCAP_EC][$level];
2295
	}
2296
2297
	/**
2298
	 * Return the width of the symbol for the version.
2299
	 * @param $version (int) version
2300
	 * @return int width
2301
	 */
2302
	protected function getWidth($version) {
2303
		return $this->capacity[$version][QRCAP_WIDTH];
2304
	}
2305
2306
	/**
2307
	 * Return the numer of remainder bits.
2308
	 * @param $version (int) version
2309
	 * @return int number of remainder bits
2310
	 */
2311
	protected function getRemainder($version) {
2312
		return $this->capacity[$version][QRCAP_REMINDER];
2313
	}
2314
2315
	/**
2316
	 * Return a version number that satisfies the input code length.
2317
	 * @param $size (int) input code length (bytes)
2318
	 * @param $level (int) error correction level
2319
	 * @return int version number
2320
	 */
2321
	protected function getMinimumVersion($size, $level) {
2322
		for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2323
			$words = ($this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]);
2324
			if ($words >= $size) {
2325
				return $i;
2326
			}
2327
		}
2328
		// the size of input data is greater than QR capacity, try to lover the error correction mode
2329
		return -1;
2330
	}
2331
2332
	/**
2333
	 * Return the size of length indicator for the mode and version.
2334
	 * @param $mode (int) encoding mode
2335
	 * @param $version (int) version
2336
	 * @return int the size of the appropriate length indicator (bits).
2337
	 */
2338
	protected function lengthIndicator($mode, $version) {
2339
		if ($mode == QR_MODE_ST) {
2340
			return 0;
2341
		}
2342 View Code Duplication
		if ($version <= 9) {
2343
			$l = 0;
2344
		} elseif ($version <= 26) {
2345
			$l = 1;
2346
		} else {
2347
			$l = 2;
2348
		}
2349
		return $this->lengthTableBits[$mode][$l];
2350
	}
2351
2352
	/**
2353
	 * Return the maximum length for the mode and version.
2354
	 * @param $mode (int) encoding mode
2355
	 * @param $version (int) version
2356
	 * @return int the maximum length (bytes)
2357
	 */
2358
	protected function maximumWords($mode, $version) {
2359
		if ($mode == QR_MODE_ST) {
2360
			return 3;
2361
		}
2362 View Code Duplication
		if ($version <= 9) {
2363
			$l = 0;
2364
		} else if ($version <= 26) {
2365
			$l = 1;
2366
		} else {
2367
			$l = 2;
2368
		}
2369
		$bits = $this->lengthTableBits[$mode][$l];
2370
		$words = (1 << $bits) - 1;
2371
		if ($mode == QR_MODE_KJ) {
2372
			$words *= 2; // the number of bytes is required
2373
		}
2374
		return $words;
2375
	}
2376
2377
	/**
2378
	 * Return an array of ECC specification.
2379
	 * @param $version (int) version
2380
	 * @param $level (int) error correction level
2381
	 * @param $spec (array) an array of ECC specification contains as following: {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
2382
	 * @return array spec
2383
	 */
2384
	protected function getEccSpec($version, $level, $spec) {
2385
		if (count($spec) < 5) {
2386
			$spec = array(0, 0, 0, 0, 0);
2387
		}
2388
		$b1 = $this->eccTable[$version][$level][0];
2389
		$b2 = $this->eccTable[$version][$level][1];
2390
		$data = $this->getDataLength($version, $level);
2391
		$ecc = $this->getECCLength($version, $level);
2392
		if ($b2 == 0) {
2393
			$spec[0] = $b1;
2394
			$spec[1] = (int)($data / $b1);
2395
			$spec[2] = (int)($ecc / $b1);
2396
			$spec[3] = 0;
2397
			$spec[4] = 0;
2398
		} else {
2399
			$spec[0] = $b1;
2400
			$spec[1] = (int)($data / ($b1 + $b2));
2401
			$spec[2] = (int)($ecc  / ($b1 + $b2));
2402
			$spec[3] = $b2;
2403
			$spec[4] = $spec[1] + 1;
2404
		}
2405
		return $spec;
2406
	}
2407
2408
	/**
2409
	 * Put an alignment marker.
2410
	 * @param $frame (array) frame
2411
	 * @param $ox (int) X center coordinate of the pattern
2412
	 * @param $oy (int) Y center coordinate of the pattern
2413
	 * @return array frame
2414
	 */
2415
	protected function putAlignmentMarker($frame, $ox, $oy) {
2416
		$finder = array(
2417
			"\xa1\xa1\xa1\xa1\xa1",
2418
			"\xa1\xa0\xa0\xa0\xa1",
2419
			"\xa1\xa0\xa1\xa0\xa1",
2420
			"\xa1\xa0\xa0\xa0\xa1",
2421
			"\xa1\xa1\xa1\xa1\xa1"
2422
			);
2423
		$yStart = $oy - 2;
2424
		$xStart = $ox - 2;
2425 View Code Duplication
		for ($y=0; $y < 5; $y++) {
2426
			$frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
2427
		}
2428
		return $frame;
2429
	}
2430
2431
	/**
2432
	 * Put an alignment pattern.
2433
	 * @param $version (int) version
2434
	 * @param $frame (array) frame
2435
	 * @param $width (int) width
2436
	 * @return array frame
2437
	 */
2438
	 protected function putAlignmentPattern($version, $frame, $width) {
2439
		if ($version < 2) {
2440
			return $frame;
2441
		}
2442
		$d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
2443
		if ($d < 0) {
2444
			$w = 2;
2445
		} else {
2446
			$w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
2447
		}
2448
		if ($w * $w - 3 == 1) {
2449
			$x = $this->alignmentPattern[$version][0];
2450
			$y = $this->alignmentPattern[$version][0];
2451
			$frame = $this->putAlignmentMarker($frame, $x, $y);
2452
			return $frame;
2453
		}
2454
		$cx = $this->alignmentPattern[$version][0];
2455
		$wo = $w - 1;
2456
		for ($x=1; $x < $wo; ++$x) {
2457
			$frame = $this->putAlignmentMarker($frame, 6, $cx);
2458
			$frame = $this->putAlignmentMarker($frame, $cx,  6);
2459
			$cx += $d;
2460
		}
2461
		$cy = $this->alignmentPattern[$version][0];
2462
		for ($y=0; $y < $wo; ++$y) {
2463
			$cx = $this->alignmentPattern[$version][0];
2464
			for ($x=0; $x < $wo; ++$x) {
2465
				$frame = $this->putAlignmentMarker($frame, $cx, $cy);
2466
				$cx += $d;
2467
			}
2468
			$cy += $d;
2469
		}
2470
		return $frame;
2471
	}
2472
2473
	/**
2474
	 * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2475
	 * @param $version (int) version
2476
	 * @return BCH encoded version information pattern
2477
	 */
2478
	protected function getVersionPattern($version) {
2479
		if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2480
			return 0;
2481
		}
2482
		return $this->versionPattern[($version - 7)];
2483
	}
2484
2485
	/**
2486
	 * Return BCH encoded format information pattern.
2487
	 * @param $mask (array)
2488
	 * @param $level (int) error correction level
2489
	 * @return BCH encoded format information pattern
2490
	 */
2491
	protected function getFormatInfo($mask, $level) {
2492
		if (($mask < 0) OR ($mask > 7)) {
2493
			return 0;
2494
		}
2495
		if (($level < 0) OR ($level > 3)) {
2496
			return 0;
2497
		}
2498
		return $this->formatInfo[$level][$mask];
2499
	}
2500
2501
	/**
2502
	 * Put a finder pattern.
2503
	 * @param $frame (array) frame
2504
	 * @param $ox (int) X center coordinate of the pattern
2505
	 * @param $oy (int) Y center coordinate of the pattern
2506
	 * @return array frame
2507
	 */
2508
	protected function putFinderPattern($frame, $ox, $oy) {
2509
		$finder = array(
2510
		"\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2511
		"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2512
		"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2513
		"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2514
		"\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2515
		"\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2516
		"\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2517
		);
2518 View Code Duplication
		for ($y=0; $y < 7; $y++) {
2519
			$frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2520
		}
2521
		return $frame;
2522
	}
2523
2524
	/**
2525
	 * Return a copy of initialized frame.
2526
	 * @param $version (int) version
2527
	 * @return Array of unsigned char.
2528
	 */
2529
	protected function createFrame($version) {
2530
		$width = $this->capacity[$version][QRCAP_WIDTH];
2531
		$frameLine = str_repeat ("\0", $width);
2532
		$frame = array_fill(0, $width, $frameLine);
2533
		// Finder pattern
2534
		$frame = $this->putFinderPattern($frame, 0, 0);
2535
		$frame = $this->putFinderPattern($frame, $width - 7, 0);
2536
		$frame = $this->putFinderPattern($frame, 0, $width - 7);
2537
		// Separator
2538
		$yOffset = $width - 7;
2539
		for ($y=0; $y < 7; ++$y) {
2540
			$frame[$y][7] = "\xc0";
2541
			$frame[$y][$width - 8] = "\xc0";
2542
			$frame[$yOffset][7] = "\xc0";
2543
			++$yOffset;
2544
		}
2545
		$setPattern = str_repeat("\xc0", 8);
2546
		$frame = $this->qrstrset($frame, 0, 7, $setPattern);
2547
		$frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
2548
		$frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
2549
		// Format info
2550
		$setPattern = str_repeat("\x84", 9);
2551
		$frame = $this->qrstrset($frame, 0, 8, $setPattern);
2552
		$frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
0 ignored issues
show
Documentation introduced by
8 is of type integer, but the function expects a boolean.

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...
2553
		$yOffset = $width - 8;
2554
		for ($y=0; $y < 8; ++$y,++$yOffset) {
2555
			$frame[$y][8] = "\x84";
2556
			$frame[$yOffset][8] = "\x84";
2557
		}
2558
		// Timing pattern
2559
		$wo = $width - 15;
2560
		for ($i=1; $i < $wo; ++$i) {
2561
			$frame[6][7+$i] = chr(0x90 | ($i & 1));
2562
			$frame[7+$i][6] = chr(0x90 | ($i & 1));
2563
		}
2564
		// Alignment pattern
2565
		$frame = $this->putAlignmentPattern($version, $frame, $width);
2566
		// Version information
2567
		if ($version >= 7) {
2568
			$vinf = $this->getVersionPattern($version);
2569
			$v = $vinf;
2570 View Code Duplication
			for ($x=0; $x<6; ++$x) {
2571
				for ($y=0; $y<3; ++$y) {
2572
					$frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
2573
					$v = $v >> 1;
2574
				}
2575
			}
2576
			$v = $vinf;
2577 View Code Duplication
			for ($y=0; $y<6; ++$y) {
2578
				for ($x=0; $x<3; ++$x) {
2579
					$frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
2580
					$v = $v >> 1;
2581
				}
2582
			}
2583
		}
2584
		// and a little bit...
2585
		$frame[$width - 8][8] = "\x81";
2586
		return $frame;
2587
	}
2588
2589
	/**
2590
	 * Set new frame for the specified version.
2591
	 * @param $version (int) version
2592
	 * @return Array of unsigned char.
2593
	 */
2594
	protected function newFrame($version) {
2595
		if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2596
			return NULL;
2597
		}
2598
		if (!isset($this->frames[$version])) {
2599
			$this->frames[$version] = $this->createFrame($version);
2600
		}
2601
		if (is_null($this->frames[$version])) {
2602
			return NULL;
2603
		}
2604
		return $this->frames[$version];
2605
	}
2606
2607
	/**
2608
	 * Return block number 0
2609
	 * @param $spec (array)
2610
	 * @return int value
2611
	 */
2612
	 protected function rsBlockNum($spec) {
2613
		return ($spec[0] + $spec[3]);
2614
	}
2615
2616
	/**
2617
	* Return block number 1
2618
	 * @param $spec (array)
2619
	 * @return int value
2620
	 */
2621
	 protected function rsBlockNum1($spec) {
2622
		return $spec[0];
2623
	}
2624
2625
	/**
2626
	 * Return data codes 1
2627
	 * @param $spec (array)
2628
	 * @return int value
2629
	 */
2630
	 protected function rsDataCodes1($spec) {
2631
		return $spec[1];
2632
	}
2633
2634
	/**
2635
	 * Return ecc codes 1
2636
	 * @param $spec (array)
2637
	 * @return int value
2638
	 */
2639
	 protected function rsEccCodes1($spec) {
2640
		return $spec[2];
2641
	}
2642
2643
	/**
2644
	 * Return block number 2
2645
	 * @param $spec (array)
2646
	 * @return int value
2647
	 */
2648
	 protected function rsBlockNum2($spec) {
2649
		return $spec[3];
2650
	}
2651
2652
	/**
2653
	 * Return data codes 2
2654
	 * @param $spec (array)
2655
	 * @return int value
2656
	 */
2657
	 protected function rsDataCodes2($spec) {
2658
		return $spec[4];
2659
	}
2660
2661
	/**
2662
	 * Return ecc codes 2
2663
	 * @param $spec (array)
2664
	 * @return int value
2665
	 */
2666
	 protected function rsEccCodes2($spec) {
2667
		return $spec[2];
2668
	}
2669
2670
	/**
2671
	 * Return data length
2672
	 * @param $spec (array)
2673
	 * @return int value
2674
	 */
2675
	 protected function rsDataLength($spec) {
2676
		return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2677
	}
2678
2679
	/**
2680
	 * Return ecc length
2681
	 * @param $spec (array)
2682
	 * @return int value
2683
	 */
2684
	 protected function rsEccLength($spec) {
2685
		return ($spec[0] + $spec[3]) * $spec[2];
2686
	}
2687
2688
	// - - - - - - - - - - - - - - - - - - - - - - - - -
2689
2690
	// QRrs
2691
2692
	/**
2693
	 * Initialize a Reed-Solomon codec and add it to existing rsitems
2694
	 * @param $symsize (int) symbol size, bits
2695
	 * @param $gfpoly (int)  Field generator polynomial coefficients
2696
	 * @param $fcr (int)  first root of RS code generator polynomial, index form
2697
	 * @param $prim (int)  primitive element to generate polynomial roots
2698
	 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2699
	 * @param $pad (int)  padding bytes at front of shortened block
2700
	 * @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>.
2701
	 */
2702
	 protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2703
		foreach ($this->rsitems as $rs) {
2704
			if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2705
				OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2706
				continue;
2707
			}
2708
			return $rs;
2709
		}
2710
		$rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2711
		array_unshift($this->rsitems, $rs);
2712
		return $rs;
2713
	}
2714
2715
	// - - - - - - - - - - - - - - - - - - - - - - - - -
2716
2717
	// QRrsItem
2718
2719
	/**
2720
	 * modnn
2721
	 * @param $rs (array) RS values
2722
	 * @param $x (int) X position
2723
	 * @return int X osition
2724
	 */
2725
	 protected function modnn($rs, $x) {
2726
		while ($x >= $rs['nn']) {
2727
			$x -= $rs['nn'];
2728
			$x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2729
		}
2730
		return $x;
2731
	}
2732
2733
	/**
2734
	 * Initialize a Reed-Solomon codec and returns an array of values.
2735
	 * @param $symsize (int) symbol size, bits
2736
	 * @param $gfpoly (int)  Field generator polynomial coefficients
2737
	 * @param $fcr (int)  first root of RS code generator polynomial, index form
2738
	 * @param $prim (int)  primitive element to generate polynomial roots
2739
	 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2740
	 * @param $pad (int)  padding bytes at front of shortened block
2741
	 * @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>.
2742
	 */
2743
	protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2744
		// Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2745
		$rs = null;
2746
		// Check parameter ranges
2747
		if (($symsize < 0) OR ($symsize > 8)) {
2748
			return $rs;
2749
		}
2750
		if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
2751
			return $rs;
2752
		}
2753
		if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
2754
			return $rs;
2755
		}
2756
		if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
2757
			return $rs;
2758
		}
2759
		if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
2760
			return $rs;
2761
		}
2762
		$rs = array();
2763
		$rs['mm'] = $symsize;
2764
		$rs['nn'] = (1 << $symsize) - 1;
2765
		$rs['pad'] = $pad;
2766
		$rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2767
		$rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2768
		// PHP style macro replacement ;)
2769
		$NN =& $rs['nn'];
2770
		$A0 =& $NN;
2771
		// Generate Galois field lookup tables
2772
		$rs['index_of'][0] = $A0; // log(zero) = -inf
2773
		$rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2774
		$sr = 1;
2775
		for ($i=0; $i<$rs['nn']; ++$i) {
2776
			$rs['index_of'][$sr] = $i;
2777
			$rs['alpha_to'][$i] = $sr;
2778
			$sr <<= 1;
2779
			if ($sr & (1 << $symsize)) {
2780
				$sr ^= $gfpoly;
2781
			}
2782
			$sr &= $rs['nn'];
2783
		}
2784
		if ($sr != 1) {
2785
			// field generator polynomial is not primitive!
2786
			return NULL;
2787
		}
2788
		// Form RS code generator polynomial from its roots
2789
		$rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2790
		$rs['fcr'] = $fcr;
2791
		$rs['prim'] = $prim;
2792
		$rs['nroots'] = $nroots;
2793
		$rs['gfpoly'] = $gfpoly;
2794
		// Find prim-th root of 1, used in decoding
2795
		for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2796
			; // intentional empty-body loop!
2797
		}
2798
		$rs['iprim'] = (int)($iprim / $prim);
2799
		$rs['genpoly'][0] = 1;
2800
		for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2801
			$rs['genpoly'][$i+1] = 1;
2802
			// Multiply rs->genpoly[] by  @**(root + x)
2803
			for ($j = $i; $j > 0; --$j) {
2804
				if ($rs['genpoly'][$j] != 0) {
2805
					$rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2806
				} else {
2807
					$rs['genpoly'][$j] = $rs['genpoly'][$j-1];
2808
				}
2809
			}
2810
			// rs->genpoly[0] can never be zero
2811
			$rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2812
		}
2813
		// convert rs->genpoly[] to index form for quicker encoding
2814
		for ($i = 0; $i <= $nroots; ++$i) {
2815
			$rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2816
		}
2817
		return $rs;
2818
	}
2819
2820
	/**
2821
	 * Encode a Reed-Solomon codec and returns the parity array
2822
	 * @param $rs (array) RS values
2823
	 * @param $data (array) data
2824
	 * @param $parity (array) parity
2825
	 * @return parity array
2826
	 */
2827
	 protected function encode_rs_char($rs, $data, $parity) {
2828
		$MM       =& $rs['mm']; // bits per symbol
2829
		$NN       =& $rs['nn']; // the total number of symbols in a RS block
2830
		$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
2831
		$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
2832
		$GENPOLY  =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2833
		$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
2834
		$FCR      =& $rs['fcr']; // first consecutive root, index form
2835
		$PRIM     =& $rs['prim']; // primitive element, index form
2836
		$IPRIM    =& $rs['iprim']; // prim-th root of 1, index form
2837
		$PAD      =& $rs['pad']; // the number of pad symbols in a block
2838
		$A0       =& $NN;
2839
		$parity = array_fill(0, $NROOTS, 0);
2840
		for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
2841
			$feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2842
			if ($feedback != $A0) {
2843
				// feedback term is non-zero
2844
				// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2845
				// always be for the polynomials constructed by init_rs()
2846
				$feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2847
				for ($j=1; $j < $NROOTS; ++$j) {
2848
				$parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2849
				}
2850
			}
2851
			// Shift
2852
			array_shift($parity);
2853
			if ($feedback != $A0) {
2854
				array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
2855
			} else {
2856
				array_push($parity, 0);
2857
			}
2858
		}
2859
		return $parity;
2860
	}
2861
2862
} // end QRcode class
2863
2864
//============================================================+
2865
// END OF FILE
2866
//============================================================+
2867