Completed
Pull Request — master (#140)
by
unknown
08:01
created

Fpdf::addlink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 7
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace NFePHP\DA\Legacy\FPDF;
4
5
use Exception;
6
7
class Fpdf
8
{
9
    const FPDF_VERSION = '1.6';
10
    
11
    public $page;               //current page number
12
    public $n;                  //current object number
13
    public $offsets;            //array of object offsets
14
    public $buffer;             //buffer holding in-memory PDF
15
    public $pages;              //array containing pages
16
    public $state;              //current document state
17
    public $compress;           //compression flag
18
    public $k;                  //scale factor (number of points in user unit)
19
    public $defOrientation;     //default orientation
20
    public $curOrientation;     //current orientation
21
    public $pageFormats;        //available page formats
22
    public $defPageFormat;      //default page format
23
    public $curPageFormat;      //current page format
24
    public $pageSizes;          //array storing non-default page sizes
25
    public $wPt;
26
    public $hPt;           //dimensions of current page in points
27
    public $w;
28
    public $h;               //dimensions of current page in user unit
29
    public $lMargin;            //left margin
30
    public $tMargin;            //top margin
31
    public $rMargin;            //right margin
32
    public $bMargin;            //page break margin
33
    public $cMargin;            //cell margin
34
    public $x;
35
    public $y;               //current position in user unit
36
    public $lasth;              //height of last printed cell
37
    public $lineWidth;          //line width in user unit
38
    public $coreFonts;          //array of standard font names
39
    public $fonts;              //array of used fonts
40
    public $fontFiles;          //array of font files
41
    public $diffs;              //array of encoding differences
42
    public $fontFamily;         //current font family
43
    public $fontStyle;          //current font style
44
    public $underline;          //underlining flag
45
    public $currentFont;        //current font info
46
    public $fontSizePt;         //current font size in points
47
    public $fontSize;           //current font size in user unit
48
    public $drawColor;          //commands for drawing color
49
    public $fillColor;          //commands for filling color
50
    public $textColor;          //commands for text color
51
    public $colorFlag;          //indicates whether fill and text colors are different
52
    public $ws;                 //word spacing
53
    public $images;             //array of used images
54
    public $PageLinks;          //array of links in pages
55
    public $links;              //array of internal links
56
    public $autoPageBreak;      //automatic page breaking
57
    public $pageBreakTrigger;   //threshold used to trigger page breaks
58
    public $inHeader;           //flag set when processing header
59
    public $inFooter;           //flag set when processing footer
60
    public $zoomMode;           //zoom display mode
61
    public $layoutMode;         //layout display mode
62
    public $title;              //title
63
    public $subject;            //subject
64
    public $author;             //author
65
    public $keywords;           //keywords
66
    public $creator;            //creator
67
    public $aliasNbPages;       //alias for total number of pages
68
    public $pdfVersion;         //PDF version number
69
    
70
    private $tmpFiles = array();
71
    
72 1
    public function __construct($orientation = 'P', $unit = 'mm', $format = 'A4')
73
    {
74
        //Some checks
75 1
        $this->dochecks();
76
        //Initialization of properties
77 1
        $this->page = 0;
78 1
        $this->n = 2;
79 1
        $this->buffer = '';
80 1
        $this->pages = array();
81 1
        $this->pageSizes = array();
82 1
        $this->state = 0;
83 1
        $this->fonts = array();
84 1
        $this->fontFiles = array();
85 1
        $this->diffs = array();
86 1
        $this->images = array();
87 1
        $this->links = array();
88 1
        $this->inHeader = false;
89 1
        $this->inFooter = false;
90 1
        $this->lasth = 0;
91 1
        $this->fontFamily = '';
92 1
        $this->fontStyle = '';
93 1
        $this->fontSizePt = 12;
94 1
        $this->underline = false;
95 1
        $this->drawColor = '0 G';
96 1
        $this->fillColor = '0 g';
97 1
        $this->textColor = '0 g';
98 1
        $this->colorFlag = false;
99 1
        $this->ws = 0;
100
        //Standard fonts
101 1
        $this->coreFonts = [
102
            'courier'=>'Courier',
103
            'courierB'=>'Courier-Bold',
104
            'courierI'=>'Courier-Oblique',
105
            'courierBI'=>'Courier-BoldOblique',
106
            'helvetica'=>'Helvetica',
107
            'helveticaB'=>'Helvetica-Bold',
108
            'helveticaI'=>'Helvetica-Oblique',
109
            'helveticaBI'=>'Helvetica-BoldOblique',
110
            'times'=>'Times-Roman',
111
            'timesB'=>'Times-Bold',
112
            'timesI'=>'Times-Italic',
113
            'timesBI'=>'Times-BoldItalic',
114
            'symbol'=>'Symbol',
115
            'zapfdingbats'=>'ZapfDingbats'
116
        ];
117
        //Scale factor
118 1
        if ($unit == 'pt') {
119
            $this->k = 1;
120 1
        } elseif ($unit == 'mm') {
121 1
            $this->k = 72/25.4;
122
        } elseif ($unit == 'cm') {
123
            $this->k = 72/2.54;
124
        } elseif ($unit == 'in') {
125
            $this->k = 72;
126
        } else {
127
            $this->error('Incorrect unit: '.$unit);
128
        }
129
        //Page format
130 1
        $this->pageFormats = array(
131
            'a3' => array(841.89,1190.55),
132
            'a4' => array(595.28,841.89),
133
            'a5' => array(420.94,595.28),
134
            'letter' => array(612,792),
135
            'legal' => array(612,1008)
136
        );
137 1
        if (is_string($format)) {
138 1
            $format = $this->getpageformat($format);
139
        }
140 1
        $this->defPageFormat = $format;
141 1
        $this->curPageFormat = $format;
142
        //Page orientation
143 1
        $orientation = strtolower($orientation);
144 1
        if ($orientation == 'p' || $orientation == 'portrait') {
145 1
            $this->defOrientation='P';
146 1
            $this->w = $this->defPageFormat[0];
147 1
            $this->h = $this->defPageFormat[1];
148
        } elseif ($orientation == 'l' || $orientation == 'landscape') {
149
            $this->defOrientation = 'L';
150
            $this->w = $this->defPageFormat[1];
151
            $this->h = $this->defPageFormat[0];
152
        } else {
153
            $this->error('Incorrect orientation: '.$orientation);
154
        }
155 1
        $this->curOrientation = $this->defOrientation;
156 1
        $this->wPt = $this->w*$this->k;
157 1
        $this->hPt = $this->h*$this->k;
158
        //Page margins (1 cm)
159 1
        $margin = 28.35/$this->k;
160 1
        $this->setMargins($margin, $margin);
161
        //Interior cell margin (1 mm)
162 1
        $this->cMargin = $margin/10;
163
        //Line width (0.2 mm)
164 1
        $this->lineWidth = .567/$this->k;
165
        //Automatic page break
166 1
        $this->setAutoPageBreak(true, 2*$margin);
167
        //Full width display mode
168 1
        $this->setDisplayMode('fullwidth');
169
        //Enable compression
170 1
        $this->setCompression(true);
171
        //Set default PDF version number
172 1
        $this->pdfVersion='1.3';
173 1
    }
174
    
175 1
    public function setMargins($left, $top, $right = null)
176
    {
177
        //Set left, top and right margins
178 1
        $this->lMargin = $left;
179 1
        $this->tMargin = $top;
180 1
        if ($right === null) {
181 1
            $right = $left;
182
        }
183 1
        $this->rMargin=$right;
184 1
    }
185
    
186
    public function setLeftMargin($margin)
187
    {
188
        //Set left margin
189
        $this->lMargin = $margin;
190
        if ($this->page>0 && $this->x<$margin) {
191
            $this->x = $margin;
192
        }
193
    }
194
    
195
    public function setTopMargin($margin)
196
    {
197
        //Set top margin
198
        $this->tMargin = $margin;
199
    }
200
    
201
    public function setRightMargin($margin)
202
    {
203
        //Set right margin
204
        $this->rMargin = $margin;
205
    }
206
    
207 1
    public function setAutoPageBreak($auto, $margin = 0)
208
    {
209
        //Set auto page break mode and triggering margin
210 1
        $this->autoPageBreak = $auto;
211 1
        $this->bMargin = $margin;
212 1
        $this->pageBreakTrigger = $this->h-$margin;
213 1
    }
214
    
215 1
    public function setDisplayMode($zoom, $layout = 'continuous')
216
    {
217
        //Set display mode in viewer
218 1
        if ($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom)) {
219 1
            $this->zoomMode = $zoom;
220
        } else {
221
            $this->error('Incorrect zoom display mode: '.$zoom);
222
        }
223 1
        if ($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default') {
224 1
            $this->layoutMode = $layout;
225
        } else {
226
            $this->error('Incorrect layout display mode: '.$layout);
227
        }
228 1
    }
229
    
230 1
    public function setCompression($compress)
231
    {
232
        //Set page compression
233 1
        if (function_exists('gzcompress')) {
234 1
            $this->compress = $compress;
235
        } else {
236
            $this->compress = false;
237
        }
238 1
    }
239
    
240
    public function setTitle($title, $isUTF8 = false)
241
    {
242
        //Title of document
243
        if ($isUTF8) {
244
            $title = $this->utf8Toutf16($title);
245
        }
246
        $this->title = $title;
247
    }
248
    
249
    public function setSubject($subject, $isUTF8 = false)
250
    {
251
        //Subject of document
252
        if ($isUTF8) {
253
            $subject = $this->utf8Toutf16($subject);
254
        }
255
        $this->subject = $subject;
256
    }
257
    
258
    public function setAuthor($author, $isUTF8 = false)
259
    {
260
        //Author of document
261
        if ($isUTF8) {
262
            $author = $this->utf8Toutf16($author);
263
        }
264
        $this->author=$author;
265
    }
266
    
267
    public function setKeywords($keywords, $isUTF8 = false)
268
    {
269
        //Keywords of document
270
        if ($isUTF8) {
271
            $keywords = $this->utf8Toutf16($keywords);
272
        }
273
        $this->keywords = $keywords;
274
    }
275
    
276
    public function setCreator($creator, $isUTF8 = false)
277
    {
278
        //Creator of document
279
        if ($isUTF8) {
280
            $creator = $this->utf8Toutf16($creator);
281
        }
282
        $this->creator = $creator;
283
    }
284
    
285 1
    public function aliasNbPages($alias = '{nb}')
286
    {
287
        //Define an alias for total number of pages
288 1
        $this->aliasNbPages=$alias;
289 1
    }
290
    
291
    public function error($msg)
292
    {
293
        throw new Exception($msg);
294
    }
295
    
296 1
    public function open()
297
    {
298 1
        $this->state = 1;
299 1
    }
300
    
301 1
    public function close()
302
    {
303
        //Terminate document
304 1
        if ($this->state == 3) {
305
            return;
306
        }
307 1
        if ($this->page == 0) {
308
            $this->addPage();
309
        }
310
        //Page footer
311 1
        $this->inFooter = true;
312 1
        $this->footer();
313 1
        $this->inFooter = false;
314
        //Close page
315 1
        $this->endPage();
316
        //Close document
317 1
        $this->endDoc();
318 1
        foreach ($this->tmpFiles as $tmp) {
319
            @unlink($tmp);
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...
320
        }
321 1
    }
322
    
323 1
    public function addPage($orientation = '', $format = '')
324
    {
325
        //Start a new page
326 1
        if ($this->state == 0) {
327
            $this->open();
328
        }
329 1
        $family = $this->fontFamily;
330 1
        $style = $this->fontStyle.($this->underline ? 'U' : '');
331 1
        $size = $this->fontSizePt;
332 1
        $lw = $this->lineWidth;
333 1
        $dc = $this->drawColor;
334 1
        $fc = $this->fillColor;
335 1
        $tc = $this->textColor;
336 1
        $cf = $this->colorFlag;
337 1
        if ($this->page > 0) {
338
            //Page footer
339
            $this->inFooter = true;
340
            $this->footer();
341
            $this->inFooter = false;
342
            //Close page
343
            $this->endPage();
344
        }
345
        //Start new page
346 1
        $this->beginPage($orientation, $format);
347
        //Set line cap style to square
348 1
        $this->out('2 J');
349
        //Set line width
350 1
        $this->lineWidth = $lw;
351 1
        $this->out(sprintf('%.2F w', $lw*$this->k));
352
        //Set font
353 1
        if ($family) {
354
            $this->setFont($family, $style, $size);
355
        }
356
        //Set colors
357 1
        $this->drawColor = $dc;
358 1
        if ($dc!='0 G') {
359 1
            $this->out($dc);
360
        }
361 1
        $this->fillColor = $fc;
362 1
        if ($fc != '0 g') {
363 1
            $this->out($fc);
364
        }
365 1
        $this->textColor = $tc;
366 1
        $this->colorFlag = $cf;
367
        //Page header
368 1
        $this->inHeader = true;
369 1
        $this->Header();
370 1
        $this->inHeader = false;
371
        //Restore line width
372 1
        if ($this->lineWidth != $lw) {
373
            $this->lineWidth = $lw;
374
            $this->out(sprintf('%.2F w', $lw*$this->k));
375
        }
376
        //Restore font
377 1
        if ($family) {
378
            $this->setFont($family, $style, $size);
379
        }
380
        //Restore colors
381 1
        if ($this->drawColor != $dc) {
382
            $this->drawColor = $dc;
383
            $this->out($dc);
384
        }
385 1
        if ($this->fillColor != $fc) {
386
            $this->fillColor = $fc;
387
            $this->out($fc);
388
        }
389 1
        $this->textColor = $tc;
390 1
        $this->colorFlag = $cf;
391 1
    }
392
    
393 1
    public function header()
394
    {
395
        //To be implemented in your own inherited class
396 1
    }
397
    
398 1
    public function footer()
399
    {
400
        //To be implemented in your own inherited class
401 1
    }
402
    
403
    public function pageNo()
404
    {
405
        //Get current page number
406
        return $this->page;
407
    }
408
    
409 1
    public function setDrawColor($r, $g = null, $b = null)
410
    {
411
        //Set color for all stroking operations
412 1
        if (($r==0 && $g==0 && $b==0) || $g===null) {
413 1
            $this->drawColor = sprintf('%.3F G', $r/255);
414
        } else {
415
            $this->drawColor = sprintf('%.3F %.3F %.3F RG', $r/255, $g/255, $b/255);
416
        }
417 1
        if ($this->page > 0) {
418
            $this->out($this->drawColor);
419
        }
420 1
    }
421
    
422 1
    public function setFillColor($r, $g = null, $b = null)
423
    {
424
        //Set color for all filling operations
425 1
        if (($r==0 && $g==0 && $b==0) || $g===null) {
426 1
            $this->fillColor = sprintf('%.3F g', $r/255);
427
        } else {
428 1
            $this->fillColor = sprintf('%.3F %.3F %.3F rg', $r/255, $g/255, $b/255);
429
        }
430 1
        $this->colorFlag = ($this->fillColor != $this->textColor);
431 1
        if ($this->page > 0) {
432 1
            $this->out($this->fillColor);
433
        }
434 1
    }
435
    
436 1
    public function settextColor($r, $g = null, $b = null)
437
    {
438
        //Set color for text
439 1
        if (($r==0 && $g==0 && $b==0) || $g===null) {
440 1
            $this->textColor = sprintf('%.3F g', $r/255);
441
        } else {
442 1
            $this->textColor = sprintf('%.3F %.3F %.3F rg', $r/255, $g/255, $b/255);
443
        }
444 1
        $this->colorFlag = ($this->fillColor != $this->textColor);
445 1
    }
446
    
447 1
    public function getStringWidth($s)
448
    {
449
        //Get width of a string in the current font
450 1
        $s = (string)$s;
451 1
        $cw =& $this->currentFont['cw'];
452 1
        $w = 0;
453 1
        $l = strlen($s);
454 1
        for ($i=0; $i<$l; $i++) {
455 1
            $w += $cw[$s[$i]];
456
        }
457 1
        return $w*$this->fontSize/1000;
458
    }
459
    
460 1
    public function setLineWidth($width)
461
    {
462
        //Set line width
463 1
        $this->lineWidth = $width;
464 1
        if ($this->page > 0) {
465 1
            $this->out(sprintf('%.2F w', $width*$this->k));
466
        }
467 1
    }
468
    
469
    public function line($x1, $y1, $x2, $y2)
470
    {
471
        //Draw a line
472
        $this->out(
473
            sprintf(
474
                '%.2F %.2F m %.2F %.2F l S',
475
                $x1*$this->k,
476
                ($this->h-$y1)*$this->k,
477
                $x2*$this->k,
478
                ($this->h-$y2)*$this->k
479
            )
480
        );
481
    }
482
    
483 1
    public function rect($x, $y, $w, $h, $style = '')
484
    {
485
        //Draw a rectangle
486 1
        if ($style == 'F') {
487 1
            $op = 'f';
488
        } elseif ($style == 'FD' || $style == 'DF') {
489
            $op = 'B';
490
        } else {
491
            $op = 'S';
492
        }
493 1
        $this->out(
494
            sprintf(
495 1
                '%.2F %.2F %.2F %.2F re %s',
496 1
                $x*$this->k,
497 1
                ($this->h-$y)*$this->k,
498 1
                $w*$this->k,
499 1
                -$h*$this->k,
500
                $op
501
            )
502
        );
503 1
    }
504
    
505
    public function addFont($family, $style = '', $file = '')
506
    {
507
        //Add a TrueType or Type1 font
508
        $family = strtolower($family);
509
        if ($file == '') {
510
            $file = str_replace(' ', '', $family).strtolower($style).'.php';
511
        }
512
        if ($family=='arial') {
513
            $family='helvetica';
514
        }
515
        $style = strtoupper($style);
516
        if ($style == 'IB') {
517
            $style = 'BI';
518
        }
519
        $fontkey = $family.$style;
520
        if (isset($this->fonts[$fontkey])) {
521
            return;
522
        }
523
        include $this->getFontPath().$file;
524
        if (!isset($name)) {
0 ignored issues
show
Bug introduced by
The variable $name seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
525
            $this->error('Could not include font definition file');
526
        }
527
        $i = count($this->fonts)+1;
528
        $this->fonts[$fontkey] = [
529
            'i'=>$i,
530
            'type'=>$type,
0 ignored issues
show
Bug introduced by
The variable $type does not exist. Did you forget to declare it?

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

Loading history...
531
            'name'=>$name,
0 ignored issues
show
Bug introduced by
The variable $name 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...
532
            'desc'=>$desc,
0 ignored issues
show
Bug introduced by
The variable $desc does not exist. Did you forget to declare it?

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

Loading history...
533
            'up'=>$up,
0 ignored issues
show
Bug introduced by
The variable $up does not exist. Did you forget to declare it?

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

Loading history...
534
            'ut'=>$ut,
0 ignored issues
show
Bug introduced by
The variable $ut does not exist. Did you forget to declare it?

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

Loading history...
535
            'cw'=>$cw,
0 ignored issues
show
Bug introduced by
The variable $cw does not exist. Did you forget to declare it?

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

Loading history...
536
            'enc'=>$enc,
0 ignored issues
show
Bug introduced by
The variable $enc does not exist. Did you forget to declare it?

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

Loading history...
537
            'file'=>$file
538
        ];
539
        if ($diff) {
540
            //Search existing encodings
541
            $d = 0;
542
            $nb = count($this->diffs);
543
            for ($i=1; $i<=$nb; $i++) {
544
                if ($this->diffs[$i] == $diff) {
0 ignored issues
show
Bug introduced by
The variable $diff does not exist. Did you forget to declare it?

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

Loading history...
545
                    $d = $i;
546
                    break;
547
                }
548
            }
549
            if ($d == 0) {
550
                $d = $nb+1;
551
                $this->diffs[$d] = $diff;
552
            }
553
            $this->fonts[$fontkey]['diff'] = $d;
554
        }
555
        if ($file) {
556
            if ($type=='TrueType') {
557
                $this->fontFiles[$file] = array('length1'=>$originalsize);
0 ignored issues
show
Bug introduced by
The variable $originalsize does not exist. Did you forget to declare it?

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

Loading history...
558
            } else {
559
                $this->fontFiles[$file] = array('length1'=>$size1, 'length2'=>$size2);
0 ignored issues
show
Bug introduced by
The variable $size1 does not exist. Did you forget to declare it?

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

Loading history...
Bug introduced by
The variable $size2 does not exist. Did you forget to declare it?

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

Loading history...
560
            }
561
        }
562
    }
563
    
564 1
    public function setFont($family, $style = '', $size = 0)
565
    {
566
        //Select a font; size given in points
567 1
        global $fpdf_charwidths;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
568 1
        $family = strtolower($family);
569 1
        if ($family == '') {
570
            $family = $this->fontFamily;
571
        }
572 1
        if ($family == 'arial') {
573
            $family = 'helvetica';
574 1
        } elseif ($family == 'symbol' || $family == 'zapfdingbats') {
575
            $style = '';
576
        }
577 1
        $style = strtoupper($style);
578 1
        if (strpos($style, 'U') !== false) {
579
            $this->underline = true;
580
            $style = str_replace('U', '', $style);
581
        } else {
582 1
            $this->underline = false;
583
        }
584 1
        if ($style == 'IB') {
585
            $style = 'BI';
586
        }
587 1
        if ($size == 0) {
588
            $size = $this->fontSizePt;
589
        }
590
        //Test if font is already selected
591 1
        if ($this->fontFamily==$family && $this->fontStyle==$style && $this->fontSizePt==$size) {
592 1
            return;
593
        }
594
        //Test if used for the first time
595 1
        $fontkey = $family.$style;
596 1
        if (!isset($this->fonts[$fontkey])) {
597
            //Check if one of the standard fonts
598 1
            if (isset($this->coreFonts[$fontkey])) {
599 1
                if (!isset($fpdf_charwidths[$fontkey])) {
600
                    //Load metric file
601 1
                    $file=$family;
602 1
                    if ($family=='times' || $family=='helvetica') {
603 1
                        $file .= strtolower($style);
604
                    }
605 1
                    include $this->getFontPath().$file.'.php';
606 1
                    if (!isset($fpdf_charwidths[$fontkey])) {
607
                        $this->error('Could not include font metric file');
608
                    }
609
                }
610 1
                $i = count($this->fonts)+1;
611 1
                $name = $this->coreFonts[$fontkey];
612 1
                $cw = $fpdf_charwidths[$fontkey];
613 1
                $this->fonts[$fontkey] = ['i'=>$i, 'type'=>'core', 'name'=>$name, 'up'=>-100, 'ut'=>50, 'cw'=>$cw];
614
            } else {
615
                $this->error('Undefined font: '.$family.' '.$style);
616
            }
617
        }
618
        //Select it
619 1
        $this->fontFamily = $family;
620 1
        $this->fontStyle = $style;
621 1
        $this->fontSizePt = $size;
622 1
        $this->fontSize = $size/$this->k;
623 1
        $this->currentFont =& $this->fonts[$fontkey];
624 1
        if ($this->page > 0) {
625 1
            $this->out(sprintf('BT /F%d %.2F Tf ET', $this->currentFont['i'], $this->fontSizePt));
626
        }
627 1
    }
628
    
629
    public function setFontSize($size)
630
    {
631
        //Set font size in points
632
        if ($this->fontSizePt == $size) {
633
            return;
634
        }
635
        $this->fontSizePt = $size;
636
        $this->fontSize = $size/$this->k;
637
        if ($this->page > 0) {
638
            $this->out(sprintf('BT /F%d %.2F Tf ET', $this->currentFont['i'], $this->fontSizePt));
639
        }
640
    }
641
    
642
    public function addlink()
643
    {
644
        //Create a new internal link
645
        $n = count($this->links)+1;
646
        $this->links[$n] = array(0, 0);
647
        return $n;
648
    }
649
    
650
    public function setlink($link, $y = 0, $page = -1)
651
    {
652
        //Set destination of internal link
653
        if ($y == -1) {
654
            $y = $this->y;
655
        }
656
        if ($page == -1) {
657
            $page = $this->page;
658
        }
659
        $this->links[$link] = array($page, $y);
660
    }
661
    
662
    public function link($x, $y, $w, $h, $link)
663
    {
664
        //Put a link on the page
665
        $this->PageLinks[$this->page][] = [
666
            $x*$this->k,
667
            $this->hPt-$y*$this->k,
668
            $w*$this->k,
669
            $h*$this->k,
670
            $link
671
        ];
672
    }
673
    
674 1
    public function text($x, $y, $txt)
675
    {
676
        //Output a string
677 1
        $s = sprintf('BT %.2F %.2F Td (%s) Tj ET', $x*$this->k, ($this->h-$y)*$this->k, $this->escape($txt));
678 1
        if ($this->underline && $txt!='') {
679
            $s .= ' '.$this->doUnderLine($x, $y, $txt);
680
        }
681 1
        if ($this->colorFlag) {
682 1
            $s = 'q '.$this->textColor.' '.$s.' Q';
683
        }
684 1
        $this->out($s);
685 1
    }
686
    
687
    public function acceptPageBreak()
688
    {
689
        //Accept automatic page break or not
690
        return $this->autoPageBreak;
691
    }
692
    
693
    public function cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = false, $link = '')
