Issues (61)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Printers/DefaultPrinter.php (10 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Posprint\Printers;
4
5
/*
6
 * Default class for POS thermal printers.
7
 * 
8
 * From this class all other are extended.
9
 * In the child classes should be included all the commands that are different
10
 * from those in this class, especially those specific to particular brand and 
11
 * model of printer
12
 * 
13
 * NOTE: It was built around the commands of the Epson TM-T20,
14
 * so in theory the Epson class will be almost empty just extending this class.
15
 * 
16
 * CodePage default CP437
17
 * CountyPage default LATIN
18
 * 
19
 * @category   NFePHP
20
 * @package    Posprint
21
 * @copyright  Copyright (c) 2016
22
 * @license    http://www.gnu.org/licenses/lesser.html LGPL v3
23
 * @author     Roberto L. Machado <linux.rlm at gmail dot com>
24
 * @link       http://github.com/nfephp-org/posprint for the canonical source repository
25
 */
26
27
use Posprint\Printers\PrinterInterface;
28
use Posprint\Connectors\ConnectorInterface;
29
use Posprint\Connectors\Buffer;
30
use Posprint\Graphics\Graphics;
31
use Posprint\Printers\Barcodes\Barcode1DAnalysis;
32
use RuntimeException;
33
use InvalidArgumentException;
34
35
abstract class DefaultPrinter implements PrinterInterface
36
{
37
    //set standards
38
    const NUL = "\x0"; //Nulo
39
    const EOT = "\x4"; //EOT fim da transmissão
40
    const ENQ = "\x5"; //ENQ colocar na fila Pedido de status 1
41
    const HT = "\x9"; //tabulação horizontal
42
    const VT = "\xb"; //tabulação vertical
43
    const LF = "\x0a"; //Inicia a impressão e avança uma linha
44
    const FF = "\x0c"; //avança pagina
45
    const CR = "\x0d"; //retorno de carro
46
    const DLE = "\x10"; //Data Link Escape
47
    const CAN = "\x18"; //CAN Cancela linha enviada
48
    const BEL = "\x07"; //BEL sinal sonoro
49
    const ESC = "\x1b"; //escape
50
    const FS = "\x1c"; //FS
51
    const GS = "\x1d"; //GS
52
    const SO = "\x0e"; //SO Inicia modo expandido
53
    const DC1 = "\x11"; //DC1 Inicia modo enfatizado
54
    const DC2 = "\x12"; //DC2 Cancela modo condensado
55
    const DC3 = "\x13"; //DC3 Cancela modo enfatizado
56
    const DC4 = "\x14"; //DC4 Controle de dispositivo 4 Inicia modo normal
57
    const SI = "\x0f"; //Seleciona modo condensado
58
    const EM = "\x19"; //Avança 4 linhas
59
    const DEL = "\x7f"; //Cancela último caracter
60
    const NAK = "\x15"; //
61
    const SYN = "\x16"; //Sincronismo
62
    const NOTRANS = false; //not translate characters codepage
63
    const TRANS = true; //perform a character convertion to codepage
64
    const ACK = '\x06'; //Acknowledge
65
    //Cut types
66
    const CUT_FULL = 65;
67
    const CUT_PARTIAL = 66;
68
    //Image sizing options
69
    const IMG_DEFAULT = 0;
70
    const IMG_DOUBLE_WIDTH = 1;
71
    const IMG_DOUBLE_HEIGHT = 2;
72
73
    /**
74
     * List all available region pages.
75
     *
76
     * @var array
77
     */
78
    protected $aRegion = array(
79
        'USA',
80
        'FRANCE',
81
        'GERMANY',
82
        'UK',
83
        'DENMARK',
84
        'SWEDEN',
85
        'ITALY',
86
        'SPAIN',
87
        'JAPAN',
88
        'NORWAY',
89
        'DENMARK2',
90
        'SPAIN2',
91
        'LATIN',
92
        'KOREA',
93
        'SLOVENIA',
94
        'CHINA',
95
        'VIETNAM',
96
        'ARABIA'
97
    );
98
99
    /**
100
     * List all available code pages.
101
     *
102
     * @var array
103
     */
104
    protected $aCodePage = array(
105
        'CP437' => array('conv' => '437', 'table' => '0', 'desc' => 'PC437: USA, Standard Europe'),
106
        'CP850' => array('conv' => '850', 'table' => '2', 'desc' => 'PC850: Multilingual'),
107
        'CP860' => array('conv' => '860', 'table' => '3', 'desc' => 'PC860: Portuguese'),
108
        'CP863' => array('conv' => '863', 'table' => '4', 'desc' => 'PC863: Canadian-French'),
109
        'CP865' => array('conv' => '865', 'table' => '5', 'desc' => 'PC865: Nordic'),
110
        'CP851' => array('conv' => '851', 'table' => '11', 'desc' => 'PC851: Greek'),
111
        'CP853' => array('conv' => '853', 'table' => '12', 'desc' => 'PC853: Turkish'),
112
        'CP857' => array('conv' => '857', 'table' => '13', 'desc' => 'PC857: Turkish'),
113
        'CP737' => array('conv' => '737', 'table' => '14', 'desc' => 'PC737: Greek'),
114
        'ISO8859-7' => array('conv' => 'ISO8859-7', 'table' => '15', 'desc' => 'ISO8859-7: Greek'),
115
        'CP866' => array('conv' => '866', 'table' => '17', 'desc' => 'PC866: Cyrillic #2'),
116
        'CP852' => array('conv' => '852', 'table' => '18', 'desc' => 'PC852: Latin2'),
117
        'CP858' => array('conv' => '858', 'table' => '19', 'desc' => 'PC858: Euro'),
118
        'CP720' => array('conv' => '720', 'table' => '32', 'desc' => 'PC720: Arabic'),
119
        'CP855' => array('conv' => '855', 'table' => '34', 'desc' => 'PC855: Cyrillic'),
120
        'CP861' => array('conv' => '861', 'table' => '35', 'desc' => 'PC861: Icelandic'),
121
        'CP862' => array('conv' => '862', 'table' => '36', 'desc' => 'PC862: Hebrew'),
122
        'CP864' => array('conv' => '864', 'table' => '37', 'desc' => 'PC864: Arabic'),
123
        'CP869' => array('conv' => '869', 'table' => '38', 'desc' => 'PC869: Greek'),
124
        'ISO8859-2' => array('conv' => 'ISO8859-2', 'table' => '39', 'desc' => 'ISO8859-2: Latin2'),
125
        'ISO8859-15' => array('conv' => 'ISO8859-15', 'table' => '40', 'desc' => 'ISO8859-15: Latin9'),
126
        'WINDOWS-1250' => array('conv' => 'WINDOWS-1250', 'table' => '45', 'desc' => 'WPC1250: Latin2'),
127
        'WINDOWS-1251' => array('conv' => 'WINDOWS-1251', 'table' => '46', 'desc' => 'WPC1251: Cyrillic'),
128
        'WINDOWS-1252' => array('conv' => 'WINDOWS-1252', 'table' => '47', 'desc' => 'WPC1253: Greek'),
129
        'WINDOWS-1254' => array('conv' => 'WINDOWS-1254', 'table' => '48', 'desc' => 'WPC1254: Turkish'),
130
        'WINDOWS-1255' => array('conv' => 'WINDOWS-1255', 'table' => '49', 'desc' => 'WPC1255: Hebrew'),
131
        'WINDOWS-1256' => array('conv' => 'WINDOWS-1256', 'table' => '50', 'desc' => 'WPC1256: Arabic'),
132
        'WINDOWS-1257' => array('conv' => 'WINDOWS-1257', 'table' => '51', 'desc' => 'WPC1257: Baltic Rim'),
133
        'WINDOWS-1258' => array('conv' => 'WINDOWS-1258', 'table' => '52', 'desc' => 'WPC1258: Vietnamese'),
134
    );
135
    
136
    /**
137
     * Seleted code page
138
     * Defined in printer class.
139
     * @var string
140
     */
141
    protected $codepage = 'CP437';
142
    /**
143
     * Number of codpage in printer memory.
144
     * @var int
145
     */
146
    protected $charsetTableNum = 0;
147
    /**
148
     * Selected Region character page
149
     * Defined in printer class.
150
     * @var string
151
     */
152
    protected $region = 'LATIN';
153
    /**
154
     * List all avaiable fonts
155
     * @var array
156
     */
157
    protected $aFont = array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 97 => 'SA', 98 => 'SB');
158
    /**
159
     * Selected internal font.
160
     * @var string
161
     */
162
    protected $font = 'A';
163
    /**
164
     * Resolution in dpi.
165
     * @var int
166
     */
167
    public $dpi = 203; //dots per inch
168
    /**
169
     * Resolution in dpmm.
170
     * @var int
171
     */
172
    public $dpmm = 8; //dots per mm
173
    /**
174
     * Maximum width paper.
175
     * @var int
176
     */
177
    public $widthMaxmm = 80;//mm
178
    /**
179
     * Selected Width paper.
180
     * @var int
181
     */
182
    public $widthPaper = 80;//mm
183
    /**
184
     * Maximum width for printed area.
185
     * @var int
186
     */
187
    public $widthPrint = 72;//mm
188
    /**
189
     * Maximum width for printed area in dots.
190
     * @var int
191
     */
192
    public $widthMaxdots = 576;//dots
193
    /**
194
     * Maximum number of characters per line.
195
     * @var int
196
     */
197
    public $maxchars = 48;//max characters per line
198
199
    //protected property standards
200
    /**
201
     * Connector to printer.
202
     * @var ConnectorInterface|null
203
     */
204
    protected $connector = null;
205
    /**
206
     * Seleted printer mode.
207
     * @var string
208
     */
209
    protected $printerMode = 'normal';
210
    /**
211
     * Selected bold mode.
212
     * @var bool
213
     */
214
    protected $boldMode = false;
215
    /**
216
     * Selected italic mode.
217
     * @var bool
218
     */
219
    protected $italicMode = false;
220
    /**
221
     * Selected condenced mode.
222
     * @var bool
223
     */
224
    protected $condensedMode = false;
225
    /**
226
     * Selected expanded mode.
227
     * @var bool
228
     */
229
    protected $expandedMode = false;
230
    /**
231
     * Seleted double higth mode.
232
     * @var bool
233
     */
234
    protected $doubleHeigth = false;
235
    /**
236
     * Selected reverse colors mode.
237
     * @var bool
238
     */
239
    protected $reverseColors = false;
240
    /**
241
     * Selected under lined mode.
242
     * @var bool
243
     */
244
    protected $underlineMode = false;
245
    /**
246
     * Selected rotate 90 degrees mode
247
     * @var bool
248
     */
249
    protected $rotateMode = false;
250
    /**
251
     * Buffer class.
252
     * @var Buffer
253
     */
254
    protected $buffer = null;
255
    /**
256
     * Acceptable barcodes list
257
     * @var array
258
     */
259
    protected $barcode1Dlist = [
260
        'UPC_A' => 65,
261
        'UPC_E' => 66,
262
        'EAN13' => 67,
263
        'EAN8' => 68,
264
        'CODE39' => 69,
265
        'I25' => 70,
266
        'CODABAR' => 71,
267
        'CODE93' => 72,
268
        'CODE128' => 73,
269
        'GS1128' => 74,
270
        'GS1DATABAROMINI' => 75,
271
        'GS1DATABARTRUNC' => 76,
272
        'GS1DATABARLIMIT' => 77,
273
        'GS1DATABAREXPAN' => 78
274
    ];
275
    /**
276
     * List of supported models
277
     * @var array
278
     */
279
    protected $modelList = [
280
        'T20'
281
    ];
282
    /**
283
     * Selected model
284
     * @var string
285
     */
286
    protected $printerModel = 'T20';
287
288
    /**
289
     * Class constructor
290
     * Instantiates the data buffer.
291
     *
292
     * @param ConnectorInterface $conn
293
     */
294
    public function __construct(ConnectorInterface $conn = null)
295
    {
296
        if (!is_null($conn)) {
297
            $this->connector = $conn;
298
        }
299
        $this->buffer = new Buffer();
300
    }
301
    
302
    /**
303
     * Return default printer model
304
     * @param string $model
305
     * @return string|array
306
     */
307
    public function defaultModel($model = null)
308
    {
309
        if (!is_null($model)) {
310
            $model = strtoupper(trim($model));
311
            if ($model == 'ALL') {
312
                return $this->modelList;
313
            }
314
        }
315
        if (array_key_exists($model, $this->modelList)) {
316 27
            $this->printerModel = $model;
317
        }
318 27
        return $model;
319
    }
320
    
321 27
    /**
322 27
     * Returns a default region for codepage
323
     * if param $region is null will return actual default region from class
324
     * if param $region is 'all' will return a array with all avaiable regions
325
     * if param $region is a string will set the region parameter of class and returns it.
326
     * NOTE: This command do not set the printer, only class parameters
327
     *
328
     * @param  string $region
329 20
     * @return string|array
330
     */
331 20
    public function defaultRegionPage($region = null)
332 20
    {
333 20
        if (!is_null($region)) {
334
            $region = strtoupper(trim($region));
335
            if ($region == 'ALL') {
336 20
                return $this->aRegion;
337 20
            }
338
            $reg = array_search($region, $this->aRegion, true);
339
            if ($reg !== false) {
340 20
                $this->region = $region;
341
            }
342
        }
343
        return $this->region;
344
    }
345
346
    /**
347
     * Returns a default codepage
348
     * if param $codepage is null will return actual default codepage from class
349
     * if param $codepage is 'all' will return a array with all avaiable codepages
350
     * if param $codepage is a string will set the codepage parameter of class and returns it.
351
     * NOTE: This command do not set the printer, only class parameters
352
     *
353 21
     * @param  string $codepage
354
     * @return string|array
355 21
     */
356 2
    public function defaultCodePage($codepage = null)
357 2
    {
358 1
        if (!is_null($codepage)) {
359
            $codepage = strtoupper(trim($codepage));
360 2
            if ($codepage == 'ALL') {
361 2
                return array_keys($this->aCodePage);
362 2
            }
363 2
            if (array_key_exists($codepage, $this->aCodePage)) {
364 2
                $this->codepage = $codepage;
365 21
                $table = $this->aCodePage[$codepage];
366
                $this->charsetTableNum = $table['table'];
367
            }
368
        }
369
        return $this->codepage;
370
    }
371
372
    /**
373
     * Returns the default printer font
374
     * A - Font A (12 x 24)
375
     * B - Font B (9 x 17)
376
     * C - Font C
377
     * D - Font D
378 21
     * E - Font E
379
     * Special A
380 21
     * Special B
381 3
     * Default Font A.
382 3
     * if param $font is null will return actual default font from class
383 1
     * if param $font is 'all' will return a array with all avaiable printer fonts
384
     * if param $font is a string will set the font parameter of class and returns it.
385 3
     * NOTE: This command do not set the printer, only class parameters
386 3
     *
387 3
     * @param  string $font
388 3
     * @return array|string
389 3
     */
390 3
    public function defaultFont($font = null)
391 21
    {
392
        if (!is_null($font)) {
393
            $font = strtoupper(trim($font));
394
            if ($font == 'ALL') {
395
                //return array
396
                return $this->aFont;
397
            }
398
            //set $this->font
399
            $fonts = array_flip($this->aFont);
400
            $keys = array_keys($fonts);
401
            $reg = array_search($font, $keys, true);
402
            if ($reg !== false) {
403
                $this->font = $font;
404
            }
405
        }
406
        return $this->font;
407
    }
408
409
    /**
410
     * initialize printer
411
     * Clears the data in the print buffer and resets the printer modes to
412 22
     * the modes that were in effect when the power was turned on.
413
     */
414 22
    public function initialize()
415 3
    {
416 3
        $this->rotateMode = false;
417
        $this->boldMode = false;
418 1
        $this->italicMode = false;
419
        $this->underlineMode = false;
420
        $this->printerMode = 'normal';
421 2
        $this->defaultModel();
422 2
        $this->defaultCodePage();
423 2
        $this->defaultRegionPage();
424 2
        $this->defaultFont();
425 2
        $this->buffer->write(self::ESC.'@');
426 2
        $this->setPrintMode();
427 2
        $this->setFont();
428 21
        $this->setCodePage();
429
        $this->setRegionPage();
430
    }
431
432
    /**
433
     * Set the printer mode.
434
     */
435
    abstract public function setPrintMode($mode = null);
436 21
    
437
    /**
438 21
     * Set a codepage table in printer.
439 21
     *
440 21
     * @param string $codepage
441 21
     */
442 21
    public function setCodePage($codepage = null)
443 21
    {
444 21
        $codepage = $this->defaultCodePage($codepage);
0 ignored issues
show
$codepage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
445 21
        $this->buffer->write(self::ESC.'t'.chr($this->charsetTableNum));
446 21
    }
447 21
448 21
    /**
449 21
     * Set a region page.
450 21
     * The numeric key of array $this->aRegion is the command parameter.
451 21
     *
452 21
     * @param string $region
453
     */
454
    public function setRegionPage($region = null)
455
    {
456
        $region = $this->defaultRegionPage($region);
457
        $mode = array_keys($this->aRegion, $region, true);
458
        $this->buffer->write(self::ESC.'R'.chr($mode[0]));
459
    }
460
    
461
    /**
462
     * Set a printer font
463
     * If send a valid font name will set the printer otherelse a default font is selected
464 20
     *
465
     * @param string $font
466 20
     */
467 20
    public function setFont($font = null)
468 20
    {
469
        $font = $this->defaultFont($font);
470
        $mode = array_keys($this->aFont, $font, true);
471
        $this->buffer->write(self::ESC.'M'.chr($mode[0]));
472
    }
473
474
    /**
475
     * Set emphasys mode on or off.
476 20
     */
477
    public function setBold()
478 20
    {
479 20
        $mode = 1;
480 20
        if ($this->boldMode) {
481 20
            $mode = 0;
482
        }
483
        $this->boldMode = ! $this->boldMode;
484
        $this->buffer->write(self::ESC . 'E' . chr($mode));
485
    }
486
487
    /**
488
     * Set underline mode on or off.
489 20
     */
490
    public function setUnderlined()
491 20
    {
492 20
        $mode = 1;
493 20
        if ($this->underlineMode) {
494 20
            $mode = 0;
495
        }
496
        $this->underlineMode = ! $this->underlineMode;
497
        $this->buffer->write(self::ESC . '-' . chr($mode));
498
    }
499 1
    
500
    /**
501 1
     * Set italic mode on or off
502 1
     *
503 1
     * @return bool
504 1
     */
505 1
    public function setItalic()
506 1
    {
507 1
        //dont exists in this printer
508
    }
509
    
510
    /**
511
     * Aligns all data in one line to the selected layout in standard mode.
512 1
     * L - left  C - center  R - rigth
513
     *
514 1
     * @param string $align
515 1
     */
516 1
    public function setAlign($align = null)
517 1
    {
518 1
        if (is_null($align)) {
519 1
            $align = 'L';
520 1
        }
521
        $value = strtoupper($align);
522
        switch ($value) {
523
            case 'C':
524
                $mode = 1;
525
                break;
526
            case 'R':
527
                $mode = 2;
528
                break;
529
            default:
530
                $mode = 0;
531
        }
532
        $this->buffer->write(self::ESC . 'a' . chr($mode));
533
    }
534
    
535
    /**
536
     * Turns white/black reverse print On or Off for characters.
537
     * n = odd: On, n = even: Off.
538 1
     */
539
    public function setReverseColors()
540 1
    {
541
        $mode = 0;
542
        $this->reverseColors = ! $this->reverseColors;
543 1
        if ($this->reverseColors) {
544
            $mode = 1;
545 1
        }
546 1
        $this->buffer->write(self::GS.'B'.chr($mode));
547 1
    }
548 1
    
549
    /**
550
     * Set expanded mode.
551 1
     * @param int $size multiplies normal size 1 - 8
552 1
     */
553 1
    public function setExpanded($size = null)
554 1
    {
555 1
        $size = self::validateInteger($size, 1, 8, 1);
556
        $aSize = [
557
            [0, 0],
558
            [16, 1],
559
            [32, 2],
560
            [48, 3],
561 1
            [64, 4],
562
            [80, 5],
563 1
            [96, 6],
564 1
            [112, 7]
565 1
        ];
566 1
        $mode = $aSize[$size-1][0] + $aSize[$size-1][1];
567 1
        $this->buffer->write(self::ESC.'!'.chr($mode));
568 1
    }
569 1
570
    /**
571
     * Set condensed mode.
572
     * @return void
573
     */
574
    public function setCondensed()
575
    {
576 1
        $this->setExpanded(1);
577
        $this->setFont('B');
578 1
    }
579
    
580 1
    /**
581 1
     * Set rotate 90 degrees.
582 1
     * @return void
583 1
     */
584 1
    public function setRotate90()
585 1
    {
586 1
        $this->rotateMode = !$this->rotateMode;
587 1
        $mode = 0;
588 1
        if ($this->rotateMode) {
589 1
            $mode = 1;
590 1
        }
591 1
        $this->buffer->write(self::ESC.'V'.chr($mode));
592
    }
593
    
594
    /**
595
     * Send message or command to buffer
596
     * when sending commands is not required to convert characters,
597
     * so the variable may translate by false.
598
     * @param string $text
599
     */
600
    public function text($text = '')
601
    {
602
        $text = $this->translate($text);
603
        $this->buffer->write($text);
604
    }
605 1
606
    /**
607 1
     * Set horizontal and vertical motion units
608 1
     * $horizontal => character spacing 1/x"
609 1
     * $vertical => line spacing 1/y".
610 1
     * @param int $horizontal
611 1
     * @param int $vertical
612 1
     */
613 1
    public function setSpacing($horizontal = 30, $vertical = 30)
614
    {
615
        $horizontal = self::validateInteger($horizontal, 0, 255, 30);
616
        $vertical = self::validateInteger($vertical, 0, 255, 30);
617
        $this->buffer->write(self::GS.'P'.chr($horizontal).chr($vertical));
618
    }
619
620
    /**
621
     * Set right-side character spacing
622 1
     * 0 ≤ n ≤ 255 => 1/x".
623
     * @param int $value
624 1
     */
625 1
    public function setCharSpacing($value = 3)
626 1
    {
627
        $value = self::validateInteger($value, 0, 255, 0);
628
        $this->buffer->write(self::ESC.' '.chr($value));
629
    }
630
631
    /**
632
     * Line spacing
633
     * The default is set to zero and 30/180 "
634
     * any different number of zero will generate multiples of.
635
     * n  1/180-inch vertical motion
636 1
     * normal paragraph 30/180" => 4.23 mm
637
     * @param int $value
638 1
     */
639 1
    public function setParagraph($value = 0)
640 1
    {
641 1
        $value = self::validateInteger($value, 0, 255, 0);
642
        $paragraph = ceil($value);
643
        if ($paragraph == 0) {
644
            $this->buffer->write(self::ESC.'2');
645
            return;
646
        }
647
        if ($paragraph < 25) {
648
            $paragraph = 25;
649 1
        } elseif ($paragraph > 255) {
650
            $paragraph = 255;
651 1
        }
652 1
        $this->buffer->write(self::ESC.'3'.chr($paragraph));
653 1
    }
654
655
    /**
656
     * Prints data and feeds paper n lines
657
     * ESC d n Prints data and feeds paper n lines.
658
     * @param int|null $lines
659
     */
660
    public function lineFeed($lines = 1)
661
    {
662
        $lines = self::validateInteger($lines, 0, 255, 1);
663
        if ($lines == 1) {
664 1
            $this->buffer->write(self::LF);
665
            return;
666 1
        }
667 1
        $this->buffer->write(self::ESC.'d'.chr($lines));
668 1
    }
669 1
670 1
    /**
671
     * Prints data and feeds paper n dots
672 1
     * ESC J n Prints data and feeds paper n dots.
673
     * @param int $dots
674 1
     */
675
    public function dotFeed($dots = 1)
676
    {
677 1
        $dots = self::validateInteger($dots, 0, 80, 0);
678 1
        $this->buffer->write(self::ESC.'J'.chr($dots));
679
    }
680
681
    /**
682
     * Generate a pulse, for opening a cash drawer if one is connected.
683
     * The default settings should open an Epson drawer.
684
     * @param int $pin    0 or 1, for pin 2 or pin 5 kick-out connector respectively.
685
     * @param int $on_ms  pulse ON time, in milliseconds.
686 1
     * @param int $off_ms pulse OFF time, in milliseconds.
687
     */
688 1
    public function pulse($pin = 0, $on_ms = 120, $off_ms = 240)
689 1
    {
690 1
        $pin = self::validateInteger($pin, 0, 1, 0);
691 1
        $on_ms = self::validateInteger($on_ms, 1, 511, 120);
692
        $off_ms = self::validateInteger($off_ms, 1, 511, 240);
693 1
        $this->buffer->write(self::ESC.'p'.chr($pin + 48).chr($on_ms / 2).chr($off_ms / 2));
694 1
    }
695
696
    /**
697
     * Cut the paper.
698
     * @param int $mode  FULL or PARTIAL. If not specified, FULL will be used.
699
     * @param int $lines Number of lines to feed after cut
700
     */
701
    public function cut($mode = 'PARTIAL', $lines = 3)
702 1
    {
703
        $lines = self::validateInteger($lines, 1, 10, 3);
704 1
        if ($mode == 'FULL') {
705 1
            $mode = self::CUT_FULL;
706 1
        } else {
707
            $mode = self::CUT_PARTIAL;
708
        }
709
        $this->buffer->write(self::GS.'V'.chr($mode).chr($lines));
710
    }
711
712
    /**
713
     * Implements barcodes 1D
714
     * GS k m n d1...dn
715
     * Prints bar code. n specifies the data length.
716 1
     *   m    bar code system             number of d (=k)
717
     *  "A"     UPC-A                       11 or 12
718 1
     *  "B"     UPC-E                       6, 7, 8, 11 or 12
719 1
     *  "C"     JAN13 / EAN13               12 or 13
720 1
     *  "D"     JAN8 / EAN8                 7 or 8
721 1
     *  "E"     CODE39                      1 or more
722 1
     *  "F"     ITF                         even
723
     *  "G"     CODABAR (NW-7)              2 or more
724
     *  "H"     CODE93                      1–255
725
     *  "I"     CODE128                     2–255
726
     *  "J"     GS1-128                     2–255
727
     *  "K"     GS1 DataBar Omnidirectional 13
728
     *  "L"     GS1 DataBar Truncated       13
729
     *  "M"     GS1 DataBar Limited         13
730 1
     *  "N"     GS1 DataBar Expanded        2–255.
731
     *
732 1
     *  GS h n Sets bar code height to n dots.
733 1
     *  GS w n Sets bar width of bar code. n = 2–6 (thin–thick)
734 1
     *  GS H n Selects print position of HRI characters.
735 1
     *           n = 0, "0": Not printed
736 1
     *           n = 1, "1": Above the bar code
737
     *           n = 2, "2": Below the bar code
738 1
     *           n = 3, "3": Both above and below the bar code
739 1
     *  GS f n Selects font for the HRI characters.
740
     *           n = 0, "0": Font A,
741
     *           n = 1, "1": Font B
742
     *
743
     * @param string $data
744
     * @param string $type Default CODE128
745
     * @param int $height
746
     * @param int $lineWidth
747
     * @param string $txtPosition
748
     * @param string $txtFont
749
     */
750
    public function barcode(
751
        $data = '123456',
752
        $type = 'CODE128',
753
        $height = 162,
754
        $lineWidth = 2,
755
        $txtPosition = 'none',
756
        $txtFont = ''
757
    ) {
758
        switch ($txtPosition) {
759
            case 'Above':
760
                $tPos = 1;
761
                break;
762
            case 'Below':
763
                $tPos = 2;
764
                break;
765
            case 'Both':
766
                $tPos = 3;
767
                break;
768
            default:
769
                //none
770
                $tPos = 0;
771
        }
772
        $font = 0;
773
        if ($txtFont === 'B') {
774
            $font = 1;
775
        }
776
        if (! $data = Barcodes\Barcode1DAnalysis::validate($data, $type)) {
777
            throw new \InvalidArgumentException('Data or barcode type is incorrect.');
778
        }
779 1
        if (! array_key_exists($type, $this->barcode1Dlist)) {
780
            throw new \InvalidArgumentException('This barcode type is not listed.');
781
        }
782
        $id = $this->barcode1Dlist[$type];
783
        if (is_null($id)) {
784
            return;
785
        }
786
        $height = self::validateInteger($height, 1, 255, 4);
787
        $lineWidth = self::validateInteger($lineWidth, 1, 6, 2);
788 1
        $nlen = strlen($data);
789
        //set barcode height
790
        $this->buffer->write(self::GS.'h'.chr($height));
791 1
        //set barcode bar width
792
        $this->buffer->write(self::GS.'w'.chr($lineWidth));
793
        //Selects print position of HRI characters.
794 1
        $this->buffer->write(self::GS.'H'.chr($tPos));
795
        //Selects font for the HRI characters.
796
        $this->buffer->write(self::GS.'f'.chr($font));
797 1
        //Print barcode
798
        $this->buffer->write(self::GS.'k'.chr($id).chr($nlen).$data);
799 1
    }
800 1
    
801 1
    /**
802 1
     * Print PDF 417 2D barcode
803
     * @param string $data
804
     * @param integer $ecc
805 1
     * @param integer $pheight
806
     * @param integer $pwidth
807
     * @param integer $colunms
808 1
     * @return boolean
809
     */
810
    public function barcodePDF417($data = '', $ecc = 5, $pheight = 2, $pwidth = 2, $colunms = 3)
811 1
    {
812 1
        if (empty($data)) {
813
            return false;
814
        }
815 1
        $ecc = self::validateInteger($ecc, 0, 8, 5);
816 1
        $pheight = self::validateInteger($pheight, 1, 8, 2);
817 1
        $n = $ecc + 48;
818
        $length = strlen($data);
819 1
        $pH = intval($length / 256);
820
        $pL = ($length % 256);
821 1
        //Set the number of columns in the data region
822
        //GS (   k  pL pH cn fn n
823 1
        //29 40 107 3   0 48 65 n
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
824
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(65).chr(0));
825 1
        //Set the number of rows
826
        //GS  (      k   pL  pH  cn fn n
827 1
        //29  40    107  3    0  48 66 n
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
828 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(66).chr(0));
829
        //Set the width of the module
