Completed
Push — master ( 6706d8...93737b )
by
unknown
07:43
created

Cpdf::quadTo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 4
1
<?php
2
/**
3
 * A PHP class to provide the basic functionality to create a pdf document without
4
 * any requirement for additional modules.
5
 *
6
 * Extended by Orion Richardson to support Unicode / UTF-8 characters using
7
 * TCPDF and others as a guide.
8
 *
9
 * @author  Wayne Munro <[email protected]>
10
 * @author  Orion Richardson <[email protected]>
11
 * @author  Helmut Tischer <[email protected]>
12
 * @author  Ryan H. Masten <[email protected]>
13
 * @author  Brian Sweeney <[email protected]>
14
 * @author  Fabien Ménager <[email protected]>
15
 * @license Public Domain http://creativecommons.org/licenses/publicdomain/
16
 * @package Cpdf
17
 */
18
use FontLib\Font;
19
use FontLib\BinaryStream;
20
21
class Cpdf
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
22
{
23
24
    /**
25
     * @var integer The current number of pdf objects in the document
26
     */
27
    public $numObj = 0;
28
29
    /**
30
     * @var array This array contains all of the pdf objects, ready for final assembly
31
     */
32
    public $objects = array();
33
34
    /**
35
     * @var integer The objectId (number within the objects array) of the document catalog
36
     */
37
    public $catalogId;
38
39
    /**
40
     * @var array Array carrying information about the fonts that the system currently knows about
41
     * Used to ensure that a font is not loaded twice, among other things
42
     */
43
    public $fonts = array();
44
45
    /**
46
     * @var string The default font metrics file to use if no other font has been loaded.
47
     * The path to the directory containing the font metrics should be included
48
     */
49
    public $defaultFont = './fonts/Helvetica.afm';
50
51
    /**
52
     * @string A record of the current font
53
     */
54
    public $currentFont = '';
55
56
    /**
57
     * @var string The current base font
58
     */
59
    public $currentBaseFont = '';
60
61
    /**
62
     * @var integer The number of the current font within the font array
63
     */
64
    public $currentFontNum = 0;
65
66
    /**
67
     * @var integer
68
     */
69
    public $currentNode;
70
71
    /**
72
     * @var integer Object number of the current page
73
     */
74
    public $currentPage;
75
76
    /**
77
     * @var integer Object number of the currently active contents block
78
     */
79
    public $currentContents;
80
81
    /**
82
     * @var integer Number of fonts within the system
83
     */
84
    public $numFonts = 0;
85
86
    /**
87
     * @var integer Number of graphic state resources used
88
     */
89
    private $numStates = 0;
90
91
    /**
92
     * @var array Number of graphic state resources used
93
     */
94
    private $gstates = array();
95
96
    /**
97
     * @var array Current color for fill operations, defaults to inactive value,
98
     * all three components should be between 0 and 1 inclusive when active
99
     */
100
    public $currentColor = null;
101
102
    /**
103
     * @var array Current color for stroke operations (lines etc.)
104
     */
105
    public $currentStrokeColor = null;
106
107
    /**
108
     * @var string Fill rule (nonzero or evenodd)
109
     */
110
    public $fillRule = "nonzero";
111
112
    /**
113
     * @var string Current style that lines are drawn in
114
     */
115
    public $currentLineStyle = '';
116
117
    /**
118
     * @var array Current line transparency (partial graphics state)
119
     */
120
    public $currentLineTransparency = array("mode" => "Normal", "opacity" => 1.0);
121
122
    /**
123
     * array Current fill transparency (partial graphics state)
124
     */
125
    public $currentFillTransparency = array("mode" => "Normal", "opacity" => 1.0);
126
127
    /**
128
     * @var array An array which is used to save the state of the document, mainly the colors and styles
129
     * it is used to temporarily change to another state, then change back to what it was before
130
     */
131
    public $stateStack = array();
132
133
    /**
134
     * @var integer Number of elements within the state stack
135
     */
136
    public $nStateStack = 0;
137
138
    /**
139
     * @var integer Number of page objects within the document
140
     */
141
    public $numPages = 0;
142
143
    /**
144
     * @var array Object Id storage stack
145
     */
146
    public $stack = array();
147
148
    /**
149
     * @var integer Number of elements within the object Id storage stack
150
     */
151
    public $nStack = 0;
152
153
    /**
154
     * an array which contains information about the objects which are not firmly attached to pages
155
     * these have been added with the addObject function
156
     */
157
    public $looseObjects = array();
158
159
    /**
160
     * array contains information about how the loose objects are to be added to the document
161
     */
162
    public $addLooseObjects = array();
163
164
    /**
165
     * @var integer The objectId of the information object for the document
166
     * this contains authorship, title etc.
167
     */
168
    public $infoObject = 0;
169
170
    /**
171
     * @var integer Number of images being tracked within the document
172
     */
173
    public $numImages = 0;
174
175
    /**
176
     * @var array An array containing options about the document
177
     * it defaults to turning on the compression of the objects
178
     */
179
    public $options = array('compression' => true);
180
181
    /**
182
     * @var integer The objectId of the first page of the document
183
     */
184
    public $firstPageId;
185
186
    /**
187
     * @var integer The object Id of the procset object
188
     */
189
    public $procsetObjectId;
190
191
    /**
192
     * @var array Store the information about the relationship between font families
193
     * this used so that the code knows which font is the bold version of another font, etc.
194
     * the value of this array is initialised in the constructor function.
195
     */
196
    public $fontFamilies = array();
197
198
    /**
199
     * @var string Folder for php serialized formats of font metrics files.
200
     * If empty string, use same folder as original metrics files.
201
     * This can be passed in from class creator.
202
     * If this folder does not exist or is not writable, Cpdf will be **much** slower.
203
     * Because of potential trouble with php safe mode, folder cannot be created at runtime.
204
     */
205
    public $fontcache = '';
206
207
    /**
208
     * @var integer The version of the font metrics cache file.
209
     * This value must be manually incremented whenever the internal font data structure is modified.
210
     */
211
    public $fontcacheVersion = 6;
212
213
    /**
214
     * @var string Temporary folder.
215
     * If empty string, will attempt system tmp folder.
216
     * This can be passed in from class creator.
217
     */
218
    public $tmp = '';
219
220
    /**
221
     * @var string Track if the current font is bolded or italicised
222
     */
223
    public $currentTextState = '';
224
225
    /**
226
     * @var string Messages are stored here during processing, these can be selected afterwards to give some useful debug information
227
     */
228
    public $messages = '';
229
230
    /**
231
     * @var string The encryption array for the document encryption is stored here
232
     */
233
    public $arc4 = '';
234
235
    /**
236
     * @var integer The object Id of the encryption information
237
     */
238
    public $arc4_objnum = 0;
239
240
    /**
241
     * @var string The file identifier, used to uniquely identify a pdf document
242
     */
243
    public $fileIdentifier = '';
244
245
    /**
246
     * @var boolean A flag to say if a document is to be encrypted or not
247
     */
248
    public $encrypted = false;
249
250
    /**
251
     * @var string The encryption key for the encryption of all the document content (structure is not encrypted)
252
     */
253
    public $encryptionKey = '';
254
255
    /**
256
     * @var array Array which forms a stack to keep track of nested callback functions
257
     */
258
    public $callback = array();
259
260
    /**
261
     * @var integer The number of callback functions in the callback array
262
     */
263
    public $nCallback = 0;
264
265
    /**
266
     * @var array Store label->id pairs for named destinations, these will be used to replace internal links
267
     * done this way so that destinations can be defined after the location that links to them
268
     */
269
    public $destinations = array();
270
271
    /**
272
     * @var array Store the stack for the transaction commands, each item in here is a record of the values of all the
273
     * publiciables within the class, so that the user can rollback at will (from each 'start' command)
274
     * note that this includes the objects array, so these can be large.
275
     */
276
    public $checkpoint = '';
277
278
    /**
279
     * @var array Table of Image origin filenames and image labels which were already added with o_image().
280
     * Allows to merge identical images
281
     */
282
    public $imagelist = array();
283
284
    /**
285
     * @var boolean Whether the text passed in should be treated as Unicode or just local character set.
286
     */
287
    public $isUnicode = false;
288
289
    /**
290
     * @var string the JavaScript code of the document
291
     */
292
    public $javascript = '';
293
294
    /**
295
     * @var boolean whether the compression is possible
296
     */
297
    protected $compressionReady = false;
298
299
    /**
300
     * @var array Current page size
301
     */
302
    protected $currentPageSize = array("width" => 0, "height" => 0);
303
304
    /**
305
     * @var array All the chars that will be required in the font subsets
306
     */
307
    protected $stringSubsets = array();
308
309
    /**
310
     * @var string The target internal encoding
311
     */
312
    static protected $targetEncoding = 'Windows-1252';
313
314
    /**
315
     * @var array The list of the core fonts
316
     */
317
    static protected $coreFonts = array(
318
        'courier',
319
        'courier-bold',
320
        'courier-oblique',
321
        'courier-boldoblique',
322
        'helvetica',
323
        'helvetica-bold',
324
        'helvetica-oblique',
325
        'helvetica-boldoblique',
326
        'times-roman',
327
        'times-bold',
328
        'times-italic',
329
        'times-bolditalic',
330
        'symbol',
331
        'zapfdingbats'
332
    );
333
334
    /**
335
     * Class constructor
336
     * This will start a new document
337
     *
338
     * @param array   $pageSize  Array of 4 numbers, defining the bottom left and upper right corner of the page. first two are normally zero.
339
     * @param boolean $isUnicode Whether text will be treated as Unicode or not.
340
     * @param string  $fontcache The font cache folder
341
     * @param string  $tmp       The temporary folder
342
     */
343
    function __construct($pageSize = array(0, 0, 612, 792), $isUnicode = false, $fontcache = '', $tmp = '')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
344
    {
345
        $this->isUnicode = $isUnicode;
346
        $this->fontcache = rtrim($fontcache, DIRECTORY_SEPARATOR."/\\");
347
        $this->tmp = ($tmp !== '' ? $tmp : sys_get_temp_dir());
348
        $this->newDocument($pageSize);
349
350
        $this->compressionReady = function_exists('gzcompress');
351
352
        if (in_array('Windows-1252', mb_list_encodings())) {
353
            self::$targetEncoding = 'Windows-1252';
354
        }
355
356
        // also initialize the font families that are known about already
357
        $this->setFontFamily('init');
358
    }
359
360
    /**
361
     * Document object methods (internal use only)
362
     *
363
     * There is about one object method for each type of object in the pdf document
364
     * Each function has the same call list ($id,$action,$options).
365
     * $id = the object ID of the object, or what it is to be if it is being created
366
     * $action = a string specifying the action to be performed, though ALL must support:
367
     *           'new' - create the object with the id $id
368
     *           'out' - produce the output for the pdf object
369
     * $options = optional, a string or array containing the various parameters for the object
370
     *
371
     * These, in conjunction with the output function are the ONLY way for output to be produced
372
     * within the pdf 'file'.
373
     */
374
375
    /**
376
     * Destination object, used to specify the location for the user to jump to, presently on opening
377
     *
378
     * @param $id
379
     * @param $action
380
     * @param string $options
381
     * @return string|null
382
     */
383
    protected function o_destination($id, $action, $options = '')
384
    {
385
        switch ($action) {
386
            case 'new':
387
                $this->objects[$id] = array('t' => 'destination', 'info' => array());
388
                $tmp = '';
389
                switch ($options['type']) {
390
                    case 'XYZ':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
391
                    /** @noinspection PhpMissingBreakStatementInspection */
392
                    case 'FitR':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
393
                        $tmp = ' ' . $options['p3'] . $tmp;
394
                    case 'FitH':
395
                    case 'FitV':
396
                    case 'FitBH':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
397
                    /** @noinspection PhpMissingBreakStatementInspection */
398
                    case 'FitBV':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
399
                        $tmp = ' ' . $options['p1'] . ' ' . $options['p2'] . $tmp;
400
                    case 'Fit':
401
                    case 'FitB':
402
                        $tmp = $options['type'] . $tmp;
403
                        $this->objects[$id]['info']['string'] = $tmp;
404
                        $this->objects[$id]['info']['page'] = $options['page'];
405
                }
406
                break;
407
408
            case 'out':
409
                $o = &$this->objects[$id];
410
411
                $tmp = $o['info'];
412
                $res = "\n$id 0 obj\n" . '[' . $tmp['page'] . ' 0 R /' . $tmp['string'] . "]\nendobj";
413
414
                return $res;
415
        }
416
417
        return null;
418
    }
419
420
    /**
421
     * set the viewer preferences
422
     *
423
     * @param $id
424
     * @param $action
425
     * @param string|array $options
426
     * @return string|null
427
     */
428
    protected function o_viewerPreferences($id, $action, $options = '')
429
    {
430
        switch ($action) {
431
            case 'new':
432
                $this->objects[$id] = array('t' => 'viewerPreferences', 'info' => array());
433
                break;
434
435
            case 'add':
436
                $o = &$this->objects[$id];
437
438
                foreach ($options as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $options 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...
439
                    switch ($k) {
440
                        // Boolean keys
441
                        case 'HideToolbar':
442
                        case 'HideMenubar':
443
                        case 'HideWindowUI':
444
                        case 'FitWindow':
445
                        case 'CenterWindow':
446
                        case 'DisplayDocTitle':
447
                        case 'PickTrayByPDFSize':
448
                            $o['info'][$k] = (bool)$v;
449
                            break;
450
451
                        // Integer keys
452
                        case 'NumCopies':
453
                            $o['info'][$k] = (int)$v;
454
                            break;
455
456
                        // Name keys
457
                        case 'ViewArea':
458
                        case 'ViewClip':
459
                        case 'PrintClip':
460
                        case 'PrintArea':
461
                            $o['info'][$k] = (string)$v;
462
                            break;
463
464
                        // Named with limited valid values
465
                        case 'NonFullScreenPageMode':
466
                            if (!in_array($v, array('UseNone', 'UseOutlines', 'UseThumbs', 'UseOC'))) {
467
                                continue;
468
                            }
469
                            $o['info'][$k] = $v;
470
                            break;
471
472 View Code Duplication
                        case 'Direction':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
473
                            if (!in_array($v, array('L2R', 'R2L'))) {
474
                                continue;
475
                            }
476
                            $o['info'][$k] = $v;
477
                            break;
478
479 View Code Duplication
                        case 'PrintScaling':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
480
                            if (!in_array($v, array('None', 'AppDefault'))) {
481
                                continue;
482
                            }
483
                            $o['info'][$k] = $v;
484
                            break;
485
486 View Code Duplication
                        case 'Duplex':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
487
                            if (!in_array($v, array('None', 'AppDefault'))) {
488
                                continue;
489
                            }
490
                            $o['info'][$k] = $v;
491
                            break;
492
493
                        // Integer array
494
                        case 'PrintPageRange':
495
                            // Cast to integer array
496
                            foreach ($v as $vK => $vV) {
497
                                $v[$vK] = (int)$vV;
498
                            }
499
                            $o['info'][$k] = array_values($v);
500
                            break;
501
                    }
502
                }
503
                break;
504
505
            case 'out':
506
                $o = &$this->objects[$id];
507
                $res = "\n$id 0 obj\n<< ";
508
509
                foreach ($o['info'] as $k => $v) {
510
                    if (is_string($v)) {
511
                        $v = '/' . $v;
512
                    } elseif (is_int($v)) {
513
                        $v = (string) $v;
514
                    } elseif (is_bool($v)) {
515
                        $v = ($v ? 'true' : 'false');
516
                    } elseif (is_array($v)) {
517
                        $v = '[' . implode(' ', $v) . ']';
518
                    }
519
                    $res .= "\n/$k $v";
520
                }
521
                $res .= "\n>>\n";
522
523
                return $res;
524
        }
525
526
        return null;
527
    }
528
529
    /**
530
     * define the document catalog, the overall controller for the document
531
     *
532
     * @param $id
533
     * @param $action
534
     * @param string|array $options
535
     * @return string|null
536
     */
537
    protected function o_catalog($id, $action, $options = '')
538
    {
539
        if ($action !== 'new') {
540
            $o = &$this->objects[$id];
541
        }
542
543
        switch ($action) {
544
            case 'new':
545
                $this->objects[$id] = array('t' => 'catalog', 'info' => array());
546
                $this->catalogId = $id;
547
                break;
548
549
            case 'outlines':
550
            case 'pages':
551
            case 'openHere':
552
            case 'javascript':
553
                $o['info'][$action] = $options;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
554
                break;
555
556
            case 'viewerPreferences':
557
                if (!isset($o['info']['viewerPreferences'])) {
558
                    $this->numObj++;
559
                    $this->o_viewerPreferences($this->numObj, 'new');
560
                    $o['info']['viewerPreferences'] = $this->numObj;
561
                }
562
563
                $vp = $o['info']['viewerPreferences'];
564
                $this->o_viewerPreferences($vp, 'add', $options);
565
566
                break;
567
568
            case 'out':
569
                $res = "\n$id 0 obj\n<< /Type /Catalog";
570
571
                foreach ($o['info'] as $k => $v) {
572
                    switch ($k) {
573
                        case 'outlines':
574
                            $res .= "\n/Outlines $v 0 R";
575
                            break;
576
577
                        case 'pages':
578
                            $res .= "\n/Pages $v 0 R";
579
                            break;
580
581
                        case 'viewerPreferences':
582
                            $res .= "\n/ViewerPreferences $v 0 R";
583
                            break;
584
585
                        case 'openHere':
586
                            $res .= "\n/OpenAction $v 0 R";
587
                            break;
588
589
                        case 'javascript':
590
                            $res .= "\n/Names <</JavaScript $v 0 R>>";
591
                            break;
592
                    }
593
                }
594
595
                $res .= " >>\nendobj";
596
597
                return $res;
598
        }
599
600
        return null;
601
    }
602
603
    /**
604
     * object which is a parent to the pages in the document
605
     *
606
     * @param $id
607
     * @param $action
608
     * @param string $options
609
     * @return string|null
610
     */
611
    protected function o_pages($id, $action, $options = '')
612
    {
613
        if ($action !== 'new') {
614
            $o = &$this->objects[$id];
615
        }
616
617
        switch ($action) {
618 View Code Duplication
            case 'new':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
619
                $this->objects[$id] = array('t' => 'pages', 'info' => array());
620
                $this->o_catalog($this->catalogId, 'pages', $id);
621
                break;
622
623
            case 'page':
624
                if (!is_array($options)) {
625
                    // then it will just be the id of the new page
626
                    $o['info']['pages'][] = $options;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
627
                } else {
628
                    // then it should be an array having 'id','rid','pos', where rid=the page to which this one will be placed relative
629
                    // and pos is either 'before' or 'after', saying where this page will fit.
630
                    if (isset($options['id']) && isset($options['rid']) && isset($options['pos'])) {
631
                        $i = array_search($options['rid'], $o['info']['pages']);
632
                        if (isset($o['info']['pages'][$i]) && $o['info']['pages'][$i] == $options['rid']) {
633
634
                            // then there is a match
635
                            // make a space
636
                            switch ($options['pos']) {
637
                                case 'before':
638
                                    $k = $i;
639
                                    break;
640
641
                                case 'after':
642
                                    $k = $i + 1;
643
                                    break;
644
645
                                default:
646
                                    $k = -1;
647
                                    break;
648
                            }
649
650
                            if ($k >= 0) {
651
                                for ($j = count($o['info']['pages']) - 1; $j >= $k; $j--) {
652
                                    $o['info']['pages'][$j + 1] = $o['info']['pages'][$j];
653
                                }
654
655
                                $o['info']['pages'][$k] = $options['id'];
656
                            }
657
                        }
658
                    }
659
                }
660
                break;
661
662
            case 'procset':
663
                $o['info']['procset'] = $options;
664
                break;
665
666
            case 'mediaBox':
667
                $o['info']['mediaBox'] = $options;
668
                // which should be an array of 4 numbers
669
                $this->currentPageSize = array('width' => $options[2], 'height' => $options[3]);
670
                break;
671
672 View Code Duplication
            case 'font':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
673
                $o['info']['fonts'][] = array('objNum' => $options['objNum'], 'fontNum' => $options['fontNum']);
674
                break;
675
676
            case 'extGState':
677
                $o['info']['extGStates'][] = array('objNum' => $options['objNum'], 'stateNum' => $options['stateNum']);
678
                break;
679
680 View Code Duplication
            case 'xObject':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
681
                $o['info']['xObjects'][] = array('objNum' => $options['objNum'], 'label' => $options['label']);
682
                break;
683
684
            case 'out':
685
                if (count($o['info']['pages'])) {
686
                    $res = "\n$id 0 obj\n<< /Type /Pages\n/Kids [";
687
                    foreach ($o['info']['pages'] as $v) {
688
                        $res .= "$v 0 R\n";
689
                    }
690
691
                    $res .= "]\n/Count " . count($this->objects[$id]['info']['pages']);
692
693
                    if ((isset($o['info']['fonts']) && count($o['info']['fonts'])) ||
694
                        isset($o['info']['procset']) ||
695
                        (isset($o['info']['extGStates']) && count($o['info']['extGStates']))
696
                    ) {
697
                        $res .= "\n/Resources <<";
698
699
                        if (isset($o['info']['procset'])) {
700
                            $res .= "\n/ProcSet " . $o['info']['procset'] . " 0 R";
701
                        }
702
703 View Code Duplication
                        if (isset($o['info']['fonts']) && count($o['info']['fonts'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
704
                            $res .= "\n/Font << ";
705
                            foreach ($o['info']['fonts'] as $finfo) {
706
                                $res .= "\n/F" . $finfo['fontNum'] . " " . $finfo['objNum'] . " 0 R";
707
                            }
708
                            $res .= "\n>>";
709
                        }
710
711 View Code Duplication
                        if (isset($o['info']['xObjects']) && count($o['info']['xObjects'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
712
                            $res .= "\n/XObject << ";
713
                            foreach ($o['info']['xObjects'] as $finfo) {
714
                                $res .= "\n/" . $finfo['label'] . " " . $finfo['objNum'] . " 0 R";
715
                            }
716
                            $res .= "\n>>";
717
                        }
718
719 View Code Duplication
                        if (isset($o['info']['extGStates']) && count($o['info']['extGStates'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
720
                            $res .= "\n/ExtGState << ";
721
                            foreach ($o['info']['extGStates'] as $gstate) {
722
                                $res .= "\n/GS" . $gstate['stateNum'] . " " . $gstate['objNum'] . " 0 R";
723
                            }
724
                            $res .= "\n>>";
725
                        }
726
727
                        $res .= "\n>>";
728 View Code Duplication
                        if (isset($o['info']['mediaBox'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
729
                            $tmp = $o['info']['mediaBox'];
730
                            $res .= "\n/MediaBox [" . sprintf(
731
                                    '%.3F %.3F %.3F %.3F',
732
                                    $tmp[0],
733
                                    $tmp[1],
734
                                    $tmp[2],
735
                                    $tmp[3]
736
                                ) . ']';
737
                        }
738
                    }
739
740
                    $res .= "\n >>\nendobj";
741
                } else {
742
                    $res = "\n$id 0 obj\n<< /Type /Pages\n/Count 0\n>>\nendobj";
743
                }
744
745
                return $res;
746
        }
747
748
        return null;
749
    }
750
751
    /**
752
     * define the outlines in the doc, empty for now
753
     *
754
     * @param $id
755
     * @param $action
756
     * @param string $options
757
     * @return string|null
758
     */
759
    protected function o_outlines($id, $action, $options = '')
760
    {
761
        if ($action !== 'new') {
762
            $o = &$this->objects[$id];
763
        }
764
765
        switch ($action) {
766 View Code Duplication
            case 'new':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
767
                $this->objects[$id] = array('t' => 'outlines', 'info' => array('outlines' => array()));
768
                $this->o_catalog($this->catalogId, 'outlines', $id);
769
                break;
770
771
            case 'outline':
772
                $o['info']['outlines'][] = $options;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
773
                break;
774
775
            case 'out':
776
                if (count($o['info']['outlines'])) {
777
                    $res = "\n$id 0 obj\n<< /Type /Outlines /Kids [";
778
                    foreach ($o['info']['outlines'] as $v) {
779
                        $res .= "$v 0 R ";
780
                    }
781
782
                    $res .= "] /Count " . count($o['info']['outlines']) . " >>\nendobj";
783
                } else {
784
                    $res = "\n$id 0 obj\n<< /Type /Outlines /Count 0 >>\nendobj";
785
                }
786
787
                return $res;
788
        }
789
790
        return null;
791
    }
792
793
    /**
794
     * an object to hold the font description
795
     *
796
     * @param $id
797
     * @param $action
798
     * @param string|array $options
799
     * @return string|null
800
     */
801
    protected function o_font($id, $action, $options = '')
802
    {
803
        if ($action !== 'new') {
804
            $o = &$this->objects[$id];
805
        }
806
807
        switch ($action) {
808
            case 'new':
809
                $this->objects[$id] = array(
810
                    't'    => 'font',
811
                    'info' => array(
812
                        'name'         => $options['name'],
813
                        'fontFileName' => $options['fontFileName'],
814
                        'SubType'      => 'Type1'
815
                    )
816
                );
817
                $fontNum = $this->numFonts;
818
                $this->objects[$id]['info']['fontNum'] = $fontNum;
819
820
                // deal with the encoding and the differences
821
                if (isset($options['differences'])) {
822
                    // then we'll need an encoding dictionary
823
                    $this->numObj++;
824
                    $this->o_fontEncoding($this->numObj, 'new', $options);
0 ignored issues
show
Bug introduced by
It seems like $options defined by parameter $options on line 801 can also be of type array; however, Cpdf::o_fontEncoding() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
825
                    $this->objects[$id]['info']['encodingDictionary'] = $this->numObj;
826
                } else {
827
                    if (isset($options['encoding'])) {
828
                        // we can specify encoding here
829
                        switch ($options['encoding']) {
830
                            case 'WinAnsiEncoding':
831
                            case 'MacRomanEncoding':
832
                            case 'MacExpertEncoding':
833
                                $this->objects[$id]['info']['encoding'] = $options['encoding'];
834
                                break;
835
836
                            case 'none':
837
                                break;
838
839
                            default:
840
                                $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
841
                                break;
842
                        }
843
                    } else {
844
                        $this->objects[$id]['info']['encoding'] = 'WinAnsiEncoding';
845
                    }
846
                }
847
848
                if ($this->fonts[$options['fontFileName']]['isUnicode']) {
849
                    // For Unicode fonts, we need to incorporate font data into
850
                    // sub-sections that are linked from the primary font section.
851
                    // Look at o_fontGIDtoCID and o_fontDescendentCID functions
852
                    // for more information.
853
                    //
854
                    // All of this code is adapted from the excellent changes made to
855
                    // transform FPDF to TCPDF (http://tcpdf.sourceforge.net/)
856
857
                    $toUnicodeId = ++$this->numObj;
858
                    $this->o_contents($toUnicodeId, 'new', 'raw');
859
                    $this->objects[$id]['info']['toUnicode'] = $toUnicodeId;
860
861
                    $stream = <<<EOT
862
/CIDInit /ProcSet findresource begin
863
12 dict begin
864
begincmap
865
/CIDSystemInfo
866
<</Registry (Adobe)
867
/Ordering (UCS)
868
/Supplement 0
869
>> def
870
/CMapName /Adobe-Identity-UCS def
871
/CMapType 2 def
872
1 begincodespacerange
873
<0000> <FFFF>
874
endcodespacerange
875
1 beginbfrange
876
<0000> <FFFF> <0000>
877
endbfrange
878
endcmap
879
CMapName currentdict /CMap defineresource pop
880
end
881
end
882
EOT;
883
884
                    $res = "<</Length " . mb_strlen($stream, '8bit') . " >>\n";
885
                    $res .= "stream\n" . $stream . "\nendstream";
886
887
                    $this->objects[$toUnicodeId]['c'] = $res;
888
889
                    $cidFontId = ++$this->numObj;
890
                    $this->o_fontDescendentCID($cidFontId, 'new', $options);
891
                    $this->objects[$id]['info']['cidFont'] = $cidFontId;
892
                }
893
894
                // also tell the pages node about the new font
895
                $this->o_pages($this->currentNode, 'font', array('fontNum' => $fontNum, 'objNum' => $id));
0 ignored issues
show
Documentation introduced by
array('fontNum' => $fontNum, 'objNum' => $id) is of type array<string,?,{"fontNum...integer","objNum":"?"}>, but the function expects a string.

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...
896
                break;
897
898
            case 'add':
899
                foreach ($options as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $options 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...
900
                    switch ($k) {
901
                        case 'BaseFont':
902
                            $o['info']['name'] = $v;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
903
                            break;
904
                        case 'FirstChar':
905
                        case 'LastChar':
906
                        case 'Widths':
907
                        case 'FontDescriptor':
908
                        case 'SubType':
909
                            $this->addMessage('o_font ' . $k . " : " . $v);
910
                            $o['info'][$k] = $v;
911
                            break;
912
                    }
913
                }
914
915
                // pass values down to descendent font
916
                if (isset($o['info']['cidFont'])) {
917
                    $this->o_fontDescendentCID($o['info']['cidFont'], 'add', $options);
918
                }
919
                break;
920
921
            case 'out':
922
                if ($this->fonts[$this->objects[$id]['info']['fontFileName']]['isUnicode']) {
923
                    // For Unicode fonts, we need to incorporate font data into
924
                    // sub-sections that are linked from the primary font section.
925
                    // Look at o_fontGIDtoCID and o_fontDescendentCID functions
926
                    // for more information.
927
                    //
928
                    // All of this code is adapted from the excellent changes made to
929
                    // transform FPDF to TCPDF (http://tcpdf.sourceforge.net/)
930
931
                    $res = "\n$id 0 obj\n<</Type /Font\n/Subtype /Type0\n";
932
                    $res .= "/BaseFont /" . $o['info']['name'] . "\n";
933
934
                    // The horizontal identity mapping for 2-byte CIDs; may be used
935
                    // with CIDFonts using any Registry, Ordering, and Supplement values.
936
                    $res .= "/Encoding /Identity-H\n";
937
                    $res .= "/DescendantFonts [" . $o['info']['cidFont'] . " 0 R]\n";
938
                    $res .= "/ToUnicode " . $o['info']['toUnicode'] . " 0 R\n";
939
                    $res .= ">>\n";
940
                    $res .= "endobj";
941
                } else {
942
                    $res = "\n$id 0 obj\n<< /Type /Font\n/Subtype /" . $o['info']['SubType'] . "\n";
943
                    $res .= "/Name /F" . $o['info']['fontNum'] . "\n";
944
                    $res .= "/BaseFont /" . $o['info']['name'] . "\n";
945
946
                    if (isset($o['info']['encodingDictionary'])) {
947
                        // then place a reference to the dictionary
948
                        $res .= "/Encoding " . $o['info']['encodingDictionary'] . " 0 R\n";
949 View Code Duplication
                    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
950
                        if (isset($o['info']['encoding'])) {
951
                            // use the specified encoding
952
                            $res .= "/Encoding /" . $o['info']['encoding'] . "\n";
953
                        }
954
                    }
955
956
                    if (isset($o['info']['FirstChar'])) {
957
                        $res .= "/FirstChar " . $o['info']['FirstChar'] . "\n";
958
                    }
959
960
                    if (isset($o['info']['LastChar'])) {
961
                        $res .= "/LastChar " . $o['info']['LastChar'] . "\n";
962
                    }
963
964
                    if (isset($o['info']['Widths'])) {
965
                        $res .= "/Widths " . $o['info']['Widths'] . " 0 R\n";
966
                    }
967
968 View Code Duplication
                    if (isset($o['info']['FontDescriptor'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
969
                        $res .= "/FontDescriptor " . $o['info']['FontDescriptor'] . " 0 R\n";
970
                    }
971
972
                    $res .= ">>\n";
973
                    $res .= "endobj";
974
                }
975
976
                return $res;
977
        }
978
979
        return null;
980
    }
981
982
    /**
983
     * a font descriptor, needed for including additional fonts
984
     *
985
     * @param $id
986
     * @param $action
987
     * @param string $options
988
     * @return null|string
989
     */
990
    protected function o_fontDescriptor($id, $action, $options = '')
991
    {
992
        if ($action !== 'new') {
993
            $o = &$this->objects[$id];
994
        }
995
996
        switch ($action) {
997
            case 'new':
998
                $this->objects[$id] = array('t' => 'fontDescriptor', 'info' => $options);
999
                break;
1000
1001
            case 'out':
1002
                $res = "\n$id 0 obj\n<< /Type /FontDescriptor\n";
1003
                foreach ($o['info'] as $label => $value) {
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1004
                    switch ($label) {
1005
                        case 'Ascent':
1006
                        case 'CapHeight':
1007
                        case 'Descent':
1008
                        case 'Flags':
1009
                        case 'ItalicAngle':
1010
                        case 'StemV':
1011
                        case 'AvgWidth':
1012
                        case 'Leading':
1013
                        case 'MaxWidth':
1014
                        case 'MissingWidth':
1015
                        case 'StemH':
1016
                        case 'XHeight':
1017
                        case 'CharSet':
1018
                            if (mb_strlen($value, '8bit')) {
1019
                                $res .= "/$label $value\n";
1020
                            }
1021
1022
                            break;
1023
                        case 'FontFile':
1024
                        case 'FontFile2':
1025
                        case 'FontFile3':
1026
                            $res .= "/$label $value 0 R\n";
1027
                            break;
1028
1029
                        case 'FontBBox':
1030
                            $res .= "/$label [$value[0] $value[1] $value[2] $value[3]]\n";
1031
                            break;
1032
1033
                        case 'FontName':
1034
                            $res .= "/$label /$value\n";
1035
                            break;
1036
                    }
1037
                }
1038
1039
                $res .= ">>\nendobj";
1040
1041
                return $res;
1042
        }
1043
1044
        return null;
1045
    }
1046
1047
    /**
1048
     * the font encoding
1049
     *
1050
     * @param $id
1051
     * @param $action
1052
     * @param string $options
1053
     * @return null|string
1054
     */
1055
    protected function o_fontEncoding($id, $action, $options = '')
1056
    {
1057
        if ($action !== 'new') {
1058
            $o = &$this->objects[$id];
1059
        }
1060
1061
        switch ($action) {
1062
            case 'new':
1063
                // the options array should contain 'differences' and maybe 'encoding'
1064
                $this->objects[$id] = array('t' => 'fontEncoding', 'info' => $options);
1065
                break;
1066
1067
            case 'out':
1068
                $res = "\n$id 0 obj\n<< /Type /Encoding\n";
1069
                if (!isset($o['info']['encoding'])) {
1070
                    $o['info']['encoding'] = 'WinAnsiEncoding';
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1071
                }
1072
1073 View Code Duplication
                if ($o['info']['encoding'] !== 'none') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1074
                    $res .= "/BaseEncoding /" . $o['info']['encoding'] . "\n";
1075
                }
1076
1077
                $res .= "/Differences \n[";
1078
1079
                $onum = -100;
1080
1081
                foreach ($o['info']['differences'] as $num => $label) {
1082
                    if ($num != $onum + 1) {
1083
                        // we cannot make use of consecutive numbering
1084
                        $res .= "\n$num /$label";
1085
                    } else {
1086
                        $res .= " /$label";
1087
                    }
1088
1089
                    $onum = $num;
1090
                }
1091
1092
                $res .= "\n]\n>>\nendobj";
1093
1094
                return $res;
1095
        }
1096
1097
        return null;
1098
    }
1099
1100
    /**
1101
     * a descendent cid font, needed for unicode fonts
1102
     *
1103
     * @param $id
1104
     * @param $action
1105
     * @param string|array $options
1106
     * @return null|string
1107
     */
1108
    protected function o_fontDescendentCID($id, $action, $options = '')
1109
    {
1110
        if ($action !== 'new') {
1111
            $o = &$this->objects[$id];
1112
        }
1113
1114
        switch ($action) {
1115
            case 'new':
1116
                $this->objects[$id] = array('t' => 'fontDescendentCID', 'info' => $options);
1117
1118
                // we need a CID system info section
1119
                $cidSystemInfoId = ++$this->numObj;
1120
                $this->o_contents($cidSystemInfoId, 'new', 'raw');
1121
                $this->objects[$id]['info']['cidSystemInfo'] = $cidSystemInfoId;
1122
                $res = "<</Registry (Adobe)\n"; // A string identifying an issuer of character collections
1123
                $res .= "/Ordering (UCS)\n"; // A string that uniquely names a character collection issued by a specific registry
1124
                $res .= "/Supplement 0\n"; // The supplement number of the character collection.
1125
                $res .= ">>";
1126
                $this->objects[$cidSystemInfoId]['c'] = $res;
1127
1128
                // and a CID to GID map
1129
                $cidToGidMapId = ++$this->numObj;
1130
                $this->o_fontGIDtoCIDMap($cidToGidMapId, 'new', $options);
0 ignored issues
show
Bug introduced by
It seems like $options defined by parameter $options on line 1108 can also be of type array; however, Cpdf::o_fontGIDtoCIDMap() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1131
                $this->objects[$id]['info']['cidToGidMap'] = $cidToGidMapId;
1132
                break;
1133
1134
            case 'add':
1135
                foreach ($options as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $options 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...
1136
                    switch ($k) {
1137
                        case 'BaseFont':
1138
                            $o['info']['name'] = $v;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1139
                            break;
1140
1141
                        case 'FirstChar':
1142
                        case 'LastChar':
1143
                        case 'MissingWidth':
1144
                        case 'FontDescriptor':
1145
                        case 'SubType':
1146
                            $this->addMessage("o_fontDescendentCID $k : $v");
1147
                            $o['info'][$k] = $v;
1148
                            break;
1149
                    }
1150
                }
1151
1152
                // pass values down to cid to gid map
1153
                $this->o_fontGIDtoCIDMap($o['info']['cidToGidMap'], 'add', $options);
0 ignored issues
show
Bug introduced by
It seems like $options defined by parameter $options on line 1108 can also be of type array; however, Cpdf::o_fontGIDtoCIDMap() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1154
                break;
1155
1156
            case 'out':
1157
                $res = "\n$id 0 obj\n";
1158
                $res .= "<</Type /Font\n";
1159
                $res .= "/Subtype /CIDFontType2\n";
1160
                $res .= "/BaseFont /" . $o['info']['name'] . "\n";
1161
                $res .= "/CIDSystemInfo " . $o['info']['cidSystemInfo'] . " 0 R\n";
1162
                //      if (isset($o['info']['FirstChar'])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
83% 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...
1163
                //        $res.= "/FirstChar ".$o['info']['FirstChar']."\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% 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...
1164
                //      }
1165
1166
                //      if (isset($o['info']['LastChar'])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
83% 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...
1167
                //        $res.= "/LastChar ".$o['info']['LastChar']."\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% 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...
1168
                //      }
1169 View Code Duplication
                if (isset($o['info']['FontDescriptor'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1170
                    $res .= "/FontDescriptor " . $o['info']['FontDescriptor'] . " 0 R\n";
1171
                }
1172
1173
                if (isset($o['info']['MissingWidth'])) {
1174
                    $res .= "/DW " . $o['info']['MissingWidth'] . "\n";
1175
                }
1176
1177
                if (isset($o['info']['fontFileName']) && isset($this->fonts[$o['info']['fontFileName']]['CIDWidths'])) {
1178
                    $cid_widths = &$this->fonts[$o['info']['fontFileName']]['CIDWidths'];
1179
                    $w = '';
1180
                    foreach ($cid_widths as $cid => $width) {
1181
                        $w .= "$cid [$width] ";
1182
                    }
1183
                    $res .= "/W [$w]\n";
1184
                }
1185
1186
                $res .= "/CIDToGIDMap " . $o['info']['cidToGidMap'] . " 0 R\n";
1187
                $res .= ">>\n";
1188
                $res .= "endobj";
1189
1190
                return $res;
1191
        }
1192
1193
        return null;
1194
    }
1195
1196
    /**
1197
     * a font glyph to character map, needed for unicode fonts
1198
     *
1199
     * @param $id
1200
     * @param $action
1201
     * @param string $options
1202
     * @return null|string
1203
     */
1204
    protected function o_fontGIDtoCIDMap($id, $action, $options = '')
1205
    {
1206
        if ($action !== 'new') {
1207
            $o = &$this->objects[$id];
1208
        }
1209
1210
        switch ($action) {
1211
            case 'new':
1212
                $this->objects[$id] = array('t' => 'fontGIDtoCIDMap', 'info' => $options);
1213
                break;
1214
1215
            case 'out':
1216
                $res = "\n$id 0 obj\n";
1217
                $fontFileName = $o['info']['fontFileName'];
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1218
                $tmp = $this->fonts[$fontFileName]['CIDtoGID'] = base64_decode($this->fonts[$fontFileName]['CIDtoGID']);
1219
1220
                $compressed = isset($this->fonts[$fontFileName]['CIDtoGID_Compressed']) &&
1221
                    $this->fonts[$fontFileName]['CIDtoGID_Compressed'];
1222
1223
                if (!$compressed && isset($o['raw'])) {
1224
                    $res .= $tmp;
1225
                } else {
1226
                    $res .= "<<";
1227
1228 View Code Duplication
                    if (!$compressed && $this->compressionReady && $this->options['compression']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1229
                        // then implement ZLIB based compression on this content stream
1230
                        $compressed = true;
1231
                        $tmp = gzcompress($tmp, 6);
1232
                    }
1233
                    if ($compressed) {
1234
                        $res .= "\n/Filter /FlateDecode";
1235
                    }
1236
1237
                    if ($this->encrypted) {
1238
                        $this->encryptInit($id);
1239
                        $tmp = $this->ARC4($tmp);
1240
                    }
1241
1242
                    $res .= "\n/Length " . mb_strlen($tmp, '8bit') . ">>\nstream\n$tmp\nendstream";
1243
                }
1244
1245
                $res .= "\nendobj";
1246
1247
                return $res;
1248
        }
1249
1250
        return null;
1251
    }
1252
1253
    /**
1254
     * the document procset, solves some problems with printing to old PS printers
1255
     *
1256
     * @param $id
1257
     * @param $action
1258
     * @param string $options
1259
     * @return null|string
1260
     */
1261
    protected function o_procset($id, $action, $options = '')
1262
    {
1263
        if ($action !== 'new') {
1264
            $o = &$this->objects[$id];
1265
        }
1266
1267
        switch ($action) {
1268 View Code Duplication
            case 'new':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1269
                $this->objects[$id] = array('t' => 'procset', 'info' => array('PDF' => 1, 'Text' => 1));
1270
                $this->o_pages($this->currentNode, 'procset', $id);
1271
                $this->procsetObjectId = $id;
1272
                break;
1273
1274
            case 'add':
1275
                // this is to add new items to the procset list, despite the fact that this is considered
1276
                // obsolete, the items are required for printing to some postscript printers
1277
                switch ($options) {
1278
                    case 'ImageB':
1279
                    case 'ImageC':
1280
                    case 'ImageI':
1281
                        $o['info'][$options] = 1;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1282
                        break;
1283
                }
1284
                break;
1285
1286
            case 'out':
1287
                $res = "\n$id 0 obj\n[";
1288
                foreach ($o['info'] as $label => $val) {
1289
                    $res .= "/$label ";
1290
                }
1291
                $res .= "]\nendobj";
1292
1293
                return $res;
1294
        }
1295
1296
        return null;
1297
    }
1298
1299
    /**
1300
     * define the document information
1301
     *
1302
     * @param $id
1303
     * @param $action
1304
     * @param string $options
1305
     * @return null|string
1306
     */
1307
    protected function o_info($id, $action, $options = '')
1308
    {
1309
        switch ($action) {
1310
            case 'new':
1311
                $this->infoObject = $id;
1312
                $date = 'D:' . @date('Ymd');
1313
                $this->objects[$id] = array(
1314
                    't'    => 'info',
1315
                    'info' => array(
1316
                        'Producer'      => 'CPDF (dompdf)',
1317
                        'CreationDate' => $date
1318
                    )
1319
                );
1320
                break;
1321
            case 'Title':
1322
            case 'Author':
1323
            case 'Subject':
1324
            case 'Keywords':
1325
            case 'Creator':
1326
            case 'Producer':
1327
            case 'CreationDate':
1328
            case 'ModDate':
1329
            case 'Trapped':
1330
                $this->objects[$id]['info'][$action] = $options;
1331
                break;
1332
1333
            case 'out':
1334
                $encrypted = $this->encrypted;
1335
                if ($encrypted) {
1336
                    $this->encryptInit($id);
1337
                }
1338
1339
                $res = "\n$id 0 obj\n<<\n";
1340
                $o = &$this->objects[$id];
1341
                foreach ($o['info'] as $k => $v) {
1342
                    $res .= "/$k (";
1343
1344
                    // dates must be outputted as-is, without Unicode transformations
1345
                    if ($k !== 'CreationDate' && $k !== 'ModDate') {
1346
                        $v = $this->filterText($v, true, false);
1347
                    }
1348
1349
                    if ($encrypted) {
1350
                        $v = $this->ARC4($v);
1351
                    }
1352
1353
                    $res .= $v;
1354
                    $res .= ")\n";
1355
                }
1356
1357
                $res .= ">>\nendobj";
1358
1359
                return $res;
1360
        }
1361
1362
        return null;
1363
    }
1364
1365
    /**
1366
     * an action object, used to link to URLS initially
1367
     *
1368
     * @param $id
1369
     * @param $action
1370
     * @param string $options
1371
     * @return null|string
1372
     */
1373
    protected function o_action($id, $action, $options = '')
1374
    {
1375
        if ($action !== 'new') {
1376
            $o = &$this->objects[$id];
1377
        }
1378
1379
        switch ($action) {
1380
            case 'new':
1381
                if (is_array($options)) {
1382
                    $this->objects[$id] = array('t' => 'action', 'info' => $options, 'type' => $options['type']);
1383
                } else {
1384
                    // then assume a URI action
1385
                    $this->objects[$id] = array('t' => 'action', 'info' => $options, 'type' => 'URI');
1386
                }
1387
                break;
1388
1389
            case 'out':
1390
                if ($this->encrypted) {
1391
                    $this->encryptInit($id);
1392
                }
1393
1394
                $res = "\n$id 0 obj\n<< /Type /Action";
1395
                switch ($o['type']) {
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1396
                    case 'ilink':
1397
                        if (!isset($this->destinations[(string)$o['info']['label']])) {
1398
                            break;
1399
                        }
1400
1401
                        // there will be an 'label' setting, this is the name of the destination
1402
                        $res .= "\n/S /GoTo\n/D " . $this->destinations[(string)$o['info']['label']] . " 0 R";
1403
                        break;
1404
1405
                    case 'URI':
1406
                        $res .= "\n/S /URI\n/URI (";
1407
                        if ($this->encrypted) {
1408
                            $res .= $this->filterText($this->ARC4($o['info']), true, false);
1409
                        } else {
1410
                            $res .= $this->filterText($o['info'], true, false);
1411
                        }
1412
1413
                        $res .= ")";
1414
                        break;
1415
                }
1416
1417
                $res .= "\n>>\nendobj";
1418
1419
                return $res;
1420
        }
1421
1422
        return null;
1423
    }
1424
1425
    /**
1426
     * an annotation object, this will add an annotation to the current page.
1427
     * initially will support just link annotations
1428
     *
1429
     * @param $id
1430
     * @param $action
1431
     * @param string $options
1432
     * @return null|string
1433
     */
1434
    protected function o_annotation($id, $action, $options = '')
1435
    {
1436
        if ($action !== 'new') {
1437
            $o = &$this->objects[$id];
1438
        }
1439
1440
        switch ($action) {
1441
            case 'new':
1442
                // add the annotation to the current page
1443
                $pageId = $this->currentPage;
1444
                $this->o_page($pageId, 'annot', $id);
1445
1446
                // and add the action object which is going to be required
1447
                switch ($options['type']) {
1448
                    case 'link':
1449
                        $this->objects[$id] = array('t' => 'annotation', 'info' => $options);
1450
                        $this->numObj++;
1451
                        $this->o_action($this->numObj, 'new', $options['url']);
1452
                        $this->objects[$id]['info']['actionId'] = $this->numObj;
1453
                        break;
1454
1455
                    case 'ilink':
1456
                        // this is to a named internal link
1457
                        $label = $options['label'];
1458
                        $this->objects[$id] = array('t' => 'annotation', 'info' => $options);
1459
                        $this->numObj++;
1460
                        $this->o_action($this->numObj, 'new', array('type' => 'ilink', 'label' => $label));
0 ignored issues
show
Documentation introduced by
array('type' => 'ilink', 'label' => $label) is of type array<string,string,{"ty...ing","label":"string"}>, but the function expects a string.

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...
1461
                        $this->objects[$id]['info']['actionId'] = $this->numObj;
1462
                        break;
1463
                }
1464
                break;
1465
1466
            case 'out':
1467
                $res = "\n$id 0 obj\n<< /Type /Annot";
1468
                switch ($o['info']['type']) {
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1469
                    case 'link':
1470
                    case 'ilink':
1471
                        $res .= "\n/Subtype /Link";
1472
                        break;
1473
                }
1474
                $res .= "\n/A " . $o['info']['actionId'] . " 0 R";
1475
                $res .= "\n/Border [0 0 0]";
1476
                $res .= "\n/H /I";
1477
                $res .= "\n/Rect [ ";
1478
1479
                foreach ($o['info']['rect'] as $v) {
1480
                    $res .= sprintf("%.4F ", $v);
1481
                }
1482
1483
                $res .= "]";
1484
                $res .= "\n>>\nendobj";
1485
1486
                return $res;
1487
        }
1488
1489
        return null;
1490
    }
1491
1492
    /**
1493
     * a page object, it also creates a contents object to hold its contents
1494
     *
1495
     * @param $id
1496
     * @param $action
1497
     * @param string $options
1498
     * @return null|string
1499
     */
1500
    protected function o_page($id, $action, $options = '')
1501
    {
1502
        if ($action !== 'new') {
1503
            $o = &$this->objects[$id];
1504
        }
1505
1506
        switch ($action) {
1507
            case 'new':
1508
                $this->numPages++;
1509
                $this->objects[$id] = array(
1510
                    't'    => 'page',
1511
                    'info' => array(
1512
                        'parent'  => $this->currentNode,
1513
                        'pageNum' => $this->numPages,
1514
                        'mediaBox' => $this->objects[$this->currentNode]['info']['mediaBox']
1515
                    )
1516
                );
1517
1518
                if (is_array($options)) {
1519
                    // then this must be a page insertion, array should contain 'rid','pos'=[before|after]
1520
                    $options['id'] = $id;
1521
                    $this->o_pages($this->currentNode, 'page', $options);
0 ignored issues
show
Documentation introduced by
$options is of type array<string,?,{"id":"?"}>, but the function expects a string.

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...
1522
                } else {
1523
                    $this->o_pages($this->currentNode, 'page', $id);
1524
                }
1525
1526
                $this->currentPage = $id;
1527
                //make a contents object to go with this page
1528
                $this->numObj++;
1529
                $this->o_contents($this->numObj, 'new', $id);
1530
                $this->currentContents = $this->numObj;
1531
                $this->objects[$id]['info']['contents'] = array();
1532
                $this->objects[$id]['info']['contents'][] = $this->numObj;
1533
1534
                $match = ($this->numPages % 2 ? 'odd' : 'even');
1535
                foreach ($this->addLooseObjects as $oId => $target) {
1536
                    if ($target === 'all' || $match === $target) {
1537
                        $this->objects[$id]['info']['contents'][] = $oId;
1538
                    }
1539
                }
1540
                break;
1541
1542
            case 'content':
1543
                $o['info']['contents'][] = $options;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1544
                break;
1545
1546
            case 'annot':
1547
                // add an annotation to this page
1548
                if (!isset($o['info']['annot'])) {
1549
                    $o['info']['annot'] = array();
1550
                }
1551
1552
                // $options should contain the id of the annotation dictionary
1553
                $o['info']['annot'][] = $options;
1554
                break;
1555
1556
            case 'out':
1557
                $res = "\n$id 0 obj\n<< /Type /Page";
1558 View Code Duplication
                if (isset($o['info']['mediaBox'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1559
                    $tmp = $o['info']['mediaBox'];
1560
                    $res .= "\n/MediaBox [" . sprintf(
1561
                            '%.3F %.3F %.3F %.3F',
1562
                            $tmp[0],
1563
                            $tmp[1],
1564
                            $tmp[2],
1565
                            $tmp[3]
1566
                        ) . ']';
1567
                }
1568
                $res .= "\n/Parent " . $o['info']['parent'] . " 0 R";
1569
1570
                if (isset($o['info']['annot'])) {
1571
                    $res .= "\n/Annots [";
1572
                    foreach ($o['info']['annot'] as $aId) {
1573
                        $res .= " $aId 0 R";
1574
                    }
1575
                    $res .= " ]";
1576
                }
1577
1578
                $count = count($o['info']['contents']);
1579
                if ($count == 1) {
1580
                    $res .= "\n/Contents " . $o['info']['contents'][0] . " 0 R";
1581
                } else {
1582
                    if ($count > 1) {
1583
                        $res .= "\n/Contents [\n";
1584
1585
                        // reverse the page contents so added objects are below normal content
1586
                        //foreach (array_reverse($o['info']['contents']) as $cId) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
1587
                        // Back to normal now that I've got transparency working --Benj
1588
                        foreach ($o['info']['contents'] as $cId) {
1589
                            $res .= "$cId 0 R\n";
1590
                        }
1591
                        $res .= "]";
1592
                    }
1593
                }
1594
1595
                $res .= "\n>>\nendobj";
1596
1597
                return $res;
1598
        }
1599
1600
        return null;
1601
    }
1602
1603
    /**
1604
     * the contents objects hold all of the content which appears on pages
1605
     *
1606
     * @param $id
1607
     * @param $action
1608
     * @param string|array $options
1609
     * @return null|string
1610
     */
1611
    protected function o_contents($id, $action, $options = '')
1612
    {
1613
        if ($action !== 'new') {
1614
            $o = &$this->objects[$id];
1615
        }
1616
1617
        switch ($action) {
1618
            case 'new':
1619
                $this->objects[$id] = array('t' => 'contents', 'c' => '', 'info' => array());
1620
                if (mb_strlen($options, '8bit') && intval($options)) {
1621
                    // then this contents is the primary for a page
1622
                    $this->objects[$id]['onPage'] = $options;
1623
                } else {
1624
                    if ($options === 'raw') {
1625
                        // then this page contains some other type of system object
1626
                        $this->objects[$id]['raw'] = 1;
1627
                    }
1628
                }
1629
                break;
1630
1631
            case 'add':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1632
                // add more options to the declaration
1633
                foreach ($options as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $options 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...
1634
                    $o['info'][$k] = $v;
0 ignored issues
show
Bug introduced by
The variable $o does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1635
                }
1636
1637
            case 'out':
1638
                $tmp = $o['c'];
1639
                $res = "\n$id 0 obj\n";
1640
1641
                if (isset($this->objects[$id]['raw'])) {
1642
                    $res .= $tmp;
1643
                } else {
1644
                    $res .= "<<";
1645 View Code Duplication
                    if ($this->compressionReady && $this->options['compression']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1646
                        // then implement ZLIB based compression on this content stream
1647
                        $res .= " /Filter /FlateDecode";
1648
                        $tmp = gzcompress($tmp, 6);
1649
                    }
1650
1651
                    if ($this->encrypted) {
1652
                        $this->encryptInit($id);
1653
                        $tmp = $this->ARC4($tmp);
1654
                    }
1655
1656
                    foreach ($o['info'] as $k => $v) {
1657
                        $res .= "\n/$k $v";
1658
                    }
1659
1660
                    $res .= "\n/Length " . mb_strlen($tmp, '8bit') . " >>\nstream\n$tmp\nendstream";
1661
                }
1662
1663
                $res .= "\nendobj";
1664
1665
                return $res;
1666
        }
1667
1668
        return null;
1669
    }
1670
1671
    /**
1672
     * @param $id
1673
     * @param $action
1674
     * @return string|null
1675
     */
1676
    protected function o_embedjs($id, $action)
1677
    {
1678
        switch ($action) {
1679
            case 'new':
1680
                $this->objects[$id] = array(
1681
                    't'    => 'embedjs',
1682
                    'info' => array(
1683
                        'Names' => '[(EmbeddedJS) ' . ($id + 1) . ' 0 R]'
1684
                    )
1685
                );
1686
                break;
1687
1688 View Code Duplication
            case 'out':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1689
                $o = &$this->objects[$id];
1690
                $res = "\n$id 0 obj\n<< ";
1691
                foreach ($o['info'] as $k => $v) {
1692
                    $res .= "\n/$k $v";
1693
                }
1694
                $res .= "\n>>\nendobj";
1695
1696
                return $res;
1697
        }
1698
1699
        return null;
1700
    }
1701
1702
    /**
1703
     * @param $id
1704
     * @param $action
1705
     * @param string $code
1706
     * @return null|string
1707
     */
1708
    protected function o_javascript($id, $action, $code = '')
1709
    {
1710
        switch ($action) {
1711
            case 'new':
1712
                $this->objects[$id] = array(
1713
                    't'    => 'javascript',
1714
                    'info' => array(
1715
                        'S'  => '/JavaScript',
1716
                        'JS' => '(' . $this->filterText($code, true, false) . ')',
1717
                    )
1718
                );
1719
                break;
1720
1721 View Code Duplication
            case 'out':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1722
                $o = &$this->objects[$id];
1723
                $res = "\n$id 0 obj\n<< ";
1724
1725
                foreach ($o['info'] as $k => $v) {
1726
                    $res .= "\n/$k $v";
1727
                }
1728
                $res .= "\n>>\nendobj";
1729
1730
                return $res;
1731
        }
1732
1733
        return null;
1734
    }
1735
1736
    /**
1737
     * an image object, will be an XObject in the document, includes description and data
1738
     *
1739
     * @param $id
1740
     * @param $action
1741
     * @param string $options
1742
     * @return null|string
1743
     */
1744
    protected function o_image($id, $action, $options = '')
1745
    {
1746
        switch ($action) {
1747
            case 'new':
1748
                // make the new object
1749
                $this->objects[$id] = array('t' => 'image', 'data' => &$options['data'], 'info' => array());
1750
1751
                $info =& $this->objects[$id]['info'];
1752
1753
                $info['Type'] = '/XObject';
1754
                $info['Subtype'] = '/Image';
1755
                $info['Width'] = $options['iw'];
1756
                $info['Height'] = $options['ih'];
1757
1758
                if (isset($options['masked']) && $options['masked']) {
1759
                    $info['SMask'] = ($this->numObj - 1) . ' 0 R';
1760
                }
1761
1762
                if (!isset($options['type']) || $options['type'] === 'jpg') {
1763
                    if (!isset($options['channels'])) {
1764
                        $options['channels'] = 3;
1765
                    }
1766
1767
                    switch ($options['channels']) {
1768
                        case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1769
                            $info['ColorSpace'] = '/DeviceGray';
1770
                            break;
1771
                        case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1772
                            $info['ColorSpace'] = '/DeviceCMYK';
1773
                            break;
1774
                        default:
1775
                            $info['ColorSpace'] = '/DeviceRGB';
1776
                            break;
1777
                    }
1778
1779
                    if ($info['ColorSpace'] === '/DeviceCMYK') {
1780
                        $info['Decode'] = '[1 0 1 0 1 0 1 0]';
1781
                    }
1782
1783
                    $info['Filter'] = '/DCTDecode';
1784
                    $info['BitsPerComponent'] = 8;
1785
                } else {
1786
                    if ($options['type'] === 'png') {
1787
                        $info['Filter'] = '/FlateDecode';
1788
                        $info['DecodeParms'] = '<< /Predictor 15 /Colors ' . $options['ncolor'] . ' /Columns ' . $options['iw'] . ' /BitsPerComponent ' . $options['bitsPerComponent'] . '>>';
1789
1790
                        if ($options['isMask']) {
1791
                            $info['ColorSpace'] = '/DeviceGray';
1792
                        } else {
1793
                            if (mb_strlen($options['pdata'], '8bit')) {
1794
                                $tmp = ' [ /Indexed /DeviceRGB ' . (mb_strlen($options['pdata'], '8bit') / 3 - 1) . ' ';
1795
                                $this->numObj++;
1796
                                $this->o_contents($this->numObj, 'new');
1797
                                $this->objects[$this->numObj]['c'] = $options['pdata'];
1798
                                $tmp .= $this->numObj . ' 0 R';
1799
                                $tmp .= ' ]';
1800
                                $info['ColorSpace'] = $tmp;
1801
1802 View Code Duplication
                                if (isset($options['transparency'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1803
                                    $transparency = $options['transparency'];
1804
                                    switch ($transparency['type']) {
1805
                                        case 'indexed':
1806
                                            $tmp = ' [ ' . $transparency['data'] . ' ' . $transparency['data'] . '] ';
1807
                                            $info['Mask'] = $tmp;
1808
                                            break;
1809
1810
                                        case 'color-key':
1811
                                            $tmp = ' [ ' .
1812
                                                $transparency['r'] . ' ' . $transparency['r'] .
1813
                                                $transparency['g'] . ' ' . $transparency['g'] .
1814
                                                $transparency['b'] . ' ' . $transparency['b'] .
1815
                                                ' ] ';
1816
                                            $info['Mask'] = $tmp;
1817
                                            break;
1818
                                    }
1819
                                }
1820
                            } else {
1821 View Code Duplication
                                if (isset($options['transparency'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1822
                                    $transparency = $options['transparency'];
1823
1824
                                    switch ($transparency['type']) {
1825
                                        case 'indexed':
1826
                                            $tmp = ' [ ' . $transparency['data'] . ' ' . $transparency['data'] . '] ';
1827
                                            $info['Mask'] = $tmp;
1828
                                            break;
1829
1830
                                        case 'color-key':
1831
                                            $tmp = ' [ ' .
1832
                                                $transparency['r'] . ' ' . $transparency['r'] . ' ' .
1833
                                                $transparency['g'] . ' ' . $transparency['g'] . ' ' .
1834
                                                $transparency['b'] . ' ' . $transparency['b'] .
1835
                                                ' ] ';
1836
                                            $info['Mask'] = $tmp;
1837
                                            break;
1838
                                    }
1839
                                }
1840
                                $info['ColorSpace'] = '/' . $options['color'];
1841
                            }
1842
                        }
1843
1844
                        $info['BitsPerComponent'] = $options['bitsPerComponent'];
1845
                    }
1846
                }
1847
1848
                // assign it a place in the named resource dictionary as an external object, according to
1849
                // the label passed in with it.
1850
                $this->o_pages($this->currentNode, 'xObject', array('label' => $options['label'], 'objNum' => $id));
0 ignored issues
show
Documentation introduced by
array('label' => $option...bel'], 'objNum' => $id) is of type array<string,?,{"label":"string","objNum":"?"}>, but the function expects a string.

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...
1851
1852
                // also make sure that we have the right procset object for it.
1853
                $this->o_procset($this->procsetObjectId, 'add', 'ImageC');
1854
                break;
1855
1856
            case 'out':
1857
                $o = &$this->objects[$id];
1858
                $tmp = &$o['data'];
1859
                $res = "\n$id 0 obj\n<<";
1860
1861
                foreach ($o['info'] as $k => $v) {
1862
                    $res .= "\n/$k $v";
1863
                }
1864
1865
                if ($this->encrypted) {
1866
                    $this->encryptInit($id);
1867
                    $tmp = $this->ARC4($tmp);
1868
                }
1869
1870
                $res .= "\n/Length " . mb_strlen($tmp, '8bit') . ">>\nstream\n$tmp\nendstream\nendobj";
1871
1872
                return $res;
1873
        }
1874
1875
        return null;
1876
    }
1877
1878
    /**
1879
     * graphics state object
1880
     *
1881
     * @param $id
1882
     * @param $action
1883
     * @param string $options
1884
     * @return null|string
1885
     */
1886
    protected function o_extGState($id, $action, $options = "")
1887
    {
1888
        static $valid_params = array(
1889
            "LW",
1890
            "LC",
1891
            "LC",
1892
            "LJ",
1893
            "ML",
1894
            "D",
1895
            "RI",
1896
            "OP",
1897
            "op",
1898
            "OPM",
1899
            "Font",
1900
            "BG",
1901
            "BG2",
1902
            "UCR",
1903
            "TR",
1904
            "TR2",
1905
            "HT",
1906
            "FL",
1907
            "SM",
1908
            "SA",
1909
            "BM",
1910
            "SMask",
1911
            "CA",
1912
            "ca",
1913
            "AIS",
1914
            "TK"
1915
        );
1916
1917
        switch ($action) {
1918 View Code Duplication
            case "new":
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1919
                $this->objects[$id] = array('t' => 'extGState', 'info' => $options);
1920
1921
                // Tell the pages about the new resource
1922
                $this->numStates++;
1923
                $this->o_pages($this->currentNode, 'extGState', array("objNum" => $id, "stateNum" => $this->numStates));
0 ignored issues
show
Documentation introduced by
array('objNum' => $id, '...m' => $this->numStates) is of type array<string,?,{"objNum"...,"stateNum":"integer"}>, but the function expects a string.

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...
1924
                break;
1925
1926 View Code Duplication
            case "out":
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1927
                $o = &$this->objects[$id];
1928
                $res = "\n$id 0 obj\n<< /Type /ExtGState\n";
1929
1930
                foreach ($o["info"] as $k => $v) {
1931
                    if (!in_array($k, $valid_params)) {
1932
                        continue;
1933
                    }
1934
                    $res .= "/$k $v\n";
1935
                }
1936
1937
                $res .= ">>\nendobj";
1938
1939
                return $res;
1940
        }
1941
1942
        return null;
1943
    }
1944
1945
    /**
1946
     * encryption object.
1947
     *
1948
     * @param $id
1949
     * @param $action
1950
     * @param string $options
1951
     * @return string|null
1952
     */
1953
    protected function o_encryption($id, $action, $options = '')
1954
    {
1955
        switch ($action) {
1956
            case 'new':
1957
                // make the new object
1958
                $this->objects[$id] = array('t' => 'encryption', 'info' => $options);
1959
                $this->arc4_objnum = $id;
1960
                break;
1961
1962
            case 'keys':
1963
                // figure out the additional parameters required
1964
                $pad = chr(0x28) . chr(0xBF) . chr(0x4E) . chr(0x5E) . chr(0x4E) . chr(0x75) . chr(0x8A) . chr(0x41)
1965
                    . chr(0x64) . chr(0x00) . chr(0x4E) . chr(0x56) . chr(0xFF) . chr(0xFA) . chr(0x01) . chr(0x08)
1966
                    . chr(0x2E) . chr(0x2E) . chr(0x00) . chr(0xB6) . chr(0xD0) . chr(0x68) . chr(0x3E) . chr(0x80)
1967
                    . chr(0x2F) . chr(0x0C) . chr(0xA9) . chr(0xFE) . chr(0x64) . chr(0x53) . chr(0x69) . chr(0x7A);
1968
1969
                $info = $this->objects[$id]['info'];
1970
1971
                $len = mb_strlen($info['owner'], '8bit');
1972
1973 View Code Duplication
                if ($len > 32) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1974
                    $owner = substr($info['owner'], 0, 32);
1975
                } else {
1976
                    if ($len < 32) {
1977
                        $owner = $info['owner'] . substr($pad, 0, 32 - $len);
1978
                    } else {
1979
                        $owner = $info['owner'];
1980
                    }
1981
                }
1982
1983
                $len = mb_strlen($info['user'], '8bit');
1984 View Code Duplication
                if ($len > 32) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1985
                    $user = substr($info['user'], 0, 32);
1986
                } else {
1987
                    if ($len < 32) {
1988
                        $user = $info['user'] . substr($pad, 0, 32 - $len);
1989
                    } else {
1990
                        $user = $info['user'];
1991
                    }
1992
                }
1993
1994
                $tmp = $this->md5_16($owner);
1995
                $okey = substr($tmp, 0, 5);
1996
                $this->ARC4_init($okey);
1997
                $ovalue = $this->ARC4($user);
1998
                $this->objects[$id]['info']['O'] = $ovalue;
1999
2000
                // now make the u value, phew.
2001
                $tmp = $this->md5_16(
2002
                    $user . $ovalue . chr($info['p']) . chr(255) . chr(255) . chr(255) . hex2bin($this->fileIdentifier)
2003
                );
2004
2005
                $ukey = substr($tmp, 0, 5);
2006
                $this->ARC4_init($ukey);
2007
                $this->encryptionKey = $ukey;
2008
                $this->encrypted = true;
2009
                $uvalue = $this->ARC4($pad);
2010
                $this->objects[$id]['info']['U'] = $uvalue;
2011
                // initialize the arc4 array
2012
                break;
2013
2014
            case 'out':
2015
                $o = &$this->objects[$id];
2016
2017
                $res = "\n$id 0 obj\n<<";
2018
                $res .= "\n/Filter /Standard";
2019
                $res .= "\n/V 1";
2020
                $res .= "\n/R 2";
2021
                $res .= "\n/O (" . $this->filterText($o['info']['O'], false, false) . ')';
2022
                $res .= "\n/U (" . $this->filterText($o['info']['U'], false, false) . ')';
2023
                // and the p-value needs to be converted to account for the twos-complement approach
2024
                $o['info']['p'] = (($o['info']['p'] ^ 255) + 1) * -1;
2025
                $res .= "\n/P " . ($o['info']['p']);
2026
                $res .= "\n>>\nendobj";
2027
2028
                return $res;
2029
        }
2030
2031
        return null;
2032
    }
2033
2034
    /**
2035
     * ARC4 functions
2036
     * A series of function to implement ARC4 encoding in PHP
2037
     */
2038
2039
    /**
2040
     * calculate the 16 byte version of the 128 bit md5 digest of the string
2041
     *
2042
     * @param $string
2043
     * @return string
2044
     */
2045
    function md5_16($string)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2046
    {
2047
        $tmp = md5($string);
2048
        $out = '';
2049
        for ($i = 0; $i <= 30; $i = $i + 2) {
2050
            $out .= chr(hexdec(substr($tmp, $i, 2)));
2051
        }
2052
2053
        return $out;
2054
    }
2055
2056
    /**
2057
     * initialize the encryption for processing a particular object
2058
     *
2059
     * @param $id
2060
     */
2061
    function encryptInit($id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2062
    {
2063
        $tmp = $this->encryptionKey;
2064
        $hex = dechex($id);
2065
        if (mb_strlen($hex, '8bit') < 6) {
2066
            $hex = substr('000000', 0, 6 - mb_strlen($hex, '8bit')) . $hex;
2067
        }
2068
        $tmp .= chr(hexdec(substr($hex, 4, 2)))
2069
            . chr(hexdec(substr($hex, 2, 2)))
2070
            . chr(hexdec(substr($hex, 0, 2)))
2071
            . chr(0)
2072
            . chr(0)
2073
        ;
2074
        $key = $this->md5_16($tmp);
2075
        $this->ARC4_init(substr($key, 0, 10));
2076
    }
2077
2078
    /**
2079
     * initialize the ARC4 encryption
2080
     *
2081
     * @param string $key
2082
     */
2083
    function ARC4_init($key = '')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2084
    {
2085
        $this->arc4 = '';
2086
2087
        // setup the control array
2088
        if (mb_strlen($key, '8bit') == 0) {
2089
            return;
2090
        }
2091
2092
        $k = '';
2093
        while (mb_strlen($k, '8bit') < 256) {
2094
            $k .= $key;
2095
        }
2096
2097
        $k = substr($k, 0, 256);
2098
        for ($i = 0; $i < 256; $i++) {
2099
            $this->arc4 .= chr($i);
2100
        }
2101
2102
        $j = 0;
2103
2104
        for ($i = 0; $i < 256; $i++) {
2105
            $t = $this->arc4[$i];
2106
            $j = ($j + ord($t) + ord($k[$i])) % 256;
2107
            $this->arc4[$i] = $this->arc4[$j];
2108
            $this->arc4[$j] = $t;
2109
        }
2110
    }
2111
2112
    /**
2113
     * ARC4 encrypt a text string
2114
     *
2115
     * @param $text
2116
     * @return string
2117
     */
2118
    function ARC4($text)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2119
    {
2120
        $len = mb_strlen($text, '8bit');
2121
        $a = 0;
2122
        $b = 0;
2123
        $c = $this->arc4;
2124
        $out = '';
2125
        for ($i = 0; $i < $len; $i++) {
2126
            $a = ($a + 1) % 256;
2127
            $t = $c[$a];
2128
            $b = ($b + ord($t)) % 256;
2129
            $c[$a] = $c[$b];
2130
            $c[$b] = $t;
2131
            $k = ord($c[(ord($c[$a]) + ord($c[$b])) % 256]);
2132
            $out .= chr(ord($text[$i]) ^ $k);
2133
        }
2134
2135
        return $out;
2136
    }
2137
2138
    /**
2139
     * functions which can be called to adjust or add to the document
2140
     */
2141
2142
    /**
2143
     * add a link in the document to an external URL
2144
     *
2145
     * @param $url
2146
     * @param $x0
2147
     * @param $y0
2148
     * @param $x1
2149
     * @param $y1
2150
     */
2151
    function addLink($url, $x0, $y0, $x1, $y1)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2152
    {
2153
        $this->numObj++;
2154
        $info = array('type' => 'link', 'url' => $url, 'rect' => array($x0, $y0, $x1, $y1));
2155
        $this->o_annotation($this->numObj, 'new', $info);
0 ignored issues
show
Documentation introduced by
$info is of type array<string,?,{"type":"...:\"?\",\"3\":\"?\"}>"}>, but the function expects a string.

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...
2156
    }
2157
2158
    /**
2159
     * add a link in the document to an internal destination (ie. within the document)
2160
     *
2161
     * @param $label
2162
     * @param $x0
2163
     * @param $y0
2164
     * @param $x1
2165
     * @param $y1
2166
     */
2167
    function addInternalLink($label, $x0, $y0, $x1, $y1)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2168
    {
2169
        $this->numObj++;
2170
        $info = array('type' => 'ilink', 'label' => $label, 'rect' => array($x0, $y0, $x1, $y1));
2171
        $this->o_annotation($this->numObj, 'new', $info);
0 ignored issues
show
Documentation introduced by
$info is of type array<string,?,{"type":"...:\"?\",\"3\":\"?\"}>"}>, but the function expects a string.

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...
2172
    }
2173
2174
    /**
2175
     * set the encryption of the document
2176
     * can be used to turn it on and/or set the passwords which it will have.
2177
     * also the functions that the user will have are set here, such as print, modify, add
2178
     *
2179
     * @param string $userPass
2180
     * @param string $ownerPass
2181
     * @param array $pc
2182
     */
2183
    function setEncryption($userPass = '', $ownerPass = '', $pc = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2184
    {
2185
        $p = bindec("11000000");
2186
2187
        $options = array('print' => 4, 'modify' => 8, 'copy' => 16, 'add' => 32);
2188
2189
        foreach ($pc as $k => $v) {
2190
            if ($v && isset($options[$k])) {
2191
                $p += $options[$k];
2192
            } else {
2193
                if (isset($options[$v])) {
2194
                    $p += $options[$v];
2195
                }
2196
            }
2197
        }
2198
2199
        // implement encryption on the document
2200
        if ($this->arc4_objnum == 0) {
2201
            // then the block does not exist already, add it.
2202
            $this->numObj++;
2203
            if (mb_strlen($ownerPass) == 0) {
2204
                $ownerPass = $userPass;
2205
            }
2206
2207
            $this->o_encryption($this->numObj, 'new', array('user' => $userPass, 'owner' => $ownerPass, 'p' => $p));
0 ignored issues
show
Documentation introduced by
array('user' => $userPas... $ownerPass, 'p' => $p) is of type array<string,string|inte...,"p":"integer|double"}>, but the function expects a string.

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...
2208
        }
2209
    }
2210
2211
    /**
2212
     * should be used for internal checks, not implemented as yet
2213
     */
2214
    function checkAllHere()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2215
    {
2216
    }
2217
2218
    /**
2219
     * return the pdf stream as a string returned from the function
2220
     *
2221
     * @param bool $debug
2222
     * @return string
2223
     */
2224
    function output($debug = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2225
    {
2226
        if ($debug) {
2227
            // turn compression off
2228
            $this->options['compression'] = false;
2229
        }
2230
2231
        if ($this->javascript) {
2232
            $this->numObj++;
2233
2234
            $js_id = $this->numObj;
2235
            $this->o_embedjs($js_id, 'new');
2236
            $this->o_javascript(++$this->numObj, 'new', $this->javascript);
2237
2238
            $id = $this->catalogId;
2239
2240
            $this->o_catalog($id, 'javascript', $js_id);
2241
        }
2242
2243
        if ($this->fileIdentifier === '') {
2244
            $tmp = implode('',  $this->objects[$this->infoObject]['info']);
2245
            $this->fileIdentifier = md5('DOMPDF' . __FILE__ . $tmp . microtime() . mt_rand());
2246
        }
2247
2248
        if ($this->arc4_objnum) {
2249
            $this->o_encryption($this->arc4_objnum, 'keys');
2250
            $this->ARC4_init($this->encryptionKey);
2251
        }
2252
2253
        $this->checkAllHere();
2254
2255
        $xref = array();
2256
        $content = '%PDF-1.3';
2257
        $pos = mb_strlen($content, '8bit');
2258
2259
        foreach ($this->objects as $k => $v) {
2260
            $tmp = 'o_' . $v['t'];
2261
            $cont = $this->$tmp($k, 'out');
2262
            $content .= $cont;
2263
            $xref[] = $pos + 1; //+1 to account for \n at the start of each object
2264
            $pos += mb_strlen($cont, '8bit');
2265
        }
2266
2267
        $content .= "\nxref\n0 " . (count($xref) + 1) . "\n0000000000 65535 f \n";
2268
2269
        foreach ($xref as $p) {
2270
            $content .= str_pad($p, 10, "0", STR_PAD_LEFT) . " 00000 n \n";
2271
        }
2272
2273
        $content .= "trailer\n<<\n" .
2274
            '/Size ' . (count($xref) + 1) . "\n" .
2275
            '/Root 1 0 R' . "\n" .
2276
            '/Info ' . $this->infoObject . " 0 R\n"
2277
        ;
2278
2279
        // if encryption has been applied to this document then add the marker for this dictionary
2280
        if ($this->arc4_objnum > 0) {
2281
            $content .= '/Encrypt ' . $this->arc4_objnum . " 0 R\n";
2282
        }
2283
2284
        $content .= '/ID[<' . $this->fileIdentifier . '><' . $this->fileIdentifier . ">]\n";
2285
2286
        // account for \n added at start of xref table
2287
        $pos++;
2288
2289
        $content .= ">>\nstartxref\n$pos\n%%EOF\n";
2290
2291
        return $content;
2292
    }
2293
2294
    /**
2295
     * initialize a new document
2296
     * if this is called on an existing document results may be unpredictable, but the existing document would be lost at minimum
2297
     * this function is called automatically by the constructor function
2298
     *
2299
     * @param array $pageSize
2300
     */
2301
    private function newDocument($pageSize = array(0, 0, 612, 792))
2302
    {
2303
        $this->numObj = 0;
2304
        $this->objects = array();
2305
2306
        $this->numObj++;
2307
        $this->o_catalog($this->numObj, 'new');
2308
2309
        $this->numObj++;
2310
        $this->o_outlines($this->numObj, 'new');
2311
2312
        $this->numObj++;
2313
        $this->o_pages($this->numObj, 'new');
2314
2315
        $this->o_pages($this->numObj, 'mediaBox', $pageSize);
0 ignored issues
show
Documentation introduced by
$pageSize is of type array, but the function expects a string.

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...
2316
        $this->currentNode = 3;
2317
2318
        $this->numObj++;
2319
        $this->o_procset($this->numObj, 'new');
2320
2321
        $this->numObj++;
2322
        $this->o_info($this->numObj, 'new');
2323
2324
        $this->numObj++;
2325
        $this->o_page($this->numObj, 'new');
2326
2327
        // need to store the first page id as there is no way to get it to the user during
2328
        // startup
2329
        $this->firstPageId = $this->currentContents;
2330
    }
2331
2332
    /**
2333
     * open the font file and return a php structure containing it.
2334
     * first check if this one has been done before and saved in a form more suited to php
2335
     * note that if a php serialized version does not exist it will try and make one, but will
2336
     * require write access to the directory to do it... it is MUCH faster to have these serialized
2337
     * files.
2338
     *
2339
     * @param $font
2340
     */
2341
    private function openFont($font)
2342
    {
2343
        // assume that $font contains the path and file but not the extension
2344
        $name = basename($font);
2345
        $dir = dirname($font) . '/';
2346
2347
        $fontcache = $this->fontcache;
2348
        if ($fontcache == '') {
2349
            $fontcache = rtrim($dir, DIRECTORY_SEPARATOR."/\\");
2350
        }
2351
2352
        //$name       filename without folder and extension of font metrics
2353
        //$dir      folder of font metrics
2354
        //$fontcache  folder of runtime created php serialized version of font metrics.
2355
        //            If this is not given, the same folder as the font metrics will be used.
2356
        //            Storing and reusing serialized versions improves speed much
2357
2358
        $this->addMessage("openFont: $font - $name");
2359
2360
        if (!$this->isUnicode || in_array(mb_strtolower(basename($name)), self::$coreFonts)) {
2361
            $metrics_name = "$name.afm";
2362
        } else {
2363
            $metrics_name = "$name.ufm";
2364
        }
2365
2366
        $cache_name = "$metrics_name.php";
2367
        $this->addMessage("metrics: $metrics_name, cache: $cache_name");
2368
2369
        if (file_exists($fontcache . '/' . $cache_name)) {
2370
            $this->addMessage("openFont: php file exists $fontcache/$cache_name");
2371
            $this->fonts[$font] = require($fontcache . '/' . $cache_name);
2372
2373
            if (!isset($this->fonts[$font]['_version_']) || $this->fonts[$font]['_version_'] != $this->fontcacheVersion) {
2374
                // if the font file is old, then clear it out and prepare for re-creation
2375
                $this->addMessage('openFont: clear out, make way for new version.');
2376
                $this->fonts[$font] = null;
2377
                unset($this->fonts[$font]);
2378
            }
2379
        } else {
2380
            $old_cache_name = "php_$metrics_name";
2381
            if (file_exists($fontcache . '/' . $old_cache_name)) {
2382
                $this->addMessage(
2383
                    "openFont: php file doesn't exist $fontcache/$cache_name, creating it from the old format"
2384
                );
2385
                $old_cache = file_get_contents($fontcache . '/' . $old_cache_name);
2386
                file_put_contents($fontcache . '/' . $cache_name, '<?php return ' . $old_cache . ';');
2387
2388
                $this->openFont($font);
2389
                return;
2390
            }
2391
        }
2392
2393
        if (!isset($this->fonts[$font]) && file_exists($dir . $metrics_name)) {
2394
            // then rebuild the php_<font>.afm file from the <font>.afm file
2395
            $this->addMessage("openFont: build php file from $dir$metrics_name");
2396
            $data = array();
2397
2398
            // 20 => 'space'
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
2399
            $data['codeToName'] = array();
2400
2401
            // Since we're not going to enable Unicode for the core fonts we need to use a font-based
2402
            // setting for Unicode support rather than a global setting.
2403
            $data['isUnicode'] = (strtolower(substr($metrics_name, -3)) !== 'afm');
2404
2405
            $cidtogid = '';
2406
            if ($data['isUnicode']) {
2407
                $cidtogid = str_pad('', 256 * 256 * 2, "\x00");
2408
            }
2409
2410
            $file = file($dir . $metrics_name);
2411
2412
            foreach ($file as $rowA) {
2413
                $row = trim($rowA);
2414
                $pos = strpos($row, ' ');
2415
2416
                if ($pos) {
2417
                    // then there must be some keyword
2418
                    $key = substr($row, 0, $pos);
2419
                    switch ($key) {
2420
                        case 'FontName':
2421
                        case 'FullName':
2422
                        case 'FamilyName':
2423
                        case 'PostScriptName':
2424
                        case 'Weight':
2425
                        case 'ItalicAngle':
2426
                        case 'IsFixedPitch':
2427
                        case 'CharacterSet':
2428
                        case 'UnderlinePosition':
2429
                        case 'UnderlineThickness':
2430
                        case 'Version':
2431
                        case 'EncodingScheme':
2432
                        case 'CapHeight':
2433
                        case 'XHeight':
2434
                        case 'Ascender':
2435
                        case 'Descender':
2436
                        case 'StdHW':
2437
                        case 'StdVW':
2438
                        case 'StartCharMetrics':
2439
                        case 'FontHeightOffset': // OAR - Added so we can offset the height calculation of a Windows font.  Otherwise it's too big.
2440
                            $data[$key] = trim(substr($row, $pos));
2441
                            break;
2442
2443
                        case 'FontBBox':
2444
                            $data[$key] = explode(' ', trim(substr($row, $pos)));
2445
                            break;
2446
2447
                        //C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
2448
                        case 'C': // Found in AFM files
2449
                            $bits = explode(';', trim($row));
2450
                            $dtmp = array();
2451
2452 View Code Duplication
                            foreach ($bits as $bit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2453
                                $bits2 = explode(' ', trim($bit));
2454
                                if (mb_strlen($bits2[0], '8bit') == 0) {
2455
                                    continue;
2456
                                }
2457
2458
                                if (count($bits2) > 2) {
2459
                                    $dtmp[$bits2[0]] = array();
2460
                                    for ($i = 1; $i < count($bits2); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2461
                                        $dtmp[$bits2[0]][] = $bits2[$i];
2462
                                    }
2463
                                } else {
2464
                                    if (count($bits2) == 2) {
2465
                                        $dtmp[$bits2[0]] = $bits2[1];
2466
                                    }
2467
                                }
2468
                            }
2469
2470
                            $c = (int)$dtmp['C'];
2471
                            $n = $dtmp['N'];
2472
                            $width = floatval($dtmp['WX']);
2473
2474
                            if ($c >= 0) {
2475
                                if ($c != hexdec($n)) {
2476
                                    $data['codeToName'][$c] = $n;
2477
                                }
2478
                                $data['C'][$c] = $width;
2479
                            } else {
2480
                                $data['C'][$n] = $width;
2481
                            }
2482
2483 View Code Duplication
                            if (!isset($data['MissingWidth']) && $c == -1 && $n === '.notdef') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2484
                                $data['MissingWidth'] = $width;
2485
                            }
2486
2487
                            break;
2488
2489
                        // U 827 ; WX 0 ; N squaresubnosp ; G 675 ;
2490
                        case 'U': // Found in UFM files
2491
                            if (!$data['isUnicode']) {
2492
                                break;
2493
                            }
2494
2495
                            $bits = explode(';', trim($row));
2496
                            $dtmp = array();
2497
2498 View Code Duplication
                            foreach ($bits as $bit) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2499
                                $bits2 = explode(' ', trim($bit));
2500
                                if (mb_strlen($bits2[0], '8bit') === 0) {
2501
                                    continue;
2502
                                }
2503
2504
                                if (count($bits2) > 2) {
2505
                                    $dtmp[$bits2[0]] = array();
2506
                                    for ($i = 1; $i < count($bits2); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2507
                                        $dtmp[$bits2[0]][] = $bits2[$i];
2508
                                    }
2509
                                } else {
2510
                                    if (count($bits2) == 2) {
2511
                                        $dtmp[$bits2[0]] = $bits2[1];
2512
                                    }
2513
                                }
2514
                            }
2515
2516
                            $c = (int)$dtmp['U'];
2517
                            $n = $dtmp['N'];
2518
                            $glyph = $dtmp['G'];
2519
                            $width = floatval($dtmp['WX']);
2520
2521
                            if ($c >= 0) {
2522
                                // Set values in CID to GID map
2523 View Code Duplication
                                if ($c >= 0 && $c < 0xFFFF && $glyph) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2524
                                    $cidtogid[$c * 2] = chr($glyph >> 8);
2525
                                    $cidtogid[$c * 2 + 1] = chr($glyph & 0xFF);
2526
                                }
2527
2528
                                if ($c != hexdec($n)) {
2529
                                    $data['codeToName'][$c] = $n;
2530
                                }
2531
                                $data['C'][$c] = $width;
2532
                            } else {
2533
                                $data['C'][$n] = $width;
2534
                            }
2535
2536 View Code Duplication
                            if (!isset($data['MissingWidth']) && $c == -1 && $n === '.notdef') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2537
                                $data['MissingWidth'] = $width;
2538
                            }
2539
2540
                            break;
2541
2542
                        case 'KPX':
2543
                            break; // don't include them as they are not used yet
2544
                            //KPX Adieresis yacute -40
2545
                            /*$bits = explode(' ', trim($row));
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
2546
                            $data['KPX'][$bits[1]][$bits[2]] = $bits[3];
2547
                            break;*/
2548
                    }
2549
                }
2550
            }
2551
2552 View Code Duplication
            if ($this->compressionReady && $this->options['compression']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2553
                // then implement ZLIB based compression on CIDtoGID string
2554
                $data['CIDtoGID_Compressed'] = true;
2555
                $cidtogid = gzcompress($cidtogid, 6);
2556
            }
2557
            $data['CIDtoGID'] = base64_encode($cidtogid);
2558
            $data['_version_'] = $this->fontcacheVersion;
2559
            $this->fonts[$font] = $data;
2560
2561
            //Because of potential trouble with php safe mode, expect that the folder already exists.
2562
            //If not existing, this will hit performance because of missing cached results.
2563
            if (is_dir($fontcache) && is_writable($fontcache)) {
2564
                file_put_contents($fontcache . '/' . $cache_name, '<?php return ' . var_export($data, true) . ';');
2565
            }
2566
            $data = null;
0 ignored issues
show
Unused Code introduced by
$data 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...
2567
        }
2568
2569
        if (!isset($this->fonts[$font])) {
2570
            $this->addMessage("openFont: no font file found for $font. Do you need to run load_font.php?");
2571
        }
2572
2573
        //pre_r($this->messages);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
2574
    }
2575
2576
    /**
2577
     * if the font is not loaded then load it and make the required object
2578
     * else just make it the current font
2579
     * the encoding array can contain 'encoding'=> 'none','WinAnsiEncoding','MacRomanEncoding' or 'MacExpertEncoding'
2580
     * note that encoding='none' will need to be used for symbolic fonts
2581
     * and 'differences' => an array of mappings between numbers 0->255 and character names.
2582
     *
2583
     * @param $fontName
2584
     * @param string $encoding
2585
     * @param bool $set
2586
     * @return int
2587
     */
2588
    function selectFont($fontName, $encoding = '', $set = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2589
    {
2590
        $ext = substr($fontName, -4);
2591
        if ($ext === '.afm' || $ext === '.ufm') {
2592
            $fontName = substr($fontName, 0, mb_strlen($fontName) - 4);
2593
        }
2594
2595
        if (!isset($this->fonts[$fontName])) {
2596
            $this->addMessage("selectFont: selecting - $fontName - $encoding, $set");
2597
2598
            // load the file
2599
            $this->openFont($fontName);
2600
2601
            if (isset($this->fonts[$fontName])) {
2602
                $this->numObj++;
2603
                $this->numFonts++;
2604
2605
                $font = &$this->fonts[$fontName];
2606
2607
                $name = basename($fontName);
2608
                $dir = dirname($fontName) . '/';
0 ignored issues
show
Unused Code introduced by
$dir 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...
2609
                $options = array('name' => $name, 'fontFileName' => $fontName);
2610
2611
                if (is_array($encoding)) {
2612
                    // then encoding and differences might be set
2613
                    if (isset($encoding['encoding'])) {
2614
                        $options['encoding'] = $encoding['encoding'];
2615
                    }
2616
2617
                    if (isset($encoding['differences'])) {
2618
                        $options['differences'] = $encoding['differences'];
2619
                    }
2620
                } else {
2621
                    if (mb_strlen($encoding, '8bit')) {
2622
                        // then perhaps only the encoding has been set
2623
                        $options['encoding'] = $encoding;
2624
                    }
2625
                }
2626
2627
                $fontObj = $this->numObj;
2628
                $this->o_font($this->numObj, 'new', $options);
2629
                $font['fontNum'] = $this->numFonts;
2630
2631
                // if this is a '.afm' font, and there is a '.pfa' file to go with it (as there
2632
                // should be for all non-basic fonts), then load it into an object and put the
2633
                // references into the font object
2634
                $basefile = $fontName;
2635
2636
                $fbtype = '';
2637
                if (file_exists("$basefile.ttf")) {
2638
                    $fbtype = 'ttf';
2639
                } elseif (file_exists("$basefile.TTF")) {
2640
                    $fbtype = 'TTF';
2641
                } elseif (file_exists("$basefile.pfb")) {
2642
                    $fbtype = 'pfb';
2643
                } elseif (file_exists("$basefile.PFB")) {
2644
                    $fbtype = 'PFB';
2645
                }
2646
2647
                $fbfile = "$basefile.$fbtype";
2648
2649
                //      $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% 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...
2650
                //      $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% 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...
2651
                $this->addMessage('selectFont: checking for - ' . $fbfile);
2652
2653
                // OAR - I don't understand this old check
2654
                // if (substr($fontName, -4) ===  '.afm' &&  strlen($fbtype)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% 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...
2655
                if ($fbtype) {
2656
                    $adobeFontName = isset($font['PostScriptName']) ? $font['PostScriptName'] : $font['FontName'];
2657
                    //        $fontObj = $this->numObj;
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% 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...
2658
                    $this->addMessage("selectFont: adding font file - $fbfile - $adobeFontName");
2659
2660
                    // find the array of font widths, and put that into an object.
2661
                    $firstChar = -1;
2662
                    $lastChar = 0;
2663
                    $widths = array();
2664
                    $cid_widths = array();
2665
2666
                    foreach ($font['C'] as $num => $d) {
2667
                        if (intval($num) > 0 || $num == '0') {
2668
                            if (!$font['isUnicode']) {
2669
                                // With Unicode, widths array isn't used
2670
                                if ($lastChar > 0 && $num > $lastChar + 1) {
2671
                                    for ($i = $lastChar + 1; $i < $num; $i++) {
2672
                                        $widths[] = 0;
2673
                                    }
2674
                                }
2675
                            }
2676
2677
                            $widths[] = $d;
2678
2679
                            if ($font['isUnicode']) {
2680
                                $cid_widths[$num] = $d;
2681
                            }
2682
2683
                            if ($firstChar == -1) {
2684
                                $firstChar = $num;
2685
                            }
2686
2687
                            $lastChar = $num;
2688
                        }
2689
                    }
2690
2691
                    // also need to adjust the widths for the differences array
2692
                    if (isset($options['differences'])) {
2693
                        foreach ($options['differences'] as $charNum => $charName) {
2694
                            if ($charNum > $lastChar) {
2695
                                if (!$font['isUnicode']) {
2696
                                    // With Unicode, widths array isn't used
2697
                                    for ($i = $lastChar + 1; $i <= $charNum; $i++) {
2698
                                        $widths[] = 0;
2699
                                    }
2700
                                }
2701
2702
                                $lastChar = $charNum;
2703
                            }
2704
2705
                            if (isset($font['C'][$charName])) {
2706
                                $widths[$charNum - $firstChar] = $font['C'][$charName];
2707
                                if ($font['isUnicode']) {
2708
                                    $cid_widths[$charName] = $font['C'][$charName];
2709
                                }
2710
                            }
2711
                        }
2712
                    }
2713
2714
                    if ($font['isUnicode']) {
2715
                        $font['CIDWidths'] = $cid_widths;
2716
                    }
2717
2718
                    $this->addMessage('selectFont: FirstChar = ' . $firstChar);
2719
                    $this->addMessage('selectFont: LastChar = ' . $lastChar);
2720
2721
                    $widthid = -1;
2722
2723
                    if (!$font['isUnicode']) {
2724
                        // With Unicode, widths array isn't used
2725
2726
                        $this->numObj++;
2727
                        $this->o_contents($this->numObj, 'new', 'raw');
2728
                        $this->objects[$this->numObj]['c'] .= '[' . implode(' ', $widths) . ']';
2729
                        $widthid = $this->numObj;
2730
                    }
2731
2732
                    $missing_width = 500;
2733
                    $stemV = 70;
2734
2735
                    if (isset($font['MissingWidth'])) {
2736
                        $missing_width = $font['MissingWidth'];
2737
                    }
2738
                    if (isset($font['StdVW'])) {
2739
                        $stemV = $font['StdVW'];
2740
                    } else {
2741
                        if (isset($font['Weight']) && preg_match('!(bold|black)!i', $font['Weight'])) {
2742
                            $stemV = 120;
2743
                        }
2744
                    }
2745
2746
                    // load the pfb file, and put that into an object too.
2747
                    // note that pdf supports only binary format type 1 font files, though there is a
2748
                    // simple utility to convert them from pfa to pfb.
2749
                    // FIXME: should we move font subset creation to CPDF::output? See notes in issue #750.
2750
                    if (!$this->isUnicode || strtolower($fbtype) !== 'ttf' || empty($this->stringSubsets)) {
2751
                        $data = file_get_contents($fbfile);
2752
                    } else {
2753
                        $this->stringSubsets[$fontName][] = 32; // Force space if not in yet
2754
2755
                        $subset = $this->stringSubsets[$fontName];
2756
                        sort($subset);
2757
2758
                        // Load font
2759
                        $font_obj = Font::load($fbfile);
2760
                        $font_obj->parse();
2761
2762
                        // Define subset
2763
                        $font_obj->setSubset($subset);
2764
                        $font_obj->reduce();
2765
2766
                        // Write new font
2767
                        $tmp_name = $this->tmp . "/" . basename($fbfile) . ".tmp." . uniqid();
2768
                        $font_obj->open($tmp_name, BinaryStream::modeWrite);
2769
                        $font_obj->encode(array("OS/2"));
2770
                        $font_obj->close();
2771
2772
                        // Parse the new font to get cid2gid and widths
2773
                        $font_obj = Font::load($tmp_name);
2774
2775
                        // Find Unicode char map table
2776
                        $subtable = null;
2777
                        foreach ($font_obj->getData("cmap", "subtables") as $_subtable) {
2778
                            if ($_subtable["platformID"] == 0 || $_subtable["platformID"] == 3 && $_subtable["platformSpecificID"] == 1) {
2779
                                $subtable = $_subtable;
2780
                                break;
2781
                            }
2782
                        }
2783
2784
                        if ($subtable) {
2785
                            $glyphIndexArray = $subtable["glyphIndexArray"];
2786
                            $hmtx = $font_obj->getData("hmtx");
2787
2788
                            unset($glyphIndexArray[0xFFFF]);
2789
2790
                            $cidtogid = str_pad('', max(array_keys($glyphIndexArray)) * 2 + 1, "\x00");
2791
                            $font['CIDWidths'] = array();
2792
                            foreach ($glyphIndexArray as $cid => $gid) {
2793 View Code Duplication
                                if ($cid >= 0 && $cid < 0xFFFF && $gid) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2794
                                    $cidtogid[$cid * 2] = chr($gid >> 8);
2795
                                    $cidtogid[$cid * 2 + 1] = chr($gid & 0xFF);
2796
                                }
2797
2798
                                $width = $font_obj->normalizeFUnit(isset($hmtx[$gid]) ? $hmtx[$gid][0] : $hmtx[0][0]);
2799
                                $font['CIDWidths'][$cid] = $width;
2800
                            }
2801
2802
                            $font['CIDtoGID'] = base64_encode(gzcompress($cidtogid));
2803
                            $font['CIDtoGID_Compressed'] = true;
2804
2805
                            $data = file_get_contents($tmp_name);
2806
                        } else {
2807
                            $data = file_get_contents($fbfile);
2808
                        }
2809
2810
                        $font_obj->close();
2811
                        unlink($tmp_name);
2812
                    }
2813
2814
                    // create the font descriptor
2815
                    $this->numObj++;
2816
                    $fontDescriptorId = $this->numObj;
2817
2818
                    $this->numObj++;
2819
                    $pfbid = $this->numObj;
2820
2821
                    // determine flags (more than a little flakey, hopefully will not matter much)
2822
                    $flags = 0;
2823
2824
                    if ($font['ItalicAngle'] != 0) {
2825
                        $flags += pow(2, 6);
2826
                    }
2827
2828
                    if ($font['IsFixedPitch'] === 'true') {
2829
                        $flags += 1;
2830
                    }
2831
2832
                    $flags += pow(2, 5); // assume non-sybolic
2833
                    $list = array(
2834
                        'Ascent'       => 'Ascender',
2835
                        'CapHeight'    => 'Ascender', //FIXME: php-font-lib is not grabbing this value, so we'll fake it and use the Ascender value // 'CapHeight'
2836
                        'MissingWidth' => 'MissingWidth',
2837
                        'Descent'      => 'Descender',
2838
                        'FontBBox'     => 'FontBBox',
2839
                        'ItalicAngle'  => 'ItalicAngle'
2840
                    );
2841
                    $fdopt = array(
2842
                        'Flags'    => $flags,
2843
                        'FontName' => $adobeFontName,
2844
                        'StemV'    => $stemV
2845
                    );
2846
2847
                    foreach ($list as $k => $v) {
2848
                        if (isset($font[$v])) {
2849
                            $fdopt[$k] = $font[$v];
2850
                        }
2851
                    }
2852
2853
                    if (strtolower($fbtype) === 'pfb') {
2854
                        $fdopt['FontFile'] = $pfbid;
2855
                    } elseif (strtolower($fbtype) === 'ttf') {
2856
                        $fdopt['FontFile2'] = $pfbid;
2857
                    }
2858
2859
                    $this->o_fontDescriptor($fontDescriptorId, 'new', $fdopt);
0 ignored issues
show
Documentation introduced by
$fdopt is of type array<string,?>, but the function expects a string.

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...
2860
2861
                    // embed the font program
2862
                    $this->o_contents($this->numObj, 'new');
2863
                    $this->objects[$pfbid]['c'] .= $data;
2864
2865
                    // determine the cruicial lengths within this file
2866
                    if (strtolower($fbtype) === 'pfb') {
2867
                        $l1 = strpos($data, 'eexec') + 6;
2868
                        $l2 = strpos($data, '00000000') - $l1;
2869
                        $l3 = mb_strlen($data, '8bit') - $l2 - $l1;
2870
                        $this->o_contents(
2871
                            $this->numObj,
2872
                            'add',
2873
                            array('Length1' => $l1, 'Length2' => $l2, 'Length3' => $l3)
2874
                        );
2875
                    } elseif (strtolower($fbtype) == 'ttf') {
2876
                        $l1 = mb_strlen($data, '8bit');
2877
                        $this->o_contents($this->numObj, 'add', array('Length1' => $l1));
2878
                    }
2879
2880
                    // tell the font object about all this new stuff
2881
                    $tmp = array(
2882
                        'BaseFont'       => $adobeFontName,
2883
                        'MissingWidth'   => $missing_width,
2884
                        'Widths'         => $widthid,
2885
                        'FirstChar'      => $firstChar,
2886
                        'LastChar'       => $lastChar,
2887
                        'FontDescriptor' => $fontDescriptorId
2888
                    );
2889
2890
                    if (strtolower($fbtype) === 'ttf') {
2891
                        $tmp['SubType'] = 'TrueType';
2892
                    }
2893
2894
                    $this->addMessage("adding extra info to font.($fontObj)");
2895
2896
                    foreach ($tmp as $fk => $fv) {
2897
                        $this->addMessage("$fk : $fv");
2898
                    }
2899
2900
                    $this->o_font($fontObj, 'add', $tmp);
2901
                } else {
2902
                    $this->addMessage(
2903
                        'selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts'
2904
                    );
2905
                }
2906
2907
                // also set the differences here, note that this means that these will take effect only the
2908
                //first time that a font is selected, else they are ignored
2909
                if (isset($options['differences'])) {
2910
                    $font['differences'] = $options['differences'];
2911
                }
2912
            }
2913
        }
2914
2915
        if ($set && isset($this->fonts[$fontName])) {
2916
            // so if for some reason the font was not set in the last one then it will not be selected
2917
            $this->currentBaseFont = $fontName;
2918
2919
            // the next lines mean that if a new font is selected, then the current text state will be
2920
            // applied to it as well.
2921
            $this->currentFont = $this->currentBaseFont;
2922
            $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
2923
2924
            //$this->setCurrentFont();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% 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...
2925
        }
2926
2927
        return $this->currentFontNum;
2928
        //return $this->numObj;
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
2929
    }
2930
2931
    /**
2932
     * sets up the current font, based on the font families, and the current text state
2933
     * note that this system is quite flexible, a bold-italic font can be completely different to a
2934
     * italic-bold font, and even bold-bold will have to be defined within the family to have meaning
2935
     * This function is to be called whenever the currentTextState is changed, it will update
2936
     * the currentFont setting to whatever the appropriate family one is.
2937
     * If the user calls selectFont themselves then that will reset the currentBaseFont, and the currentFont
2938
     * This function will change the currentFont to whatever it should be, but will not change the
2939
     * currentBaseFont.
2940
     */
2941
    private function setCurrentFont()
2942
    {
2943
        //   if (strlen($this->currentBaseFont) == 0){
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
2944
        //     // then assume an initial font
2945
        //     $this->selectFont($this->defaultFont);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
2946
        //   }
2947
        //   $cf = substr($this->currentBaseFont,strrpos($this->currentBaseFont,'/')+1);
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% 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...
2948
        //   if (strlen($this->currentTextState)
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
2949
        //     && isset($this->fontFamilies[$cf])
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
2950
        //       && isset($this->fontFamilies[$cf][$this->currentTextState])){
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% 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...
2951
        //     // then we are in some state or another
2952
        //     // and this font has a family, and the current setting exists within it
2953
        //     // select the font, then return it
2954
        //     $nf = substr($this->currentBaseFont,0,strrpos($this->currentBaseFont,'/')+1).$this->fontFamilies[$cf][$this->currentTextState];
0 ignored issues
show
Unused Code Comprehensibility introduced by
68% 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...
2955
        //     $this->selectFont($nf,'',0);
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% 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...
2956
        //     $this->currentFont = $nf;
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% 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...
2957
        //     $this->currentFontNum = $this->fonts[$nf]['fontNum'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% 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...
2958
        //   } else {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
2959
        //     // the this font must not have the right family member for the current state
2960
        //     // simply assume the base font
2961
        $this->currentFont = $this->currentBaseFont;
2962
        $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
2963
        //  }
2964
    }
2965
2966
    /**
2967
     * function for the user to find out what the ID is of the first page that was created during
2968
     * startup - useful if they wish to add something to it later.
2969
     *
2970
     * @return int
2971
     */
2972
    function getFirstPageId()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2973
    {
2974
        return $this->firstPageId;
2975
    }
2976
2977
    /**
2978
     * add content to the currently active object
2979
     *
2980
     * @param $content
2981
     */
2982
    private function addContent($content)
2983
    {
2984
        $this->objects[$this->currentContents]['c'] .= $content;
2985
    }
2986
2987
    /**
2988
     * sets the color for fill operations
2989
     *
2990
     * @param $color
2991
     * @param bool $force
2992
     */
2993 View Code Duplication
    function setColor($color, $force = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2994
    {
2995
        $new_color = array($color[0], $color[1], $color[2], isset($color[3]) ? $color[3] : null);
2996
2997
        if (!$force && $this->currentColor == $new_color) {
2998
            return;
2999
        }
3000
3001
        if (isset($new_color[3])) {
3002
            $this->currentColor = $new_color;
3003
            $this->addContent(vsprintf("\n%.3F %.3F %.3F %.3F k", $this->currentColor));
3004
        } else {
3005
            if (isset($new_color[2])) {
3006
                $this->currentColor = $new_color;
3007
                $this->addContent(vsprintf("\n%.3F %.3F %.3F rg", $this->currentColor));
3008
            }
3009
        }
3010
    }
3011
3012
    /**
3013
     * sets the color for fill operations
3014
     *
3015
     * @param $fillRule
3016
     */
3017
    function setFillRule($fillRule)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3018
    {
3019
        if (!in_array($fillRule, array("nonzero", "evenodd"))) {
3020
            return;
3021
        }
3022
3023
        $this->fillRule = $fillRule;
3024
    }
3025
3026
    /**
3027
     * sets the color for stroke operations
3028
     *
3029
     * @param $color
3030
     * @param bool $force
3031
     */
3032 View Code Duplication
    function setStrokeColor($color, $force = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3033
    {
3034
        $new_color = array($color[0], $color[1], $color[2], isset($color[3]) ? $color[3] : null);
3035
3036
        if (!$force && $this->currentStrokeColor == $new_color) {
3037
            return;
3038
        }
3039
3040
        if (isset($new_color[3])) {
3041
            $this->currentStrokeColor = $new_color;
3042
            $this->addContent(vsprintf("\n%.3F %.3F %.3F %.3F K", $this->currentStrokeColor));
3043
        } else {
3044
            if (isset($new_color[2])) {
3045
                $this->currentStrokeColor = $new_color;
3046
                $this->addContent(vsprintf("\n%.3F %.3F %.3F RG", $this->currentStrokeColor));
3047
            }
3048
        }
3049
    }
3050
3051
    /**
3052
     * Set the graphics state for compositions
3053
     *
3054
     * @param $parameters
3055
     */
3056
    function setGraphicsState($parameters)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3057
    {
3058
        // Create a new graphics state object if necessary
3059
        if (($gstate = array_search($parameters, $this->gstates)) === false) {
3060
            $this->numObj++;
3061
            $this->o_extGState($this->numObj, 'new', $parameters);
3062
            $gstate = $this->numStates;
3063
            $this->gstates[$gstate] = $parameters;
3064
        }
3065
        $this->addContent("\n/GS$gstate gs");
3066
    }
3067
3068
    /**
3069
     * Set current blend mode & opacity for lines.
3070
     *
3071
     * Valid blend modes are:
3072
     *
3073
     * Normal, Multiply, Screen, Overlay, Darken, Lighten,
3074
     * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
3075
     * Exclusion
3076
     *
3077
     * @param string $mode    the blend mode to use
3078
     * @param float  $opacity 0.0 fully transparent, 1.0 fully opaque
3079
     */
3080 View Code Duplication
    function setLineTransparency($mode, $opacity)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3081
    {
3082
        static $blend_modes = array(
3083
            "Normal",
3084
            "Multiply",
3085
            "Screen",
3086
            "Overlay",
3087
            "Darken",
3088
            "Lighten",
3089
            "ColorDogde",
3090
            "ColorBurn",
3091
            "HardLight",
3092
            "SoftLight",
3093
            "Difference",
3094
            "Exclusion"
3095
        );
3096
3097
        if (!in_array($mode, $blend_modes)) {
3098
            $mode = "Normal";
3099
        }
3100
3101
        // Only create a new graphics state if required
3102
        if ($mode === $this->currentLineTransparency["mode"] &&
3103
            $opacity == $this->currentLineTransparency["opacity"]
3104
        ) {
3105
            return;
3106
        }
3107
3108
        $this->currentLineTransparency["mode"] = $mode;
3109
        $this->currentLineTransparency["opacity"] = $opacity;
3110
3111
        $options = array(
3112
            "BM" => "/$mode",
3113
            "CA" => (float)$opacity
3114
        );
3115
3116
        $this->setGraphicsState($options);
3117
    }
3118
3119
    /**
3120
     * Set current blend mode & opacity for filled objects.
3121
     *
3122
     * Valid blend modes are:
3123
     *
3124
     * Normal, Multiply, Screen, Overlay, Darken, Lighten,
3125
     * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
3126
     * Exclusion
3127
     *
3128
     * @param string $mode    the blend mode to use
3129
     * @param float  $opacity 0.0 fully transparent, 1.0 fully opaque
3130
     */
3131 View Code Duplication
    function setFillTransparency($mode, $opacity)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3132
    {
3133
        static $blend_modes = array(
3134
            "Normal",
3135
            "Multiply",
3136
            "Screen",
3137
            "Overlay",
3138
            "Darken",
3139
            "Lighten",
3140
            "ColorDogde",
3141
            "ColorBurn",
3142
            "HardLight",
3143
            "SoftLight",
3144
            "Difference",
3145
            "Exclusion"
3146
        );
3147
3148
        if (!in_array($mode, $blend_modes)) {
3149
            $mode = "Normal";
3150
        }
3151
3152
        if ($mode === $this->currentFillTransparency["mode"] &&
3153
            $opacity == $this->currentFillTransparency["opacity"]
3154
        ) {
3155
            return;
3156
        }
3157
3158
        $this->currentFillTransparency["mode"] = $mode;
3159
        $this->currentFillTransparency["opacity"] = $opacity;
3160
3161
        $options = array(
3162
            "BM" => "/$mode",
3163
            "ca" => (float)$opacity,
3164
        );
3165
3166
        $this->setGraphicsState($options);
3167
    }
3168
3169
    /**
3170
     * draw a line from one set of coordinates to another
3171
     *
3172
     * @param $x1
3173
     * @param $y1
3174
     * @param $x2
3175
     * @param $y2
3176
     * @param bool $stroke
3177
     */
3178
    function line($x1, $y1, $x2, $y2, $stroke = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3179
    {
3180
        $this->addContent(sprintf("\n%.3F %.3F m %.3F %.3F l", $x1, $y1, $x2, $y2));
3181
3182
        if ($stroke) {
3183
            $this->addContent(' S');
3184
        }
3185
    }
3186
3187
    /**
3188
     * draw a bezier curve based on 4 control points
3189
     *
3190
     * @param $x0
3191
     * @param $y0
3192
     * @param $x1
3193
     * @param $y1
3194
     * @param $x2
3195
     * @param $y2
3196
     * @param $x3
3197
     * @param $y3
3198
     */
3199
    function curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3200
    {
3201
        // in the current line style, draw a bezier curve from (x0,y0) to (x3,y3) using the other two points
3202
        // as the control points for the curve.
3203
        $this->addContent(
3204
            sprintf("\n%.3F %.3F m %.3F %.3F %.3F %.3F %.3F %.3F c S", $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
3205
        );
3206
    }
3207
3208
    /**
3209
     * draw a part of an ellipse
3210
     *
3211
     * @param $x0
3212
     * @param $y0
3213
     * @param $astart
3214
     * @param $afinish
3215
     * @param $r1
3216
     * @param int $r2
3217
     * @param int $angle
3218
     * @param int $nSeg
3219
     */
3220
    function partEllipse($x0, $y0, $astart, $afinish, $r1, $r2 = 0, $angle = 0, $nSeg = 8)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3221
    {
3222
        $this->ellipse($x0, $y0, $r1, $r2, $angle, $nSeg, $astart, $afinish, false);
3223
    }
3224
3225
    /**
3226
     * draw a filled ellipse
3227
     *
3228
     * @param $x0
3229
     * @param $y0
3230
     * @param $r1
3231
     * @param int $r2
3232
     * @param int $angle
3233
     * @param int $nSeg
3234
     * @param int $astart
3235
     * @param int $afinish
3236
     */
3237
    function filledEllipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3238
    {
3239
        $this->ellipse($x0, $y0, $r1, $r2, $angle, $nSeg, $astart, $afinish, true, true);
3240
    }
3241
3242
    /**
3243
     * @param $x
3244
     * @param $y
3245
     */
3246
    function lineTo($x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3247
    {
3248
        $this->addContent(sprintf("\n%.3F %.3F l", $x, $y));
3249
    }
3250
3251
    /**
3252
     * @param $x
3253
     * @param $y
3254
     */
3255
    function moveTo($x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3256
    {
3257
        $this->addContent(sprintf("\n%.3F %.3F m", $x, $y));
3258
    }
3259
3260
    /**
3261
     * draw a bezier curve based on 4 control points
3262
     *
3263
     * @param $x1
3264
     * @param $y1
3265
     * @param $x2
3266
     * @param $y2
3267
     * @param $x3
3268
     * @param $y3
3269
     */
3270
    function curveTo($x1, $y1, $x2, $y2, $x3, $y3)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3271
    {
3272
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F %.3F %.3F c", $x1, $y1, $x2, $y2, $x3, $y3));
3273
    }
3274
 
3275
    /**
3276
     * draw a bezier curve based on 4 control points
3277
     */    function quadTo($cpx, $cpy, $x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3278
    {
3279
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F v", $cpx, $cpy, $x, $y));
3280
    }
3281
    
3282
    function closePath()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3283
    {
3284
        $this->addContent(' h');
3285
    }
3286
3287
    function endPath()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3288
    {
3289
        $this->addContent(' n');
3290
    }
3291
3292
    /**
3293
     * draw an ellipse
3294
     * note that the part and filled ellipse are just special cases of this function
3295
     *
3296
     * draws an ellipse in the current line style
3297
     * centered at $x0,$y0, radii $r1,$r2
3298
     * if $r2 is not set, then a circle is drawn
3299
     * from $astart to $afinish, measured in degrees, running anti-clockwise from the right hand side of the ellipse.
3300
     * nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a
3301
     * pretty crappy shape at 2, as we are approximating with bezier curves.
3302
     *
3303
     * @param $x0
3304
     * @param $y0
3305
     * @param $r1
3306
     * @param int $r2
3307
     * @param int $angle
3308
     * @param int $nSeg
3309
     * @param int $astart
3310
     * @param int $afinish
3311
     * @param bool $close
3312
     * @param bool $fill
3313
     * @param bool $stroke
3314
     * @param bool $incomplete
3315
     */
3316
    function ellipse(
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3317
        $x0,
3318
        $y0,
3319
        $r1,
3320
        $r2 = 0,
3321
        $angle = 0,
3322
        $nSeg = 8,
3323
        $astart = 0,
3324
        $afinish = 360,
3325
        $close = true,
3326
        $fill = false,
3327
        $stroke = true,
3328
        $incomplete = false
3329
    ) {
3330
        if ($r1 == 0) {
3331
            return;
3332
        }
3333
3334
        if ($r2 == 0) {
3335
            $r2 = $r1;
3336
        }
3337
3338
        if ($nSeg < 2) {
3339
            $nSeg = 2;
3340
        }
3341
3342
        $astart = deg2rad((float)$astart);
3343
        $afinish = deg2rad((float)$afinish);
3344
        $totalAngle = $afinish - $astart;
3345
3346
        $dt = $totalAngle / $nSeg;
3347
        $dtm = $dt / 3;
3348
3349
        if ($angle != 0) {
3350
            $a = -1 * deg2rad((float)$angle);
3351
3352
            $this->addContent(
3353
                sprintf("\n q %.3F %.3F %.3F %.3F %.3F %.3F cm", cos($a), -sin($a), sin($a), cos($a), $x0, $y0)
3354
            );
3355
3356
            $x0 = 0;
3357
            $y0 = 0;
3358
        }
3359
3360
        $t1 = $astart;
3361
        $a0 = $x0 + $r1 * cos($t1);
3362
        $b0 = $y0 + $r2 * sin($t1);
3363
        $c0 = -$r1 * sin($t1);
3364
        $d0 = $r2 * cos($t1);
3365
3366
        if (!$incomplete) {
3367
            $this->addContent(sprintf("\n%.3F %.3F m ", $a0, $b0));
3368
        }
3369
3370
        for ($i = 1; $i <= $nSeg; $i++) {
3371
            // draw this bit of the total curve
3372
            $t1 = $i * $dt + $astart;
3373
            $a1 = $x0 + $r1 * cos($t1);
3374
            $b1 = $y0 + $r2 * sin($t1);
3375
            $c1 = -$r1 * sin($t1);
3376
            $d1 = $r2 * cos($t1);
3377
3378
            $this->addContent(
3379
                sprintf(
3380
                    "\n%.3F %.3F %.3F %.3F %.3F %.3F c",
3381
                    ($a0 + $c0 * $dtm),
3382
                    ($b0 + $d0 * $dtm),
3383
                    ($a1 - $c1 * $dtm),
3384
                    ($b1 - $d1 * $dtm),
3385
                    $a1,
3386
                    $b1
3387
                )
3388
            );
3389
3390
            $a0 = $a1;
3391
            $b0 = $b1;
3392
            $c0 = $c1;
3393
            $d0 = $d1;
3394
        }
3395
3396
        if (!$incomplete) {
3397
            if ($fill) {
3398
                $this->addContent(' f');
3399
            }
3400
3401
            if ($stroke) {
3402
                if ($close) {
3403
                    $this->addContent(' s'); // small 's' signifies closing the path as well
3404
                } else {
3405
                    $this->addContent(' S');
3406
                }
3407
            }
3408
        }
3409
3410
        if ($angle != 0) {
3411
            $this->addContent(' Q');
3412
        }
3413
    }
3414
3415
    /**
3416
     * this sets the line drawing style.
3417
     * width, is the thickness of the line in user units
3418
     * cap is the type of cap to put on the line, values can be 'butt','round','square'
3419
     *    where the diffference between 'square' and 'butt' is that 'square' projects a flat end past the
3420
     *    end of the line.
3421
     * join can be 'miter', 'round', 'bevel'
3422
     * dash is an array which sets the dash pattern, is a series of length values, which are the lengths of the
3423
     *   on and off dashes.
3424
     *   (2) represents 2 on, 2 off, 2 on , 2 off ...
3425
     *   (2,1) is 2 on, 1 off, 2 on, 1 off.. etc
3426
     * phase is a modifier on the dash pattern which is used to shift the point at which the pattern starts.
3427
     *
3428
     * @param int $width
3429
     * @param string $cap
3430
     * @param string $join
3431
     * @param string $dash
3432
     * @param int $phase
3433
     */
3434
    function setLineStyle($width = 1, $cap = '', $join = '', $dash = '', $phase = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3435
    {
3436
        // this is quite inefficient in that it sets all the parameters whenever 1 is changed, but will fix another day
3437
        $string = '';
3438
3439
        if ($width > 0) {
3440
            $string .= "$width w";
3441
        }
3442
3443
        $ca = array('butt' => 0, 'round' => 1, 'square' => 2);
3444
3445
        if (isset($ca[$cap])) {
3446
            $string .= " $ca[$cap] J";
3447
        }
3448
3449
        $ja = array('miter' => 0, 'round' => 1, 'bevel' => 2);
3450
3451
        if (isset($ja[$join])) {
3452
            $string .= " $ja[$join] j";
3453
        }
3454
3455
        if (is_array($dash)) {
3456
            $string .= ' [ ' . implode(' ', $dash) . " ] $phase d";
3457
        }
3458
3459
        $this->currentLineStyle = $string;
3460
        $this->addContent("\n$string");
3461
    }
3462
3463
    /**
3464
     * draw a polygon, the syntax for this is similar to the GD polygon command
3465
     *
3466
     * @param $p
3467
     * @param $np
3468
     * @param bool $f
3469
     */
3470
    function polygon($p, $np, $f = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3471
    {
3472
        $this->addContent(sprintf("\n%.3F %.3F m ", $p[0], $p[1]));
3473
3474
        for ($i = 2; $i < $np * 2; $i = $i + 2) {
3475
            $this->addContent(sprintf("%.3F %.3F l ", $p[$i], $p[$i + 1]));
3476
        }
3477
3478
        if ($f) {
3479
            $this->addContent(' f');
3480
        } else {
3481
            $this->addContent(' S');
3482
        }
3483
    }
3484
3485
    /**
3486
     * a filled rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
3487
     * the coordinates of the upper-right corner
3488
     *
3489
     * @param $x1
3490
     * @param $y1
3491
     * @param $width
3492
     * @param $height
3493
     */
3494
    function filledRectangle($x1, $y1, $width, $height)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3495
    {
3496
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F re f", $x1, $y1, $width, $height));
3497
    }
3498
3499
    /**
3500
     * draw a rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
3501
     * the coordinates of the upper-right corner
3502
     *
3503
     * @param $x1
3504
     * @param $y1
3505
     * @param $width
3506
     * @param $height
3507
     */
3508
    function rectangle($x1, $y1, $width, $height)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3509
    {
3510
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F re S", $x1, $y1, $width, $height));
3511
    }
3512
3513
    /**
3514
     * draw a rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
3515
     * the coordinates of the upper-right corner
3516
     *
3517
     * @param $x1
3518
     * @param $y1
3519
     * @param $width
3520
     * @param $height
3521
     */
3522
    function rect($x1, $y1, $width, $height)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3523
    {
3524
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F re", $x1, $y1, $width, $height));
3525
    }
3526
3527
    function stroke()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3528
    {
3529
        $this->addContent("\nS");
3530
    }
3531
3532
    function fill()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3533
    {
3534
        $this->addContent("\nf" . ($this->fillRule === "evenodd" ? "*" : ""));
3535
    }
3536
3537
    function fillStroke()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3538
    {
3539
        $this->addContent("\nb" . ($this->fillRule === "evenodd" ? "*" : ""));
3540
    }
3541
3542
    /**
3543
     * save the current graphic state
3544
     */
3545
    function save()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3546
    {
3547
        // we must reset the color cache or it will keep bad colors after clipping
3548
        $this->currentColor = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $currentColor.

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

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

Loading history...
3549
        $this->currentStrokeColor = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $currentStrokeColor.

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

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

Loading history...
3550
        $this->addContent("\nq");
3551
    }
3552
3553
    /**
3554
     * restore the last graphic state
3555
     */
3556
    function restore()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3557
    {
3558
        // we must reset the color cache or it will keep bad colors after clipping
3559
        $this->currentColor = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $currentColor.

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

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

Loading history...
3560
        $this->currentStrokeColor = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $currentStrokeColor.

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

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

Loading history...
3561
        $this->addContent("\nQ");
3562
    }
3563
3564
    /**
3565
     * draw a clipping rectangle, all the elements added after this will be clipped
3566
     *
3567
     * @param $x1
3568
     * @param $y1
3569
     * @param $width
3570
     * @param $height
3571
     */
3572
    function clippingRectangle($x1, $y1, $width, $height)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3573
    {
3574
        $this->save();
3575
        $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F re W n", $x1, $y1, $width, $height));
3576
    }
3577
3578
    /**
3579
     * draw a clipping rounded rectangle, all the elements added after this will be clipped
3580
     *
3581
     * @param $x1
3582
     * @param $y1
3583
     * @param $w
3584
     * @param $h
3585
     * @param $rTL
3586
     * @param $rTR
3587
     * @param $rBR
3588
     * @param $rBL
3589
     */
3590
    function clippingRectangleRounded($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3591
    {
3592
        $this->save();
3593
3594
        // start: top edge, left end
3595
        $this->addContent(sprintf("\n%.3F %.3F m ", $x1, $y1 - $rTL + $h));
3596
3597
        // line: bottom edge, left end
3598
        $this->addContent(sprintf("\n%.3F %.3F l ", $x1, $y1 + $rBL));
3599
3600
        // curve: bottom-left corner
3601
        $this->ellipse($x1 + $rBL, $y1 + $rBL, $rBL, 0, 0, 8, 180, 270, false, false, false, true);
3602
3603
        // line: right edge, bottom end
3604
        $this->addContent(sprintf("\n%.3F %.3F l ", $x1 + $w - $rBR, $y1));
3605
3606
        // curve: bottom-right corner
3607
        $this->ellipse($x1 + $w - $rBR, $y1 + $rBR, $rBR, 0, 0, 8, 270, 360, false, false, false, true);
3608
3609
        // line: right edge, top end
3610
        $this->addContent(sprintf("\n%.3F %.3F l ", $x1 + $w, $y1 + $h - $rTR));
3611
3612
        // curve: bottom-right corner
3613
        $this->ellipse($x1 + $w - $rTR, $y1 + $h - $rTR, $rTR, 0, 0, 8, 0, 90, false, false, false, true);
3614
3615
        // line: bottom edge, right end
3616
        $this->addContent(sprintf("\n%.3F %.3F l ", $x1 + $rTL, $y1 + $h));
3617
3618
        // curve: top-right corner
3619
        $this->ellipse($x1 + $rTL, $y1 + $h - $rTL, $rTL, 0, 0, 8, 90, 180, false, false, false, true);
3620
3621
        // line: top edge, left end
3622
        $this->addContent(sprintf("\n%.3F %.3F l ", $x1 + $rBL, $y1));
3623
3624
        // Close & clip
3625
        $this->addContent(" W n");
3626
    }
3627
3628
    /**
3629
     * ends the last clipping shape
3630
     */
3631
    function clippingEnd()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3632
    {
3633
        $this->restore();
3634
    }
3635
3636
    /**
3637
     * scale
3638
     *
3639
     * @param float $s_x scaling factor for width as percent
3640
     * @param float $s_y scaling factor for height as percent
3641
     * @param float $x   Origin abscissa
3642
     * @param float $y   Origin ordinate
3643
     */
3644
    function scale($s_x, $s_y, $x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3645
    {
3646
        $y = $this->currentPageSize["height"] - $y;
3647
3648
        $tm = array(
3649
            $s_x,
3650
            0,
3651
            0,
3652
            $s_y,
3653
            $x * (1 - $s_x),
3654
            $y * (1 - $s_y)
3655
        );
3656
3657
        $this->transform($tm);
3658
    }
3659
3660
    /**
3661
     * translate
3662
     *
3663
     * @param float $t_x movement to the right
3664
     * @param float $t_y movement to the bottom
3665
     */
3666
    function translate($t_x, $t_y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3667
    {
3668
        $tm = array(
3669
            1,
3670
            0,
3671
            0,
3672
            1,
3673
            $t_x,
3674
            -$t_y
3675
        );
3676
3677
        $this->transform($tm);
3678
    }
3679
3680
    /**
3681
     * rotate
3682
     *
3683
     * @param float $angle angle in degrees for counter-clockwise rotation
3684
     * @param float $x     Origin abscissa
3685
     * @param float $y     Origin ordinate
3686
     */
3687
    function rotate($angle, $x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3688
    {
3689
        $y = $this->currentPageSize["height"] - $y;
3690
3691
        $a = deg2rad($angle);
3692
        $cos_a = cos($a);
3693
        $sin_a = sin($a);
3694
3695
        $tm = array(
3696
            $cos_a,
3697
            -$sin_a,
3698
            $sin_a,
3699
            $cos_a,
3700
            $x - $sin_a * $y - $cos_a * $x,
3701
            $y - $cos_a * $y + $sin_a * $x,
3702
        );
3703
3704
        $this->transform($tm);
3705
    }
3706
3707
    /**
3708
     * skew
3709
     *
3710
     * @param float $angle_x
3711
     * @param float $angle_y
3712
     * @param float $x Origin abscissa
3713
     * @param float $y Origin ordinate
3714
     */
3715
    function skew($angle_x, $angle_y, $x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3716
    {
3717
        $y = $this->currentPageSize["height"] - $y;
3718
3719
        $tan_x = tan(deg2rad($angle_x));
3720
        $tan_y = tan(deg2rad($angle_y));
3721
3722
        $tm = array(
3723
            1,
3724
            -$tan_y,
3725
            -$tan_x,
3726
            1,
3727
            $tan_x * $y,
3728
            $tan_y * $x,
3729
        );
3730
3731
        $this->transform($tm);
3732
    }
3733
3734
    /**
3735
     * apply graphic transformations
3736
     *
3737
     * @param array $tm transformation matrix
3738
     */
3739
    function transform($tm)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3740
    {
3741
        $this->addContent(vsprintf("\n %.3F %.3F %.3F %.3F %.3F %.3F cm", $tm));
3742
    }
3743
3744
    /**
3745
     * add a new page to the document
3746
     * this also makes the new page the current active object
3747
     *
3748
     * @param int $insert
3749
     * @param int $id
3750
     * @param string $pos
3751
     * @return int
3752
     */
3753
    function newPage($insert = 0, $id = 0, $pos = 'after')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3754
    {
3755
        // if there is a state saved, then go up the stack closing them
3756
        // then on the new page, re-open them with the right setings
3757
3758
        if ($this->nStateStack) {
3759
            for ($i = $this->nStateStack; $i >= 1; $i--) {
3760
                $this->restoreState($i);
3761
            }
3762
        }
3763
3764
        $this->numObj++;
3765
3766
        if ($insert) {
3767
            // the id from the ezPdf class is the id of the contents of the page, not the page object itself
3768
            // query that object to find the parent
3769
            $rid = $this->objects[$id]['onPage'];
3770
            $opt = array('rid' => $rid, 'pos' => $pos);
3771
            $this->o_page($this->numObj, 'new', $opt);
0 ignored issues
show
Documentation introduced by
$opt is of type array<string,?,{"rid":"?","pos":"string"}>, but the function expects a string.

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...
3772
        } else {
3773
            $this->o_page($this->numObj, 'new');
3774
        }
3775
3776
        // if there is a stack saved, then put that onto the page
3777
        if ($this->nStateStack) {
3778
            for ($i = 1; $i <= $this->nStateStack; $i++) {
3779
                $this->saveState($i);
3780
            }
3781
        }
3782
3783
        // and if there has been a stroke or fill color set, then transfer them
3784
        if (isset($this->currentColor)) {
3785
            $this->setColor($this->currentColor, true);
3786
        }
3787
3788
        if (isset($this->currentStrokeColor)) {
3789
            $this->setStrokeColor($this->currentStrokeColor, true);
3790
        }
3791
3792
        // if there is a line style set, then put this in too
3793
        if (mb_strlen($this->currentLineStyle, '8bit')) {
3794
            $this->addContent("\n$this->currentLineStyle");
3795
        }
3796
3797
        // the call to the o_page object set currentContents to the present page, so this can be returned as the page id
3798
        return $this->currentContents;
3799
    }
3800
3801
    /**
3802
     * Streams the PDF to the client.
3803
     *
3804
     * @param string $filename The filename to present to the client.
3805
     * @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
3806
     */
3807
    function stream($filename = "document.pdf", $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3808
    {
3809
        if (headers_sent()) {
3810
            die("Unable to stream pdf: headers already sent");
0 ignored issues
show
Coding Style Compatibility introduced by
The method stream() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
3811
        }
3812
3813
        if (!isset($options["compress"])) $options["compress"] = true;
3814
        if (!isset($options["Attachment"])) $options["Attachment"] = true;
3815
3816
        $debug = !$options['compress'];
3817
        $tmp = ltrim($this->output($debug));
3818
3819
        header("Cache-Control: private");
3820
        header("Content-Type: application/pdf");
3821
        header("Content-Length: " . mb_strlen($tmp, "8bit"));
3822
3823
        $filename = str_replace(array("\n", "'"), "", basename($filename, ".pdf")) . ".pdf";
3824
        $attachment = $options["Attachment"] ? "attachment" : "inline";
3825
3826
        $encoding = mb_detect_encoding($filename);
3827
        $fallbackfilename = mb_convert_encoding($filename, "ISO-8859-1", $encoding);
3828
        $fallbackfilename = str_replace("\"", "", $fallbackfilename);
3829
        $encodedfilename = rawurlencode($filename);
3830
3831
        $contentDisposition = "Content-Disposition: $attachment; filename=\"$fallbackfilename\"";
3832
        if ($fallbackfilename !== $filename) {
3833
            $contentDisposition .= "; filename*=UTF-8''$encodedfilename";
3834
        }
3835
        header($contentDisposition);
3836
3837
        echo $tmp;
3838
        flush();
3839
    }
3840
3841
    /**
3842
     * return the height in units of the current font in the given size
3843
     *
3844
     * @param $size
3845
     * @return float|int
3846
     */
3847
    function getFontHeight($size)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3848
    {
3849
        if (!$this->numFonts) {
3850
            $this->selectFont($this->defaultFont);
3851
        }
3852
3853
        $font = $this->fonts[$this->currentFont];
3854
3855
        // for the current font, and the given size, what is the height of the font in user units
3856
        if (isset($font['Ascender']) && isset($font['Descender'])) {
3857
            $h = $font['Ascender'] - $font['Descender'];
3858
        } else {
3859
            $h = $font['FontBBox'][3] - $font['FontBBox'][1];
3860
        }
3861
3862
        // have to adjust by a font offset for Windows fonts.  unfortunately it looks like
3863
        // the bounding box calculations are wrong and I don't know why.
3864
        if (isset($font['FontHeightOffset'])) {
3865
            // For CourierNew from Windows this needs to be -646 to match the
3866
            // Adobe native Courier font.
3867
            //
3868
            // For FreeMono from GNU this needs to be -337 to match the
3869
            // Courier font.
3870
            //
3871
            // Both have been added manually to the .afm and .ufm files.
3872
            $h += (int)$font['FontHeightOffset'];
3873
        }
3874
3875
        return $size * $h / 1000;
3876
    }
3877
3878
    /**
3879
     * @param $size
3880
     * @return float|int
3881
     */
3882
    function getFontXHeight($size)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3883
    {
3884
        if (!$this->numFonts) {
3885
            $this->selectFont($this->defaultFont);
3886
        }
3887
3888
        $font = $this->fonts[$this->currentFont];
3889
3890
        // for the current font, and the given size, what is the height of the font in user units
3891
        if (isset($font['XHeight'])) {
3892
            $xh = $font['Ascender'] - $font['Descender'];
3893
        } else {
3894
            $xh = $this->getFontHeight($size) / 2;
3895
        }
3896
3897
        return $size * $xh / 1000;
3898
    }
3899
3900
    /**
3901
     * return the font descender, this will normally return a negative number
3902
     * if you add this number to the baseline, you get the level of the bottom of the font
3903
     * it is in the pdf user units
3904
     *
3905
     * @param $size
3906
     * @return float|int
3907
     */
3908
    function getFontDescender($size)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3909
    {
3910
        // note that this will most likely return a negative value
3911
        if (!$this->numFonts) {
3912
            $this->selectFont($this->defaultFont);
3913
        }
3914
3915
        //$h = $this->fonts[$this->currentFont]['FontBBox'][1];
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% 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...
3916
        $h = $this->fonts[$this->currentFont]['Descender'];
3917
3918
        return $size * $h / 1000;
3919
    }
3920
3921
    /**
3922
     * filter the text, this is applied to all text just before being inserted into the pdf document
3923
     * it escapes the various things that need to be escaped, and so on
3924
     *
3925
     * @access private
3926
     *
3927
     * @param $text
3928
     * @param bool $bom
3929
     * @param bool $convert_encoding
3930
     * @return string
3931
     */
3932
    function filterText($text, $bom = true, $convert_encoding = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3933
    {
3934
        if (!$this->numFonts) {
3935
            $this->selectFont($this->defaultFont);
3936
        }
3937
3938
        if ($convert_encoding) {
3939
            $cf = $this->currentFont;
3940
            if (isset($this->fonts[$cf]) && $this->fonts[$cf]['isUnicode']) {
3941
                $text = $this->utf8toUtf16BE($text, $bom);
3942
            } else {
3943
                //$text = html_entity_decode($text, ENT_QUOTES);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
3944
                $text = mb_convert_encoding($text, self::$targetEncoding, 'UTF-8');
3945
            }
3946
        } else if ($bom) {
3947
            $text = $this->utf8toUtf16BE($text, $bom);
3948
        }
3949
3950
        // the chr(13) substitution fixes a bug seen in TCPDF (bug #1421290)
3951
        return strtr($text, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
3952
    }
3953
3954
    /**
3955
     * return array containing codepoints (UTF-8 character values) for the
3956
     * string passed in.
3957
     *
3958
     * based on the excellent TCPDF code by Nicola Asuni and the
3959
     * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
3960
     *
3961
     * @access private
3962
     * @author Orion Richardson
3963
     * @since  January 5, 2008
3964
     *
3965
     * @param string $text UTF-8 string to process
3966
     *
3967
     * @return array UTF-8 codepoints array for the string
3968
     */
3969
    function utf8toCodePointsArray(&$text)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3970
    {
3971
        $length = mb_strlen($text, '8bit'); // http://www.php.net/manual/en/function.mb-strlen.php#77040
3972
        $unicode = array(); // array containing unicode values
3973
        $bytes = array(); // array containing single character byte sequences
3974
        $numbytes = 1; // number of octets needed to represent the UTF-8 character
3975
3976
        for ($i = 0; $i < $length; $i++) {
3977
            $c = ord($text[$i]); // get one string character at time
3978
            if (count($bytes) === 0) { // get starting octect
3979
                if ($c <= 0x7F) {
3980
                    $unicode[] = $c; // use the character "as is" because is ASCII
3981
                    $numbytes = 1;
3982 View Code Duplication
                } elseif (($c >> 0x05) === 0x06) { // 2 bytes character (0x06 = 110 BIN)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3983
                    $bytes[] = ($c - 0xC0) << 0x06;
3984
                    $numbytes = 2;
3985
                } elseif (($c >> 0x04) === 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
3986
                    $bytes[] = ($c - 0xE0) << 0x0C;
3987
                    $numbytes = 3;
3988 View Code Duplication
                } elseif (($c >> 0x03) === 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3989
                    $bytes[] = ($c - 0xF0) << 0x12;
3990
                    $numbytes = 4;
3991
                } else {
3992
                    // use replacement character for other invalid sequences
3993
                    $unicode[] = 0xFFFD;
3994
                    $bytes = array();
3995
                    $numbytes = 1;
3996
                }
3997
            } elseif (($c >> 0x06) === 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
3998
                $bytes[] = $c - 0x80;
3999
                if (count($bytes) === $numbytes) {
4000
                    // compose UTF-8 bytes to a single unicode value
4001
                    $c = $bytes[0];
4002
                    for ($j = 1; $j < $numbytes; $j++) {
4003
                        $c += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
4004
                    }
4005
                    if ((($c >= 0xD800) AND ($c <= 0xDFFF)) OR ($c >= 0x10FFFF)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
4006
                        // The definition of UTF-8 prohibits encoding character numbers between
4007
                        // U+D800 and U+DFFF, which are reserved for use with the UTF-16
4008
                        // encoding form (as surrogate pairs) and do not directly represent
4009
                        // characters.
4010
                        $unicode[] = 0xFFFD; // use replacement character
4011
                    } else {
4012
                        $unicode[] = $c; // add char to array
4013
                    }
4014
                    // reset data for next char
4015
                    $bytes = array();
4016
                    $numbytes = 1;
4017
                }
4018
            } else {
4019
                // use replacement character for other invalid sequences
4020
                $unicode[] = 0xFFFD;
4021
                $bytes = array();
4022
                $numbytes = 1;
4023
            }
4024
        }
4025
4026
        return $unicode;
4027
    }
4028
4029
    /**
4030
     * convert UTF-8 to UTF-16 with an additional byte order marker
4031
     * at the front if required.
4032
     *
4033
     * based on the excellent TCPDF code by Nicola Asuni and the
4034
     * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
4035
     *
4036
     * @access private
4037
     * @author Orion Richardson
4038
     * @since  January 5, 2008
4039
     *
4040
     * @param string  $text UTF-8 string to process
4041
     * @param boolean $bom  whether to add the byte order marker
4042
     *
4043
     * @return string UTF-16 result string
4044
     */
4045
    function utf8toUtf16BE(&$text, $bom = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4046
    {
4047
        $out = $bom ? "\xFE\xFF" : '';
4048
4049
        $unicode = $this->utf8toCodePointsArray($text);
4050
        foreach ($unicode as $c) {
4051
            if ($c === 0xFFFD) {
4052
                $out .= "\xFF\xFD"; // replacement character
4053
            } elseif ($c < 0x10000) {
4054
                $out .= chr($c >> 0x08) . chr($c & 0xFF);
4055
            } else {
4056
                $c -= 0x10000;
4057
                $w1 = 0xD800 | ($c >> 0x10);
4058
                $w2 = 0xDC00 | ($c & 0x3FF);
4059
                $out .= chr($w1 >> 0x08) . chr($w1 & 0xFF) . chr($w2 >> 0x08) . chr($w2 & 0xFF);
4060
            }
4061
        }
4062
4063
        return $out;
4064
    }
4065
4066
    /**
4067
     * given a start position and information about how text is to be laid out, calculate where
4068
     * on the page the text will end
4069
     *
4070
     * @param $x
4071
     * @param $y
4072
     * @param $angle
4073
     * @param $size
4074
     * @param $wa
4075
     * @param $text
4076
     * @return array
4077
     */
4078
    private function getTextPosition($x, $y, $angle, $size, $wa, $text)
4079
    {
4080
        // given this information return an array containing x and y for the end position as elements 0 and 1
4081
        $w = $this->getTextWidth($size, $text);
4082
4083
        // need to adjust for the number of spaces in this text
4084
        $words = explode(' ', $text);
4085
        $nspaces = count($words) - 1;
4086
        $w += $wa * $nspaces;
4087
        $a = deg2rad((float)$angle);
4088
4089
        return array(cos($a) * $w + $x, -sin($a) * $w + $y);
4090
    }
4091
4092
    /**
4093
     * Callback method used by smallCaps
4094
     *
4095
     * @param array $matches
4096
     *
4097
     * @return string
4098
     */
4099
    function toUpper($matches)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4100
    {
4101
        return mb_strtoupper($matches[0]);
4102
    }
4103
4104
    function concatMatches($matches)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4105
    {
4106
        $str = "";
4107
        foreach ($matches as $match) {
4108
            $str .= $match[0];
4109
        }
4110
4111
        return $str;
4112
    }
4113
4114
    /**
4115
     * register text for font subsetting
4116
     *
4117
     * @param $font
4118
     * @param $text
4119
     */
4120
    function registerText($font, $text)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4121
    {
4122
        if (!$this->isUnicode || in_array(mb_strtolower(basename($font)), self::$coreFonts)) {
4123
            return;
4124
        }
4125
4126
        if (!isset($this->stringSubsets[$font])) {
4127
            $this->stringSubsets[$font] = array();
4128
        }
4129
4130
        $this->stringSubsets[$font] = array_unique(
4131
            array_merge($this->stringSubsets[$font], $this->utf8toCodePointsArray($text))
4132
        );
4133
    }
4134
4135
    /**
4136
     * add text to the document, at a specified location, size and angle on the page
4137
     *
4138
     * @param $x
4139
     * @param $y
4140
     * @param $size
4141
     * @param $text
4142
     * @param int $angle
4143
     * @param int $wordSpaceAdjust
4144
     * @param int $charSpaceAdjust
4145
     * @param bool $smallCaps
4146
     */
4147
    function addText($x, $y, $size, $text, $angle = 0, $wordSpaceAdjust = 0, $charSpaceAdjust = 0, $smallCaps = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4148
    {
4149
        if (!$this->numFonts) {
4150
            $this->selectFont($this->defaultFont);
4151
        }
4152
4153
        $text = str_replace(array("\r", "\n"), "", $text);
4154
4155
        if ($smallCaps) {
4156
            preg_match_all("/(\P{Ll}+)/u", $text, $matches, PREG_SET_ORDER);
4157
            $lower = $this->concatMatches($matches);
4158
            d($lower);
4159
4160
            preg_match_all("/(\p{Ll}+)/u", $text, $matches, PREG_SET_ORDER);
4161
            $other = $this->concatMatches($matches);
4162
            d($other);
4163
4164
            //$text = preg_replace_callback("/\p{Ll}/u", array($this, "toUpper"), $text);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
4165
        }
4166
4167
        // if there are any open callbacks, then they should be called, to show the start of the line
4168
        if ($this->nCallback > 0) {
4169
            for ($i = $this->nCallback; $i > 0; $i--) {
4170
                // call each function
4171
                $info = array(
4172
                    'x'         => $x,
4173
                    'y'         => $y,
4174
                    'angle'     => $angle,
4175
                    'status'    => 'sol',
4176
                    'p'         => $this->callback[$i]['p'],
4177
                    'nCallback' => $this->callback[$i]['nCallback'],
4178
                    'height'    => $this->callback[$i]['height'],
4179
                    'descender' => $this->callback[$i]['descender']
4180
                );
4181
4182
                $func = $this->callback[$i]['f'];
4183
                $this->$func($info);
4184
            }
4185
        }
4186
4187
        if ($angle == 0) {
4188
            $this->addContent(sprintf("\nBT %.3F %.3F Td", $x, $y));
4189
        } else {
4190
            $a = deg2rad((float)$angle);
4191
            $this->addContent(
4192
                sprintf("\nBT %.3F %.3F %.3F %.3F %.3F %.3F Tm", cos($a), -sin($a), sin($a), cos($a), $x, $y)
4193
            );
4194
        }
4195
4196
        if ($wordSpaceAdjust != 0) {
4197
            $this->addContent(sprintf(" %.3F Tw", $wordSpaceAdjust));
4198
        }
4199
4200
        if ($charSpaceAdjust != 0) {
4201
            $this->addContent(sprintf(" %.3F Tc", $charSpaceAdjust));
4202
        }
4203
4204
        $len = mb_strlen($text);
4205
        $start = 0;
4206
4207
        if ($start < $len) {
4208
            $part = $text; // OAR - Don't need this anymore, given that $start always equals zero.  substr($text, $start);
4209
            $place_text = $this->filterText($part, false);
4210
            // modify unicode text so that extra word spacing is manually implemented (bug #)
4211
            $cf = $this->currentFont;
4212
            if ($this->fonts[$cf]['isUnicode'] && $wordSpaceAdjust != 0) {
4213
                $space_scale = 1000 / $size;
4214
                $place_text = str_replace("\x00\x20", "\x00\x20)\x00\x20" . (-round($space_scale * $wordSpaceAdjust)) . "\x00\x20(", $place_text);
4215
            }
4216
            $this->addContent(" /F$this->currentFontNum " . sprintf('%.1F Tf ', $size));
4217
            $this->addContent(" [($place_text)] TJ");
4218
        }
4219
4220
        if ($wordSpaceAdjust != 0) {
4221
            $this->addContent(sprintf(" %.3F Tw", 0));
4222
        }
4223
4224
        if ($charSpaceAdjust != 0) {
4225
            $this->addContent(sprintf(" %.3F Tc", 0));
4226
        }
4227
4228
        $this->addContent(' ET');
4229
4230
        // if there are any open callbacks, then they should be called, to show the end of the line
4231
        if ($this->nCallback > 0) {
4232
            for ($i = $this->nCallback; $i > 0; $i--) {
4233
                // call each function
4234
                $tmp = $this->getTextPosition($x, $y, $angle, $size, $wordSpaceAdjust, $text);
4235
                $info = array(
4236
                    'x'         => $tmp[0],
4237
                    'y'         => $tmp[1],
4238
                    'angle'     => $angle,
4239
                    'status'    => 'eol',
4240
                    'p'         => $this->callback[$i]['p'],
4241
                    'nCallback' => $this->callback[$i]['nCallback'],
4242
                    'height'    => $this->callback[$i]['height'],
4243
                    'descender' => $this->callback[$i]['descender']
4244
                );
4245
                $func = $this->callback[$i]['f'];
4246
                $this->$func($info);
4247
            }
4248
        }
4249
    }
4250
4251
    /**
4252
     * calculate how wide a given text string will be on a page, at a given size.
4253
     * this can be called externally, but is also used by the other class functions
4254
     *
4255
     * @param $size
4256
     * @param $text
4257
     * @param int $word_spacing
4258
     * @param int $char_spacing
4259
     * @return float|int
4260
     */
4261
    function getTextWidth($size, $text, $word_spacing = 0, $char_spacing = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4262
    {
4263
        static $ord_cache = array();
4264
4265
        // this function should not change any of the settings, though it will need to
4266
        // track any directives which change during calculation, so copy them at the start
4267
        // and put them back at the end.
4268
        $store_currentTextState = $this->currentTextState;
4269
4270
        if (!$this->numFonts) {
4271
            $this->selectFont($this->defaultFont);
4272
        }
4273
4274
        $text = str_replace(array("\r", "\n"), "", $text);
4275
4276
        // converts a number or a float to a string so it can get the width
4277
        $text = "$text";
4278
4279
        // hmm, this is where it all starts to get tricky - use the font information to
4280
        // calculate the width of each character, add them up and convert to user units
4281
        $w = 0;
4282
        $cf = $this->currentFont;
4283
        $current_font = $this->fonts[$cf];
4284
        $space_scale = 1000 / ($size > 0 ? $size : 1);
4285
        $n_spaces = 0;
4286
4287
        if ($current_font['isUnicode']) {
4288
            // for Unicode, use the code points array to calculate width rather
4289
            // than just the string itself
4290
            $unicode = $this->utf8toCodePointsArray($text);
4291
4292
            foreach ($unicode as $char) {
4293
                // check if we have to replace character
4294
                if (isset($current_font['differences'][$char])) {
4295
                    $char = $current_font['differences'][$char];
4296
                }
4297
4298 View Code Duplication
                if (isset($current_font['C'][$char])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4299
                    $char_width = $current_font['C'][$char];
4300
4301
                    // add the character width
4302
                    $w += $char_width;
4303
4304
                    // add additional padding for space
4305
                    if (isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space') {  // Space
4306
                        $w += $word_spacing * $space_scale;
4307
                        $n_spaces++;
4308
                    }
4309
                }
4310
            }
4311
4312
            // add additional char spacing
4313
            if ($char_spacing != 0) {
4314
                $w += $char_spacing * $space_scale * (count($unicode) + $n_spaces);
4315
            }
4316
4317
        } else {
4318
            // If CPDF is in Unicode mode but the current font does not support Unicode we need to convert the character set to Windows-1252
4319
            if ($this->isUnicode) {
4320
                $text = mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
4321
            }
4322
4323
            $len = mb_strlen($text, 'Windows-1252');
4324
4325
            for ($i = 0; $i < $len; $i++) {
4326
                $c = $text[$i];
4327
                $char = isset($ord_cache[$c]) ? $ord_cache[$c] : ($ord_cache[$c] = ord($c));
4328
4329
                // check if we have to replace character
4330
                if (isset($current_font['differences'][$char])) {
4331
                    $char = $current_font['differences'][$char];
4332
                }
4333
4334 View Code Duplication
                if (isset($current_font['C'][$char])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4335
                    $char_width = $current_font['C'][$char];
4336
4337
                    // add the character width
4338
                    $w += $char_width;
4339
4340
                    // add additional padding for space
4341
                    if (isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space') {  // Space
4342
                        $w += $word_spacing * $space_scale;
4343
                        $n_spaces++;
4344
                    }
4345
                }
4346
            }
4347
4348
            // add additional char spacing
4349
            if ($char_spacing != 0) {
4350
                $w += $char_spacing * $space_scale * ($len + $n_spaces);
4351
            }
4352
        }
4353
4354
        $this->currentTextState = $store_currentTextState;
4355
        $this->setCurrentFont();
4356
4357
        return $w * $size / 1000;
4358
    }
4359
4360
    /**
4361
     * this will be called at a new page to return the state to what it was on the
4362
     * end of the previous page, before the stack was closed down
4363
     * This is to get around not being able to have open 'q' across pages
4364
     *
4365
     * @param int $pageEnd
4366
     */
4367
    function saveState($pageEnd = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4368
    {
4369
        if ($pageEnd) {
4370
            // this will be called at a new page to return the state to what it was on the
4371
            // end of the previous page, before the stack was closed down
4372
            // This is to get around not being able to have open 'q' across pages
4373
            $opt = $this->stateStack[$pageEnd];
4374
            // ok to use this as stack starts numbering at 1
4375
            $this->setColor($opt['col'], true);
4376
            $this->setStrokeColor($opt['str'], true);
4377
            $this->addContent("\n" . $opt['lin']);
4378
            //    $this->currentLineStyle = $opt['lin'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
4379
        } else {
4380
            $this->nStateStack++;
4381
            $this->stateStack[$this->nStateStack] = array(
4382
                'col' => $this->currentColor,
4383
                'str' => $this->currentStrokeColor,
4384
                'lin' => $this->currentLineStyle
4385
            );
4386
        }
4387
4388
        $this->save();
4389
    }
4390
4391
    /**
4392
     * restore a previously saved state
4393
     *
4394
     * @param int $pageEnd
4395
     */
4396
    function restoreState($pageEnd = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4397
    {
4398
        if (!$pageEnd) {
4399
            $n = $this->nStateStack;
4400
            $this->currentColor = $this->stateStack[$n]['col'];
4401
            $this->currentStrokeColor = $this->stateStack[$n]['str'];
4402
            $this->addContent("\n" . $this->stateStack[$n]['lin']);
4403
            $this->currentLineStyle = $this->stateStack[$n]['lin'];
4404
            $this->stateStack[$n] = null;
4405
            unset($this->stateStack[$n]);
4406
            $this->nStateStack--;
4407
        }
4408
4409
        $this->restore();
4410
    }
4411
4412
    /**
4413
     * make a loose object, the output will go into this object, until it is closed, then will revert to
4414
     * the current one.
4415
     * this object will not appear until it is included within a page.
4416
     * the function will return the object number
4417
     *
4418
     * @return int
4419
     */
4420
    function openObject()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4421
    {
4422
        $this->nStack++;
4423
        $this->stack[$this->nStack] = array('c' => $this->currentContents, 'p' => $this->currentPage);
4424
        // add a new object of the content type, to hold the data flow
4425
        $this->numObj++;
4426
        $this->o_contents($this->numObj, 'new');
4427
        $this->currentContents = $this->numObj;
4428
        $this->looseObjects[$this->numObj] = 1;
4429
4430
        return $this->numObj;
4431
    }
4432
4433
    /**
4434
     * open an existing object for editing
4435
     *
4436
     * @param $id
4437
     */
4438
    function reopenObject($id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4439
    {
4440
        $this->nStack++;
4441
        $this->stack[$this->nStack] = array('c' => $this->currentContents, 'p' => $this->currentPage);
4442
        $this->currentContents = $id;
4443
4444
        // also if this object is the primary contents for a page, then set the current page to its parent
4445
        if (isset($this->objects[$id]['onPage'])) {
4446
            $this->currentPage = $this->objects[$id]['onPage'];
4447
        }
4448
    }
4449
4450
    /**
4451
     * close an object
4452
     */
4453
    function closeObject()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4454
    {
4455
        // close the object, as long as there was one open in the first place, which will be indicated by
4456
        // an objectId on the stack.
4457
        if ($this->nStack > 0) {
4458
            $this->currentContents = $this->stack[$this->nStack]['c'];
4459
            $this->currentPage = $this->stack[$this->nStack]['p'];
4460
            $this->nStack--;
4461
            // easier to probably not worry about removing the old entries, they will be overwritten
4462
            // if there are new ones.
4463
        }
4464
    }
4465
4466
    /**
4467
     * stop an object from appearing on pages from this point on
4468
     *
4469
     * @param $id
4470
     */
4471
    function stopObject($id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4472
    {
4473
        // if an object has been appearing on pages up to now, then stop it, this page will
4474
        // be the last one that could contain it.
4475
        if (isset($this->addLooseObjects[$id])) {
4476
            $this->addLooseObjects[$id] = '';
4477
        }
4478
    }
4479
4480
    /**
4481
     * after an object has been created, it wil only show if it has been added, using this function.
4482
     *
4483
     * @param $id
4484
     * @param string $options
4485
     */
4486
    function addObject($id, $options = 'add')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4487
    {
4488
        // add the specified object to the page
4489
        if (isset($this->looseObjects[$id]) && $this->currentContents != $id) {
4490
            // then it is a valid object, and it is not being added to itself
4491
            switch ($options) {
4492
                case 'all':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
4493
                    // then this object is to be added to this page (done in the next block) and
4494
                    // all future new pages.
4495
                    $this->addLooseObjects[$id] = 'all';
4496
4497
                case 'add':
4498
                    if (isset($this->objects[$this->currentContents]['onPage'])) {
4499
                        // then the destination contents is the primary for the page
4500
                        // (though this object is actually added to that page)
4501
                        $this->o_page($this->objects[$this->currentContents]['onPage'], 'content', $id);
4502
                    }
4503
                    break;
4504
4505 View Code Duplication
                case 'even':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4506
                    $this->addLooseObjects[$id] = 'even';
4507
                    $pageObjectId = $this->objects[$this->currentContents]['onPage'];
4508
                    if ($this->objects[$pageObjectId]['info']['pageNum'] % 2 == 0) {
4509
                        $this->addObject($id);
4510
                        // hacky huh :)
4511
                    }
4512
                    break;
4513
4514 View Code Duplication
                case 'odd':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4515
                    $this->addLooseObjects[$id] = 'odd';
4516
                    $pageObjectId = $this->objects[$this->currentContents]['onPage'];
4517
                    if ($this->objects[$pageObjectId]['info']['pageNum'] % 2 == 1) {
4518
                        $this->addObject($id);
4519
                        // hacky huh :)
4520
                    }
4521
                    break;
4522
4523
                case 'next':
4524
                    $this->addLooseObjects[$id] = 'all';
4525
                    break;
4526
4527
                case 'nexteven':
4528
                    $this->addLooseObjects[$id] = 'even';
4529
                    break;
4530
4531
                case 'nextodd':
4532
                    $this->addLooseObjects[$id] = 'odd';
4533
                    break;
4534
            }
4535
        }
4536
    }
4537
4538
    /**
4539
     * return a storable representation of a specific object
4540
     *
4541
     * @param $id
4542
     * @return string|null
4543
     */
4544
    function serializeObject($id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4545
    {
4546
        if (array_key_exists($id, $this->objects)) {
4547
            return serialize($this->objects[$id]);
4548
        }
4549
4550
        return null;
4551
    }
4552
4553
    /**
4554
     * restore an object from its stored representation.  returns its new object id.
4555
     *
4556
     * @param $obj
4557
     * @return int
4558
     */
4559
    function restoreSerializedObject($obj)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4560
    {
4561
        $obj_id = $this->openObject();
4562
        $this->objects[$obj_id] = unserialize($obj);
4563
        $this->closeObject();
4564
4565
        return $obj_id;
4566
    }
4567
4568
    /**
4569
     * add content to the documents info object
4570
     *
4571
     * @param $label
4572
     * @param int $value
4573
     */
4574
    function addInfo($label, $value = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4575
    {
4576
        // this will only work if the label is one of the valid ones.
4577
        // modify this so that arrays can be passed as well.
4578
        // if $label is an array then assume that it is key => value pairs
4579
        // else assume that they are both scalar, anything else will probably error
4580
        if (is_array($label)) {
4581
            foreach ($label as $l => $v) {
4582
                $this->o_info($this->infoObject, $l, $v);
4583
            }
4584
        } else {
4585
            $this->o_info($this->infoObject, $label, $value);
4586
        }
4587
    }
4588
4589
    /**
4590
     * set the viewer preferences of the document, it is up to the browser to obey these.
4591
     *
4592
     * @param $label
4593
     * @param int $value
4594
     */
4595
    function setPreferences($label, $value = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4596
    {
4597
        // this will only work if the label is one of the valid ones.
4598
        if (is_array($label)) {
4599
            foreach ($label as $l => $v) {
4600
                $this->o_catalog($this->catalogId, 'viewerPreferences', array($l => $v));
4601
            }
4602
        } else {
4603
            $this->o_catalog($this->catalogId, 'viewerPreferences', array($label => $value));
4604
        }
4605
    }
4606
4607
    /**
4608
     * extract an integer from a position in a byte stream
4609
     *
4610
     * @param $data
4611
     * @param $pos
4612
     * @param $num
4613
     * @return int
4614
     */
4615
    private function getBytes(&$data, $pos, $num)
4616
    {
4617
        // return the integer represented by $num bytes from $pos within $data
4618
        $ret = 0;
4619
        for ($i = 0; $i < $num; $i++) {
4620
            $ret *= 256;
4621
            $ret += ord($data[$pos + $i]);
4622
        }
4623
4624
        return $ret;
4625
    }
4626
4627
    /**
4628
     * Check if image already added to pdf image directory.
4629
     * If yes, need not to create again (pass empty data)
4630
     *
4631
     * @param $imgname
4632
     * @return bool
4633
     */
4634
    function image_iscached($imgname)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4635
    {
4636
        return isset($this->imagelist[$imgname]);
4637
    }
4638
4639
    /**
4640
     * add a PNG image into the document, from a GD object
4641
     * this should work with remote files
4642
     *
4643
     * @param string $file The PNG file
4644
     * @param float $x X position
4645
     * @param float $y Y position
4646
     * @param float $w Width
4647
     * @param float $h Height
4648
     * @param resource $img A GD resource
4649
     * @param bool $is_mask true if the image is a mask
4650
     * @param bool $mask true if the image is masked
4651
     * @throws Exception
4652
     */
4653
    function addImagePng($file, $x, $y, $w = 0.0, $h = 0.0, &$img, $is_mask = false, $mask = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4654
    {
4655
        if (!function_exists("imagepng")) {
4656
            throw new \Exception("The PHP GD extension is required, but is not installed.");
4657
        }
4658
4659
        //if already cached, need not to read again
4660
        if (isset($this->imagelist[$file])) {
4661
            $data = null;
4662
        } else {
4663
            // Example for transparency handling on new image. Retain for current image
4664
            // $tIndex = imagecolortransparent($img);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
4665
            // if ($tIndex > 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
4666
            //   $tColor    = imagecolorsforindex($img, $tIndex);
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% 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...
4667
            //   $new_tIndex    = imagecolorallocate($new_img, $tColor['red'], $tColor['green'], $tColor['blue']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
4668
            //   imagefill($new_img, 0, 0, $new_tIndex);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
4669
            //   imagecolortransparent($new_img, $new_tIndex);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
4670
            // }
4671
            // blending mode (literal/blending) on drawing into current image. not relevant when not saved or not drawn
4672
            //imagealphablending($img, true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
4673
4674
            //default, but explicitely set to ensure pdf compatibility
4675
            imagesavealpha($img, false/*!$is_mask && !$mask*/);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
4676
4677
            $error = 0;
4678
            //DEBUG_IMG_TEMP
4679
            //debugpng
4680
            if (defined("DEBUGPNG") && DEBUGPNG) {
4681
                print '[addImagePng ' . $file . ']';
4682
            }
4683
4684
            ob_start();
4685
            @imagepng($img);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4686
            $data = ob_get_clean();
4687
4688 View Code Duplication
            if ($data == '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4689
                $error = 1;
4690
                $errormsg = 'trouble writing file from GD';
4691
                //DEBUG_IMG_TEMP
4692
                //debugpng
4693
                if (defined("DEBUGPNG") && DEBUGPNG) {
4694
                    print 'trouble writing file from GD';
4695
                }
4696
            }
4697
4698
            if ($error) {
4699
                $this->addMessage('PNG error - (' . $file . ') ' . $errormsg);
0 ignored issues
show
Bug introduced by
The variable $errormsg does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4700
4701
                return;
4702
            }
4703
        }  //End isset($this->imagelist[$file]) (png Duplicate removal)
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% 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...
4704
4705
        $this->addPngFromBuf($file, $x, $y, $w, $h, $data, $is_mask, $mask);
0 ignored issues
show
Bug introduced by
It seems like $mask defined by parameter $mask on line 4653 can also be of type boolean; however, Cpdf::addPngFromBuf() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
4706
    }
4707
4708
    /**
4709
     * @param $file
4710
     * @param $x
4711
     * @param $y
4712
     * @param $w
4713
     * @param $h
4714
     * @param $byte
4715
     */
4716
    protected function addImagePngAlpha($file, $x, $y, $w, $h, $byte)
4717
    {
4718
        // generate images
4719
        $img = imagecreatefrompng($file);
4720
4721
        if ($img === false) {
4722
            return;
4723
        }
4724
4725
        // FIXME The pixel transformation doesn't work well with 8bit PNGs
4726
        $eight_bit = ($byte & 4) !== 4;
4727
4728
        $wpx = imagesx($img);
4729
        $hpx = imagesy($img);
4730
4731
        imagesavealpha($img, false);
4732
4733
        // create temp alpha file
4734
        $tempfile_alpha = tempnam($this->tmp, "cpdf_img_");
4735
        @unlink($tempfile_alpha);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4736
        $tempfile_alpha = "$tempfile_alpha.png";
4737
4738
        // create temp plain file
4739
        $tempfile_plain = tempnam($this->tmp, "cpdf_img_");
4740
        @unlink($tempfile_plain);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4741
        $tempfile_plain = "$tempfile_plain.png";
4742
4743
        $imgalpha = imagecreate($wpx, $hpx);
4744
        imagesavealpha($imgalpha, false);
4745
4746
        // generate gray scale palette (0 -> 255)
4747
        for ($c = 0; $c < 256; ++$c) {
4748
            imagecolorallocate($imgalpha, $c, $c, $c);
4749
        }
4750
4751
        // Use PECL gmagick + Graphics Magic to process transparent PNG images
4752
        if (extension_loaded("gmagick")) {
4753
            $gmagick = new \Gmagick($file);
4754
            $gmagick->setimageformat('png');
4755
4756
            // Get opacity channel (negative of alpha channel)
4757
            $alpha_channel_neg = clone $gmagick;
4758
            $alpha_channel_neg->separateimagechannel(\Gmagick::CHANNEL_OPACITY);
4759
4760
            // Negate opacity channel
4761
            $alpha_channel = new \Gmagick();
4762
            $alpha_channel->newimage($wpx, $hpx, "#FFFFFF", "png");
4763
            $alpha_channel->compositeimage($alpha_channel_neg, \Gmagick::COMPOSITE_DIFFERENCE, 0, 0);
4764
            $alpha_channel->separateimagechannel(\Gmagick::CHANNEL_RED);
4765
            $alpha_channel->writeimage($tempfile_alpha);
4766
4767
            // Cast to 8bit+palette
4768
            $imgalpha_ = imagecreatefrompng($tempfile_alpha);
4769
            imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
4770
            imagedestroy($imgalpha_);
4771
            imagepng($imgalpha, $tempfile_alpha);
4772
4773
            // Make opaque image
4774
            $color_channels = new \Gmagick();
4775
            $color_channels->newimage($wpx, $hpx, "#FFFFFF", "png");
4776
            $color_channels->compositeimage($gmagick, \Gmagick::COMPOSITE_COPYRED, 0, 0);
4777
            $color_channels->compositeimage($gmagick, \Gmagick::COMPOSITE_COPYGREEN, 0, 0);
4778
            $color_channels->compositeimage($gmagick, \Gmagick::COMPOSITE_COPYBLUE, 0, 0);
4779
            $color_channels->writeimage($tempfile_plain);
4780
4781
            $imgplain = imagecreatefrompng($tempfile_plain);
4782
        }
4783
        // Use PECL imagick + ImageMagic to process transparent PNG images
4784
        elseif (extension_loaded("imagick")) {
4785
            // Native cloning was added to pecl-imagick in svn commit 263814
4786
            // the first version containing it was 3.0.1RC1
4787
            static $imagickClonable = null;
4788
            if ($imagickClonable === null) {
4789
                $imagickClonable = version_compare(Imagick::IMAGICK_EXTVER, '3.0.1rc1') > 0;
4790
            }
4791
4792
            $imagick = new \Imagick($file);
4793
            $imagick->setFormat('png');
4794
4795
            // Get opacity channel (negative of alpha channel)
4796
            $alpha_channel = $imagickClonable ? clone $imagick : $imagick->clone();
4797
            $alpha_channel->separateImageChannel(\Imagick::CHANNEL_ALPHA);
4798
            $alpha_channel->negateImage(true);
4799
            $alpha_channel->writeImage($tempfile_alpha);
4800
4801
            // Cast to 8bit+palette
4802
            $imgalpha_ = imagecreatefrompng($tempfile_alpha);
4803
            imagecopy($imgalpha, $imgalpha_, 0, 0, 0, 0, $wpx, $hpx);
4804
            imagedestroy($imgalpha_);
4805
            imagepng($imgalpha, $tempfile_alpha);
4806
4807
            // Make opaque image
4808
            $color_channels = new \Imagick();
4809
            $color_channels->newImage($wpx, $hpx, "#FFFFFF", "png");
4810
            $color_channels->compositeImage($imagick, \Imagick::COMPOSITE_COPYRED, 0, 0);
4811
            $color_channels->compositeImage($imagick, \Imagick::COMPOSITE_COPYGREEN, 0, 0);
4812
            $color_channels->compositeImage($imagick, \Imagick::COMPOSITE_COPYBLUE, 0, 0);
4813
            $color_channels->writeImage($tempfile_plain);
4814
4815
            $imgplain = imagecreatefrompng($tempfile_plain);
4816
        } else {
4817
            // allocated colors cache
4818
            $allocated_colors = array();
4819
4820
            // extract alpha channel
4821
            for ($xpx = 0; $xpx < $wpx; ++$xpx) {
4822
                for ($ypx = 0; $ypx < $hpx; ++$ypx) {
4823
                    $color = imagecolorat($img, $xpx, $ypx);
4824
                    $col = imagecolorsforindex($img, $color);
4825
                    $alpha = $col['alpha'];
4826
4827
                    if ($eight_bit) {
4828
                        // with gamma correction
4829
                        $gammacorr = 2.2;
4830
                        $pixel = pow((((127 - $alpha) * 255 / 127) / 255), $gammacorr) * 255;
4831
                    } else {
4832
                        // without gamma correction
4833
                        $pixel = (127 - $alpha) * 2;
4834
4835
                        $key = $col['red'] . $col['green'] . $col['blue'];
4836
4837
                        if (!isset($allocated_colors[$key])) {
4838
                            $pixel_img = imagecolorallocate($img, $col['red'], $col['green'], $col['blue']);
4839
                            $allocated_colors[$key] = $pixel_img;
4840
                        } else {
4841
                            $pixel_img = $allocated_colors[$key];
4842
                        }
4843
4844
                        imagesetpixel($img, $xpx, $ypx, $pixel_img);
4845
                    }
4846
4847
                    imagesetpixel($imgalpha, $xpx, $ypx, $pixel);
4848
                }
4849
            }
4850
4851
            // extract image without alpha channel
4852
            $imgplain = imagecreatetruecolor($wpx, $hpx);
4853
            imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx);
4854
            imagedestroy($img);
4855
4856
            imagepng($imgalpha, $tempfile_alpha);
4857
            imagepng($imgplain, $tempfile_plain);
4858
        }
4859
4860
        // embed mask image
4861
        $this->addImagePng($tempfile_alpha, $x, $y, $w, $h, $imgalpha, true);
4862
        imagedestroy($imgalpha);
4863
4864
        // embed image, masked with previously embedded mask
4865
        $this->addImagePng($tempfile_plain, $x, $y, $w, $h, $imgplain, false, true);
4866
        imagedestroy($imgplain);
4867
4868
        // remove temp files
4869
        unlink($tempfile_alpha);
4870
        unlink($tempfile_plain);
4871
    }
4872
4873
    /**
4874
     * add a PNG image into the document, from a file
4875
     * this should work with remote files
4876
     *
4877
     * @param $file
4878
     * @param $x
4879
     * @param $y
4880
     * @param int $w
4881
     * @param int $h
4882
     * @throws Exception
4883
     */
4884
    function addPngFromFile($file, $x, $y, $w = 0, $h = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4885
    {
4886
        if (!function_exists("imagecreatefrompng")) {
4887
            throw new \Exception("The PHP GD extension is required, but is not installed.");
4888
        }
4889
4890
        //if already cached, need not to read again
4891
        if (isset($this->imagelist[$file])) {
4892
            $img = null;
4893
        } else {
4894
            $info = file_get_contents($file, false, null, 24, 5);
4895
            $meta = unpack("CbitDepth/CcolorType/CcompressionMethod/CfilterMethod/CinterlaceMethod", $info);
4896
            $bit_depth = $meta["bitDepth"];
4897
            $color_type = $meta["colorType"];
4898
4899
            // http://www.w3.org/TR/PNG/#11IHDR
4900
            // 3 => indexed
4901
            // 4 => greyscale with alpha
4902
            // 6 => fullcolor with alpha
4903
            $is_alpha = in_array($color_type, array(4, 6)) || ($color_type == 3 && $bit_depth != 4);
4904
4905
            if ($is_alpha) { // exclude grayscale alpha
4906
                $this->addImagePngAlpha($file, $x, $y, $w, $h, $color_type);
4907
                return;
4908
            }
4909
4910
            //png files typically contain an alpha channel.
4911
            //pdf file format or class.pdf does not support alpha blending.
4912
            //on alpha blended images, more transparent areas have a color near black.
4913
            //This appears in the result on not storing the alpha channel.
4914
            //Correct would be the box background image or its parent when transparent.
4915
            //But this would make the image dependent on the background.
4916
            //Therefore create an image with white background and copy in
4917
            //A more natural background than black is white.
4918
            //Therefore create an empty image with white background and merge the
4919
            //image in with alpha blending.
4920
            $imgtmp = @imagecreatefrompng($file);
4921
            if (!$imgtmp) {
4922
                return;
4923
            }
4924
            $sx = imagesx($imgtmp);
4925
            $sy = imagesy($imgtmp);
4926
            $img = imagecreatetruecolor($sx, $sy);
4927
            imagealphablending($img, true);
4928
4929
            // @todo is it still needed ??
4930
            $ti = imagecolortransparent($imgtmp);
4931
            if ($ti >= 0) {
4932
                $tc = imagecolorsforindex($imgtmp, $ti);
4933
                $ti = imagecolorallocate($img, $tc['red'], $tc['green'], $tc['blue']);
4934
                imagefill($img, 0, 0, $ti);
4935
                imagecolortransparent($img, $ti);
4936
            } else {
4937
                imagefill($img, 1, 1, imagecolorallocate($img, 255, 255, 255));
4938
            }
4939
4940
            imagecopy($img, $imgtmp, 0, 0, 0, 0, $sx, $sy);
4941
            imagedestroy($imgtmp);
4942
        }
4943
        $this->addImagePng($file, $x, $y, $w, $h, $img);
0 ignored issues
show
Bug introduced by
It seems like $img defined by null on line 4892 can also be of type null; however, Cpdf::addImagePng() does only seem to accept resource, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
4944
4945
        if ($img) {
4946
            imagedestroy($img);
4947
        }
4948
    }
4949
4950
    /**
4951
     * add a PNG image into the document, from a file
4952
     * this should work with remote files
4953
     *
4954
     * @param $file
4955
     * @param $x
4956
     * @param $y
4957
     * @param int $w
4958
     * @param int $h
4959
     */
4960
    function addSvgFromFile($file, $x, $y, $w = 0, $h = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4961
    {
4962
        $doc = new \Svg\Document();
4963
        $doc->loadFile($file);
4964
        $dimensions = $doc->getDimensions();
4965
4966
        $this->save();
4967
4968
        $this->transform(array($w / $dimensions["width"], 0, 0, $h / $dimensions["height"], $x, $y));
4969
4970
        $surface = new \Svg\Surface\SurfaceCpdf($doc, $this);
4971
        $doc->render($surface);
4972
4973
        $this->restore();
4974
    }
4975
4976
    /**
4977
     * add a PNG image into the document, from a memory buffer of the file
4978
     *
4979
     * @param $file
4980
     * @param $x
4981
     * @param $y
4982
     * @param float $w
4983
     * @param float $h
4984
     * @param $data
4985
     * @param bool $is_mask
4986
     * @param null $mask
4987
     */
4988
    function addPngFromBuf($file, $x, $y, $w = 0.0, $h = 0.0, &$data, $is_mask = false, $mask = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
4989
    {
4990
        if (isset($this->imagelist[$file])) {
4991
            $data = null;
4992
            $info['width'] = $this->imagelist[$file]['w'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$info was never initialized. Although not strictly required by PHP, it is generally a good practice to add $info = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
4993
            $info['height'] = $this->imagelist[$file]['h'];
4994
            $label = $this->imagelist[$file]['label'];
4995
        } else {
4996
            if ($data == null) {
4997
                $this->addMessage('addPngFromBuf error - data not present!');
4998
4999
                return;
5000
            }
5001
5002
            $error = 0;
5003
5004
            if (!$error) {
5005
                $header = chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10);
5006
5007
                if (mb_substr($data, 0, 8, '8bit') != $header) {
5008
                    $error = 1;
5009
5010
                    if (defined("DEBUGPNG") && DEBUGPNG) {
5011
                        print '[addPngFromFile this file does not have a valid header ' . $file . ']';
5012
                    }
5013
5014
                    $errormsg = 'this file does not have a valid header';
5015
                }
5016
            }
5017
5018
            if (!$error) {
5019
                // set pointer
5020
                $p = 8;
5021
                $len = mb_strlen($data, '8bit');
5022
5023
                // cycle through the file, identifying chunks
5024
                $haveHeader = 0;
5025
                $info = array();
5026
                $idata = '';
5027
                $pdata = '';
5028
5029
                while ($p < $len) {
5030
                    $chunkLen = $this->getBytes($data, $p, 4);
5031
                    $chunkType = mb_substr($data, $p + 4, 4, '8bit');
5032
5033
                    switch ($chunkType) {
5034
                        case 'IHDR':
5035
                            // this is where all the file information comes from
5036
                            $info['width'] = $this->getBytes($data, $p + 8, 4);
5037
                            $info['height'] = $this->getBytes($data, $p + 12, 4);
5038
                            $info['bitDepth'] = ord($data[$p + 16]);
5039
                            $info['colorType'] = ord($data[$p + 17]);
5040
                            $info['compressionMethod'] = ord($data[$p + 18]);
5041
                            $info['filterMethod'] = ord($data[$p + 19]);
5042
                            $info['interlaceMethod'] = ord($data[$p + 20]);
5043
5044
                            //print_r($info);
5045
                            $haveHeader = 1;
5046 View Code Duplication
                            if ($info['compressionMethod'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5047
                                $error = 1;
5048
5049
                                //debugpng
5050
                                if (defined("DEBUGPNG") && DEBUGPNG) {
5051
                                    print '[addPngFromFile unsupported compression method ' . $file . ']';
5052
                                }
5053
5054
                                $errormsg = 'unsupported compression method';
5055
                            }
5056
5057 View Code Duplication
                            if ($info['filterMethod'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5058
                                $error = 1;
5059
5060
                                //debugpng
5061
                                if (defined("DEBUGPNG") && DEBUGPNG) {
5062
                                    print '[addPngFromFile unsupported filter method ' . $file . ']';
5063
                                }
5064
5065
                                $errormsg = 'unsupported filter method';
5066
                            }
5067
                            break;
5068
5069
                        case 'PLTE':
5070
                            $pdata .= mb_substr($data, $p + 8, $chunkLen, '8bit');
5071
                            break;
5072
5073
                        case 'IDAT':
5074
                            $idata .= mb_substr($data, $p + 8, $chunkLen, '8bit');
5075
                            break;
5076
5077
                        case 'tRNS':
5078
                            //this chunk can only occur once and it must occur after the PLTE chunk and before IDAT chunk
5079
                            //print "tRNS found, color type = ".$info['colorType']."\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% 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...
5080
                            $transparency = array();
5081
5082
                            switch ($info['colorType']) {
5083
                                // indexed color, rbg
5084
                                case 3:
5085
                                    /* corresponding to entries in the plte chunk
5086
                                     Alpha for palette index 0: 1 byte
5087
                                     Alpha for palette index 1: 1 byte
5088
                                     ...etc...
5089
                                    */
5090
                                    // there will be one entry for each palette entry. up until the last non-opaque entry.
5091
                                    // set up an array, stretching over all palette entries which will be o (opaque) or 1 (transparent)
5092
                                    $transparency['type'] = 'indexed';
5093
                                    $trans = 0;
5094
5095
                                    for ($i = $chunkLen; $i >= 0; $i--) {
5096
                                        if (ord($data[$p + 8 + $i]) == 0) {
5097
                                            $trans = $i;
5098
                                        }
5099
                                    }
5100
5101
                                    $transparency['data'] = $trans;
5102
                                    break;
5103
5104
                                // grayscale
5105
                                case 0:
5106
                                    /* corresponding to entries in the plte chunk
5107
                                     Gray: 2 bytes, range 0 .. (2^bitdepth)-1
5108
                                    */
5109
                                    //            $transparency['grayscale'] = $this->PRVT_getBytes($data,$p+8,2); // g = grayscale
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% 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...
5110
                                    $transparency['type'] = 'indexed';
5111
                                    $transparency['data'] = ord($data[$p + 8 + 1]);
5112
                                    break;
5113
5114
                                // truecolor
5115
                                case 2:
5116
                                    /* corresponding to entries in the plte chunk
5117
                                     Red: 2 bytes, range 0 .. (2^bitdepth)-1
5118
                                     Green: 2 bytes, range 0 .. (2^bitdepth)-1
5119
                                     Blue: 2 bytes, range 0 .. (2^bitdepth)-1
5120
                                    */
5121
                                    $transparency['r'] = $this->getBytes($data, $p + 8, 2);
5122
                                    // r from truecolor
5123
                                    $transparency['g'] = $this->getBytes($data, $p + 10, 2);
5124
                                    // g from truecolor
5125
                                    $transparency['b'] = $this->getBytes($data, $p + 12, 2);
5126
                                    // b from truecolor
5127
5128
                                    $transparency['type'] = 'color-key';
5129
                                    break;
5130
5131
                                //unsupported transparency type
5132
                                default:
5133
                                    if (defined("DEBUGPNG") && DEBUGPNG) {
5134
                                        print '[addPngFromFile unsupported transparency type ' . $file . ']';
5135
                                    }
5136
                                    break;
5137
                            }
5138
5139
                            // KS End new code
5140
                            break;
5141
5142
                        default:
5143
                            break;
5144
                    }
5145
5146
                    $p += $chunkLen + 12;
5147
                }
5148
5149 View Code Duplication
                if (!$haveHeader) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5150
                    $error = 1;
5151
5152
                    //debugpng
5153
                    if (defined("DEBUGPNG") && DEBUGPNG) {
5154
                        print '[addPngFromFile information header is missing ' . $file . ']';
5155
                    }
5156
5157
                    $errormsg = 'information header is missing';
5158
                }
5159
5160 View Code Duplication
                if (isset($info['interlaceMethod']) && $info['interlaceMethod']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5161
                    $error = 1;
5162
5163
                    //debugpng
5164
                    if (defined("DEBUGPNG") && DEBUGPNG) {
5165
                        print '[addPngFromFile no support for interlaced images in pdf ' . $file . ']';
5166
                    }
5167
5168
                    $errormsg = 'There appears to be no support for interlaced images in pdf.';
5169
                }
5170
            }
5171
5172 View Code Duplication
            if (!$error && $info['bitDepth'] > 8) {
0 ignored issues
show
Bug introduced by
The variable $info does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5173
                $error = 1;
5174
5175
                //debugpng
5176
                if (defined("DEBUGPNG") && DEBUGPNG) {
5177
                    print '[addPngFromFile bit depth of 8 or less is supported ' . $file . ']';
5178
                }
5179
5180
                $errormsg = 'only bit depth of 8 or less is supported';
5181
            }
5182
5183
            if (!$error) {
5184
                switch ($info['colorType']) {
5185
                    case 3:
5186
                        $color = 'DeviceRGB';
5187
                        $ncolor = 1;
5188
                        break;
5189
5190
                    case 2:
5191
                        $color = 'DeviceRGB';
5192
                        $ncolor = 3;
5193
                        break;
5194
5195
                    case 0:
5196
                        $color = 'DeviceGray';
5197
                        $ncolor = 1;
5198
                        break;
5199
5200
                    default:
5201
                        $error = 1;
5202
5203
                        //debugpng
5204
                        if (defined("DEBUGPNG") && DEBUGPNG) {
5205
                            print '[addPngFromFile alpha channel not supported: ' . $info['colorType'] . ' ' . $file . ']';
5206
                        }
5207
5208
                        $errormsg = 'transparency alpha channel not supported, transparency only supported for palette images.';
5209
                }
5210
            }
5211
5212
            if ($error) {
5213
                $this->addMessage('PNG error - (' . $file . ') ' . $errormsg);
0 ignored issues
show
Bug introduced by
The variable $errormsg does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5214
5215
                return;
5216
            }
5217
5218
            //print_r($info);
5219
            // so this image is ok... add it in.
5220
            $this->numImages++;
5221
            $im = $this->numImages;
5222
            $label = "I$im";
5223
            $this->numObj++;
5224
5225
            //  $this->o_image($this->numObj,'new',array('label' => $label,'data' => $idata,'iw' => $w,'ih' => $h,'type' => 'png','ic' => $info['width']));
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% 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...
5226
            $options = array(
5227
                'label'            => $label,
5228
                'data'             => $idata,
0 ignored issues
show
Bug introduced by
The variable $idata does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5229
                'bitsPerComponent' => $info['bitDepth'],
5230
                'pdata'            => $pdata,
0 ignored issues
show
Bug introduced by
The variable $pdata does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5231
                'iw'               => $info['width'],
5232
                'ih'               => $info['height'],
5233
                'type'             => 'png',
5234
                'color'            => $color,
0 ignored issues
show
Bug introduced by
The variable $color does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5235
                'ncolor'           => $ncolor,
0 ignored issues
show
Bug introduced by
The variable $ncolor does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5236
                'masked'           => $mask,
5237
                'isMask'           => $is_mask
5238
            );
5239
5240
            if (isset($transparency)) {
5241
                $options['transparency'] = $transparency;
5242
            }
5243
5244
            $this->o_image($this->numObj, 'new', $options);
0 ignored issues
show
Documentation introduced by
$options is of type array<string,?>, but the function expects a string.

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...
5245
            $this->imagelist[$file] = array('label' => $label, 'w' => $info['width'], 'h' => $info['height']);
5246
        }
5247
5248
        if ($is_mask) {
5249
            return;
5250
        }
5251
5252
        if ($w <= 0 && $h <= 0) {
5253
            $w = $info['width'];
5254
            $h = $info['height'];
5255
        }
5256
5257
        if ($w <= 0) {
5258
            $w = $h / $info['height'] * $info['width'];
5259
        }
5260
5261
        if ($h <= 0) {
5262
            $h = $w * $info['height'] / $info['width'];
5263
        }
5264
5265
        $this->addContent(sprintf("\nq\n%.3F 0 0 %.3F %.3F %.3F cm /%s Do\nQ", $w, $h, $x, $y, $label));
5266
    }
5267
5268
    /**
5269
     * add a JPEG image into the document, from a file
5270
     *
5271
     * @param $img
5272
     * @param $x
5273
     * @param $y
5274
     * @param int $w
5275
     * @param int $h
5276
     */
5277
    function addJpegFromFile($img, $x, $y, $w = 0, $h = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5278
    {
5279
        // attempt to add a jpeg image straight from a file, using no GD commands
5280
        // note that this function is unable to operate on a remote file.
5281
5282
        if (!file_exists($img)) {
5283
            return;
5284
        }
5285
5286
        if ($this->image_iscached($img)) {
5287
            $data = null;
5288
            $imageWidth = $this->imagelist[$img]['w'];
5289
            $imageHeight = $this->imagelist[$img]['h'];
5290
            $channels = $this->imagelist[$img]['c'];
5291
        } else {
5292
            $tmp = getimagesize($img);
5293
            $imageWidth = $tmp[0];
5294
            $imageHeight = $tmp[1];
5295
5296
            if (isset($tmp['channels'])) {
5297
                $channels = $tmp['channels'];
5298
            } else {
5299
                $channels = 3;
5300
            }
5301
5302
            $data = file_get_contents($img);
5303
        }
5304
5305
        if ($w <= 0 && $h <= 0) {
5306
            $w = $imageWidth;
5307
        }
5308
5309
        if ($w == 0) {
5310
            $w = $h / $imageHeight * $imageWidth;
5311
        }
5312
5313
        if ($h == 0) {
5314
            $h = $w * $imageHeight / $imageWidth;
5315
        }
5316
5317
        $this->addJpegImage_common($data, $x, $y, $w, $h, $imageWidth, $imageHeight, $channels, $img);
5318
    }
5319
5320
    /**
5321
     * common code used by the two JPEG adding functions
5322
     * @param $data
5323
     * @param $x
5324
     * @param $y
5325
     * @param int $w
5326
     * @param int $h
5327
     * @param $imageWidth
5328
     * @param $imageHeight
5329
     * @param int $channels
5330
     * @param $imgname
5331
     */
5332
    private function addJpegImage_common(
5333
        &$data,
5334
        $x,
5335
        $y,
5336
        $w = 0,
5337
        $h = 0,
5338
        $imageWidth,
5339
        $imageHeight,
5340
        $channels = 3,
5341
        $imgname
5342
    ) {
5343
        if ($this->image_iscached($imgname)) {
5344
            $label = $this->imagelist[$imgname]['label'];
5345
            //debugpng
5346
            //if (DEBUGPNG) print '[addJpegImage_common Duplicate '.$imgname.']';
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
5347
5348
        } else {
5349
            if ($data == null) {
5350
                $this->addMessage('addJpegImage_common error - (' . $imgname . ') data not present!');
5351
5352
                return;
5353
            }
5354
5355
            // note that this function is not to be called externally
5356
            // it is just the common code between the GD and the file options
5357
            $this->numImages++;
5358
            $im = $this->numImages;
5359
            $label = "I$im";
5360
            $this->numObj++;
5361
5362
            $this->o_image(
5363
                $this->numObj,
5364
                'new',
5365
                array(
0 ignored issues
show
Documentation introduced by
array('label' => $label,...channels' => $channels) is of type array<string,?,{"label":...,"channels":"integer"}>, but the function expects a string.

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...
5366
                    'label'    => $label,
5367
                    'data'     => &$data,
5368
                    'iw'       => $imageWidth,
5369
                    'ih'       => $imageHeight,
5370
                    'channels' => $channels
5371
                )
5372
            );
5373
5374
            $this->imagelist[$imgname] = array(
5375
                'label' => $label,
5376
                'w'     => $imageWidth,
5377
                'h'     => $imageHeight,
5378
                'c'     => $channels
5379
            );
5380
        }
5381
5382
        $this->addContent(sprintf("\nq\n%.3F 0 0 %.3F %.3F %.3F cm /%s Do\nQ ", $w, $h, $x, $y, $label));
5383
    }
5384
5385
    /**
5386
     * specify where the document should open when it first starts
5387
     *
5388
     * @param $style
5389
     * @param int $a
5390
     * @param int $b
5391
     * @param int $c
5392
     */
5393 View Code Duplication
    function openHere($style, $a = 0, $b = 0, $c = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5394
    {
5395
        // this function will open the document at a specified page, in a specified style
5396
        // the values for style, and the required parameters are:
5397
        // 'XYZ'  left, top, zoom
5398
        // 'Fit'
5399
        // 'FitH' top
5400
        // 'FitV' left
5401
        // 'FitR' left,bottom,right
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
5402
        // 'FitB'
5403
        // 'FitBH' top
5404
        // 'FitBV' left
5405
        $this->numObj++;
5406
        $this->o_destination(
5407
            $this->numObj,
5408
            'new',
5409
            array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c)
0 ignored issues
show
Documentation introduced by
array('page' => $this->c...'p2' => $b, 'p3' => $c) is of type array<string,?,{"page":"...teger","p3":"integer"}>, but the function expects a string.

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...
5410
        );
5411
        $id = $this->catalogId;
5412
        $this->o_catalog($id, 'openHere', $this->numObj);
5413
    }
5414
5415
    /**
5416
     * Add JavaScript code to the PDF document
5417
     *
5418
     * @param string $code
5419
     */
5420
    function addJavascript($code)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5421
    {
5422
        $this->javascript .= $code;
5423
    }
5424
5425
    /**
5426
     * create a labelled destination within the document
5427
     *
5428
     * @param $label
5429
     * @param $style
5430
     * @param int $a
5431
     * @param int $b
5432
     * @param int $c
5433
     */
5434 View Code Duplication
    function addDestination($label, $style, $a = 0, $b = 0, $c = 0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5435
    {
5436
        // associates the given label with the destination, it is done this way so that a destination can be specified after
5437
        // it has been linked to
5438
        // styles are the same as the 'openHere' function
5439
        $this->numObj++;
5440
        $this->o_destination(
5441
            $this->numObj,
5442
            'new',
5443
            array('page' => $this->currentPage, 'type' => $style, 'p1' => $a, 'p2' => $b, 'p3' => $c)
0 ignored issues
show
Documentation introduced by
array('page' => $this->c...'p2' => $b, 'p3' => $c) is of type array<string,?,{"page":"...teger","p3":"integer"}>, but the function expects a string.

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...
5444
        );
5445
        $id = $this->numObj;
5446
5447
        // store the label->idf relationship, note that this means that labels can be used only once
5448
        $this->destinations["$label"] = $id;
5449
    }
5450
5451
    /**
5452
     * define font families, this is used to initialize the font families for the default fonts
5453
     * and for the user to add new ones for their fonts. The default bahavious can be overridden should
5454
     * that be desired.
5455
     *
5456
     * @param $family
5457
     * @param string $options
5458
     */
5459
    function setFontFamily($family, $options = '')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5460
    {
5461
        if (!is_array($options)) {
5462
            if ($family === 'init') {
5463
                // set the known family groups
5464
                // these font families will be used to enable bold and italic markers to be included
5465
                // within text streams. html forms will be used... <b></b> <i></i>
5466
                $this->fontFamilies['Helvetica.afm'] =
5467
                    array(
5468
                        'b'  => 'Helvetica-Bold.afm',
5469
                        'i'  => 'Helvetica-Oblique.afm',
5470
                        'bi' => 'Helvetica-BoldOblique.afm',
5471
                        'ib' => 'Helvetica-BoldOblique.afm'
5472
                    );
5473
5474
                $this->fontFamilies['Courier.afm'] =
5475
                    array(
5476
                        'b'  => 'Courier-Bold.afm',
5477
                        'i'  => 'Courier-Oblique.afm',
5478
                        'bi' => 'Courier-BoldOblique.afm',
5479
                        'ib' => 'Courier-BoldOblique.afm'
5480
                    );
5481
5482
                $this->fontFamilies['Times-Roman.afm'] =
5483
                    array(
5484
                        'b'  => 'Times-Bold.afm',
5485
                        'i'  => 'Times-Italic.afm',
5486
                        'bi' => 'Times-BoldItalic.afm',
5487
                        'ib' => 'Times-BoldItalic.afm'
5488
                    );
5489
            }
5490
        } else {
5491
5492
            // the user is trying to set a font family
5493
            // note that this can also be used to set the base ones to something else
5494
            if (mb_strlen($family)) {
5495
                $this->fontFamilies[$family] = $options;
5496
            }
5497
        }
5498
    }
5499
5500
    /**
5501
     * used to add messages for use in debugging
5502
     *
5503
     * @param $message
5504
     */
5505
    function addMessage($message)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5506
    {
5507
        $this->messages .= $message . "\n";
5508
    }
5509
5510
    /**
5511
     * a few functions which should allow the document to be treated transactionally.
5512
     *
5513
     * @param $action
5514
     */
5515
    function transaction($action)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5516
    {
5517
        switch ($action) {
5518
            case 'start':
5519
                // store all the data away into the checkpoint variable
5520
                $data = get_object_vars($this);
5521
                $this->checkpoint = $data;
5522
                unset($data);
5523
                break;
5524
5525
            case 'commit':
5526
                if (is_array($this->checkpoint) && isset($this->checkpoint['checkpoint'])) {
5527
                    $tmp = $this->checkpoint['checkpoint'];
5528
                    $this->checkpoint = $tmp;
5529
                    unset($tmp);
5530
                } else {
5531
                    $this->checkpoint = '';
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type array of property $checkpoint.

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

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

Loading history...
5532
                }
5533
                break;
5534
5535 View Code Duplication
            case 'rewind':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5536
                // do not destroy the current checkpoint, but move us back to the state then, so that we can try again
5537
                if (is_array($this->checkpoint)) {
5538
                    // can only abort if were inside a checkpoint
5539
                    $tmp = $this->checkpoint;
5540
5541
                    foreach ($tmp as $k => $v) {
5542
                        if ($k !== 'checkpoint') {
5543
                            $this->$k = $v;
5544
                        }
5545
                    }
5546
                    unset($tmp);
5547
                }
5548
                break;
5549
5550 View Code Duplication
            case 'abort':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5551
                if (is_array($this->checkpoint)) {
5552
                    // can only abort if were inside a checkpoint
5553
                    $tmp = $this->checkpoint;
5554
                    foreach ($tmp as $k => $v) {
5555
                        $this->$k = $v;
5556
                    }
5557
                    unset($tmp);
5558
                }
5559
                break;
5560
        }
5561
    }
5562
}
5563