694
    {
695
        //Output a cell
696
        $k = $this->k;
697
        if ($this->y+$h > $this->pageBreakTrigger
698
            && !$this->InHeader
0 ignored issues
show
Bug introduced by
The property InHeader does not seem to exist. Did you mean inHeader?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
699
            && !$this->InFooter
0 ignored issues
show
Bug introduced by
The property InFooter does not seem to exist. Did you mean inFooter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
700
            && $this->acceptPageBreak()
701
        ) {
702
            //Automatic page break
703
            $x = $this->x;
704
            $ws = $this->ws;
705
            if ($ws > 0) {
706
                $this->ws = 0;
707
                $this->out('0 Tw');
708
            }
709
            $this->addPage($this->curOrientation, $this->curPageFormat);
0 ignored issues
show
Documentation introduced by
$this->curPageFormat is of type array<integer,integer|do...,"1":"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...
710
            $this->x = $x;
711
            if ($ws > 0) {
712
                $this->ws = $ws;
713
                $this->out(sprintf('%.3F Tw', $ws*$k));
714
            }
715
        }
716
        if ($w == 0) {
717
            $w = $this->w-$this->rMargin-$this->x;
718
        }
719
        $s='';
720
        if ($fill || $border==1) {
721
            if ($fill) {
722
                $op=($border==1) ? 'B' : 'f';
723
            } else {
724
                $op='S';
725
            }
726
            $s=sprintf('%.2F %.2F %.2F %.2F re %s ', $this->x*$k, ($this->h-$this->y)*$k, $w*$k, -$h*$k, $op);
727
        }
728
        if (is_string($border)) {
729
            $x = $this->x;
730
            $y = $this->y;
731
            if (strpos($border, 'L') !== false) {
732
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x*$k, ($this->h-$y)*$k, $x*$k, ($this->h-($y+$h))*$k);
733
            }
734
            if (strpos($border, 'T') !== false) {
735
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x*$k, ($this->h-$y)*$k, ($x+$w)*$k, ($this->h-$y)*$k);
736
            }
