FPDF::_putresources()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 11
rs 9.4285
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
/*******************************************************************************
3
* FPDF                                                                         *
4
*                                                                              *
5
* Version: 1.81                                                                *
6
* Date:    2015-12-20                                                          *
7
* Author:  Olivier PLATHEY                                                     *
8
*******************************************************************************/
9
10
define('FPDF_VERSION','1.81');
11
12
class FPDF
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

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

namespace YourVendor;

class YourClass { }

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

Loading history...
13
{
14
protected $page;               // current page number
15
protected $n;                  // current object number
16
protected $offsets;            // array of object offsets
17
protected $buffer;             // buffer holding in-memory PDF
18
protected $pages;              // array containing pages
19
protected $state;              // current document state
20
protected $compress;           // compression flag
21
protected $k;                  // scale factor (number of points in user unit)
22
protected $DefOrientation;     // default orientation
23
protected $CurOrientation;     // current orientation
24
protected $StdPageSizes;       // standard page sizes
25
protected $DefPageSize;        // default page size
26
protected $CurPageSize;        // current page size
27
protected $CurRotation;        // current page rotation
28
protected $PageInfo;           // page-related data
29
protected $wPt, $hPt;          // dimensions of current page in points
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
30
protected $w, $h;              // dimensions of current page in user unit
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
31
protected $lMargin;            // left margin
32
protected $tMargin;            // top margin
33
protected $rMargin;            // right margin
34
protected $bMargin;            // page break margin
35
protected $cMargin;            // cell margin
36
protected $x, $y;              // current position in user unit
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
37
protected $lasth;              // height of last printed cell
38
protected $LineWidth;          // line width in user unit
39
protected $fontpath;           // path containing fonts
40
protected $CoreFonts;          // array of core font names
41
protected $fonts;              // array of used fonts
42
protected $FontFiles;          // array of font files
43
protected $encodings;          // array of encodings
44
protected $cmaps;              // array of ToUnicode CMaps
45
protected $FontFamily;         // current font family
46
protected $FontStyle;          // current font style
47
protected $underline;          // underlining flag
48
protected $CurrentFont;        // current font info
49
protected $FontSizePt;         // current font size in points
50
protected $FontSize;           // current font size in user unit
51
protected $DrawColor;          // commands for drawing color
52
protected $FillColor;          // commands for filling color
53
protected $TextColor;          // commands for text color
54
protected $ColorFlag;          // indicates whether fill and text colors are different
55
protected $WithAlpha;          // indicates whether alpha channel is used
56
protected $ws;                 // word spacing
57
protected $images;             // array of used images
58
protected $PageLinks;          // array of links in pages
59
protected $links;              // array of internal links
60
protected $AutoPageBreak;      // automatic page breaking
61
protected $PageBreakTrigger;   // threshold used to trigger page breaks
62
protected $InHeader;           // flag set when processing header
63
protected $InFooter;           // flag set when processing footer
64
protected $AliasNbPages;       // alias for total number of pages
65
protected $ZoomMode;           // zoom display mode
66
protected $LayoutMode;         // layout display mode
67
protected $metadata;           // document properties
68
protected $PDFVersion;         // PDF version number
69
70
/*******************************************************************************
71
*                               Public methods                                 *
72
*******************************************************************************/
73
74
function __construct($orientation='P', $unit='mm', $size='A4')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
75
{
76
	// Some checks
77
	$this->_dochecks();
78
	// Initialization of properties
79
	$this->state = 0;
80
	$this->page = 0;
81
	$this->n = 2;
82
	$this->buffer = '';
83
	$this->pages = array();
84
	$this->PageInfo = array();
85
	$this->fonts = array();
86
	$this->FontFiles = array();
87
	$this->encodings = array();
88
	$this->cmaps = array();
89
	$this->images = array();
90
	$this->links = array();
91
	$this->InHeader = false;
92
	$this->InFooter = false;
93
	$this->lasth = 0;
94
	$this->FontFamily = '';
95
	$this->FontStyle = '';
96
	$this->FontSizePt = 12;
97
	$this->underline = false;
98
	$this->DrawColor = '0 G';
99
	$this->FillColor = '0 g';
100
	$this->TextColor = '0 g';
101
	$this->ColorFlag = false;
102
	$this->WithAlpha = false;
103
	$this->ws = 0;
104
	// Font path
105
	if(defined('FPDF_FONTPATH'))
106
	{
107
		$this->fontpath = FPDF_FONTPATH;
108
		if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\\')
109
			$this->fontpath .= '/';
110
	}
111
	elseif(is_dir(dirname(__FILE__).'/font'))
112
		$this->fontpath = dirname(__FILE__).'/font/';
113
	else
114
		$this->fontpath = '';
115
	// Core fonts
116
	$this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats');
117
	// Scale factor
118
	if($unit=='pt')
119
		$this->k = 1;
120
	elseif($unit=='mm')
121
		$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
	// Page sizes
129
	$this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),
130
		'letter'=>array(612,792), 'legal'=>array(612,1008));
131
	$size = $this->_getpagesize($size);
132
	$this->DefPageSize = $size;
133
	$this->CurPageSize = $size;
134
	// Page orientation
135
	$orientation = strtolower($orientation);
136
	if($orientation=='p' || $orientation=='portrait')
137
	{
138
		$this->DefOrientation = 'P';
139
		$this->w = $size[0];
140
		$this->h = $size[1];
141
	}
142
	elseif($orientation=='l' || $orientation=='landscape')
143
	{
144
		$this->DefOrientation = 'L';
145
		$this->w = $size[1];
146
		$this->h = $size[0];
147
	}
148
	else
149
		$this->Error('Incorrect orientation: '.$orientation);
150
	$this->CurOrientation = $this->DefOrientation;
151
	$this->wPt = $this->w*$this->k;
152
	$this->hPt = $this->h*$this->k;
153
	// Page rotation
154
	$this->CurRotation = 0;
155
	// Page margins (1 cm)
156
	$margin = 28.35/$this->k;
157
	$this->SetMargins($margin,$margin);
158
	// Interior cell margin (1 mm)
159
	$this->cMargin = $margin/10;
160
	// Line width (0.2 mm)
161
	$this->LineWidth = .567/$this->k;
162
	// Automatic page break
163
	$this->SetAutoPageBreak(true,2*$margin);
164
	// Default display mode
165
	$this->SetDisplayMode('default');
166
	// Enable compression
167
	$this->SetCompression(true);
168
	// Set default PDF version number
169
	$this->PDFVersion = '1.3';