830
        //GS  (   k   pL   pH  cn  fn n
831
        //29  40 107  3    0   48  67 n
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
832
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(67).chr(0));
833
        //Set the row height
834
        //GS  (    k   pL  pH  cn  fn n
835
        //29  40  107  3   0   48  68 n
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
836
        //pheight 3 or 5 time pwidth
837
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(68).chr($pheight));
838
        //Set the error correction level
839
        //GS  (    k    pL  pH     cn fn m n
840
        //29  40  107    4   0     48 69 m n n = 48 - 56
841
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(48).chr(69).chr(58).chr($n));
842
        //Select the options
843
        //GS  (    k    pL   pH   cn   fn   n
844
        //29  40  107   3     0   48   70   n
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
845
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(70).chr(0));
846
        //Store the data in the symbol storage area
847
        //GS  (   k   pL  pH   cn  fn  m   d1...dk
848
        //29  40 107  pL  pH   48  80  48  d1...dk
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
849
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(48).chr(80).chr(48).$data);
850
        //Print the symbol data in the symbol storage area
851
        //GS  (   k   pL  pH  cn  fn m
852
        //29  40 107  3    0   48  81 m
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
853
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(48).chr(81).chr(0));
854
    }
855
  
856
    /**
857
     * Prints QRCode
858
     * @param string $data   barcode data
859
     * @param string $level  correction level L,M,Q ou H
860
     * @param int $modelo QRCode model 1, 2 ou 0 Micro
861
     * @param int $wmod   width bar 3 ~ 16
862
     */