737
            if (strpos($border, 'R') !== false) {
738
                $s .= sprintf(
739
                    '%.2F %.2F m %.2F %.2F l S ',
740
                    ($x+$w)*$k,
741
                    ($this->h-$y)*$k,
742
                    ($x+$w)*$k,
743
                    ($this->h-($y+$h))*$k
744
                );
745
            }
746
            if (strpos($border, 'B') !== false) {
747
                $s .= sprintf(
748
                    '%.2F %.2F m %.2F %.2F l S ',
749
                    $x*$k,
750
                    ($this->h-($y+$h))*$k,
751
                    ($x+$w)*$k,
752
                    ($this->h-($y+$h))*$k
753
                );
754
            }
755
        }
756
        if ($txt !== '') {
757
            if ($align == 'R') {
758
                $dx = $w-$this->cMargin-$this->getStringWidth($txt);
759
            } elseif ($align == 'C') {
760
                $dx = ($w-$this->getStringWidth($txt))/2;
761
            } else {
762
                $dx = $this->cMargin;
763
            }
764
            if ($this->colorFlag) {
765
                $s .= 'q '.$this->textColor.' ';
766
            }
767
            $txt2 = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt)));
768
            $s .= sprintf(
769
                'BT %.2F %.2F Td (%s) Tj ET',
770
                ($this->x+$dx)*$k,
771
                ($this->h-($this->y+.5*$h+.3*$this->fontSize))*$k,
772
                $txt2
773
            );