170
}
171
172
function SetMargins($left, $top, $right=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
173
{
174
	// Set left, top and right margins
175
	$this->lMargin = $left;
176
	$this->tMargin = $top;
177
	if($right===null)
178
		$right = $left;
179
	$this->rMargin = $right;
180
}
181
182
function SetLeftMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
183
{
184
	// Set left margin
185
	$this->lMargin = $margin;
186
	if($this->page>0 && $this->x<$margin)
187
		$this->x = $margin;
188
}
189
190
function SetTopMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
191
{
192
	// Set top margin
193
	$this->tMargin = $margin;
194
}
195
196
function SetRightMargin($margin)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
197
{
198
	// Set right margin
199
	$this->rMargin = $margin;
200
}
201
202
function SetAutoPageBreak($auto, $margin=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
203
{
204
	// Set auto page break mode and triggering margin
205
	$this->AutoPageBreak = $auto;
206
	$this->bMargin = $margin;
207
	$this->PageBreakTrigger = $this->h-$margin;
208
}
209
210
function SetDisplayMode($zoom, $layout='default')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
211
{
212
	// Set display mode in viewer
213
	if($zoom=='fullpage' || $zoom=='fullwidth' || $zoom=='real' || $zoom=='default' || !is_string($zoom))
214
		$this->ZoomMode = $zoom;
215
	else
216
		$this->Error('Incorrect zoom display mode: '.$zoom);
217
	if($layout=='single' || $layout=='continuous' || $layout=='two' || $layout=='default')
218
		$this->LayoutMode = $layout;
219
	else
220
		$this->Error('Incorrect layout display mode: '.$layout);
221
}
222
223
function SetCompression($compress)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
224
{
225
	// Set page compression
226
	if(function_exists('gzcompress'))
227
		$this->compress = $compress;
228
	else
229
		$this->compress = false;
230
}
231
232
function SetTitle($title, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
233
{
234
	// Title of document
235
	$this->metadata['Title'] = $isUTF8 ? $title : utf8_encode($title);
236
}
237
238
function SetAuthor($author, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
239
{
240
	// Author of document
241
	$this->metadata['Author'] = $isUTF8 ? $author : utf8_encode($author);
242
}
243
244
function SetSubject($subject, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
245
{
246
	// Subject of document
247
	$this->metadata['Subject'] = $isUTF8 ? $subject : utf8_encode($subject);
248
}
249
250
function SetKeywords($keywords, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
251
{
252
	// Keywords of document
253
	$this->metadata['Keywords'] = $isUTF8 ? $keywords : utf8_encode($keywords);
254
}
255
256
function SetCreator($creator, $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
257
{
258
	// Creator of document
259
	$this->metadata['Creator'] = $isUTF8 ? $creator : utf8_encode($creator);
260
}
261
262
function AliasNbPages($alias='{nb}')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
263
{
264
	// Define an alias for total number of pages
265
	$this->AliasNbPages = $alias;
266
}
267
268
function Error($msg)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
269
{
270
	// Fatal error
271
	throw new Exception('FPDF error: '.$msg);
272
}
273
274
function Close()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
275
{
276
	// Terminate document
277
	if($this->state==3)
278
		return;
279
	if($this->page==0)
280
		$this->AddPage();
281
	// Page footer
282
	$this->InFooter = true;
283
	$this->Footer();
284
	$this->InFooter = false;
285
	// Close page
286
	$this->_endpage();
287
	// Close document
288
	$this->_enddoc();
289
}
290
291
function AddPage($orientation='', $size='', $rotation=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
292
{
293
	// Start a new page
294
	if($this->state==3)
295
		$this->Error('The document is closed');
296
	$family = $this->FontFamily;
297
	$style = $this->FontStyle.($this->underline ? 'U' : '');
298
	$fontsize = $this->FontSizePt;
299
	$lw = $this->LineWidth;
300
	$dc = $this->DrawColor;
301
	$fc = $this->FillColor;
302
	$tc = $this->TextColor;
303
	$cf = $this->ColorFlag;
304
	if($this->page>0)
305
	{
306
		// Page footer
307
		$this->InFooter = true;
308
		$this->Footer();
309
		$this->InFooter = false;
310
		// Close page
311
		$this->_endpage();
312
	}
313
	// Start new page
314
	$this->_beginpage($orientation,$size,$rotation);
315
	// Set line cap style to square
316
	$this->_out('2 J');
317
	// Set line width
318
	$this->LineWidth = $lw;
319
	$this->_out(sprintf('%.2F w',$lw*$this->k));
320
	// Set font
321
	if($family)
322
		$this->SetFont($family,$style,$fontsize);
323
	// Set colors
324
	$this->DrawColor = $dc;
325
	if($dc!='0 G')
326
		$this->_out($dc);
327
	$this->FillColor = $fc;
328
	if($fc!='0 g')
329
		$this->_out($fc);
330
	$this->TextColor = $tc;
331
	$this->ColorFlag = $cf;
332
	// Page header
333
	$this->InHeader = true;
334
	$this->Header();
335
	$this->InHeader = false;
336
	// Restore line width
337
	if($this->LineWidth!=$lw)
338
	{
339
		$this->LineWidth = $lw;
340
		$this->_out(sprintf('%.2F w',$lw*$this->k));
341
	}
342
	// Restore font
343
	if($family)
344
		$this->SetFont($family,$style,$fontsize);
345
	// Restore colors
346
	if($this->DrawColor!=$dc)
347
	{
348
		$this->DrawColor = $dc;
349
		$this->_out($dc);
350
	}
351
	if($this->FillColor!=$fc)
352
	{
353
		$this->FillColor = $fc;
354
		$this->_out($fc);
355
	}
356
	$this->TextColor = $tc;
357
	$this->ColorFlag = $cf;
358
}
359
360
function Header()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
361
{
362
	// To be implemented in your own inherited class
363
}
364
365
function Footer()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
366
{
367
	// To be implemented in your own inherited class
368
}
369
370
function PageNo()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
371
{
372
	// Get current page number
373
	return $this->page;
374
}
375
376 View Code Duplication
function SetDrawColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

Loading history...
377
{
378
	// Set color for all stroking operations
379
	if(($r==0 && $g==0 && $b==0) || $g===null)
380
		$this->DrawColor = sprintf('%.3F G',$r/255);
381
	else
382
		$this->DrawColor = sprintf('%.3F %.3F %.3F RG',$r/255,$g/255,$b/255);
383
	if($this->page>0)
384
		$this->_out($this->DrawColor);
385
}
386
387
function SetFillColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
388
{
389
	// Set color for all filling operations
390
	if(($r==0 && $g==0 && $b==0) || $g===null)
391
		$this->FillColor = sprintf('%.3F g',$r/255);
392
	else
393
		$this->FillColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
394
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
395
	if($this->page>0)
396
		$this->_out($this->FillColor);
397
}
398
399 View Code Duplication
function SetTextColor($r, $g=null, $b=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

Loading history...
400
{
401
	// Set color for text
402
	if(($r==0 && $g==0 && $b==0) || $g===null)
403
		$this->TextColor = sprintf('%.3F g',$r/255);
404
	else
405
		$this->TextColor = sprintf('%.3F %.3F %.3F rg',$r/255,$g/255,$b/255);
406
	$this->ColorFlag = ($this->FillColor!=$this->TextColor);
407
}
408
409
function GetStringWidth($s)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
410
{
411
	// Get width of a string in the current font
412
	$s = (string)$s;
413
	$cw = &$this->CurrentFont['cw'];
414
	$w = 0;
415
	$l = strlen($s);
416
	for($i=0;$i<$l;$i++)
417
		$w += $cw[$s[$i]];
418
	return $w*$this->FontSize/1000;
419
}
420
421
function SetLineWidth($width)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
422
{
423
	// Set line width
424
	$this->LineWidth = $width;
425
	if($this->page>0)
426
		$this->_out(sprintf('%.2F w',$width*$this->k));
427
}
428
429
function Line($x1, $y1, $x2, $y2)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
430
{
431
	// Draw a line
432
	$this->_out(sprintf('%.2F %.2F m %.2F %.2F l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k));
433
}
434
435
function Rect($x, $y, $w, $h, $style='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
436
{
437
	// Draw a rectangle
438
	if($style=='F')
439
		$op = 'f';
440
	elseif($style=='FD' || $style=='DF')
441
		$op = 'B';
442
	else
443
		$op = 'S';
444
	$this->_out(sprintf('%.2F %.2F %.2F %.2F re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op));
445
}
446
447
function AddFont($family, $style='', $file='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
448
{
449
	// Add a TrueType, OpenType or Type1 font
450
	$family = strtolower($family);
451 View Code Duplication
	if($file=='')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
452
		$file = str_replace(' ','',$family).strtolower($style).'.php';
453
	$style = strtoupper($style);
454
	if($style=='IB')
455
		$style = 'BI';
456
	$fontkey = $family.$style;
457
	if(isset($this->fonts[$fontkey]))
458
		return;
459
	$info = $this->_loadfont($file);
460
	$info['i'] = count($this->fonts)+1;
461
	if(!empty($info['file']))
462
	{
463
		// Embedded font
464
		if($info['type']=='TrueType')
465
			$this->FontFiles[$info['file']] = array('length1'=>$info['originalsize']);
466
		else
467
			$this->FontFiles[$info['file']] = array('length1'=>$info['size1'], 'length2'=>$info['size2']);
468
	}
469
	$this->fonts[$fontkey] = $info;
470
}
471
472
function SetFont($family, $style='', $size=0)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
473
{
474
	// Select a font; size given in points
475
	if($family=='')
476
		$family = $this->FontFamily;
477
	else
478
		$family = strtolower($family);
479
	$style = strtoupper($style);
480
	if(strpos($style,'U')!==false)
481
	{
482
		$this->underline = true;
483
		$style = str_replace('U','',$style);
484
	}
485
	else
486
		$this->underline = false;
487
	if($style=='IB')
488
		$style = 'BI';
489
	if($size==0)
490
		$size = $this->FontSizePt;
491
	// Test if font is already selected
492
	if($this->FontFamily==$family && $this->FontStyle==$style && $this->FontSizePt==$size)
493
		return;
494
	// Test if font is already loaded
495
	$fontkey = $family.$style;
496
	if(!isset($this->fonts[$fontkey]))
497
	{
498
		// Test if one of the core fonts
499
		if($family=='arial')
500
			$family = 'helvetica';
501
		if(in_array($family,$this->CoreFonts))
502
		{
503
			if($family=='symbol' || $family=='zapfdingbats')
504
				$style = '';
505
			$fontkey = $family.$style;
506
			if(!isset($this->fonts[$fontkey]))
507
				$this->AddFont($family,$style);
508
		}
509
		else
510
			$this->Error('Undefined font: '.$family.' '.$style);
511
	}
512
	// Select it
513
	$this->FontFamily = $family;
514
	$this->FontStyle = $style;
515
	$this->FontSizePt = $size;
516
	$this->FontSize = $size/$this->k;
517
	$this->CurrentFont = &$this->fonts[$fontkey];
518 View Code Duplication
	if($this->page>0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
519
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
520
}
521
522
function SetFontSize($size)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
523
{
524
	// Set font size in points
525
	if($this->FontSizePt==$size)
526
		return;
527
	$this->FontSizePt = $size;
528
	$this->FontSize = $size/$this->k;
529 View Code Duplication
	if($this->page>0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
530
		$this->_out(sprintf('BT /F%d %.2F Tf ET',$this->CurrentFont['i'],$this->FontSizePt));
531
}
532
533
function AddLink()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
534
{
535
	// Create a new internal link
536
	$n = count($this->links)+1;
537
	$this->links[$n] = array(0, 0);
538
	return $n;
539
}
540
541
function SetLink($link, $y=0, $page=-1)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
542
{
543
	// Set destination of internal link
544
	if($y==-1)
545
		$y = $this->y;
546
	if($page==-1)
547
		$page = $this->page;
548
	$this->links[$link] = array($page, $y);
549
}
550
551
function Link($x, $y, $w, $h, $link)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
552
{
553
	// Put a link on the page
554
	$this->PageLinks[$this->page][] = array($x*$this->k, $this->hPt-$y*$this->k, $w*$this->k, $h*$this->k, $link);
555
}
556
557 View Code Duplication
function Text($x, $y, $txt)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

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

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

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

Loading history...
558
{
559
	// Output a string
560
	if(!isset($this->CurrentFont))
561
		$this->Error('No font has been set');
562
	$s = sprintf('BT %.2F %.2F Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt));
563
	if($this->underline && $txt!='')
564
		$s .= ' '.$this->_dounderline($x,$y,$txt);
565
	if($this->ColorFlag)
566
		$s = 'q '.$this->TextColor.' '.$s.' Q';
567
	$this->_out($s);
568
}
569
570
function AcceptPageBreak()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
571
{
572
	// Accept automatic page break or not
573
	return $this->AutoPageBreak;
574
}
575
576
function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
577
{
578
	// Output a cell
579
	$k = $this->k;
580
	if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
581
	{
582
		// Automatic page break
583
		$x = $this->x;
584
		$ws = $this->ws;
585
		if($ws>0)
586
		{
587
			$this->ws = 0;
588
			$this->_out('0 Tw');
589
		}
590
		$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
591
		$this->x = $x;
592 View Code Duplication
		if($ws>0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
593
		{
594
			$this->ws = $ws;
595
			$this->_out(sprintf('%.3F Tw',$ws*$k));
596
		}
597
	}
598
	if($w==0)
599
		$w = $this->w-$this->rMargin-$this->x;
600
	$s = '';
601
	if($fill || $border==1)
602
	{
603
		if($fill)
604
			$op = ($border==1) ? 'B' : 'f';
605
		else
606
			$op = 'S';
607
		$s = sprintf('%.2F %.2F %.2F %.2F re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op);
608
	}
609
	if(is_string($border))
610
	{
611
		$x = $this->x;
612
		$y = $this->y;
613
		if(strpos($border,'L')!==false)
614
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k);
615
		if(strpos($border,'T')!==false)
616
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k);
617 View Code Duplication
		if(strpos($border,'R')!==false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
618
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
619 View Code Duplication
		if(strpos($border,'B')!==false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
620
			$s .= sprintf('%.2F %.2F m %.2F %.2F l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k);
621
	}
622
	if($txt!=='')
623
	{
624
		if(!isset($this->CurrentFont))
625
			$this->Error('No font has been set');
626 View Code Duplication
		if($align=='R')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
627
			$dx = $w-$this->cMargin-$this->GetStringWidth($txt);
628
		elseif($align=='C')
629
			$dx = ($w-$this->GetStringWidth($txt))/2;
630
		else
631
			$dx = $this->cMargin;
632
		if($this->ColorFlag)
633
			$s .= 'q '.$this->TextColor.' ';
634
		$s .= sprintf('BT %.2F %.2F Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$this->_escape($txt));
635 View Code Duplication
		if($this->underline)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
636
			$s .= ' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt);
637
		if($this->ColorFlag)
638
			$s .= ' Q';
639 View Code Duplication
		if($link)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
640
			$this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link);
641
	}
642
	if($s)
643
		$this->_out($s);
644
	$this->lasth = $h;
645 View Code Duplication
	if($ln>0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
646
	{
647
		// Go to next line
648
		$this->y += $h;
649
		if($ln==1)
650
			$this->x = $this->lMargin;
651
	}
652
	else
653
		$this->x += $w;
654
}
655
656
function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
657
{
658
	// Output text with automatic or explicit line breaks
659
	if(!isset($this->CurrentFont))
660
		$this->Error('No font has been set');
661
	$cw = &$this->CurrentFont['cw'];
662
	if($w==0)
663
		$w = $this->w-$this->rMargin-$this->x;
664
	$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
665
	$s = str_replace("\r",'',$txt);
666
	$nb = strlen($s);
667
	if($nb>0 && $s[$nb-1]=="\n")
668
		$nb--;
669
	$b = 0;
670
	if($border)
671
	{
672
		if($border==1)
673
		{
674
			$border = 'LTRB';
675
			$b = 'LRT';
676
			$b2 = 'LR';
677
		}
678
		else
679
		{
680
			$b2 = '';
681
			if(strpos($border,'L')!==false)
682
				$b2 .= 'L';
683
			if(strpos($border,'R')!==false)
684
				$b2 .= 'R';
685
			$b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;
686
		}
687
	}
688
	$sep = -1;
689
	$i = 0;
690
	$j = 0;
691
	$l = 0;
692
	$ns = 0;
693
	$nl = 1;
694
	while($i<$nb)
695
	{
696
		// Get next character
697
		$c = $s[$i];
698
		if($c=="\n")
699
		{
700
			// Explicit line break
701
			if($this->ws>0)
702
			{
703
				$this->ws = 0;
704
				$this->_out('0 Tw');
705
			}
706
			$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
707
			$i++;
708
			$sep = -1;
709
			$j = $i;
710
			$l = 0;
711
			$ns = 0;
712
			$nl++;
713
			if($border && $nl==2)
714
				$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...
715
			continue;
716
		}
717
		if($c==' ')
718
		{
719
			$sep = $i;
720
			$ls = $l;
721
			$ns++;
722
		}
723
		$l += $cw[$c];
724
		if($l>$wmax)
725
		{
726
			// Automatic line break
727
			if($sep==-1)
728
			{
729
				if($i==$j)
730
					$i++;
731
				if($this->ws>0)
732
				{
733
					$this->ws = 0;
734
					$this->_out('0 Tw');
735
				}
736
				$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
737
			}
738
			else
739
			{
740
				if($align=='J')
741
				{
742
					$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...
743
					$this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
744
				}
745
				$this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
746
				$i = $sep+1;
747
			}
748
			$sep = -1;
749
			$j = $i;
750
			$l = 0;
751
			$ns = 0;
752
			$nl++;
753
			if($border && $nl==2)
754
				$b = $b2;
755
		}
756
		else
757
			$i++;
758
	}
759
	// Last chunk
760
	if($this->ws>0)
761
	{
762
		$this->ws = 0;
763
		$this->_out('0 Tw');
764
	}
765
	if($border && strpos($border,'B')!==false)
766
		$b .= 'B';
767
	$this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
768
	$this->x = $this->lMargin;
769
}
770
771
function Write($h, $txt, $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
772
{
773
	// Output text in flowing mode
774
	if(!isset($this->CurrentFont))
775
		$this->Error('No font has been set');
776
	$cw = &$this->CurrentFont['cw'];
777
	$w = $this->w-$this->rMargin-$this->x;
778
	$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
779
	$s = str_replace("\r",'',$txt);
780
	$nb = strlen($s);
781
	$sep = -1;
782
	$i = 0;
783
	$j = 0;
784
	$l = 0;
785
	$nl = 1;
786
	while($i<$nb)
787
	{
788
		// Get next character
789
		$c = $s[$i];
790
		if($c=="\n")
791
		{
792
			// Explicit line break
793
			$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
794
			$i++;
795
			$sep = -1;
796
			$j = $i;
797
			$l = 0;
798 View Code Duplication
			if($nl==1)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
799
			{
800
				$this->x = $this->lMargin;
801
				$w = $this->w-$this->rMargin-$this->x;
802
				$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
803
			}
804
			$nl++;
805
			continue;
806
		}
807
		if($c==' ')
808
			$sep = $i;
809
		$l += $cw[$c];
810
		if($l>$wmax)
811
		{
812
			// Automatic line break
813
			if($sep==-1)
814
			{
815
				if($this->x>$this->lMargin)
816
				{
817
					// Move to next line
818
					$this->x = $this->lMargin;
819
					$this->y += $h;
820
					$w = $this->w-$this->rMargin-$this->x;
821
					$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
822
					$i++;
823
					$nl++;
824
					continue;
825
				}
826
				if($i==$j)
827
					$i++;
828
				$this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',false,$link);
829
			}
830
			else
831
			{
832
				$this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',false,$link);
833
				$i = $sep+1;
834
			}
835
			$sep = -1;
836
			$j = $i;
837
			$l = 0;
838 View Code Duplication
			if($nl==1)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
839
			{
840
				$this->x = $this->lMargin;
841
				$w = $this->w-$this->rMargin-$this->x;
842
				$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
843
			}
844
			$nl++;
845
		}
846
		else
847
			$i++;
848
	}
849
	// Last chunk
850
	if($i!=$j)
851
		$this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',false,$link);
852
}
853
854
function Ln($h=null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
855
{
856
	// Line feed; default value is the last cell height
857
	$this->x = $this->lMargin;
858
	if($h===null)
859
		$this->y += $this->lasth;
860
	else
861
		$this->y += $h;
862
}
863
864
function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
865
{
866
	// Put an image on the page
867
	if($file=='')
868
		$this->Error('Image file name is empty');
869
	if(!isset($this->images[$file]))
870
	{
871
		// First use of this image, get info
872
		if($type=='')
873
		{
874
			$pos = strrpos($file,'.');
875
			if(!$pos)
876
				$this->Error('Image file has no extension and no type was specified: '.$file);
877
			$type = substr($file,$pos+1);
878
		}
879
		$type = strtolower($type);
880
		if($type=='jpeg')
881
			$type = 'jpg';
882
		$mtd = '_parse'.$type;
883
		if(!method_exists($this,$mtd))
884
			$this->Error('Unsupported image type: '.$type);
885
		$info = $this->$mtd($file);
886
		$info['i'] = count($this->images)+1;
887
		$this->images[$file] = $info;
888
	}
889
	else
890
		$info = $this->images[$file];
891
892
	// Automatic width and height calculation if needed
893
	if($w==0 && $h==0)
894
	{
895
		// Put image at 96 dpi
896
		$w = -96;
897
		$h = -96;
898
	}
899
	if($w<0)
900
		$w = -$info['w']*72/$w/$this->k;
901
	if($h<0)
902
		$h = -$info['h']*72/$h/$this->k;
903
	if($w==0)
904
		$w = $h*$info['w']/$info['h'];
905
	if($h==0)
906
		$h = $w*$info['h']/$info['w'];
907
908
	// Flowing mode
909
	if($y===null)
910
	{
911
		if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())
912
		{
913
			// Automatic page break
914
			$x2 = $this->x;
915
			$this->AddPage($this->CurOrientation,$this->CurPageSize,$this->CurRotation);
916
			$this->x = $x2;
917
		}
918
		$y = $this->y;
919
		$this->y += $h;
920
	}
921
922
	if($x===null)
923
		$x = $this->x;
924
	$this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i']));
925
	if($link)
926
		$this->Link($x,$y,$w,$h,$link);
927
}
928
929
function GetPageWidth()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
930
{
931
	// Get current page width
932
	return $this->w;
933
}
934
935
function GetPageHeight()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
936
{
937
	// Get current page height
938
	return $this->h;
939
}
940
941
function GetX()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
942
{
943
	// Get x position
944
	return $this->x;
945
}
946
947
function SetX($x)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
948
{
949
	// Set x position
950
	if($x>=0)
951
		$this->x = $x;
952
	else
953
		$this->x = $this->w+$x;
954
}
955
956
function GetY()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
957
{
958
	// Get y position
959
	return $this->y;
960
}
961
962
function SetY($y, $resetX=true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
963
{
964
	// Set y position and optionally reset x
965
	if($y>=0)
966
		$this->y = $y;
967
	else
968
		$this->y = $this->h+$y;
969
	if($resetX)
970
		$this->x = $this->lMargin;
971
}
972
973
function SetXY($x, $y)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
974
{
975
	// Set x and y positions
976
	$this->SetX($x);
977
	$this->SetY($y,false);
978
}
979
980
function Output($dest='', $name='', $isUTF8=false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
981
{
982
	// Output PDF to some destination
983
	$this->Close();
984
	if(strlen($name)==1 && strlen($dest)!=1)
985
	{
986
		// Fix parameter order
987
		$tmp = $dest;
988
		$dest = $name;
989
		$name = $tmp;
990
	}
991
	if($dest=='')
992
		$dest = 'I';
993
	if($name=='')
994
		$name = 'doc.pdf';
995
	switch(strtoupper($dest))
996
	{
997 View Code Duplication
		case 'I':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
998
			// Send to standard output
999
			$this->_checkoutput();
1000
			if(PHP_SAPI!='cli')
1001
			{
1002
				// We send to a browser
1003
				header('Content-Type: application/pdf');
1004
				header('Content-Disposition: inline; '.$this->_httpencode('filename',$name,$isUTF8));
1005
				header('Cache-Control: private, max-age=0, must-revalidate');
1006
				header('Pragma: public');
1007
			}
1008
			echo $this->buffer;
1009
			break;
1010 View Code Duplication
		case 'D':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1011
			// Download file
1012
			$this->_checkoutput();
1013
			header('Content-Type: application/x-download');
1014
			header('Content-Disposition: attachment; '.$this->_httpencode('filename',$name,$isUTF8));
1015
			header('Cache-Control: private, max-age=0, must-revalidate');
1016
			header('Pragma: public');
1017
			echo $this->buffer;
1018
			break;
1019
		case 'F':
1020
			// Save to local file
1021
			if(!file_put_contents($name,$this->buffer))
1022
				$this->Error('Unable to create output file: '.$name);
1023
			break;
1024
		case 'S':
1025
			// Return as a string
1026
			return $this->buffer;
1027
		default:
1028
			$this->Error('Incorrect output destination: '.$dest);
1029
	}
1030
	return '';
1031
}
1032
1033
/*******************************************************************************
1034
*                              Protected methods                               *
1035
*******************************************************************************/
1036
1037
protected function _dochecks()
1038
{
1039
	// Check mbstring overloading
1040
	if(ini_get('mbstring.func_overload') & 2)
1041
		$this->Error('mbstring overloading must be disabled');
1042
	// Ensure runtime magic quotes are disabled
1043
	if(get_magic_quotes_runtime())
1044
		@set_magic_quotes_runtime(0);
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...
Deprecated Code introduced by
The function set_magic_quotes_runtime() has been deprecated with message: Deprecated as of PHP 5.3.0. Relying on this feature is highly discouraged.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
1045
}
1046
1047
protected function _checkoutput()
1048
{
1049
	if(PHP_SAPI!='cli')
1050
	{
1051
		if(headers_sent($file,$line))
1052
			$this->Error("Some data has already been output, can't send PDF file (output started at $file:$line)");
1053
	}
1054
	if(ob_get_length())
1055
	{
1056
		// The output buffer is not empty
1057
		if(preg_match('/^(\xEF\xBB\xBF)?\s*$/',ob_get_contents()))
1058
		{
1059
			// It contains only a UTF-8 BOM and/or whitespace, let's clean it
1060
			ob_clean();
1061
		}
1062
		else
1063
			$this->Error("Some data has already been output, can't send PDF file");
1064
	}
1065
}
1066
1067
protected function _getpagesize($size)
1068
{
1069
	if(is_string($size))
1070
	{
1071
		$size = strtolower($size);
1072
		if(!isset($this->StdPageSizes[$size]))
1073
			$this->Error('Unknown page size: '.$size);
1074
		$a = $this->StdPageSizes[$size];
1075
		return array($a[0]/$this->k, $a[1]/$this->k);
1076
	}
1077
	else
1078
	{
1079
		if($size[0]>$size[1])
1080
			return array($size[1], $size[0]);
1081
		else
1082
			return $size;
1083
	}
1084
}
1085
1086
protected function _beginpage($orientation, $size, $rotation)
1087
{
1088
	$this->page++;
1089
	$this->pages[$this->page] = '';
1090
	$this->state = 2;
1091
	$this->x = $this->lMargin;
1092
	$this->y = $this->tMargin;
1093
	$this->FontFamily = '';
1094
	// Check page size and orientation
1095
	if($orientation=='')
1096
		$orientation = $this->DefOrientation;
1097
	else
1098
		$orientation = strtoupper($orientation[0]);
1099
	if($size=='')
1100
		$size = $this->DefPageSize;
1101
	else
1102
		$size = $this->_getpagesize($size);
1103
	if($orientation!=$this->CurOrientation || $size[0]!=$this->CurPageSize[0] || $size[1]!=$this->CurPageSize[1])
1104
	{
1105
		// New size or orientation
1106 View Code Duplication
		if($orientation=='P')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1107
		{
1108
			$this->w = $size[0];
1109
			$this->h = $size[1];
1110
		}
1111
		else
1112
		{
1113
			$this->w = $size[1];
1114
			$this->h = $size[0];
1115
		}
1116
		$this->wPt = $this->w*$this->k;
1117
		$this->hPt = $this->h*$this->k;
1118
		$this->PageBreakTrigger = $this->h-$this->bMargin;
1119
		$this->CurOrientation = $orientation;
1120
		$this->CurPageSize = $size;
1121
	}
1122
	if($orientation!=$this->DefOrientation || $size[0]!=$this->DefPageSize[0] || $size[1]!=$this->DefPageSize[1])
1123
		$this->PageInfo[$this->page]['size'] = array($this->wPt, $this->hPt);
1124
	if($rotation!=0)
1125
	{
1126
		if($rotation%90!=0)
1127
			$this->Error('Incorrect rotation value: '.$rotation);
1128
		$this->CurRotation = $rotation;
1129
		$this->PageInfo[$this->page]['rotation'] = $rotation;
1130
	}
1131
}
1132
1133
protected function _endpage()
1134
{
1135
	$this->state = 1;
1136
}
1137
1138
protected function _loadfont($font)
1139
{
1140
	// Load a font definition file from the font directory
1141
	if(strpos($font,'/')!==false || strpos($font,"\\")!==false)
1142
		$this->Error('Incorrect font definition file name: '.$font);
1143
	include($this->fontpath.$font);
1144
	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...
1145
		$this->Error('Could not include font definition file');
1146
	if(isset($enc))
0 ignored issues
show
Bug introduced by
The variable $enc seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1147
		$enc = strtolower($enc);
1148
	if(!isset($subsetted))
0 ignored issues
show
Bug introduced by
The variable $subsetted seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1149
		$subsetted = false;
1150
	return get_defined_vars();
1151
}
1152
1153
protected function _isascii($s)
1154
{
1155
	// Test if string is ASCII
1156
	$nb = strlen($s);
1157
	for($i=0;$i<$nb;$i++)
1158
	{
1159
		if(ord($s[$i])>127)
1160
			return false;
1161
	}
1162
	return true;
1163
}
1164
1165
protected function _httpencode($param, $value, $isUTF8)
0 ignored issues
show
Coding Style introduced by
_httpencode uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1166
{
1167
	// Encode HTTP header field parameter
1168
	if($this->_isascii($value))
1169
		return $param.'="'.$value.'"';
1170
	if(!$isUTF8)
1171
		$value = utf8_encode($value);
1172
	if(strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')!==false)
1173
		return $param.'="'.rawurlencode($value).'"';
1174
	else
1175
		return $param."*=UTF-8''".rawurlencode($value);
1176
}
1177
1178
protected function _UTF8toUTF16($s)
1179
{
1180
	// Convert UTF-8 to UTF-16BE with BOM
1181
	$res = "\xFE\xFF";
1182
	$nb = strlen($s);
1183
	$i = 0;
1184
	while($i<$nb)
1185
	{
1186
		$c1 = ord($s[$i++]);
1187
		if($c1>=224)
1188
		{
1189
			// 3-byte character
1190
			$c2 = ord($s[$i++]);
1191
			$c3 = ord($s[$i++]);
1192
			$res .= chr((($c1 & 0x0F)<<4) + (($c2 & 0x3C)>>2));
1193
			$res .= chr((($c2 & 0x03)<<6) + ($c3 & 0x3F));
1194
		}
1195
		elseif($c1>=192)
1196
		{
1197
			// 2-byte character
1198
			$c2 = ord($s[$i++]);
1199
			$res .= chr(($c1 & 0x1C)>>2);
1200
			$res .= chr((($c1 & 0x03)<<6) + ($c2 & 0x3F));
1201
		}
1202
		else
1203
		{
1204
			// Single-byte character
1205
			$res .= "\0".chr($c1);
1206
		}
1207
	}
1208
	return $res;
1209
}
1210
1211
protected function _escape($s)
1212
{
1213
	// Escape special characters
1214
	if(strpos($s,'(')!==false || strpos($s,')')!==false || strpos($s,'\\')!==false || strpos($s,"\r")!==false)
1215
		return str_replace(array('\\','(',')',"\r"), array('\\\\','\\(','\\)','\\r'), $s);
1216
	else
1217
		return $s;
1218
}
1219
1220
protected function _textstring($s)
1221
{
1222
	// Format a text string
1223
	if(!$this->_isascii($s))
1224
		$s = $this->_UTF8toUTF16($s);
1225
	return '('.$this->_escape($s).')';
1226
}
1227
1228 View Code Duplication
protected function _dounderline($x, $y, $txt)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1229
{
1230
	// Underline text
1231
	$up = $this->CurrentFont['up'];
1232
	$ut = $this->CurrentFont['ut'];
1233
	$w = $this->GetStringWidth($txt)+$this->ws*substr_count($txt,' ');
1234
	return sprintf('%.2F %.2F %.2F %.2F re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt);
1235
}
1236
1237
protected function _parsejpg($file)
1238
{
1239
	// Extract info from a JPEG file
1240
	$a = getimagesize($file);
1241
	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...
1242
		$this->Error('Missing or incorrect image file: '.$file);
1243
	if($a[2]!=2)
1244
		$this->Error('Not a JPEG file: '.$file);
1245
	if(!isset($a['channels']) || $a['channels']==3)
1246
		$colspace = 'DeviceRGB';
1247
	elseif($a['channels']==4)
1248
		$colspace = 'DeviceCMYK';
1249
	else
1250
		$colspace = 'DeviceGray';
1251
	$bpc = isset($a['bits']) ? $a['bits'] : 8;
1252
	$data = file_get_contents($file);
1253
	return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$data);
1254
}
1255
1256
protected function _parsepng($file)
1257
{
1258
	// Extract info from a PNG file
1259
	$f = fopen($file,'rb');
1260
	if(!$f)
1261
		$this->Error('Can\'t open image file: '.$file);
1262
	$info = $this->_parsepngstream($f,$file);
1263
	fclose($f);
1264
	return $info;
1265
}
1266
1267
protected function _parsepngstream($f, $file)
1268
{
1269
	// Check signature
1270
	if($this->_readstream($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
1271
		$this->Error('Not a PNG file: '.$file);
1272
1273
	// Read header chunk
1274
	$this->_readstream($f,4);
1275
	if($this->_readstream($f,4)!='IHDR')
1276
		$this->Error('Incorrect PNG file: '.$file);
1277
	$w = $this->_readint($f);
1278
	$h = $this->_readint($f);
1279
	$bpc = ord($this->_readstream($f,1));
1280
	if($bpc>8)
1281
		$this->Error('16-bit depth not supported: '.$file);
1282
	$ct = ord($this->_readstream($f,1));
1283
	if($ct==0 || $ct==4)
1284
		$colspace = 'DeviceGray';
1285
	elseif($ct==2 || $ct==6)
1286
		$colspace = 'DeviceRGB';
1287
	elseif($ct==3)
1288
		$colspace = 'Indexed';
1289
	else
1290
		$this->Error('Unknown color type: '.$file);
1291
	if(ord($this->_readstream($f,1))!=0)
1292
		$this->Error('Unknown compression method: '.$file);
1293
	if(ord($this->_readstream($f,1))!=0)
1294
		$this->Error('Unknown filter method: '.$file);
1295
	if(ord($this->_readstream($f,1))!=0)
1296
		$this->Error('Interlacing not supported: '.$file);
1297
	$this->_readstream($f,4);
1298
	$dp = '/Predictor 15 /Colors '.($colspace=='DeviceRGB' ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w;
0 ignored issues
show
Bug introduced by
The variable $colspace 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...
1299
1300
	// Scan chunks looking for palette, transparency and image data
1301
	$pal = '';
1302
	$trns = '';
1303
	$data = '';
1304
	do
1305
	{
1306
		$n = $this->_readint($f);
1307
		$type = $this->_readstream($f,4);
1308
		if($type=='PLTE')
1309
		{
1310
			// Read palette
1311
			$pal = $this->_readstream($f,$n);
1312
			$this->_readstream($f,4);
1313
		}
1314
		elseif($type=='tRNS')
1315
		{
1316
			// Read transparency info
1317
			$t = $this->_readstream($f,$n);
1318
			if($ct==0)
1319
				$trns = array(ord(substr($t,1,1)));
1320
			elseif($ct==2)
1321
				$trns = array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
1322
			else
1323
			{
1324
				$pos = strpos($t,chr(0));
1325
				if($pos!==false)
1326
					$trns = array($pos);
1327
			}
1328
			$this->_readstream($f,4);
1329
		}
1330
		elseif($type=='IDAT')
1331
		{
1332
			// Read image data block
1333
			$data .= $this->_readstream($f,$n);
1334
			$this->_readstream($f,4);
1335
		}
1336
		elseif($type=='IEND')
1337
			break;
1338
		else
1339
			$this->_readstream($f,$n+4);
1340
	}
1341
	while($n);
1342
1343
	if($colspace=='Indexed' && empty($pal))
1344
		$this->Error('Missing palette in '.$file);
1345
	$info = array('w'=>$w, 'h'=>$h, 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'FlateDecode', 'dp'=>$dp, 'pal'=>$pal, 'trns'=>$trns);
1346
	if($ct>=4)
1347
	{
1348
		// Extract alpha channel
1349
		if(!function_exists('gzuncompress'))
1350
			$this->Error('Zlib not available, can\'t handle alpha channel: '.$file);
1351
		$data = gzuncompress($data);
1352
		$color = '';
1353
		$alpha = '';
1354
		if($ct==4)
1355
		{
1356
			// Gray image
1357
			$len = 2*$w;
1358 View Code Duplication
			for($i=0;$i<$h;$i++)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1359
			{
1360
				$pos = (1+$len)*$i;
1361
				$color .= $data[$pos];
1362
				$alpha .= $data[$pos];
1363
				$line = substr($data,$pos+1,$len);
1364
				$color .= preg_replace('/(.)./s','$1',$line);
1365
				$alpha .= preg_replace('/.(.)/s','$1',$line);
1366
			}
1367
		}
1368
		else
1369
		{
1370
			// RGB image
1371
			$len = 4*$w;
1372 View Code Duplication
			for($i=0;$i<$h;$i++)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1373
			{
1374
				$pos = (1+$len)*$i;
1375
				$color .= $data[$pos];
1376
				$alpha .= $data[$pos];
1377
				$line = substr($data,$pos+1,$len);
1378
				$color .= preg_replace('/(.{3})./s','$1',$line);
1379
				$alpha .= preg_replace('/.{3}(.)/s','$1',$line);
1380
			}
1381
		}
1382
		unset($data);
1383
		$data = gzcompress($color);
1384
		$info['smask'] = gzcompress($alpha);
1385
		$this->WithAlpha = true;
1386
		if($this->PDFVersion<'1.4')
1387
			$this->PDFVersion = '1.4';
1388
	}
1389
	$info['data'] = $data;
1390
	return $info;
1391
}
1392
1393
protected function _readstream($f, $n)
1394
{
1395
	// Read n bytes from stream
1396
	$res = '';
1397
	while($n>0 && !feof($f))
1398
	{
1399
		$s = fread($f,$n);
1400
		if($s===false)
1401
			$this->Error('Error while reading stream');
1402
		$n -= strlen($s);
1403
		$res .= $s;
1404
	}
1405
	if($n>0)
1406
		$this->Error('Unexpected end of stream');
1407
	return $res;
1408
}
1409
1410
protected function _readint($f)
1411
{
1412
	// Read a 4-byte integer from stream
1413
	$a = unpack('Ni',$this->_readstream($f,4));
1414
	return $a['i'];
1415
}
1416
1417
protected function _parsegif($file)
1418
{
1419
	// Extract info from a GIF file (via PNG conversion)
1420
	if(!function_exists('imagepng'))
1421
		$this->Error('GD extension is required for GIF support');
1422
	if(!function_exists('imagecreatefromgif'))
1423
		$this->Error('GD has no GIF read support');
1424
	$im = imagecreatefromgif($file);
1425
	if(!$im)
1426
		$this->Error('Missing or incorrect image file: '.$file);
1427
	imageinterlace($im,0);
1428
	ob_start();
1429
	imagepng($im);
1430
	$data = ob_get_clean();
1431
	imagedestroy($im);
1432
	$f = fopen('php://temp','rb+');
1433
	if(!$f)
1434
		$this->Error('Unable to create memory stream');
1435
	fwrite($f,$data);
1436
	rewind($f);
1437
	$info = $this->_parsepngstream($f,$file);
1438
	fclose($f);
1439
	return $info;
1440
}
1441
1442
protected function _out($s)
1443
{
1444
	// Add a line to the document
1445
	if($this->state==2)
1446
		$this->pages[$this->page] .= $s."\n";
1447
	elseif($this->state==1)
1448
		$this->_put($s);
1449
	elseif($this->state==0)
1450
		$this->Error('No page has been added yet');
1451
	elseif($this->state==3)
1452
		$this->Error('The document is closed');
1453
}
1454
1455
protected function _put($s)
1456
{
1457
	$this->buffer .= $s."\n";
1458
}
1459
1460
protected function _getoffset()
1461
{
1462
	return strlen($this->buffer);
1463
}
1464
1465
protected function _newobj($n=null)
1466
{
1467
	// Begin a new object
1468
	if($n===null)
1469
		$n = ++$this->n;
1470
	$this->offsets[$n] = $this->_getoffset();
1471
	$this->_put($n.' 0 obj');
1472
}
1473
1474
protected function _putstream($data)
1475
{
1476
	$this->_put('stream');
1477
	$this->_put($data);
1478
	$this->_put('endstream');
1479
}
1480
1481
protected function _putstreamobject($data)
1482
{
1483
	if($this->compress)
1484
	{
1485
		$entries = '/Filter /FlateDecode ';
1486
		$data = gzcompress($data);
1487
	}
1488
	else
1489
		$entries = '';
1490
	$entries .= '/Length '.strlen($data);
1491
	$this->_newobj();
1492
	$this->_put('<<'.$entries.'>>');
1493
	$this->_putstream($data);
1494
	$this->_put('endobj');
1495
}
1496
1497
protected function _putpage($n)
1498
{
1499
	$this->_newobj();
1500
	$this->_put('<</Type /Page');
1501
	$this->_put('/Parent 1 0 R');
1502
	if(isset($this->PageInfo[$n]['size']))
1503
		$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$this->PageInfo[$n]['size'][0],$this->PageInfo[$n]['size'][1]));
1504
	if(isset($this->PageInfo[$n]['rotation']))
1505
		$this->_put('/Rotate '.$this->PageInfo[$n]['rotation']);
1506
	$this->_put('/Resources 2 0 R');
1507
	if(isset($this->PageLinks[$n]))
1508
	{
1509
		// Links
1510
		$annots = '/Annots [';
1511
		foreach($this->PageLinks[$n] as $pl)
1512
		{
1513
			$rect = sprintf('%.2F %.2F %.2F %.2F',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
1514
			$annots .= '<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
1515
			if(is_string($pl[4]))
1516
				$annots .= '/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
1517
			else
1518
			{
1519
				$l = $this->links[$pl[4]];
1520
				if(isset($this->PageInfo[$l[0]]['size']))
1521
					$h = $this->PageInfo[$l[0]]['size'][1];
1522
				else
1523
					$h = ($this->DefOrientation=='P') ? $this->DefPageSize[1]*$this->k : $this->DefPageSize[0]*$this->k;
1524
				$annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>',$this->PageInfo[$l[0]]['n'],$h-$l[1]*$this->k);
1525
			}
1526
		}
1527
		$this->_put($annots.']');
1528
	}
1529
	if($this->WithAlpha)
1530
		$this->_put('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>');
1531
	$this->_put('/Contents '.($this->n+1).' 0 R>>');
1532
	$this->_put('endobj');
1533
	// Page content
1534
	if(!empty($this->AliasNbPages))
1535
		$this->pages[$n] = str_replace($this->AliasNbPages,$this->page,$this->pages[$n]);
1536
	$this->_putstreamobject($this->pages[$n]);
1537
}
1538
1539
protected function _putpages()
1540
{
1541
	$nb = $this->page;
1542
	for($n=1;$n<=$nb;$n++)
1543
		$this->PageInfo[$n]['n'] = $this->n+1+2*($n-1);
1544
	for($n=1;$n<=$nb;$n++)
1545
		$this->_putpage($n);
1546
	// Pages root
1547
	$this->_newobj(1);
1548
	$this->_put('<</Type /Pages');
1549
	$kids = '/Kids [';
1550
	for($n=1;$n<=$nb;$n++)
1551
		$kids .= $this->PageInfo[$n]['n'].' 0 R ';
1552
	$this->_put($kids.']');
1553
	$this->_put('/Count '.$nb);
1554 View Code Duplication
	if($this->DefOrientation=='P')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1555
	{
1556
		$w = $this->DefPageSize[0];
1557
		$h = $this->DefPageSize[1];
1558
	}
1559
	else
1560
	{
1561
		$w = $this->DefPageSize[1];
1562
		$h = $this->DefPageSize[0];
1563
	}
1564
	$this->_put(sprintf('/MediaBox [0 0 %.2F %.2F]',$w*$this->k,$h*$this->k));
1565
	$this->_put('>>');
1566
	$this->_put('endobj');
1567
}
1568
1569
protected function _putfonts()
1570
{
1571
	foreach($this->FontFiles as $file=>$info)
1572
	{
1573
		// Font file embedding
1574
		$this->_newobj();
1575
		$this->FontFiles[$file]['n'] = $this->n;
1576
		$font = file_get_contents($this->fontpath.$file,true);
1577
		if(!$font)
1578
			$this->Error('Font file not found: '.$file);
1579
		$compressed = (substr($file,-2)=='.z');
1580
		if(!$compressed && isset($info['length2']))
1581
			$font = substr($font,6,$info['length1']).substr($font,6+$info['length1']+6,$info['length2']);
1582
		$this->_put('<</Length '.strlen($font));
1583
		if($compressed)
1584
			$this->_put('/Filter /FlateDecode');
1585
		$this->_put('/Length1 '.$info['length1']);
1586
		if(isset($info['length2']))
1587
			$this->_put('/Length2 '.$info['length2'].' /Length3 0');
1588
		$this->_put('>>');
1589
		$this->_putstream($font);
1590
		$this->_put('endobj');
1591
	}
1592
	foreach($this->fonts as $k=>$font)
1593
	{
1594
		// Encoding
1595
		if(isset($font['diff']))
1596
		{
1597
			if(!isset($this->encodings[$font['enc']]))
1598
			{
1599
				$this->_newobj();
1600
				$this->_put('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$font['diff'].']>>');
1601
				$this->_put('endobj');
1602
				$this->encodings[$font['enc']] = $this->n;
1603
			}
1604
		}
1605
		// ToUnicode CMap
1606
		if(isset($font['uv']))
1607
		{
1608
			if(isset($font['enc']))
1609
				$cmapkey = $font['enc'];
1610
			else
1611
				$cmapkey = $font['name'];
1612
			if(!isset($this->cmaps[$cmapkey]))
1613
			{
1614
				$cmap = $this->_tounicodecmap($font['uv']);
1615
				$this->_putstreamobject($cmap);
1616
				$this->cmaps[$cmapkey] = $this->n;
1617
			}
1618
		}
1619
		// Font object
1620
		$this->fonts[$k]['n'] = $this->n+1;
1621
		$type = $font['type'];
1622
		$name = $font['name'];
1623
		if($font['subsetted'])
1624
			$name = 'AAAAAA+'.$name;
1625
		if($type=='Core')
1626
		{
1627
			// Core font
1628
			$this->_newobj();
1629
			$this->_put('<</Type /Font');
1630
			$this->_put('/BaseFont /'.$name);
1631
			$this->_put('/Subtype /Type1');
1632
			if($name!='Symbol' && $name!='ZapfDingbats')
1633
				$this->_put('/Encoding /WinAnsiEncoding');
1634
			if(isset($font['uv']))
1635
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
0 ignored issues
show
Bug introduced by
The variable $cmapkey 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...
1636
			$this->_put('>>');
1637
			$this->_put('endobj');
1638
		}
1639
		elseif($type=='Type1' || $type=='TrueType')
1640
		{
1641
			// Additional Type1 or TrueType/OpenType font
1642
			$this->_newobj();
1643
			$this->_put('<</Type /Font');
1644
			$this->_put('/BaseFont /'.$name);
1645
			$this->_put('/Subtype /'.$type);
1646
			$this->_put('/FirstChar 32 /LastChar 255');
1647
			$this->_put('/Widths '.($this->n+1).' 0 R');
1648
			$this->_put('/FontDescriptor '.($this->n+2).' 0 R');
1649
			if(isset($font['diff']))
1650
				$this->_put('/Encoding '.$this->encodings[$font['enc']].' 0 R');
1651
			else
1652
				$this->_put('/Encoding /WinAnsiEncoding');
1653
			if(isset($font['uv']))
1654
				$this->_put('/ToUnicode '.$this->cmaps[$cmapkey].' 0 R');
1655
			$this->_put('>>');
1656
			$this->_put('endobj');
1657
			// Widths
1658
			$this->_newobj();
1659
			$cw = &$font['cw'];
1660
			$s = '[';
1661 View Code Duplication
			for($i=32;$i<=255;$i++)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1662
				$s .= $cw[chr($i)].' ';
1663
			$this->_put($s.']');
1664
			$this->_put('endobj');
1665
			// Descriptor
1666
			$this->_newobj();
1667
			$s = '<</Type /FontDescriptor /FontName /'.$name;
1668
			foreach($font['desc'] as $k=>$v)
1669
				$s .= ' /'.$k.' '.$v;
1670
			if(!empty($font['file']))
1671
				$s .= ' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';
1672
			$this->_put($s.'>>');
1673
			$this->_put('endobj');
1674
		}
1675
		else
1676
		{
1677
			// Allow for additional types
1678
			$mtd = '_put'.strtolower($type);
1679
			if(!method_exists($this,$mtd))
1680
				$this->Error('Unsupported font type: '.$type);
1681
			$this->$mtd($font);
1682
		}
1683
	}
1684
}
1685
1686
protected function _tounicodecmap($uv)
1687
{
1688
	$ranges = '';
1689
	$nbr = 0;
1690
	$chars = '';
1691
	$nbc = 0;
1692
	foreach($uv as $c=>$v)
1693
	{
1694
		if(is_array($v))
1695
		{
1696
			$ranges .= sprintf("<%02X> <%02X> <%04X>\n",$c,$c+$v[1]-1,$v[0]);
1697
			$nbr++;
1698
		}
1699
		else
1700
		{
1701
			$chars .= sprintf("<%02X> <%04X>\n",$c,$v);
1702
			$nbc++;
1703
		}
1704
	}
1705
	$s = "/CIDInit /ProcSet findresource begin\n";
1706
	$s .= "12 dict begin\n";
1707
	$s .= "begincmap\n";
1708
	$s .= "/CIDSystemInfo\n";
1709
	$s .= "<</Registry (Adobe)\n";
1710
	$s .= "/Ordering (UCS)\n";
1711
	$s .= "/Supplement 0\n";
1712
	$s .= ">> def\n";
1713
	$s .= "/CMapName /Adobe-Identity-UCS def\n";
1714
	$s .= "/CMapType 2 def\n";
1715
	$s .= "1 begincodespacerange\n";
1716
	$s .= "<00> <FF>\n";
1717
	$s .= "endcodespacerange\n";
1718
	if($nbr>0)
1719
	{
1720
		$s .= "$nbr beginbfrange\n";
1721
		$s .= $ranges;
1722
		$s .= "endbfrange\n";
1723
	}
1724
	if($nbc>0)
1725
	{
1726
		$s .= "$nbc beginbfchar\n";
1727
		$s .= $chars;
1728
		$s .= "endbfchar\n";
1729
	}
1730
	$s .= "endcmap\n";
1731
	$s .= "CMapName currentdict /CMap defineresource pop\n";
1732
	$s .= "end\n";
1733
	$s .= "end";
1734
	return $s;
1735
}
1736
1737
protected function _putimages()
1738
{
1739
	foreach(array_keys($this->images) as $file)
1740
	{
1741
		$this->_putimage($this->images[$file]);
1742
		unset($this->images[$file]['data']);
1743
		unset($this->images[$file]['smask']);
1744
	}
1745
}
1746
1747
protected function _putimage(&$info)
1748
{
1749
	$this->_newobj();
1750
	$info['n'] = $this->n;
1751
	$this->_put('<</Type /XObject');
1752
	$this->_put('/Subtype /Image');
1753
	$this->_put('/Width '.$info['w']);
1754
	$this->_put('/Height '.$info['h']);
1755
	if($info['cs']=='Indexed')
1756
		$this->_put('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
1757
	else
1758
	{
1759
		$this->_put('/ColorSpace /'.$info['cs']);
1760
		if($info['cs']=='DeviceCMYK')
1761
			$this->_put('/Decode [1 0 1 0 1 0 1 0]');
1762
	}
1763
	$this->_put('/BitsPerComponent '.$info['bpc']);
1764
	if(isset($info['f']))
1765
		$this->_put('/Filter /'.$info['f']);
1766
	if(isset($info['dp']))
1767
		$this->_put('/DecodeParms <<'.$info['dp'].'>>');
1768
	if(isset($info['trns']) && is_array($info['trns']))
1769
	{
1770
		$trns = '';
1771
		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...
1772
			$trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';
1773
		$this->_put('/Mask ['.$trns.']');
1774
	}
1775
	if(isset($info['smask']))
1776
		$this->_put('/SMask '.($this->n+1).' 0 R');
1777
	$this->_put('/Length '.strlen($info['data']).'>>');
1778
	$this->_putstream($info['data']);
1779
	$this->_put('endobj');
1780
	// Soft mask
1781
	if(isset($info['smask']))
1782
	{
1783
		$dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns '.$info['w'];
1784
		$smask = array('w'=>$info['w'], 'h'=>$info['h'], 'cs'=>'DeviceGray', 'bpc'=>8, 'f'=>$info['f'], 'dp'=>$dp, 'data'=>$info['smask']);
1785
		$this->_putimage($smask);
1786
	}
1787
	// Palette
1788
	if($info['cs']=='Indexed')
1789
		$this->_putstreamobject($info['pal']);
1790
}
1791
1792
protected function _putxobjectdict()
1793
{
1794
	foreach($this->images as $image)
1795
		$this->_put('/I'.$image['i'].' '.$image['n'].' 0 R');
1796
}
1797
1798
protected function _putresourcedict()
1799
{
1800
	$this->_put('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
1801
	$this->_put('/Font <<');
1802
	foreach($this->fonts as $font)
1803
		$this->_put('/F'.$font['i'].' '.$font['n'].' 0 R');
1804
	$this->_put('>>');
1805
	$this->_put('/XObject <<');
1806
	$this->_putxobjectdict();
1807
	$this->_put('>>');
1808
}
1809
1810
protected function _putresources()
1811
{
1812
	$this->_putfonts();
1813
	$this->_putimages();
1814
	// Resource dictionary
1815
	$this->_newobj(2);
1816
	$this->_put('<<');
1817
	$this->_putresourcedict();
1818
	$this->_put('>>');
1819
	$this->_put('endobj');
1820
}
1821
1822
protected function _putinfo()
1823
{
1824
	$this->metadata['Producer'] = 'FPDF '.FPDF_VERSION;
1825
	$this->metadata['CreationDate'] = 'D:'.@date('YmdHis');
1826
	foreach($this->metadata as $key=>$value)
1827
		$this->_put('/'.$key.' '.$this->_textstring($value));
1828
}
1829
1830
protected function _putcatalog()
1831
{
1832
	$n = $this->PageInfo[1]['n'];
1833
	$this->_put('/Type /Catalog');
1834
	$this->_put('/Pages 1 0 R');
1835
	if($this->ZoomMode=='fullpage')
1836
		$this->_put('/OpenAction ['.$n.' 0 R /Fit]');
1837
	elseif($this->ZoomMode=='fullwidth')
1838
		$this->_put('/OpenAction ['.$n.' 0 R /FitH null]');
1839
	elseif($this->ZoomMode=='real')
1840
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null 1]');
1841
	elseif(!is_string($this->ZoomMode))
1842
		$this->_put('/OpenAction ['.$n.' 0 R /XYZ null null '.sprintf('%.2F',$this->ZoomMode/100).']');
1843
	if($this->LayoutMode=='single')
1844
		$this->_put('/PageLayout /SinglePage');
1845
	elseif($this->LayoutMode=='continuous')
1846
		$this->_put('/PageLayout /OneColumn');
1847
	elseif($this->LayoutMode=='two')
1848
		$this->_put('/PageLayout /TwoColumnLeft');
1849
}
1850
1851
protected function _putheader()
1852
{
1853
	$this->_put('%PDF-'.$this->PDFVersion);
1854
}
1855
1856
protected function _puttrailer()
1857
{
1858
	$this->_put('/Size '.($this->n+1));
1859
	$this->_put('/Root '.$this->n.' 0 R');
1860
	$this->_put('/Info '.($this->n-1).' 0 R');
1861
}
1862
1863
protected function _enddoc()
1864
{
1865
	$this->_putheader();
1866
	$this->_putpages();
1867
	$this->_putresources();
1868
	// Info
1869
	$this->_newobj();
1870
	$this->_put('<<');
1871
	$this->_putinfo();
1872
	$this->_put('>>');
1873
	$this->_put('endobj');
1874
	// Catalog
1875
	$this->_newobj();
1876
	$this->_put('<<');
1877
	$this->_putcatalog();
1878
	$this->_put('>>');
1879
	$this->_put('endobj');
1880
	// Cross-ref
1881
	$offset = $this->_getoffset();
1882
	$this->_put('xref');
1883
	$this->_put('0 '.($this->n+1));
1884
	$this->_put('0000000000 65535 f ');
1885
	for($i=1;$i<=$this->n;$i++)
1886
		$this->_put(sprintf('%010d 00000 n ',$this->offsets[$i]));
1887
	// Trailer
1888
	$this->_put('trailer');
1889
	$this->_put('<<');
1890
	$this->_puttrailer();
1891
	$this->_put('>>');
1892
	$this->_put('startxref');
1893
	$this->_put($offset);
1894
	$this->_put('%%EOF');
1895
	$this->state = 3;
1896
}
1897
}
1898
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

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

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

Loading history...
1899