863
    public function barcodeQRCode($data = '', $level = 'L', $modelo = 2, $wmod = 4)
864
    {
865
        //set model of QRCode
866
        $n1 = 50;
867
        if ($modelo == 1) {
868
            $n1 = 49;
869
        }
870
        //select QR model
871
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(49).chr(65).chr($n1).chr(0));
872
        //set module bar width
873
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(67).chr($wmod));
874
        //set error correction level
875
        $level = strtoupper($level);
876
        switch ($level) {
877
            case 'L':
878
                $n = 48;
879
                break;
880
            case 'M':
881
                $n = 49;
882
                break;
883
            case 'Q':
884
                $n = 50;
885
                break;
886
            case 'H':
887
                $n = 51;
888
                break;
889
            default:
890
                $n = 49;
891
        }
892
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(69).chr($n));
893 1
        //set data for QR Code assuming print only alphanumeric data
894
        $len = strlen($data) + 3;
895
        $pH = ($len / 256);
896 1
        $pL = $len % 256;
897 1
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(49).chr(80).chr(48).$data);
898
        //Print QR Code
899
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(81).chr(48));
900
    }
901 1
902
    /**
903 1
     * Return all data buffer.
904
     *
905 1
     * @param string $type specifies the return format
906
     */
907 1
    public function getBuffer($type = '')