774
            if ($this->underline) {
775
                $s .= ' '.$this->doUnderLine($this->x+$dx, $this->y+.5*$h+.3*$this->fontSize, $txt);
776
            }
777
            if ($this->colorFlag) {
778
                $s.=' Q';
779
            }
780
            if ($link) {
781
                $this->link(
782
                    $this->x+$dx,
783
                    $this->y+.5*$h-.5*$this->fontSize,
784
                    $this->getStringWidth($txt),
785
                    $this->fontSize,
786
                    $link
787
                );
788
            }
789
        }
790
        if ($s) {
791
            $this->out($s);
792
        }
793
        $this->lasth = $h;
794
        if ($ln > 0) {
795
            //Go to next line
796
            $this->y += $h;
797
            if ($ln == 1) {
798
                $this->x = $this->lMargin;
799
            }
800
        } else {
801
            $this->x += $w;
802
        }
803
    }
804
    
805
    public function multicell($w, $h, $txt, $border = 0, $align = 'J', $fill = false)
806
    {
807
        //Output text with automatic or explicit line breaks
808
        $cw =& $this->currentFont['cw'];
809
        if ($w == 0) {
810
            $w = $this->w-$this->rMargin-$this->x;
811
        }
812
        $wmax = ($w-2*$this->cMargin)*1000/$this->fontSize;
813
        $s = str_replace("\r", '', $txt);
814
        $nb = strlen($s);
815
        if ($nb>0 && $s[$nb-1] == "\n") {
816
            $nb--;
817
        }
818
        $b = 0;
819
        if ($border) {
820
            if ($border == 1) {
821
                $border = 'LTRB';
822
                $b = 'LRT';
823
                $b2 = 'LR';
824
            } else {
825
                $b2 = '';
826
                if (strpos($border, 'L') !== false) {
827
                    $b2 .= 'L';
828
                }
829
                if (strpos($border, 'R') !== false) {
830
                    $b2 .= 'R';
831
                }
832
                $b=(strpos($border, 'T') !== false) ? $b2.'T' : $b2;
833
            }
834
        }
835
        $sep = -1;
836
        $i = 0;
837
        $j = 0;
838
        $l = 0;
839
        $ns = 0;
840
        $nl = 1;
841
        while ($i<$nb) {
842
            //Get next character
843
            $c = $s[$i];
844
            if ($c == "\n") {
845
                //Explicit line break
846
                if ($this->ws > 0) {
847
                    $this->ws = 0;
848
                    $this->out('0 Tw');
849
                }
850
                $this->cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill);
851
                $i++;
852
                $sep = -1;
853
                $j = $i;
854
                $l = 0;
855
                $ns = 0;
856
                $nl++;
857
                if ($border && $nl == 2) {
858
                    $b=$b2;
0 ignored issues
show
Bug introduced by
The variable $b2 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...
859
                }
860
                continue;
861
            }
862
            if ($c == ' ') {
863
                $sep = $i;
864
                $ls = $l;
865
                $ns++;
866
            }
867
            $l += $cw[$c];
868
            if ($l > $wmax) {
869
                //Automatic line break
870
                if ($sep == -1) {
871
                    if ($i == $j) {
872
                        $i++;
873
                    }
874
                    if ($this->ws > 0) {
875
                        $this->ws = 0;
876
                        $this->out('0 Tw');
877
                    }
878
                    $this->cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill);
879
                } else {
880
                    if ($align=='J') {
881
                        $this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->fontSize/($ns-1) : 0;
0 ignored issues
show
Bug introduced by
The variable $ls 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...
882
                        $this->out(sprintf('%.3F Tw', $this->ws*$this->k));
883
                    }
884
                    $this->cell($w, $h, substr($s, $j, $sep-$j), $b, 2, $align, $fill);
885
                    $i = $sep+1;
886
                }
887
                $sep = -1;
888
                $j = $i;
889
                $l = 0;
890
                $ns = 0;
891
                $nl++;
892
                if ($border && $nl == 2) {
893
                    $b = $b2;
894
                }
895
            } else {
896
                $i++;
897
            }
898
        }
899
        //Last chunk
900
        if ($this->ws > 0) {
901
            $this->ws = 0;
902
            $this->out('0 Tw');
903
        }
904
        if ($border && strpos($border, 'B')!==false) {
905
            $b .= 'B';
906
        }
907
        $this->cell($w, $h, substr($s, $j, $i-$j), $b, 2, $align, $fill);
908
        $this->x = $this->lMargin;
909
    }
910
    
911
    
912
    public function write($h, $txt, $link = '')
913
    {
914
        //Output text in flowing mode
915
        $cw =& $this->currentFont['cw'];
916
        $w = $this->w-$this->rMargin-$this->x;
917
        $wmax = ($w-2*$this->cMargin)*1000/$this->fontSize;
918
        $s = str_replace("\r", '', $txt);
919
        $nb = strlen($s);
920
        $sep = -1;
921
        $i = 0;
922
        $j = 0;
923
        $l = 0;
924
        $nl = 1;
925
        while ($i < $nb) {
926
            //Get next character
927
            $c=$s[$i];
928
            if ($c=="\n") {
929
                //Explicit line break
930
                $this->cell($w, $h, substr($s, $j, $i-$j), 0, 2, '', 0, $link);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
931
                $i++;
932
                $sep = -1;
933
                $j = $i;
934
                $l = 0;
935
                if ($nl == 1) {
936
                    $this->x = $this->lMargin;
937
                    $w = $this->w-$this->rMargin-$this->x;
938
                    $wmax = ($w-2*$this->cMargin)*1000/$this->fontSize;
939
                }
940
                $nl++;
941
                continue;
942
            }
943
            if ($c == ' ') {
944
                $sep = $i;
945
            }
946
            $l += $cw[$c];
947
            if ($l > $wmax) {
948
                //Automatic line break
949
                if ($sep == -1) {
950
                    if ($this->x > $this->lMargin) {
951
                        //Move to next line
952
                        $this->x = $this->lMargin;
953
                        $this->y += $h;
954
                        $w = $this->w-$this->rMargin-$this->x;
955
                        $wmax = ($w-2*$this->cMargin)*1000/$this->fontSize;
956
                        $i++;
957
                        $nl++;
958
                        continue;
959
                    }
960
                    if ($i == $j) {
961
                        $i++;
962
                    }
963
                    $this->cell($w, $h, substr($s, $j, $i-$j), 0, 2, '', 0, $link);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
964
                } else {
965
                    $this->cell($w, $h, substr($s, $j, $sep-$j), 0, 2, '', 0, $link);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
966
                    $i = $sep+1;
967
                }
968
                $sep = -1;
969
                $j = $i;
970
                $l = 0;
971
                if ($nl == 1) {
972
                    $this->x = $this->lMargin;
973
                    $w = $this->w-$this->rMargin-$this->x;
974
                    $wmax = ($w-2*$this->cMargin)*1000/$this->fontSize;
975
                }
976
                $nl++;
977
            } else {
978
                $i++;
979
            }
980
        }
981
        //Last chunk
982
        if ($i != $j) {
983
            $this->cell($l/1000*$this->fontSize, $h, substr($s, $j), 0, 0, '', 0, $link);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
984
        }
985
    }
986
    
987
    public function ln($h = null)
988
    {
989
        //Line feed; default value is last cell height
990
        $this->x = $this->lMargin;
991
        if ($h === null) {
992
            $this->y += $this->lasth;
993
        } else {
994
            $this->y += $h;
995
        }
996
    }
997
    
998
    public function image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '', $mask = false, $img = 0)
999
    {
1000
        //Put an image on the page
1001
        if (!isset($this->images[$file])) {
1002
            //First use of this image, get info
1003
            if ($type == '') {
1004
                $pos = strrpos($file, '.');
1005
                if (!$pos) {
1006
                    $this->error('Image file has no extension and no type was specified: '.$file);
1007
                }
1008
                $type = substr($file, $pos+1);
1009
            }
1010
            $type = strtolower($type);
1011
            if ($type == 'png') {
1012
                $info = $this->parsePNG($file);
1013
                if ($info == 'alpha') {
1014
                    return $this->imagePngWithAlpha($file, $x, $y, $w, $h, $link);
1015
                }
1016
            } else {
1017
                if ($type == 'jpeg') {
1018
                    $type = 'jpg';
1019
                }
1020
                $mtd = 'parse'.strtoupper($type);
1021
                if (!method_exists($this, $mtd)) {
1022
                    $this->error('Unsupported image type: '.$type);
1023
                }
1024
                $info = $this->$mtd($file);
1025
            }
1026
            if ($mask) {
1027
                if (in_array($file, $this->tmpFiles)) {
1028
                    $info['cs'] = 'DeviceGray'; //hack necessary as GD can't produce gray scale images
1029
                }
1030
                if ($info['cs'] != 'DeviceGray') {
1031
                    $this->error('Mask must be a gray scale image');
1032
                }
1033
                if ($this->pdfVersion < '1.4') {
1034
                    $this->pdfVersion = '1.4';
1035
                }
1036
            }
1037
            $info['i'] = count($this->images)+1;
1038
            if ($img > 0) {
1039
                $info['masked'] = $img;
1040
            }
1041
            $this->images[$file] = $info;
1042
        } else {
1043
            $info = $this->images[$file];
1044
        }
1045
        //Automatic width and height calculation if needed
1046
        if ($w == 0 && $h == 0) {
1047
            //Put image at 72 dpi
1048
            $w = $info['w']/$this->k;
1049
            $h = $info['h']/$this->k;
1050
        } elseif ($w == 0) {
1051
            $w = $h*$info['w']/$info['h'];
1052
        } elseif ($h == 0) {
1053
            $h = $w*$info['h']/$info['w'];
1054
        }
1055
        //Flowing mode
1056
        if ($y === null) {
1057
            if ($this->y+$h > $this->pageBreakTrigger
1058
                && !$this->inHeader
1059
                && !$this->inFooter
1060
                && $this->acceptPageBreak()
1061
            ) {
1062
                //Automatic page break
1063
                $x2 = $this->x;
1064
                $this->addPage($this->curOrientation, $this->curPageFormat);
0 ignored issues
show
Documentation introduced by
$this->curPageFormat is of type array<integer,integer|do...,"1":"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...
1065
                $this->x = $x2;
1066
            }
1067
            $y = $this->y;
1068
            $this->y += $h;
1069
        }
1070
        if ($x === null) {
1071
            $x = $this->x;
1072
        }
1073
        if (!$mask) {
1074
            $this->out(
1075
                sprintf(
1076
                    'q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',
1077
                    $w*$this->k,
1078
                    $h*$this->k,
1079
                    $x*$this->k,
1080
                    ($this->h-($y+$h))*$this->k,
1081
                    $info['i']
1082
                )
1083
            );
1084
        }
1085
        if ($link) {
1086
            $this->link($x, $y, $w, $h, $link);
1087
        }
1088
        return $info['i'];
1089
    }
1090
    
1091
    
1092
    public function getX()
1093
    {
1094
        //Get x position
1095
        return $this->x;
1096
    }
1097
    
1098
    
1099
    public function setX($x)
1100
    {
1101
        //Set x position
1102
        if ($x >= 0) {
1103
            $this->x = $x;
1104
        } else {
1105
            $this->x = $this->w+$x;
1106
        }
1107
    }
1108
    
1109
    
1110
    public function getY()
1111
    {
1112
        //Get y position
1113
        return $this->y;
1114
    }
1115
    
1116
    
1117
    public function setY($y)
1118
    {
1119
        //Set y position and reset x
1120
        $this->x = $this->lMargin;
1121
        if ($y >= 0) {
1122
            $this->y = $y;
1123
        } else {
1124
            $this->y = $this->h+$y;
1125
        }
1126
    }
1127
    
1128
    
1129
    public function setXY($x, $y)
1130
    {
1131
        //Set x and y positions
1132
        $this->setY($y);
1133
        $this->setX($x);
1134
    }
1135
    
1136
    public function getPdf()
1137
    {
1138
        if ($this->state < 3) {
1139
            $this->close();
1140
        }
1141
        return $this->buffer;
1142
    }
1143
    
1144 1
    public function output($name = '', $dest = '')
1145
    {
1146
        //Output PDF to some destination
1147 1
        if ($this->state < 3) {
1148 1
            $this->close();
1149
        }
1150 1
        $dest = strtoupper($dest);
1151 1
        if ($dest == '') {
1152
            if ($name == '') {
1153
                $name = 'doc.pdf';
1154
                $dest = 'I';
1155
            } else {
1156
                $dest = 'F';
1157
            }
1158
        }
1159
        switch ($dest) {
1160 1
            case 'I':
1161
                //Send to standard output
1162
                if (ob_get_length()) {
1163
                    $this->error('Some data has already been output, can\'t send PDF file');
1164
                }
1165
                if (php_sapi_name() != 'cli') {
1166
                    //We send to a browser
1167
                    header('Content-Type: application/pdf');
1168
                    if (headers_sent()) {
1169
                        $this->error('Some data has already been output, can\'t send PDF file');
1170
                    }
1171
                    header('Content-Length: '.strlen($this->buffer));
1172
                    header('Content-Disposition: inline; filename="'.$name.'"');
1173
                    header('Cache-Control: private, max-age=0, must-revalidate');
1174
                    header('Pragma: public');
1175
                    ini_set('zlib.output_compression', '0');
1176
                }
1177
                echo $this->buffer;
1178
                break;
1179 1
            case 'D':
1180
                //Download file
1181
                if (ob_get_length()) {
1182
                    $this->error('Some data has already been output, can\'t send PDF file');
1183
                }
1184
                header('Content-Type: application/x-download');
1185
                if (headers_sent()) {
1186
                    $this->error('Some data has already been output, can\'t send PDF file');
1187
                }
1188
                header('Content-Length: '.strlen($this->buffer));
1189
                header('Content-Disposition: attachment; filename="'.$name.'"');
1190
                header('Cache-Control: private, max-age=0, must-revalidate');
1191
                header('Pragma: public');
1192
                ini_set('zlib.output_compression', '0');
1193
                echo $this->buffer;
1194
                break;
1195 1
            case 'F':
1196
                //Save to local file
1197 1
                $f=fopen($name, 'wb');
1198 1
                if (!$f) {
1199
                    $this->error('Unable to create output file: '.$name);
1200
                }
1201 1
                fwrite($f, $this->buffer, strlen($this->buffer));
1202 1
                fclose($f);
1203 1
                break;
1204
            case 'S':
1205
                //Return as a string
1206
                return $this->buffer;
1207
            default:
1208
                $this->error('Incorrect output destination: '.$dest);
1209
        }
1210 1
        return '';
1211
    }
1212
    
1213
    
1214 1
    protected function dochecks()
1215
    {
1216
        //Check availability of %F
1217 1
        if (sprintf('%.1F', 1.0)!='1.0') {
1218
            $this->error('This version of PHP is not supported');
1219
        }
1220
        //Check mbstring overloading
1221 1
        if (ini_get('mbstring.func_overload') & 2) {
1222
            $this->error('mbstring overloading must be disabled');
1223
        }
1224 1
    }
1225
    
1226
    
1227 1
    protected function getpageformat($format)
1228
    {
1229 1
        $format=strtolower($format);
1230 1
        if (!isset($this->pageFormats[$format])) {
1231
            $this->error('Unknown page format: '.$format);
1232
        }
1233 1
        $a=$this->pageFormats[$format];
1234 1
        return array($a[0]/$this->k, $a[1]/$this->k);
1235
    }
1236
    
1237
    
1238 1
    protected function getFontPath()
1239
    {
1240 1
        if (!defined('FPDF_FONTPATH') && is_dir(dirname(__FILE__).'/font')) {
1241
            define('FPDF_FONTPATH', dirname(__FILE__).'/font/');
1242
        }
1243 1
        return defined('FPDF_FONTPATH') ? FPDF_FONTPATH : '';
1244
    }
1245
    
1246
    
1247 1
    protected function beginPage($orientation, $format)
1248
    {
1249 1
        $this->page++;
1250 1
        $this->pages[$this->page] = '';
1251 1
        $this->state = 2;
1252 1
        $this->x = $this->lMargin;
1253 1
        $this->y = $this->tMargin;
1254 1
        $this->fontFamily = '';
1255
        //Check page size
1256 1
        if ($orientation == '') {
1257
            $orientation = $this->defOrientation;
1258
        } else {
1259 1
            $orientation = strtoupper($orientation[0]);
1260
        }
1261 1
        if ($format == '') {
1262
            $format = $this->defPageFormat;
1263
        } else {
1264 1
            if (is_string($format)) {
1265 1
                $format=$this->getpageformat($format);
1266
            }
1267
        }
1268 1
        if ($orientation != $this->curOrientation
1269 1
            || $format[0]!=$this->curPageFormat[0]
1270 1
            || $format[1]!=$this->curPageFormat[1]
1271
        ) {
1272
            //New size
1273
            if ($orientation == 'P') {
1274
                $this->w = $format[0];
1275
                $this->h = $format[1];
1276
            } else {
1277
                $this->w = $format[1];
1278
                $this->h = $format[0];
1279
            }
1280
            $this->wPt = $this->w*$this->k;
1281
            $this->hPt = $this->h*$this->k;
1282
            $this->pageBreakTrigger = $this->h-$this->bMargin;
1283
            $this->curOrientation = $orientation;
1284
            $this->curPageFormat = $format;
1285
        }
1286 1
        if ($orientation != $this->defOrientation
1287 1
            || $format[0] != $this->defPageFormat[0]
1288 1
            || $format[1] != $this->defPageFormat[1]
1289
        ) {
1290
            $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
0 ignored issues
show
Bug introduced by
The property PageSizes does not seem to exist. Did you mean pageSizes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1291
        }
1292 1
    }