908
    {
909
        switch ($type) {
910 1
            case 'binA':
911 1
                //returns a binary array of buffer
912 1
                $resp = $this->buffer->getDataBinary(true);
913
                break;
914
            case 'binS':
915
                //returns a binary string of buffer
916
                $resp = $this->buffer->getDataBinary(false);
917
                break;
918
            case 'b64A':
919
                //returns a base64 encoded array of buffer
920
                $resp = $this->buffer->getDataBase64(true);
921
                break;
922 1
            case 'b64S':
923
                //returns a base64 encoded string of buffer
924 1
                $resp = $this->buffer->getDataBase64(false);
925 1
                break;
926 1
            case 'json':
927 1
                //returns a json encoded of array buffer
928
                $resp = $this->buffer->getDataJson();
929 1
                break;
930 1
            case 'readA':
931
                //returns a human readable format of array buffer
932
                //only for debug reasons
933
                $resp = $this->buffer->getDataReadable(true);
934
                break;
935
            default:
936
                //returns a human readable format of string buffer
937 20
                //only for debug reasons
938
                $resp = $this->buffer->getDataReadable(false);
939
        }
940 20
        return $resp;
941
    }
942
943
    /**
944 20
     * Send commands from buffer to connector printer.
945
     * @param ConnectorInterface $conn
946 20
     * @return string|void
947 20
     */