1293
    
1294
    
1295 1
    protected function endPage()
1296
    {
1297 1
        $this->state = 1;
1298 1
    }
1299
    
1300
    
1301 1
    protected function escape($s)
1302
    {
1303
        //Escape special characters in strings
1304 1
        $s = str_replace('\\', '\\\\', $s);
1305 1
        $s = str_replace('(', '\\(', $s);
1306 1
        $s = str_replace(')', '\\)', $s);
1307 1
        $s = str_replace("\r", '\\r', $s);
1308 1
        return $s;
1309
    }
1310
    
1311
    
1312 1
    protected function textString($s)
1313
    {
1314
        //Format a text string
1315 1
        return '('.$this->escape($s).')';
1316
    }
1317
    
1318
    
1319
    protected function utf8Toutf16($s)
1320
    {
1321
        //Convert UTF-8 to UTF-16BE with BOM
1322
        $res = "\xFE\xFF";
1323
        $nb = strlen($s);
1324
        $i = 0;
1325
        while ($i < $nb) {
1326
            $c1 = ord($s[$i++]);
1327
            if ($c1 >= 224) {
1328
                //3-byte character
1329
                $c2 = ord($s[$i++]);
1330
                $c3 = ord($s[$i++]);
1331
                $res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
1332
                $res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
1333
            } elseif ($c1 >= 192) {
1334
                //2-byte character
1335
                $c2 = ord($s[$i++]);
1336
                $res .= chr(($c1 & 0x1C)>>2);
1337
                $res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
1338
            } else {
1339
                //Single-byte character
1340
                $res .= "\0".chr($c1);
1341
            }
1342
        }
1343
        return $res;
1344
    }
1345
    
1346
    
1347
    protected function doUnderLine($x, $y, $txt)
1348
    {
1349
        //Underline text
1350
        $up = $this->currentFont['up'];
1351
        $ut = $this->currentFont['ut'];
1352
        $w = $this->getStringWidth($txt)+$this->ws*substr_count($txt, ' ');
1353
        return sprintf(
1354
            '%.2F %.2F %.2F %.2F re f',
1355
            $x*$this->k,
1356
            ($this->h-($y-$up/1000*$this->fontSize))*$this->k,
1357
            $w*$this->k,
1358
            -$ut/1000*$this->fontSizePt
1359
        );
1360
    }
1361
    
1362
    
1363
    protected function parseJPG($file)
1364
    {
1365
        //Extract info from a JPEG file
1366
        $a = getImageSize($file);
1367
        if (!$a) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $a of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1368
            $this->error('Missing or incorrect image file: '.$file);
1369
        }
1370
        if ($a[2]!=2) {
1371
            $this->error('Not a JPEG file: '.$file);
1372
        }
1373
        if (!isset($a['channels']) || $a['channels'] == 3) {
1374
            $colspace = 'DeviceRGB';
1375
        } elseif ($a['channels'] == 4) {
1376
            $colspace = 'DeviceCMYK';
1377
        } else {
1378
            $colspace='DeviceGray';
1379
        }
1380
        $bpc = isset($a['bits']) ? $a['bits'] : 8;
1381
        //Read whole file
1382
        $f = fopen($file, 'rb');
1383
        $data = '';
1384
        while (!feof($f)) {
1385
            $data .= fread($f, 8192);
1386
        }
1387
        fclose($f);
1388
        return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
1389
    }
1390
    
1391
    
1392
    // GD seems to use a different gamma, this method is used to correct it again
1393
    protected function gamma($v)
1394
    {
1395
        return pow($v/255, 2.2)*255;
1396
    }
1397
    
1398
    
1399
    protected function parsePNG($file)
1400
    {
1401
        //Extract info from a PNG file
1402
        $f = fopen($file, 'rb');
1403
        if (!$f) {
1404
            $this->error('Can\'t open image file: '.$file);
1405
        }
1406
        //Check signature
1407
        if ($this->readstream($f, 8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
1408
            $this->error('Not a PNG file: '.$file);
1409
        }
1410
        //Read header chunk
1411
        $this->readstream($f, 4);
1412
        if ($this->readstream($f, 4)!='IHDR') {
1413
            $this->error('Incorrect PNG file: '.$file);
1414
        }
1415
        $w = $this->readint($f);
1416
        $h = $this->readint($f);
1417
        $bpc = ord($this->readstream($f, 1));
1418
        if ($bpc>8) {
1419
            $this->error('16-bit depth not supported: '.$file);
1420
        }
1421
        $ct = ord($this->readstream($f, 1));
1422
        if ($ct == 0) {
1423
            $colspace = 'DeviceGray';
1424
        } elseif ($ct == 2) {
1425
            $colspace = 'DeviceRGB';
1426
        } elseif ($ct == 3) {
1427
            $colspace = 'Indexed';
1428
        } else {
1429
            fclose($f);
1430
            return 'alpha';
1431
        }
1432
        if (ord($this->readstream($f, 1)) != 0) {
1433
            $this->error('Unknown compression method: '.$file);
1434
        }
1435
        if (ord($this->readstream($f, 1)) != 0) {
1436
            $this->error('Unknown filter method: '.$file);
1437
        }
1438
        if (ord($this->readstream($f, 1)) != 0) {
1439
            $this->error('Interlacing not supported: '.$file);
1440
        }
1441
        $this->readstream($f, 4);
1442
        $parms = '/DecodeParms <</Predictor 15 /Colors '
1443
            . ($ct==2 ? 3 : 1)
1444
            . ' /BitsPerComponent '
1445
            . $bpc
1446
            . ' /Columns '
1447
            . $w
1448
            . '>>';
1449
        //Scan chunks looking for palette, transparency and image data
1450
        $pal = '';
1451
        $trns = '';
1452
        $data = '';
1453
        do {
1454
            $n = $this->readint($f);
1455
            $type = $this->readstream($f, 4);
1456
            if ($type == 'PLTE') {
1457
                //Read palette
1458
                $pal = $this->readstream($f, $n);
1459
                $this->readstream($f, 4);
1460
            } elseif ($type == 'tRNS') {
1461
                //Read transparency info
1462
                $t = $this->readstream($f, $n);
1463
                if ($ct == 0) {
1464
                    $trns = array(ord(substr($t, 1, 1)));
1465
                } elseif ($ct == 2) {
1466
                    $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1)));
1467
                } else {
1468
                    $pos = strpos($t, chr(0));
1469
                    if ($pos !== false) {
1470
                        $trns = array($pos);
1471
                    }
1472
                }
1473
                $this->readstream($f, 4);
1474
            } elseif ($type == 'IDAT') {
1475
                //Read image data block
1476
                $data .= $this->readstream($f, $n);
1477
                $this->readstream($f, 4);
1478
            } elseif ($type == 'IEND') {
1479
                break;
1480
            } else {
1481
                $this->readstream($f, $n+4);
1482
            }
1483
        } while ($n);
1484
        if ($colspace == 'Indexed' && empty($pal)) {
1485
            $this->error('Missing palette in '.$file);
1486
        }
1487
        fclose($f);
1488
        return [
1489
            'w'=>$w,
1490
            'h'=>$h,
1491
            'cs'=>$colspace,
1492
            'bpc'=>$bpc,
1493
            'f'=>'FlateDecode',
1494
            'parms'=>$parms,
1495
            'pal'=>$pal,
1496
            'trns'=>$trns,
1497
            'data'=>$data
1498
        ];
1499
    }
1500
    
1501
    
1502
    protected function readstream($f, $n)
1503
    {
1504
        //Read n bytes from stream
1505
        $res='';
1506
        while ($n > 0 && !feof($f)) {
1507
            $s=fread($f, $n);
1508
            if ($s === false) {
1509
                $this->error('Error while reading stream');
1510
            }
1511
            $n -= strlen($s);
1512
            $res .= $s;
1513
        }
1514
        if ($n > 0) {
1515
            $this->error('Unexpected end of stream');
1516
        }
1517
        return $res;
1518
    }
1519
    
1520
    
1521
    protected function readint($f)
1522
    {
1523
        //Read a 4-byte integer from stream
1524
        $a = unpack('Ni', $this->readstream($f, 4));
1525
        return $a['i'];
1526
    }
1527
    
1528
    
1529
    protected function parseGIF($file)
1530
    {
1531
        //Extract info from a GIF file (via PNG conversion)
1532
        if (!function_exists('imagepng')) {
1533
            $this->error('GD extension is required for GIF support');
1534
        }
1535
        if (!function_exists('imagecreatefromgif')) {
1536
            $this->error('GD has no GIF read support');
1537
        }
1538
        $im = imagecreatefromgif($file);
1539
        if (!$im) {
1540
            $this->error('Missing or incorrect image file: '.$file);
1541
        }
1542
        imageinterlace($im, 0);
1543
        $tmp = tempnam('.', 'gif');
1544
        if (!$tmp) {
1545
            $this->error('Unable to create a temporary file');
1546
        }
1547
        if (!imagepng($im, $tmp)) {
1548
            $this->error('Error while saving to temporary file');
1549
        }
1550
        imagedestroy($im);
1551
        $info=$this->parsePNG($tmp);
1552
        unlink($tmp);
1553
        return $info;
1554
    }
1555
    
1556
    
1557 1
    protected function newObj()
1558
    {
1559
        //Begin a new object
1560 1
        $this->n++;
1561 1
        $this->offsets[$this->n] = strlen($this->buffer);
1562 1
        $this->out($this->n.' 0 obj');
1563 1
    }
1564
    
1565
    
1566 1
    protected function putStream($s)
1567
    {
1568 1
        $this->out('stream');
1569 1
        $this->out($s);
1570 1
        $this->out('endstream');
1571 1
    }
1572
    
1573
    
1574 1
    protected function out($s)
1575
    {
1576
        //Add a line to the document
1577 1
        if ($this->state == 2) {
1578 1
            $this->pages[$this->page].=$s."\n";
1579
        } else {
1580 1
            $this->buffer .= $s."\n";
1581
        }
1582 1
    }
1583
    
1584
    
1585 1
    protected function putPages()
1586
    {
1587 1
        $nb = $this->page;
1588 1
        if (!empty($this->aliasNbPages)) {
1589
            //Replace number of pages
1590 1
            for ($n=1; $n<=$nb; $n++) {
1591 1
                $this->pages[$n] = str_replace($this->aliasNbPages, $nb, $this->pages[$n]);
1592
            }
1593
        }
1594 1
        if ($this->defOrientation == 'P') {
1595 1
            $wPt = $this->defPageFormat[0]*$this->k;
1596 1
            $hPt = $this->defPageFormat[1]*$this->k;
1597
        } else {
1598
            $wPt = $this->defPageFormat[1]*$this->k;
1599
            $hPt = $this->defPageFormat[0]*$this->k;
1600
        }
1601 1
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
1602 1
        for ($n=1; $n<=$nb; $n++) {
1603
            //Page
1604 1
            $this->newObj();
1605 1
            $this->out('<</Type /Page');
1606 1
            $this->out('/Parent 1 0 R');
1607 1
            if (isset($this->PageSizes[$n])) {
0 ignored issues
show
Bug introduced by
The property PageSizes does not seem to exist. Did you mean pageSizes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1608
                $this->out(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->PageSizes[$n][0], $this->PageSizes[$n][1]));
0 ignored issues
show
Bug introduced by
The property PageSizes does not seem to exist. Did you mean pageSizes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1609
            }
1610 1
            $this->out('/Resources 2 0 R');
1611 1
            if (isset($this->PageLinks[$n])) {
1612
                //Links
1613
                $annots = '/Annots [';
1614
                foreach ($this->PageLinks[$n] as $pl) {
1615
                    $rect = sprintf('%.2F %.2F %.2F %.2F', $pl[0], $pl[1], $pl[0]+$pl[2], $pl[1]-$pl[3]);
1616
                    $annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
1617
                    if (is_string($pl[4])) {
1618
                        $annots .= '/A <</S /URI /URI '.$this->textString($pl[4]).'>>>>';
1619
                    } else {
1620
                        $l = $this->links[$pl[4]];
1621
                        $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt;
0 ignored issues
show
Bug introduced by
The property PageSizes does not seem to exist. Did you mean pageSizes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1622
                        $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>', 1+2*$l[0], $h-$l[1]*$this->k);
1623
                    }
1624
                }
1625
                $this->out($annots.']');
1626
            }
1627 1
            $this->out('/Contents '.($this->n+1).' 0 R>>');
1628 1
            $this->out('endobj');
1629
            //Page content
1630 1
            $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
1631 1
            $this->newObj();
1632 1
            $this->out('<<'.$filter.'/Length '.strlen($p).'>>');
1633 1
            $this->putStream($p);
1634 1
            $this->out('endobj');
1635
        }
1636
        //Pages root
1637 1
        $this->offsets[1]=strlen($this->buffer);
1638 1
        $this->out('1 0 obj');
1639 1
        $this->out('<</Type /Pages');
1640 1
        $kids = '/Kids [';
1641 1
        for ($i=0; $i<$nb; $i++) {
1642 1
            $kids .= (3+2*$i).' 0 R ';
1643
        }
1644 1
        $this->out($kids.']');
1645 1
        $this->out('/Count '.$nb);
1646 1
        $this->out(sprintf('/MediaBox [0 0 %.2F %.2F]', $wPt, $hPt));
1647 1
        $this->out('>>');
1648 1
        $this->out('endobj');
1649 1
    }
1650
    
1651
    
1652 1
    protected function putFonts()
1653
    {
1654 1
        $nf = $this->n;
1655 1
        foreach ($this->diffs as $diff) {
1656
            //Encodings
1657
            $this->newObj();
1658
            $this->out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.']>>');
1659
            $this->out('endobj');
1660
        }
1661 1
        foreach ($this->fontFiles as $file => $info) {
1662
            //Font file embedding
1663
            $this->newObj();
1664
            $this->fontFiles[$file]['n']=$this->n;
1665
            $font='';
1666
            $f = fopen($this->getFontPath().$file, 'rb', 1);
1667
            if (!$f) {
1668
                $this->error('Font file not found');
1669
            }
1670
            while (!feof($f)) {
1671
                $font.=fread($f, 8192);
1672
            }
1673
            fclose($f);
1674
            $compressed = (substr($file, -2)=='.z');
1675
            if (!$compressed && isset($info['length2'])) {
1676
                $header = (ord($font[0])==128);
1677
                if ($header) {
1678
                    //Strip first binary header
1679
                    $font = substr($font, 6);
1680
                }
1681
                if ($header && ord($font[$info['length1']]) == 128) {
1682
                    //Strip second binary header
1683
                    $font = substr($font, 0, $info['length1']).substr($font, $info['length1']+6);
1684
                }
1685
            }
1686
            $this->out('<</Length '.strlen($font));
1687
            if ($compressed) {
1688
                $this->out('/Filter /FlateDecode');
1689
            }
1690
            $this->out('/Length1 '.$info['length1']);
1691
            if (isset($info['length2'])) {
1692
                $this->out('/Length2 '.$info['length2'].' /Length3 0');
1693
            }
1694
            $this->out('>>');
1695
            $this->putStream($font);
1696
            $this->out('endobj');
1697
        }
1698 1
        foreach ($this->fonts as $k => $font) {
1699
            //Font objects
1700 1
            $this->fonts[$k]['n']=$this->n+1;
1701 1
            $type = $font['type'];
1702 1
            $name = $font['name'];
1703 1
            if ($type == 'core') {
1704
                //Standard font
1705 1
                $this->newObj();
1706 1
                $this->out('<</Type /Font');
1707 1
                $this->out('/BaseFont /'.$name);
1708 1
                $this->out('/Subtype /Type1');
1709 1
                if ($name != 'Symbol' && $name != 'ZapfDingbats') {
1710 1
                    $this->out('/Encoding /WinAnsiEncoding');
1711
                }
1712 1
                $this->out('>>');
1713 1
                $this->out('endobj');
1714
            } elseif ($type=='Type1' || $type=='TrueType') {
1715
                //Additional Type1 or TrueType font
1716
                $this->newObj();
1717
                $this->out('<</Type /Font');
1718
                $this->out('/BaseFont /'.$name);
1719
                $this->out('/Subtype /'.$type);
1720
                $this->out('/FirstChar 32 /LastChar 255');
1721
                $this->out('/Widths '.($this->n+1).' 0 R');
1722
                $this->out('/FontDescriptor '.($this->n+2).' 0 R');
1723
                if ($font['enc']) {
1724
                    if (isset($font['diff'])) {
1725
                        $this->out('/Encoding '.($nf+$font['diff']).' 0 R');
1726
                    } else {
1727
                        $this->out('/Encoding /WinAnsiEncoding');
1728
                    }
1729
                }
1730
                $this->out('>>');
1731
                $this->out('endobj');
1732
                //Widths
1733
                $this->newObj();
1734
                $cw =& $font['cw'];
1735
                $s = '[';
1736
                for ($i=32; $i<=255; $i++) {
1737
                    $s .= $cw[chr($i)].' ';
1738
                }
1739
                $this->out($s.']');
1740
                $this->out('endobj');
1741
                //Descriptor
1742
                $this->newObj();
1743
                $s='<</Type /FontDescriptor /FontName /'.$name;
1744
                foreach ($font['desc'] as $k => $v) {
1745
                    $s .= ' /'.$k.' '.$v;
1746
                }
1747
                $file=$font['file'];
1748
                if ($file) {
1749
                    $s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->fontFiles[$file]['n'].' 0 R';
1750
                }
1751
                $this->out($s.'>>');
1752
                $this->out('endobj');
1753
            } else {
1754
                //Allow for additional types
1755
                $mtd='_put'.strtolower($type);
1756
                if (!method_exists($this, $mtd)) {
1757
                    $this->error('Unsupported font type: '.$type);
1758
                }
1759 1
                $this->$mtd($font);
1760
            }
1761
        }
1762 1
    }
1763
    
1764
    