948
    public function send(ConnectorInterface $conn = null)
949
    {
950
        if (!is_null($conn)) {
951
            $this->connector = $conn;
952
        }
953
        if (is_null($this->connector)) {
954
            return $this->getBuffer();
955
        }
956
        $aCmds = $this->getBuffer('binA');
957
        foreach ($aCmds as $cmd) {
0 ignored issues
show
The expression $aCmds of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

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

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

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

Loading history...
958
            $this->connector->write($cmd);
959
        }
960
    }
961
962
    /**
963
     * Insert a image.
964
     *
965
     * @param  string $filename Path to image file
966
     * @param  int $width
967
     * @param  int $height
968
     * @param  int $size 0-normal 1-Double Width 2-Double Heigth
969
     * @throws RuntimeException
970 20
     */
971
    public function putImage($filename = '', $width = null, $height = null, $size = 0)
972
    {
973
        try {
974
            $img = new Graphics($filename, $width, $height);
975
        } catch (RuntimeException $e) {
976
            throw new RuntimeException($e->getMessage());
977
        } catch (InvalidArgumentException $e) {
978
            throw new RuntimeException($e->getMessage());
979
        }
980
        $size = self::validateInteger($size, 0, 3, 0);
981
        $imgHeader = self::dataHeader(array($img->getWidth(), $img->getHeight()), true);
982
        $tone = '0';
983
        $colors = '1';
984
        $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
985
        $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
986
        $header = $tone.$xm.$ym.$colors.$imgHeader;
987
        $this->sendGraphicsData('0', 'p', $header.$img->getRasterImage());
988
        $this->sendGraphicsData('0', '2');
989
    }
990
991
    /**
992
     * Close and clean buffer
993
     * All data will be lost.
994
     */
995
    public function close()
996
    {
997
        $this->buffer->close();
998
    }
999 1
    
1000
    /**
1001
     * Wrapper for GS ( L, to calculate and send correct data length.
1002 1
     *
1003 1
     * @param string $m    Modifier/variant for function. Usually '0'.
1004
     * @param string $fn   Function number to use, as character.
1005
     * @param string $data Data to send.
1006
     */
1007
    protected function sendGraphicsData($m, $fn, $data = '')
1008 1
    {
1009 1
        $header = $this->intLowHigh(strlen($data) + 2, 2);
1010 1
        $this->buffer->write(self::GS.'(L'.$header.$m.$fn.$data);
1011 1
    }
1012 1
1013 1
    /**
1014 1
     * Generate two characters for a number:
1015 1
     * In lower and higher parts, or more parts as needed.
1016 1
     *
1017 1
     * @param int $input Input number
1018
     * @param int $length The number of bytes to output (1 - 4).
1019
     */
1020
    protected static function intLowHigh($input, $length)
1021
    {
1022
        $maxInput = (256 << ($length * 8) - 1);
0 ignored issues
show
$maxInput is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1023
        $outp = '';
1024
        for ($i = 0; $i < $length; ++$i) {
1025
            $outp .= chr($input % 256);
1026
            $input = (int) ($input / 256);
1027
        }
1028
        return $outp;
1029
    }