1765
    // needs GD 2.x extension
1766
    // pixel-wise operation, not very fast
1767
    protected function imagePngWithAlpha($file, $x, $y, $w = 0, $h = 0, $link = '')
1768
    {
1769
        $tmp_alpha = tempnam('.', 'mska');
1770
        $this->tmpFiles[] = $tmp_alpha;
1771
        $tmp_plain = tempnam('.', 'mskp');
1772
        $this->tmpFiles[] = $tmp_plain;
1773
        list($wpx, $hpx) = getimagesize($file);
1774
        $img = imagecreatefrompng($file);
1775
        $alpha_img = imagecreate($wpx, $hpx);
1776
        // generate gray scale pallete
1777
        for ($c=0; $c<256; $c++) {
1778
            ImageColorAllocate($alpha_img, $c, $c, $c);
1779
        }
1780
        // extract alpha channel
1781
        $xpx = 0;
1782
        while ($xpx < $wpx) {
1783
            $ypx = 0;
1784
            while ($ypx < $hpx) {
1785
                $color_index = imagecolorat($img, $xpx, $ypx);
1786
                $col = imagecolorsforindex($img, $color_index);
1787
                imagesetpixel($alpha_img, $xpx, $ypx, $this->gamma((127-$col['alpha'])*255/127));
1788
                ++$ypx;
1789
            }
1790
            ++$xpx;
1791
        }
1792
        imagepng($alpha_img, $tmp_alpha);
1793
        imagedestroy($alpha_img);
1794
        // extract image without alpha channel
1795
        $plain_img = imagecreatetruecolor($wpx, $hpx);
1796
        imagecopy($plain_img, $img, 0, 0, 0, 0, $wpx, $hpx);
1797
        imagepng($plain_img, $tmp_plain);
1798
        imagedestroy($plain_img);
1799
        //first embed mask image (w, h, x, will be ignored)
1800
        $maskImg = $this->Image($tmp_alpha, 0, 0, 0, 0, 'PNG', '', true);
1801
        //embed image, masked with previously embedded mask
1802
        $this->Image($tmp_plain, $x, $y, $w, $h, 'PNG', $link, false, $maskImg);
1803
    }
1804
    
1805
    
1806 1
    protected function putImages()
1807
    {
1808 1
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
1809 1
        reset($this->images);
1810
       
1811 1
        foreach ($this->images as $file => $info) {
1812
            $this->newObj();
1813
            $this->images[$file]['n'] = $this->n;
1814
            $this->out('<</Type /XObject');
1815
            $this->out('/Subtype /Image');
1816
            $this->out('/Width '.$info['w']);
1817
            $this->out('/Height '.$info['h']);
1818
            if (isset($info['masked'])) {
1819
                $this->out('/SMask ' . ($this->n-1) . ' 0 R');
1820
            }
1821
            if ($info['cs']=='Indexed') {
1822
                $this->out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
1823
            } else {
1824
                $this->out('/ColorSpace /'.$info['cs']);
1825
                if ($info['cs']=='DeviceCMYK') {
1826
                    $this->out('/Decode [1 0 1 0 1 0 1 0]');
1827
                }
1828
            }
1829
            $this->out('/BitsPerComponent '.$info['bpc']);
1830
            if (isset($info['f'])) {
1831
                $this->out('/Filter /'.$info['f']);
1832
            }
1833
            if (isset($info['parms'])) {
1834
                $this->out($info['parms']);
1835
            }
1836
            if (isset($info['trns']) && is_array($info['trns'])) {
1837
                $trns = '';
1838
                for ($i=0; $i<count($info['trns']); $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...
1839
                    $trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
1840
                }
1841
                $this->out('/Mask ['.$trns.']');
1842
            }
1843
            $this->out('/Length '.strlen($info['data']).'>>');
1844
            $this->putStream($info['data']);
1845
            unset($this->images[$file]['data']);
1846
            $this->out('endobj');
1847
            //Palette
1848
            if ($info['cs'] == 'Indexed') {
1849
                $this->newObj();
1850
                $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
1851
                $this->out('<<'.$filter.'/Length '.strlen($pal).'>>');
1852
                $this->putStream($pal);
1853
                $this->out('endobj');
1854
            }
1855
        }
1856 1
    }
1857
    
1858 1
    protected function putXobjectDict()
1859
    {
1860 1
        foreach ($this->images as $image) {
1861
            $this->out('/I'.$image['i'].' '.$image['n'].' 0 R');
1862
        }
1863 1
    }
1864
    
1865 1
    protected function putResourceDict()
1866
    {
1867 1
        $this->out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
1868 1
        $this->out('/Font <<');
1869 1
        foreach ($this->fonts as $font) {
1870 1
            $this->out('/F'.$font['i'].' '.$font['n'].' 0 R');
1871
        }
1872 1
        $this->out('>>');
1873 1
        $this->out('/XObject <<');
1874 1
        $this->putXobjectDict();
1875 1
        $this->out('>>');
1876 1
    }
1877
    
1878 1
    protected function putResources()
1879
    {
1880 1
        $this->putFonts();
1881 1
        $this->putImages();
1882
        //Resource dictionary
1883 1
        $this->offsets[2] = strlen($this->buffer);
1884 1
        $this->out('2 0 obj');
1885 1
        $this->out('<<');
1886 1
        $this->putResourceDict();
1887 1
        $this->out('>>');
1888 1
        $this->out('endobj');
1889 1
    }
1890
    
1891 1
    protected function putInfo()
1892
    {
1893 1
        $this->out('/Producer '.$this->textString('FPDF '. self::FPDF_VERSION));
1894 1
        if (!empty($this->title)) {
1895
            $this->out('/Title '.$this->textString($this->title));
1896
        }
1897 1
        if (!empty($this->subject)) {
1898
            $this->out('/Subject '.$this->textString($this->subject));
1899
        }
1900 1
        if (!empty($this->author)) {
1901
            $this->out('/Author '.$this->textString($this->author));
1902
        }
1903 1
        if (!empty($this->keywords)) {
1904
            $this->out('/Keywords '.$this->textString($this->keywords));
1905
        }
1906 1
        if (!empty($this->creator)) {
1907
            $this->out('/Creator '.$this->textString($this->creator));
1908
        }
1909 1
        $this->out('/CreationDate '.$this->textString('D:'.@date('YmdHis')));
1910 1
    }
1911
    
1912 1
    protected function putCatalog()
1913
    {
1914 1
        $this->out('/Type /Catalog');
1915 1
        $this->out('/Pages 1 0 R');
1916 1
        if ($this->zoomMode=='fullpage') {
1917
            $this->out('/OpenAction [3 0 R /Fit]');
1918 1
        } elseif ($this->zoomMode=='fullwidth') {
1919 1
            $this->out('/OpenAction [3 0 R /FitH null]');
1920
        } elseif ($this->zoomMode=='real') {
1921
            $this->out('/OpenAction [3 0 R /XYZ null null 1]');
1922
        } elseif (!is_string($this->zoomMode)) {
1923
            $this->out('/OpenAction [3 0 R /XYZ null null '.($this->zoomMode/100).']');
1924
        }
1925 1
        if ($this->layoutMode=='single') {
1926
            $this->out('/PageLayout /SinglePage');
1927 1
        } elseif ($this->layoutMode=='continuous') {
1928 1
            $this->out('/PageLayout /OneColumn');
1929
        } elseif ($this->layoutMode=='two') {
1930
            $this->out('/PageLayout /TwoColumnLeft');
1931
        }
1932 1
    }
1933
    
1934 1
    protected function putHeader()
1935
    {
1936 1
        $this->out('%PDF-'.$this->pdfVersion);
1937 1
    }
1938
    
1939 1
    protected function putTrailer()
1940
    {
1941 1
        $this->out('/Size '.($this->n+1));
1942 1
        $this->out('/Root '.$this->n.' 0 R');
1943 1
        $this->out('/Info '.($this->n-1).' 0 R');
1944 1
    }
1945
    
1946 1
    protected function endDoc()
1947
    {
1948 1
        $this->putHeader();
1949 1
        $this->putPages();
1950 1
        $this->putResources();
1951
        //Info
1952 1
        $this->newObj();
1953 1
        $this->out('<<');
1954 1
        $this->putInfo();
1955 1
        $this->out('>>');
1956 1
        $this->out('endobj');
1957
        //Catalog
1958 1
        $this->newObj();
1959 1
        $this->out('<<');
1960 1
        $this->putCatalog();
1961 1
        $this->out('>>');
1962 1
        $this->out('endobj');
1963
        //Cross-ref
1964 1
        $o=strlen($this->buffer);
1965 1
        $this->out('xref');
1966 1
        $this->out('0 '.($this->n+1));
1967 1
        $this->out('0000000000 65535 f ');
1968 1
        for ($i=1; $i<=$this->n; $i++) {
1969 1
            $this->out(sprintf('%010d 00000 n ', $this->offsets[$i]));
1970
        }
1971
        //Trailer
1972 1
        $this->out('trailer');
1973 1
        $this->out('<<');
1974 1
        $this->putTrailer();
1975 1
        $this->out('>>');
1976 1
        $this->out('startxref');
1977 1
        $this->out($o);
1978 1
        $this->out('%%EOF');
1979 1
        $this->state=3;
1980 1
    }
1981
}
1982