1030
1031
    /**
1032
     * Convert widths and heights to characters.
1033
     * Used before sending graphics to set the size.
1034
     *
1035 1
     * @param  array $inputs
1036
     * @param  bool  $long   True to use 4 bytes, false to use 2
1037 1
     * @return string
1038 1
     */
1039 1
    protected static function dataHeader(array $inputs, $long = true)
1040
    {
1041
        $outp = array();
1042
        foreach ($inputs as $input) {
1043
            if ($long) {
1044
                $outp[] = self::intLowHigh($input, 2);
1045
            } else {
1046
                $input = self::validateInteger($input, 0, 255, 0);
1047
                $outp[] = chr($input);
1048 1
            }
1049
        }
1050 1
        return implode('', $outp);
1051 1
    }
1052 1
1053 1
    /**
1054 1
     * Verify if the argument given is not a boolean.
1055 1
     *
1056 1
     * @param  bool $test    the input to test
1057
     * @param  bool $default the default value
1058
     * @return bool
1059
     */
1060
    protected static function validateBoolean($test, $default)
1061
    {
1062
        if (!($test === true || $test === false)) {
1063
            return $default;
1064
        }
1065
        return $test;
1066
    }
1067 1
1068
    /**
1069 1
     * Verify if the argument given is not an integer within the specified range.
1070 1
     * will return default instead
1071 1
     * @param  int|null $test the input to test
1072 1
     * @param  int $min the minimum allowable value (inclusive)
1073 1
     * @param  int $max the maximum allowable value (inclusive)
1074
     * @param  int $default the default value
1075
     * @return int|null
1076
     */
1077 1
    protected static function validateInteger($test, $min, $max, $default)
1078 1
    {
1079
        if (!is_integer($test) || $test < $min || $test > $max) {
1080
            return $default;
1081
        }
1082
        return $test;
1083
    }
1084
  
1085
    /**
1086
     * Translate the text from UTF-8 for the specified codepage
1087
     * this translation uses "iconv" and admits texts ONLY in UTF-8.
1088
     *
1089
     * @param  string $text
1090
     * @return string
1091
     */
1092
    protected function translate($text = '')
1093
    {
1094
        if (empty($this->codepage)) {
1095
            $this->defaultCodePage();
1096
        }
1097
        $codep = $this->aCodePage[$this->codepage];
1098
        if (!empty($codep)) {
1099
            $text = @iconv('UTF-8', $codep['conv'], $text);
1100
        }
1101
        return $text;
1102
    }
1103
}
1104