WooCommerce PDF Invoices & Packing Slips - Version 2.0.15

Version Description

  • Fix: Prevent saving invoice number/date from order details page when not edited
Download this release

Release Info

Developer pomegranate
Plugin Icon 128x128 WooCommerce PDF Invoices & Packing Slips
Version 2.0.15
Comparing to
See all releases

Code changes from version 2.0.14 to 2.0.15

includes/class-wcpdf-admin.php CHANGED
@@ -323,15 +323,15 @@ class Admin {
323
  <p class="form-field _wcpdf_invoice_number_field ">
324
  <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
325
  <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
326
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>">
327
  <?php else : ?>
328
- <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled" >
329
  <?php endif; ?>
330
  </p>
331
  <p class="form-field form-field-wide">
332
  <label for="wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
333
  <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
334
- <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
335
  <?php else : ?>
336
  <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" disabled="disabled" value="" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
337
  <?php endif; ?>
323
  <p class="form-field _wcpdf_invoice_number_field ">
324
  <label for="_wcpdf_invoice_number"><?php _e( 'Invoice Number (unformatted!)', 'woocommerce-pdf-invoices-packing-slips' ); ?>:</label>
325
  <?php if ( $invoice->exists() && !empty($invoice_number) ) : ?>
326
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="<?php echo $invoice_number->get_plain(); ?>" disabled="disabled">
327
  <?php else : ?>
328
+ <input type="text" class="short" style="" name="_wcpdf_invoice_number" id="_wcpdf_invoice_number" value="" disabled="disabled">
329
  <?php endif; ?>
330
  </p>
331
  <p class="form-field form-field-wide">
332
  <label for="wcpdf_invoice_date"><?php _e( 'Invoice Date:', 'woocommerce-pdf-invoices-packing-slips' ); ?></label>
333
  <?php if ( $invoice->exists() && !empty($invoice_date) ) : ?>
334
+ <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" value="<?php echo $invoice_date->date_i18n( 'Y-m-d' ); ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" disabled="disabled"/>@<input type="number" class="hour" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="<?php echo $invoice_date->date_i18n( 'H' ) ?>" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="<?php echo $invoice_date->date_i18n( 'i' ); ?>" pattern="[0-5]{1}[0-9]{1}" />
335
  <?php else : ?>
336
  <input type="text" class="date-picker-field" name="wcpdf_invoice_date" id="wcpdf_invoice_date" maxlength="10" disabled="disabled" value="" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />@<input type="number" class="hour" disabled="disabled" placeholder="<?php _e( 'h', 'woocommerce' ) ?>" name="wcpdf_invoice_date_hour" id="wcpdf_invoice_date_hour" min="0" max="23" size="2" value="" pattern="([01]?[0-9]{1}|2[0-3]{1})" />:<input type="number" class="minute" placeholder="<?php _e( 'm', 'woocommerce' ) ?>" name="wcpdf_invoice_date_minute" id="wcpdf_invoice_date_minute" min="0" max="59" size="2" value="" pattern="[0-5]{1}[0-9]{1}" disabled="disabled" />
337
  <?php endif; ?>
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: woocommerce, pdf, invoices, packing slips, print, delivery notes, invoice,
5
  Requires at least: 3.5
6
  Tested up to: 4.8
7
  Requires PHP: 5.3
8
- Stable tag: 2.0.14
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -105,6 +105,9 @@ There's a setting on the Status tab of the settings page that allows you to togg
105
 
106
  **2.0 is a BIG update! Make a full site backup before upgrading**
107
 
 
 
 
108
  = 2.0.14 =
109
  * Feature: Manually resend specific order emails in WooCommerce 3.2+
110
  * Tweak: Show full size logo preview in settings
@@ -205,5 +208,5 @@ There's a setting on the Status tab of the settings page that allows you to togg
205
 
206
  == Upgrade Notice ==
207
 
208
- = 2.0.14 =
209
  **2.0 is a BIG update! Make a full site backup before upgrading!**
5
  Requires at least: 3.5
6
  Tested up to: 4.8
7
  Requires PHP: 5.3
8
+ Stable tag: 2.0.15
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
105
 
106
  **2.0 is a BIG update! Make a full site backup before upgrading**
107
 
108
+ = 2.0.15 =
109
+ * Fix: Prevent saving invoice number/date from order details page when not edited
110
+
111
  = 2.0.14 =
112
  * Feature: Manually resend specific order emails in WooCommerce 3.2+
113
  * Tweak: Show full size logo preview in settings
208
 
209
  == Upgrade Notice ==
210
 
211
+ = 2.0.15 =
212
  **2.0 is a BIG update! Make a full site backup before upgrading!**
vendor/dompdf/dompdf/src/Dompdf.php CHANGED
@@ -1,1508 +1,1517 @@
1
- <?php
2
- /**
3
- * @package dompdf
4
- * @link http://dompdf.github.com/
5
- * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
- * @author Fabien Ménager <fabien.menager@gmail.com>
7
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
- */
9
- namespace Dompdf;
10
-
11
- use DOMDocument;
12
- use DOMNode;
13
- use Dompdf\Adapter\CPDF;
14
- use DOMXPath;
15
- use Dompdf\Frame\Factory;
16
- use Dompdf\Frame\FrameTree;
17
- use HTML5_Tokenizer;
18
- use HTML5_TreeBuilder;
19
- use Dompdf\Image\Cache;
20
- use Dompdf\Renderer\ListBullet;
21
- use Dompdf\Css\Stylesheet;
22
-
23
- /**
24
- * Dompdf - PHP5 HTML to PDF renderer
25
- *
26
- * Dompdf loads HTML and does its best to render it as a PDF. It gets its
27
- * name from the new DomDocument PHP5 extension. Source HTML is first
28
- * parsed by a DomDocument object. Dompdf takes the resulting DOM tree and
29
- * attaches a {@link Frame} object to each node. {@link Frame} objects store
30
- * positioning and layout information and each has a reference to a {@link
31
- * Style} object.
32
- *
33
- * Style information is loaded and parsed (see {@link Stylesheet}) and is
34
- * applied to the frames in the tree by using XPath. CSS selectors are
35
- * converted into XPath queries, and the computed {@link Style} objects are
36
- * applied to the {@link Frame}s.
37
- *
38
- * {@link Frame}s are then decorated (in the design pattern sense of the
39
- * word) based on their CSS display property ({@link
40
- * http://www.w3.org/TR/CSS21/visuren.html#propdef-display}).
41
- * Frame_Decorators augment the basic {@link Frame} class by adding
42
- * additional properties and methods specific to the particular type of
43
- * {@link Frame}. For example, in the CSS layout model, block frames
44
- * (display: block;) contain line boxes that are usually filled with text or
45
- * other inline frames. The Block therefore adds a $lines
46
- * property as well as methods to add {@link Frame}s to lines and to add
47
- * additional lines. {@link Frame}s also are attached to specific
48
- * AbstractPositioner and {@link AbstractFrameReflower} objects that contain the
49
- * positioining and layout algorithm for a specific type of frame,
50
- * respectively. This is an application of the Strategy pattern.
51
- *
52
- * Layout, or reflow, proceeds recursively (post-order) starting at the root
53
- * of the document. Space constraints (containing block width & height) are
54
- * pushed down, and resolved positions and sizes bubble up. Thus, every
55
- * {@link Frame} in the document tree is traversed once (except for tables
56
- * which use a two-pass layout algorithm). If you are interested in the
57
- * details, see the reflow() method of the Reflower classes.
58
- *
59
- * Rendering is relatively straightforward once layout is complete. {@link
60
- * Frame}s are rendered using an adapted {@link Cpdf} class, originally
61
- * written by Wayne Munro, http://www.ros.co.nz/pdf/. (Some performance
62
- * related changes have been made to the original {@link Cpdf} class, and
63
- * the {@link Dompdf\Adapter\CPDF} class provides a simple, stateless interface to
64
- * PDF generation.) PDFLib support has now also been added, via the {@link
65
- * Dompdf\Adapter\PDFLib}.
66
- *
67
- *
68
- * @package dompdf
69
- */
70
- class Dompdf
71
- {
72
- /**
73
- * Version string for dompdf
74
- *
75
- * @var string
76
- */
77
- private $version = 'dompdf';
78
-
79
- /**
80
- * DomDocument representing the HTML document
81
- *
82
- * @var DOMDocument
83
- */
84
- private $dom;
85
-
86
- /**
87
- * FrameTree derived from the DOM tree
88
- *
89
- * @var FrameTree
90
- */
91
- private $tree;
92
-
93
- /**
94
- * Stylesheet for the document
95
- *
96
- * @var Stylesheet
97
- */
98
- private $css;
99
-
100
- /**
101
- * Actual PDF renderer
102
- *
103
- * @var Canvas
104
- */
105
- private $canvas;
106
-
107
- /**
108
- * Desired paper size ('letter', 'legal', 'A4', etc.)
109
- *
110
- * @var string
111
- */
112
- private $paperSize;
113
-
114
- /**
115
- * Paper orientation ('portrait' or 'landscape')
116
- *
117
- * @var string
118
- */
119
- private $paperOrientation = "portrait";
120
-
121
- /**
122
- * Callbacks on new page and new element
123
- *
124
- * @var array
125
- */
126
- private $callbacks = array();
127
-
128
- /**
129
- * Experimental caching capability
130
- *
131
- * @var string
132
- */
133
- private $cacheId;
134
-
135
- /**
136
- * Base hostname
137
- *
138
- * Used for relative paths/urls
139
- * @var string
140
- */
141
- private $baseHost = "";
142
-
143
- /**
144
- * Absolute base path
145
- *
146
- * Used for relative paths/urls
147
- * @var string
148
- */
149
- private $basePath = "";
150
-
151
- /**
152
- * Protcol used to request file (file://, http://, etc)
153
- *
154
- * @var string
155
- */
156
- private $protocol;
157
-
158
- /**
159
- * HTTP context created with stream_context_create()
160
- * Will be used for file_get_contents
161
- *
162
- * @var resource
163
- */
164
- private $httpContext;
165
-
166
- /**
167
- * Timestamp of the script start time
168
- *
169
- * @var int
170
- */
171
- private $startTime = null;
172
-
173
- /**
174
- * The system's locale
175
- *
176
- * @var string
177
- */
178
- private $systemLocale = null;
179
-
180
- /**
181
- * Tells if the system's locale is the C standard one
182
- *
183
- * @var bool
184
- */
185
- private $localeStandard = false;
186
-
187
- /**
188
- * The default view of the PDF in the viewer
189
- *
190
- * @var string
191
- */
192
- private $defaultView = "Fit";
193
-
194
- /**
195
- * The default view options of the PDF in the viewer
196
- *
197
- * @var array
198
- */
199
- private $defaultViewOptions = array();
200
-
201
- /**
202
- * Tells wether the DOM document is in quirksmode (experimental)
203
- *
204
- * @var bool
205
- */
206
- private $quirksmode = false;
207
-
208
- /**
209
- * Protocol whitelist
210
- *
211
- * Protocols and PHP wrappers allowed in URLs. Full support is not
212
- * guarantee for the protocols/wrappers contained in this array.
213
- *
214
- * @var array
215
- */
216
- private $allowedProtocols = array(null, "", "file://", "http://", "https://");
217
-
218
- /**
219
- * Local file extension whitelist
220
- *
221
- * File extensions supported by dompdf for local files.
222
- *
223
- * @var array
224
- */
225
- private $allowedLocalFileExtensions = array("htm", "html");
226
-
227
- /**
228
- * @var array
229
- */
230
- private $messages = array();
231
-
232
- /**
233
- * @var Options
234
- */
235
- private $options;
236
-
237
- /**
238
- * @var FontMetrics
239
- */
240
- private $fontMetrics;
241
-
242
- /**
243
- * The list of built-in fonts
244
- *
245
- * @var array
246
- * @deprecated
247
- */
248
- public static $native_fonts = array(
249
- "courier", "courier-bold", "courier-oblique", "courier-boldoblique",
250
- "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique",
251
- "times-roman", "times-bold", "times-italic", "times-bolditalic",
252
- "symbol", "zapfdinbats"
253
- );
254
-
255
- /**
256
- * The list of built-in fonts
257
- *
258
- * @var array
259
- */
260
- public static $nativeFonts = array(
261
- "courier", "courier-bold", "courier-oblique", "courier-boldoblique",
262
- "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique",
263
- "times-roman", "times-bold", "times-italic", "times-bolditalic",
264
- "symbol", "zapfdinbats"
265
- );
266
-
267
- /**
268
- * Class constructor
269
- *
270
- * @param array|Options $options
271
- */
272
- public function __construct($options = null)
273
- {
274
- mb_internal_encoding('UTF-8');
275
-
276
- if (isset($options) && $options instanceof Options) {
277
- $this->setOptions($options);
278
- } elseif (is_array($options)) {
279
- $this->setOptions(new Options($options));
280
- } else {
281
- $this->setOptions(new Options());
282
- }
283
-
284
- $versionFile = realpath(__DIR__ . '/../VERSION');
285
- if (file_exists($versionFile) && ($version = file_get_contents($versionFile)) !== false && $version !== '$Format:<%h>$') {
286
- $this->version = sprintf('dompdf %s', $version);
287
- }
288
-
289
- $this->localeStandard = sprintf('%.1f', 1.0) == '1.0';
290
- $this->saveLocale();
291
- $this->paperSize = $this->options->getDefaultPaperSize();
292
- $this->paperOrientation = $this->options->getDefaultPaperOrientation();
293
-
294
- $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
295
- $this->setFontMetrics(new FontMetrics($this->getCanvas(), $this->getOptions()));
296
- $this->css = new Stylesheet($this);
297
-
298
- $this->restoreLocale();
299
- }
300
-
301
- /**
302
- * Save the system's locale configuration and
303
- * set the right value for numeric formatting
304
- */
305
- private function saveLocale()
306
- {
307
- if ($this->localeStandard) {
308
- return;
309
- }
310
-
311
- $this->systemLocale = setlocale(LC_NUMERIC, "0");
312
- setlocale(LC_NUMERIC, "C");
313
- }
314
-
315
- /**
316
- * Restore the system's locale configuration
317
- */
318
- private function restoreLocale()
319
- {
320
- if ($this->localeStandard) {
321
- return;
322
- }
323
-
324
- setlocale(LC_NUMERIC, $this->systemLocale);
325
- }
326
-
327
- /**
328
- * @param $file
329
- * @deprecated
330
- */
331
- public function load_html_file($file)
332
- {
333
- $this->loadHtmlFile($file);
334
- }
335
-
336
- /**
337
- * Loads an HTML file
338
- * Parse errors are stored in the global array _dompdf_warnings.
339
- *
340
- * @param string $file a filename or url to load
341
- *
342
- * @throws Exception
343
- */
344
- public function loadHtmlFile($file)
345
- {
346
- $this->saveLocale();
347
-
348
- if (!$this->protocol && !$this->baseHost && !$this->basePath) {
349
- list($this->protocol, $this->baseHost, $this->basePath) = Helpers::explode_url($file);
350
- }
351
- $protocol = strtolower($this->protocol);
352
-
353
- if ( !in_array($protocol, $this->allowedProtocols) ) {
354
- throw new Exception("Permission denied on $file. The communication protocol is not supported.");
355
- }
356
-
357
- if (!$this->options->isRemoteEnabled() && ($protocol != "" && $protocol !== "file://")) {
358
- throw new Exception("Remote file requested, but remote file download is disabled.");
359
- }
360
-
361
- if ($protocol == "" || $protocol === "file://") {
362
- $realfile = realpath($file);
363
-
364
- $chroot = realpath($this->options->getChroot());
365
- if ($chroot && strpos($realfile, $chroot) !== 0) {
366
- throw new Exception("Permission denied on $file. The file could not be found under the directory specified by Options::chroot.");
367
- }
368
-
369
- $ext = strtolower(pathinfo($realfile, PATHINFO_EXTENSION));
370
- if (!in_array($ext, $this->allowedLocalFileExtensions)) {
371
- throw new Exception("Permission denied on $file.");
372
- }
373
-
374
- if (!$realfile) {
375
- throw new Exception("File '$file' not found.");
376
- }
377
-
378
- $file = $realfile;
379
- }
380
-
381
- list($contents, $http_response_header) = Helpers::getFileContent($file, $this->httpContext);
382
- $encoding = 'UTF-8';
383
-
384
- // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
385
- if (isset($http_response_header)) {
386
- foreach ($http_response_header as $_header) {
387
- if (preg_match("@Content-Type:\s*[\w/]+;\s*?charset=([^\s]+)@i", $_header, $matches)) {
388
- $encoding = strtoupper($matches[1]);
389
- break;
390
- }
391
- }
392
- }
393
-
394
- $this->restoreLocale();
395
-
396
- $this->loadHtml($contents, $encoding);
397
- }
398
-
399
- /**
400
- * @param $str
401
- * @param null $encoding
402
- * @deprecated
403
- */
404
- public function load_html($str, $encoding = 'UTF-8')
405
- {
406
- $this->loadHtml($str, $encoding);
407
- }
408
-
409
- /**
410
- * Loads an HTML string
411
- * Parse errors are stored in the global array _dompdf_warnings.
412
- * @todo use the $encoding variable
413
- *
414
- * @param string $str HTML text to load
415
- * @param string $encoding Not used yet
416
- */
417
- public function loadHtml($str, $encoding = 'UTF-8')
418
- {
419
- $this->saveLocale();
420
-
421
- // FIXME: Determine character encoding, switch to UTF8, update meta tag. Need better http/file stream encoding detection, currently relies on text or meta tag.
422
- $known_encodings = mb_list_encodings();
423
- mb_detect_order('auto');
424
- if (($file_encoding = mb_detect_encoding($str, null, true)) === false) {
425
- $file_encoding = "auto";
426
- }
427
- if (in_array(strtoupper($file_encoding), array('UTF-8','UTF8')) === false) {
428
- $str = mb_convert_encoding($str, 'UTF-8', $file_encoding);
429
- }
430
-
431
- $metatags = array(
432
- '@<meta\s+http-equiv="Content-Type"\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))?@i',
433
- '@<meta\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))"?\s+http-equiv="Content-Type"@i',
434
- '@<meta [^>]*charset\s*=\s*["\']?\s*([^"\' ]+)@i',
435
- );
436
- foreach ($metatags as $metatag) {
437
- if (preg_match($metatag, $str, $matches)) {
438
- if (isset($matches[1]) && in_array($matches[1], $known_encodings)) {
439
- $document_encoding = $matches[1];
440
- break;
441
- }
442
- }
443
- }
444
- if (isset($document_encoding) && in_array(strtoupper($document_encoding), array('UTF-8','UTF8')) === false) {
445
- $str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str);
446
- } elseif (isset($document_encoding) === false && strpos($str, '<head>') !== false) {
447
- $str = str_replace('<head>', '<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">', $str);
448
- } elseif (isset($document_encoding) === false) {
449
- $str = '<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">' . $str;
450
- }
451
- //FIXME: since we're not using this just yet
452
- $encoding = 'UTF-8';
453
-
454
- // remove BOM mark from UTF-8, it's treated as document text by DOMDocument
455
- // FIXME: roll this into the encoding detection using UTF-8/16/32 BOM (http://us2.php.net/manual/en/function.mb-detect-encoding.php#91051)?
456
- if (substr($str, 0, 3) == chr(0xEF) . chr(0xBB) . chr(0xBF)) {
457
- $str = substr($str, 3);
458
- }
459
-
460
- // Store parsing warnings as messages
461
- set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
462
-
463
- // @todo Take the quirksmode into account
464
- // http://hsivonen.iki.fi/doctype/
465
- // https://developer.mozilla.org/en/mozilla's_quirks_mode
466
- $quirksmode = false;
467
-
468
- if ($this->options->isHtml5ParserEnabled()) {
469
- $tokenizer = new HTML5_Tokenizer($str);
470
- $tokenizer->parse();
471
- $doc = $tokenizer->save();
472
-
473
- // Remove #text children nodes in nodes that shouldn't have
474
- $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
475
- foreach ($tag_names as $tag_name) {
476
- $nodes = $doc->getElementsByTagName($tag_name);
477
-
478
- foreach ($nodes as $node) {
479
- self::removeTextNodes($node);
480
- }
481
- }
482
-
483
- $quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS);
484
- } else {
485
- // loadHTML assumes ISO-8859-1 unless otherwise specified on the HTML document header.
486
- // http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/ (see #4)
487
- // http://stackoverflow.com/a/11310258/264628
488
- $doc = new DOMDocument("1.0", $encoding);
489
- $doc->preserveWhiteSpace = true;
490
- $doc->loadHTML($str);
491
- $doc->encoding = $encoding;
492
-
493
- // If some text is before the doctype, we are in quirksmode
494
- if (preg_match("/^(.+)<!doctype/i", ltrim($str), $matches)) {
495
- $quirksmode = true;
496
- } // If no doctype is provided, we are in quirksmode
497
- elseif (!preg_match("/^<!doctype/i", ltrim($str), $matches)) {
498
- $quirksmode = true;
499
- } else {
500
- // HTML5 <!DOCTYPE html>
501
- if (!$doc->doctype->publicId && !$doc->doctype->systemId) {
502
- $quirksmode = false;
503
- }
504
-
505
- // not XHTML
506
- if (!preg_match("/xhtml/i", $doc->doctype->publicId)) {
507
- $quirksmode = true;
508
- }
509
- }
510
- }
511
-
512
- $this->dom = $doc;
513
- $this->quirksmode = $quirksmode;
514
-
515
- $this->tree = new FrameTree($this->dom);
516
-
517
- restore_error_handler();
518
-
519
- $this->restoreLocale();
520
- }
521
-
522
- /**
523
- * @param DOMNode $node
524
- * @deprecated
525
- */
526
- public static function remove_text_nodes(DOMNode $node)
527
- {
528
- self::removeTextNodes($node);
529
- }
530
-
531
- /**
532
- * @param DOMNode $node
533
- */
534
- public static function removeTextNodes(DOMNode $node)
535
- {
536
- $children = array();
537
- for ($i = 0; $i < $node->childNodes->length; $i++) {
538
- $child = $node->childNodes->item($i);
539
- if ($child->nodeName === "#text") {
540
- $children[] = $child;
541
- }
542
- }
543
-
544
- foreach ($children as $child) {
545
- $node->removeChild($child);
546
- }
547
- }
548
-
549
- /**
550
- * Builds the {@link FrameTree}, loads any CSS and applies the styles to
551
- * the {@link FrameTree}
552
- */
553
- private function processHtml()
554
- {
555
- $this->tree->build_tree();
556
-
557
- $this->css->load_css_file(Stylesheet::getDefaultStylesheet(), Stylesheet::ORIG_UA);
558
-
559
- $acceptedmedia = Stylesheet::$ACCEPTED_GENERIC_MEDIA_TYPES;
560
- $acceptedmedia[] = $this->options->getDefaultMediaType();
561
-
562
- // <base href="" />
563
- $base_nodes = $this->dom->getElementsByTagName("base");
564
- if ($base_nodes->length && ($href = $base_nodes->item(0)->getAttribute("href"))) {
565
- list($this->protocol, $this->baseHost, $this->basePath) = Helpers::explode_url($href);
566
- }
567
-
568
- // Set the base path of the Stylesheet to that of the file being processed
569
- $this->css->set_protocol($this->protocol);
570
- $this->css->set_host($this->baseHost);
571
- $this->css->set_base_path($this->basePath);
572
-
573
- // Get all the stylesheets so that they are processed in document order
574
- $xpath = new DOMXPath($this->dom);
575
- $stylesheets = $xpath->query("//*[name() = 'link' or name() = 'style']");
576
-
577
- /** @var \DOMElement $tag */
578
- foreach ($stylesheets as $tag) {
579
- switch (strtolower($tag->nodeName)) {
580
- // load <link rel="STYLESHEET" ... /> tags
581
- case "link":
582
- if (mb_strtolower(stripos($tag->getAttribute("rel"), "stylesheet") !== false) || // may be "appendix stylesheet"
583
- mb_strtolower($tag->getAttribute("type")) === "text/css"
584
- ) {
585
- //Check if the css file is for an accepted media type
586
- //media not given then always valid
587
- $formedialist = preg_split("/[\s\n,]/", $tag->getAttribute("media"), -1, PREG_SPLIT_NO_EMPTY);
588
- if (count($formedialist) > 0) {
589
- $accept = false;
590
- foreach ($formedialist as $type) {
591
- if (in_array(mb_strtolower(trim($type)), $acceptedmedia)) {
592
- $accept = true;
593
- break;
594
- }
595
- }
596
-
597
- if (!$accept) {
598
- //found at least one mediatype, but none of the accepted ones
599
- //Skip this css file.
600
- continue;
601
- }
602
- }
603
-
604
- $url = $tag->getAttribute("href");
605
- $url = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $url);
606
-
607
- $this->css->load_css_file($url, Stylesheet::ORIG_AUTHOR);
608
- }
609
- break;
610
-
611
- // load <style> tags
612
- case "style":
613
- // Accept all <style> tags by default (note this is contrary to W3C
614
- // HTML 4.0 spec:
615
- // http://www.w3.org/TR/REC-html40/present/styles.html#adef-media
616
- // which states that the default media type is 'screen'
617
- if ($tag->hasAttributes() &&
618
- ($media = $tag->getAttribute("media")) &&
619
- !in_array($media, $acceptedmedia)
620
- ) {
621
- continue;
622
- }
623
-
624
- $css = "";
625
- if ($tag->hasChildNodes()) {
626
- $child = $tag->firstChild;
627
- while ($child) {
628
- $css .= $child->nodeValue; // Handle <style><!-- blah --></style>
629
- $child = $child->nextSibling;
630
- }
631
- } else {
632
- $css = $tag->nodeValue;
633
- }
634
-
635
- $this->css->load_css($css, Stylesheet::ORIG_AUTHOR);
636
- break;
637
- }
638
- }
639
- }
640
-
641
- /**
642
- * @param string $cacheId
643
- * @deprecated
644
- */
645
- public function enable_caching($cacheId)
646
- {
647
- $this->enableCaching($cacheId);
648
- }
649
-
650
- /**
651
- * Enable experimental caching capability
652
- *
653
- * @param string $cacheId
654
- */
655
- public function enableCaching($cacheId)
656
- {
657
- $this->cacheId = $cacheId;
658
- }
659
-
660
- /**
661
- * @param string $value
662
- * @return bool
663
- * @deprecated
664
- */
665
- public function parse_default_view($value)
666
- {
667
- return $this->parseDefaultView($value);
668
- }
669
-
670
- /**
671
- * @param string $value
672
- * @return bool
673
- */
674
- public function parseDefaultView($value)
675
- {
676
- $valid = array("XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV");
677
-
678
- $options = preg_split("/\s*,\s*/", trim($value));
679
- $defaultView = array_shift($options);
680
-
681
- if (!in_array($defaultView, $valid)) {
682
- return false;
683
- }
684
-
685
- $this->setDefaultView($defaultView, $options);
686
- return true;
687
- }
688
-
689
- /**
690
- * Renders the HTML to PDF
691
- */
692
- public function render()
693
- {
694
- $this->saveLocale();
695
- $options = $this->options;
696
-
697
- $logOutputFile = $options->getLogOutputFile();
698
- if ($logOutputFile) {
699
- if (!file_exists($logOutputFile) && is_writable(dirname($logOutputFile))) {
700
- touch($logOutputFile);
701
- }
702
-
703
- $this->startTime = microtime(true);
704
- if (is_writable($logOutputFile)) {
705
- ob_start();
706
- }
707
- }
708
-
709
- $this->processHtml();
710
-
711
- $this->css->apply_styles($this->tree);
712
-
713
- // @page style rules : size, margins
714
- $pageStyles = $this->css->get_page_styles();
715
- $basePageStyle = $pageStyles["base"];
716
- unset($pageStyles["base"]);
717
-
718
- foreach ($pageStyles as $pageStyle) {
719
- $pageStyle->inherit($basePageStyle);
720
- }
721
-
722
- $defaultOptionPaperSize = $this->getPaperSize($options->getDefaultPaperSize());
723
- // If there is a CSS defined paper size compare to the paper size used to create the canvas to determine a
724
- // recreation need
725
- if (is_array($basePageStyle->size)) {
726
- $basePageStyleSize = $basePageStyle->size;
727
- $this->setPaper(array(0, 0, $basePageStyleSize[0], $basePageStyleSize[1]));
728
- }
729
-
730
- $paperSize = $this->getPaperSize();
731
- if (
732
- $defaultOptionPaperSize[2] !== $paperSize[2] ||
733
- $defaultOptionPaperSize[3] !== $paperSize[3] ||
734
- $options->getDefaultPaperOrientation() !== $this->paperOrientation
735
- ) {
736
- $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
737
- $this->fontMetrics->setCanvas($this->getCanvas());
738
- }
739
-
740
- $canvas = $this->getCanvas();
741
-
742
- if ($options->isFontSubsettingEnabled() && $canvas instanceof CPDF) {
743
- foreach ($this->tree->get_frames() as $frame) {
744
- $style = $frame->get_style();
745
- $node = $frame->get_node();
746
-
747
- // Handle text nodes
748
- if ($node->nodeName === "#text") {
749
- $chars = mb_strtoupper($node->nodeValue) . mb_strtolower($node->nodeValue);
750
- $canvas->register_string_subset($style->font_family, $chars);
751
- continue;
752
- }
753
-
754
- // Handle generated content (list items)
755
- if ($style->display === "list-item") {
756
- $chars = ListBullet::get_counter_chars($style->list_style_type);
757
- $canvas->register_string_subset($style->font_family, $chars);
758
- continue;
759
- }
760
-
761
- // Handle other generated content (pseudo elements)
762
- // FIXME: This only captures the text of the stylesheet declaration,
763
- // not the actual generated content, and forces all possible counter
764
- // values. See notes in issue #750.
765
- if ($frame->get_node()->nodeName == "dompdf_generated") {
766
- // all possible counter values, just in case
767
- $chars = ListBullet::get_counter_chars('decimal');
768
- $canvas->register_string_subset($style->font_family, $chars);
769
- $chars = ListBullet::get_counter_chars('upper-alpha');
770
- $canvas->register_string_subset($style->font_family, $chars);
771
- $chars = ListBullet::get_counter_chars('lower-alpha');
772
- $canvas->register_string_subset($style->font_family, $chars);
773
- $chars = ListBullet::get_counter_chars('lower-greek');
774
- $canvas->register_string_subset($style->font_family, $chars);
775
-
776
- // the hex-decoded text of the content property, duplicated from AbstrctFrameReflower::_parse_string
777
- $decoded_string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/",
778
- function ($matches) { return \Dompdf\Helpers::unichr(hexdec($matches[1])); },
779
- $style->content);
780
- $chars = mb_strtoupper($style->content) . mb_strtolower($style->content) . mb_strtoupper($decoded_string) . mb_strtolower($decoded_string);
781
- $canvas->register_string_subset($style->font_family, $chars);
782
- continue;
783
- }
784
- }
785
- }
786
-
787
- $root = null;
788
-
789
- foreach ($this->tree->get_frames() as $frame) {
790
- // Set up the root frame
791
- if (is_null($root)) {
792
- $root = Factory::decorate_root($this->tree->get_root(), $this);
793
- continue;
794
- }
795
-
796
- // Create the appropriate decorators, reflowers & positioners.
797
- Factory::decorate_frame($frame, $this, $root);
798
- }
799
-
800
- // Add meta information
801
- $title = $this->dom->getElementsByTagName("title");
802
- if ($title->length) {
803
- $canvas->add_info("Title", trim($title->item(0)->nodeValue));
804
- }
805
-
806
- $metas = $this->dom->getElementsByTagName("meta");
807
- $labels = array(
808
- "author" => "Author",
809
- "keywords" => "Keywords",
810
- "description" => "Subject",
811
- );
812
- /** @var \DOMElement $meta */
813
- foreach ($metas as $meta) {
814
- $name = mb_strtolower($meta->getAttribute("name"));
815
- $value = trim($meta->getAttribute("content"));
816
-
817
- if (isset($labels[$name])) {
818
- $canvas->add_info($labels[$name], $value);
819
- continue;
820
- }
821
-
822
- if ($name === "dompdf.view" && $this->parseDefaultView($value)) {
823
- $canvas->set_default_view($this->defaultView, $this->defaultViewOptions);
824
- }
825
- }
826
-
827
- $root->set_containing_block(0, 0,$canvas->get_width(), $canvas->get_height());
828
- $root->set_renderer(new Renderer($this));
829
-
830
- // This is where the magic happens:
831
- $root->reflow();
832
-
833
- // Clean up cached images
834
- Cache::clear();
835
-
836
- global $_dompdf_warnings, $_dompdf_show_warnings;
837
- if ($_dompdf_show_warnings && isset($_dompdf_warnings)) {
838
- echo '<b>Dompdf Warnings</b><br><pre>';
839
- foreach ($_dompdf_warnings as $msg) {
840
- echo $msg . "\n";
841
- }
842
-
843
- if ($canvas instanceof CPDF) {
844
- echo $canvas->get_cpdf()->messages;
845
- }
846
- echo '</pre>';
847
- flush();
848
- }
849
-
850
- if ($logOutputFile && is_writable($logOutputFile)) {
851
- $this->write_log();
852
- ob_end_clean();
853
- }
854
-
855
- $this->restoreLocale();
856
- }
857
-
858
- /**
859
- * Add meta information to the PDF after rendering
860
- */
861
- public function add_info($label, $value)
862
- {
863
- $canvas = $this->getCanvas();
864
- if (!is_null($canvas)) {
865
- $canvas->add_info($label, $value);
866
- }
867
- }
868
-
869
- /**
870
- * Writes the output buffer in the log file
871
- *
872
- * @return void
873
- */
874
- private function write_log()
875
- {
876
- $log_output_file = $this->getOptions()->getLogOutputFile();
877
- if (!$log_output_file || !is_writable($log_output_file)) {
878
- return;
879
- }
880
-
881
- $frames = Frame::$ID_COUNTER;
882
- $memory = memory_get_peak_usage(true) / 1024;
883
- $time = (microtime(true) - $this->startTime) * 1000;
884
-
885
- $out = sprintf(
886
- "<span style='color: #000' title='Frames'>%6d</span>" .
887
- "<span style='color: #009' title='Memory'>%10.2f KB</span>" .
888
- "<span style='color: #900' title='Time'>%10.2f ms</span>" .
889
- "<span title='Quirksmode'> " .
890
- ($this->quirksmode ? "<span style='color: #d00'> ON</span>" : "<span style='color: #0d0'>OFF</span>") .
891
- "</span><br />", $frames, $memory, $time);
892
-
893
- $out .= ob_get_contents();
894
- ob_clean();
895
-
896
- file_put_contents($log_output_file, $out);
897
- }
898
-
899
- /**
900
- * Streams the PDF to the client
901
- *
902
- * The file will open a download dialog by default. The options
903
- * parameter controls the output. Accepted options (array keys) are:
904
- *
905
- * 'Accept-Ranges' => 1 or 0 (=default): Send an 'Accept-Ranges:'
906
- * HTTP header, see https://tools.ietf.org/html/rfc2616#section-14.5
907
- * This header seems to have caused some problems, despite the fact
908
- * that it is supposed to solve them, so I am leaving it off by default.
909
- *
910
- * 'compress' = > 1 (=default) or 0:
911
- * Apply content stream compression
912
- *
913
- * 'Attachment' => 1 (=default) or 0:
914
- * Set the 'Content-Disposition:' HTTP header to 'attachment'
915
- * (thereby causing the browser to open a download dialog)
916
- *
917
- * @param string $filename the name of the streamed file
918
- * @param array $options header options (see above)
919
- */
920
- public function stream($filename = 'document.pdf', $options = null)
921
- {
922
- $this->saveLocale();
923
-
924
- $canvas = $this->getCanvas();
925
- if (!is_null($canvas)) {
926
- $canvas->stream($filename, $options);
927
- }
928
-
929
- $this->restoreLocale();
930
- }
931
-
932
- /**
933
- * Returns the PDF as a string
934
- *
935
- * The file will open a download dialog by default. The options
936
- * parameter controls the output. Accepted options are:
937
- *
938
- *
939
- * 'compress' = > 1 or 0 - apply content stream compression, this is
940
- * on (1) by default
941
- *
942
- *
943
- * @param array $options options (see above)
944
- *
945
- * @return string
946
- */
947
- public function output($options = null)
948
- {
949
- $this->saveLocale();
950
-
951
- $canvas = $this->getCanvas();
952
- if (is_null($canvas)) {
953
- return null;
954
- }
955
-
956
- $output = $canvas->output($options);
957
-
958
- $this->restoreLocale();
959
-
960
- return $output;
961
- }
962
-
963
- /**
964
- * @return string
965
- * @deprecated
966
- */
967
- public function output_html()
968
- {
969
- return $this->outputHtml();
970
- }
971
-
972
- /**
973
- * Returns the underlying HTML document as a string
974
- *
975
- * @return string
976
- */
977
- public function outputHtml()
978
- {
979
- return $this->dom->saveHTML();
980
- }
981
-
982
- /**
983
- * Get the dompdf option value
984
- *
985
- * @param string $key
986
- * @return mixed
987
- * @deprecated
988
- */
989
- public function get_option($key)
990
- {
991
- return $this->options->get($key);
992
- }
993
-
994
- /**
995
- * @param string $key
996
- * @param mixed $value
997
- * @return $this
998
- * @deprecated
999
- */
1000
- public function set_option($key, $value)
1001
- {
1002
- $this->options->set($key, $value);
1003
- return $this;
1004
- }
1005
-
1006
- /**
1007
- * @param array $options
1008
- * @return $this
1009
- * @deprecated
1010
- */
1011
- public function set_options(array $options)
1012
- {
1013
- $this->options->set($options);
1014
- return $this;
1015
- }
1016
-
1017
- /**
1018
- * @param string $size
1019
- * @param string $orientation
1020
- * @deprecated
1021
- */
1022
- public function set_paper($size, $orientation = "portrait")
1023
- {
1024
- $this->setPaper($size, $orientation);
1025
- }
1026
-
1027
- /**
1028
- * Sets the paper size & orientation
1029
- *
1030
- * @param string $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}
1031
- * @param string $orientation 'portrait' or 'landscape'
1032
- * @return $this
1033
- */
1034
- public function setPaper($size, $orientation = "portrait")
1035
- {
1036
- $this->paperSize = $size;
1037
- $this->paperOrientation = $orientation;
1038
- return $this;
1039
- }
1040
-
1041
- /**
1042
- * Gets the paper size
1043
- *
1044
- * @param null|string|array $paperSize
1045
- * @return \int[] A four-element integer array
1046
- */
1047
- public function getPaperSize($paperSize = null)
1048
- {
1049
- $size = $paperSize !== null ? $paperSize : $this->paperSize;
1050
- if (is_array($size)) {
1051
- return $size;
1052
- } else if (isset(Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)])) {
1053
- return Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)];
1054
- } else {
1055
- return Adapter\CPDF::$PAPER_SIZES["letter"];
1056
- }
1057
- }
1058
-
1059
- /**
1060
- * Gets the paper orientation
1061
- *
1062
- * @return string Either "portrait" or "landscape"
1063
- */
1064
- public function getPaperOrientation()
1065
- {
1066
- return $this->paperOrientation;
1067
- }
1068
-
1069
- /**
1070
- * @param FrameTree $tree
1071
- * @return $this
1072
- */
1073
- public function setTree(FrameTree $tree)
1074
- {
1075
- $this->tree = $tree;
1076
- return $this;
1077
- }
1078
-
1079
- /**
1080
- * @return FrameTree
1081
- * @deprecated
1082
- */
1083
- public function get_tree()
1084
- {
1085
- return $this->getTree();
1086
- }
1087
-
1088
- /**
1089
- * Returns the underlying {@link FrameTree} object
1090
- *
1091
- * @return FrameTree
1092
- */
1093
- public function getTree()
1094
- {
1095
- return $this->tree;
1096
- }
1097
-
1098
- /**
1099
- * @param string $protocol
1100
- * @return $this
1101
- * @deprecated
1102
- */
1103
- public function set_protocol($protocol)
1104
- {
1105
- return $this->setProtocol($protocol);
1106
- }
1107
-
1108
- /**
1109
- * Sets the protocol to use
1110
- * FIXME validate these
1111
- *
1112
- * @param string $protocol
1113
- * @return $this
1114
- */
1115
- public function setProtocol($protocol)
1116
- {
1117
- $this->protocol = $protocol;
1118
- return $this;
1119
- }
1120
-
1121
- /**
1122
- * @return string
1123
- * @deprecated
1124
- */
1125
- public function get_protocol()
1126
- {
1127
- return $this->getProtocol();
1128
- }
1129
-
1130
- /**
1131
- * Returns the protocol in use
1132
- *
1133
- * @return string
1134
- */
1135
- public function getProtocol()
1136
- {
1137
- return $this->protocol;
1138
- }
1139
-
1140
- /**
1141
- * @param string $host
1142
- * @deprecated
1143
- */
1144
- public function set_host($host)
1145
- {
1146
- $this->setBaseHost($host);
1147
- }
1148
-
1149
- /**
1150
- * Sets the base hostname
1151
- *
1152
- * @param string $baseHost
1153
- * @return $this
1154
- */
1155
- public function setBaseHost($baseHost)
1156
- {
1157
- $this->baseHost = $baseHost;
1158
- return $this;
1159
- }
1160
-
1161
- /**
1162
- * @return string
1163
- * @deprecated
1164
- */
1165
- public function get_host()
1166
- {
1167
- return $this->getBaseHost();
1168
- }
1169
-
1170
- /**
1171
- * Returns the base hostname
1172
- *
1173
- * @return string
1174
- */
1175
- public function getBaseHost()
1176
- {
1177
- return $this->baseHost;
1178
- }
1179
-
1180
- /**
1181
- * Sets the base path
1182
- *
1183
- * @param string $path
1184
- * @deprecated
1185
- */
1186
- public function set_base_path($path)
1187
- {
1188
- $this->setBasePath($path);
1189
- }
1190
-
1191
- /**
1192
- * Sets the base path
1193
- *
1194
- * @param string $basePath
1195
- * @return $this
1196
- */
1197
- public function setBasePath($basePath)
1198
- {
1199
- $this->basePath = $basePath;
1200
- return $this;
1201
- }
1202
-
1203
- /**
1204
- * @return string
1205
- * @deprecated
1206
- */
1207
- public function get_base_path()
1208
- {
1209
- return $this->getBasePath();
1210
- }
1211
-
1212
- /**
1213
- * Returns the base path
1214
- *
1215
- * @return string
1216
- */
1217
- public function getBasePath()
1218
- {
1219
- return $this->basePath;
1220
- }
1221
-
1222
- /**
1223
- * @param string $default_view The default document view
1224
- * @param array $options The view's options
1225
- * @return $this
1226
- * @deprecated
1227
- */
1228
- public function set_default_view($default_view, $options)
1229
- {
1230
- return $this->setDefaultView($default_view, $options);
1231
- }
1232
-
1233
- /**
1234
- * Sets the default view
1235
- *
1236
- * @param string $defaultView The default document view
1237
- * @param array $options The view's options
1238
- * @return $this
1239
- */
1240
- public function setDefaultView($defaultView, $options)
1241
- {
1242
- $this->defaultView = $defaultView;
1243
- $this->defaultViewOptions = $options;
1244
- return $this;
1245
- }
1246
-
1247
- /**
1248
- * @param resource $http_context
1249
- * @return $this
1250
- * @deprecated
1251
- */
1252
- public function set_http_context($http_context)
1253
- {
1254
- return $this->setHttpContext($http_context);
1255
- }
1256
-
1257
- /**
1258
- * Sets the HTTP context
1259
- *
1260
- * @param resource $httpContext
1261
- * @return $this
1262
- */
1263
- public function setHttpContext($httpContext)
1264
- {
1265
- $this->httpContext = $httpContext;
1266
- return $this;
1267
- }
1268
-
1269
- /**
1270
- * @return resource
1271
- * @deprecated
1272
- */
1273
- public function get_http_context()
1274
- {
1275
- return $this->getHttpContext();
1276
- }
1277
-
1278
- /**
1279
- * Returns the HTTP context
1280
- *
1281
- * @return resource
1282
- */
1283
- public function getHttpContext()
1284
- {
1285
- return $this->httpContext;
1286
- }
1287
-
1288
- /**
1289
- * @param Canvas $canvas
1290
- * @return $this
1291
- */
1292
- public function setCanvas(Canvas $canvas)
1293
- {
1294
- $this->canvas = $canvas;
1295
- return $this;
1296
- }
1297
-
1298
- /**
1299
- * @return Canvas
1300
- * @deprecated
1301
- */
1302
- public function get_canvas()
1303
- {
1304
- return $this->getCanvas();
1305
- }
1306
-
1307
- /**
1308
- * Return the underlying Canvas instance (e.g. Dompdf\Adapter\CPDF, Dompdf\Adapter\GD)
1309
- *
1310
- * @return Canvas
1311
- */
1312
- public function getCanvas()
1313
- {
1314
- return $this->canvas;
1315
- }
1316
-
1317
- /**
1318
- * @param Stylesheet $css
1319
- * @return $this
1320
- */
1321
- public function setCss(Stylesheet $css)
1322
- {
1323
- $this->css = $css;
1324
- return $this;
1325
- }
1326
-
1327
- /**
1328
- * @return Stylesheet
1329
- * @deprecated
1330
- */
1331
- public function get_css()
1332
- {
1333
- return $this->getCss();
1334
- }
1335
-
1336
- /**
1337
- * Returns the stylesheet
1338
- *
1339
- * @return Stylesheet
1340
- */
1341
- public function getCss()
1342
- {
1343
- return $this->css;
1344
- }
1345
-
1346
- /**
1347
- * @param DOMDocument $dom
1348
- * @return $this
1349
- */
1350
- public function setDom(DOMDocument $dom)
1351
- {
1352
- $this->dom = $dom;
1353
- return $this;
1354
- }
1355
-
1356
- /**
1357
- * @return DOMDocument
1358
- * @deprecated
1359
- */
1360
- public function get_dom()
1361
- {
1362
- return $this->getDom();
1363
- }
1364
-
1365
- /**
1366
- * @return DOMDocument
1367
- */
1368
- public function getDom()
1369
- {
1370
- return $this->dom;
1371
- }
1372
-
1373
- /**
1374
- * @param Options $options
1375
- * @return $this
1376
- */
1377
- public function setOptions(Options $options)
1378
- {
1379
- $this->options = $options;
1380
- $fontMetrics = $this->getFontMetrics();
1381
- if (isset($fontMetrics)) {
1382
- $fontMetrics->setOptions($options);
1383
- }
1384
- return $this;
1385
- }
1386
-
1387
- /**
1388
- * @return Options
1389
- */
1390
- public function getOptions()
1391
- {
1392
- return $this->options;
1393
- }
1394
-
1395
- /**
1396
- * @return array
1397
- * @deprecated
1398
- */
1399
- public function get_callbacks()
1400
- {
1401
- return $this->getCallbacks();
1402
- }
1403
-
1404
- /**
1405
- * Returns the callbacks array
1406
- *
1407
- * @return array
1408
- */
1409
- public function getCallbacks()
1410
- {
1411
- return $this->callbacks;
1412
- }
1413
-
1414
- /**
1415
- * @param array $callbacks the set of callbacks to set
1416
- * @deprecated
1417
- */
1418
- public function set_callbacks($callbacks)
1419
- {
1420
- $this->setCallbacks($callbacks);
1421
- }
1422
-
1423
- /**
1424
- * Sets callbacks for events like rendering of pages and elements.
1425
- * The callbacks array contains arrays with 'event' set to 'begin_page',
1426
- * 'end_page', 'begin_frame', or 'end_frame' and 'f' set to a function or
1427
- * object plus method to be called.
1428
- *
1429
- * The function 'f' must take an array as argument, which contains info
1430
- * about the event.
1431
- *
1432
- * @param array $callbacks the set of callbacks to set
1433
- */
1434
- public function setCallbacks($callbacks)
1435
- {
1436
- if (is_array($callbacks)) {
1437
- $this->callbacks = array();
1438
- foreach ($callbacks as $c) {
1439
- if (is_array($c) && isset($c['event']) && isset($c['f'])) {
1440
- $event = $c['event'];
1441
- $f = $c['f'];
1442
- if (is_callable($f) && is_string($event)) {
1443
- $this->callbacks[$event][] = $f;
1444
- }
1445
- }
1446
- }
1447
- }
1448
- }
1449
-
1450
- /**
1451
- * @return boolean
1452
- * @deprecated
1453
- */
1454
- public function get_quirksmode()
1455
- {
1456
- return $this->getQuirksmode();
1457
- }
1458
-
1459
- /**
1460
- * Get the quirks mode
1461
- *
1462
- * @return boolean true if quirks mode is active
1463
- */
1464
- public function getQuirksmode()
1465
- {
1466
- return $this->quirksmode;
1467
- }
1468
-
1469
- /**
1470
- * @param FontMetrics $fontMetrics
1471
- * @return $this
1472
- */
1473
- public function setFontMetrics(FontMetrics $fontMetrics)
1474
- {
1475
- $this->fontMetrics = $fontMetrics;
1476
- return $this;
1477
- }
1478
-
1479
- /**
1480
- * @return FontMetrics
1481
- */
1482
- public function getFontMetrics()
1483
- {
1484
- return $this->fontMetrics;
1485
- }
1486
-
1487
- /**
1488
- * PHP5 overloaded getter
1489
- * Along with {@link Dompdf::__set()} __get() provides access to all
1490
- * properties directly. Typically __get() is not called directly outside
1491
- * of this class.
1492
- *
1493
- * @param string $prop
1494
- *
1495
- * @throws Exception
1496
- * @return mixed
1497
- */
1498
- function __get($prop)
1499
- {
1500
- switch ($prop)
1501
- {
1502
- case 'version' :
1503
- return $this->version;
1504
- default:
1505
- throw new Exception( 'Invalid property: ' . $prop );
1506
- }
1507
- }
1508
- }
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package dompdf
4
+ * @link http://dompdf.github.com/
5
+ * @author Benj Carson <benjcarson@digitaljunkies.ca>
6
+ * @author Fabien Ménager <fabien.menager@gmail.com>
7
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8
+ */
9
+ namespace Dompdf;
10
+
11
+ use DOMDocument;
12
+ use DOMNode;
13
+ use Dompdf\Adapter\CPDF;
14
+ use DOMXPath;
15
+ use Dompdf\Frame\Factory;
16
+ use Dompdf\Frame\FrameTree;
17
+ use HTML5_Tokenizer;
18
+ use HTML5_TreeBuilder;
19
+ use Dompdf\Image\Cache;
20
+ use Dompdf\Renderer\ListBullet;
21
+ use Dompdf\Css\Stylesheet;
22
+
23
+ /**
24
+ * Dompdf - PHP5 HTML to PDF renderer
25
+ *
26
+ * Dompdf loads HTML and does its best to render it as a PDF. It gets its
27
+ * name from the new DomDocument PHP5 extension. Source HTML is first
28
+ * parsed by a DomDocument object. Dompdf takes the resulting DOM tree and
29
+ * attaches a {@link Frame} object to each node. {@link Frame} objects store
30
+ * positioning and layout information and each has a reference to a {@link
31
+ * Style} object.
32
+ *
33
+ * Style information is loaded and parsed (see {@link Stylesheet}) and is
34
+ * applied to the frames in the tree by using XPath. CSS selectors are
35
+ * converted into XPath queries, and the computed {@link Style} objects are
36
+ * applied to the {@link Frame}s.
37
+ *
38
+ * {@link Frame}s are then decorated (in the design pattern sense of the
39
+ * word) based on their CSS display property ({@link
40
+ * http://www.w3.org/TR/CSS21/visuren.html#propdef-display}).
41
+ * Frame_Decorators augment the basic {@link Frame} class by adding
42
+ * additional properties and methods specific to the particular type of
43
+ * {@link Frame}. For example, in the CSS layout model, block frames
44
+ * (display: block;) contain line boxes that are usually filled with text or
45
+ * other inline frames. The Block therefore adds a $lines
46
+ * property as well as methods to add {@link Frame}s to lines and to add
47
+ * additional lines. {@link Frame}s also are attached to specific
48
+ * AbstractPositioner and {@link AbstractFrameReflower} objects that contain the
49
+ * positioining and layout algorithm for a specific type of frame,
50
+ * respectively. This is an application of the Strategy pattern.
51
+ *
52
+ * Layout, or reflow, proceeds recursively (post-order) starting at the root
53
+ * of the document. Space constraints (containing block width & height) are
54
+ * pushed down, and resolved positions and sizes bubble up. Thus, every
55
+ * {@link Frame} in the document tree is traversed once (except for tables
56
+ * which use a two-pass layout algorithm). If you are interested in the
57
+ * details, see the reflow() method of the Reflower classes.
58
+ *
59
+ * Rendering is relatively straightforward once layout is complete. {@link
60
+ * Frame}s are rendered using an adapted {@link Cpdf} class, originally
61
+ * written by Wayne Munro, http://www.ros.co.nz/pdf/. (Some performance
62
+ * related changes have been made to the original {@link Cpdf} class, and
63
+ * the {@link Dompdf\Adapter\CPDF} class provides a simple, stateless interface to
64
+ * PDF generation.) PDFLib support has now also been added, via the {@link
65
+ * Dompdf\Adapter\PDFLib}.
66
+ *
67
+ *
68
+ * @package dompdf
69
+ */
70
+ class Dompdf
71
+ {
72
+ /**
73
+ * Version string for dompdf
74
+ *
75
+ * @var string
76
+ */
77
+ private $version = 'dompdf';
78
+
79
+ /**
80
+ * DomDocument representing the HTML document
81
+ *
82
+ * @var DOMDocument
83
+ */
84
+ private $dom;
85
+
86
+ /**
87
+ * FrameTree derived from the DOM tree
88
+ *
89
+ * @var FrameTree
90
+ */
91
+ private $tree;
92
+
93
+ /**
94
+ * Stylesheet for the document
95
+ *
96
+ * @var Stylesheet
97
+ */
98
+ private $css;
99
+
100
+ /**
101
+ * Actual PDF renderer
102
+ *
103
+ * @var Canvas
104
+ */
105
+ private $canvas;
106
+
107
+ /**
108
+ * Desired paper size ('letter', 'legal', 'A4', etc.)
109
+ *
110
+ * @var string
111
+ */
112
+ private $paperSize;
113
+
114
+ /**
115
+ * Paper orientation ('portrait' or 'landscape')
116
+ *
117
+ * @var string
118
+ */
119
+ private $paperOrientation = "portrait";
120
+
121
+ /**
122
+ * Callbacks on new page and new element
123
+ *
124
+ * @var array
125
+ */
126
+ private $callbacks = array();
127
+
128
+ /**
129
+ * Experimental caching capability
130
+ *
131
+ * @var string
132
+ */
133
+ private $cacheId;
134
+
135
+ /**
136
+ * Base hostname
137
+ *
138
+ * Used for relative paths/urls
139
+ * @var string
140
+ */
141
+ private $baseHost = "";
142
+
143
+ /**
144
+ * Absolute base path
145
+ *
146
+ * Used for relative paths/urls
147
+ * @var string
148
+ */
149
+ private $basePath = "";
150
+
151
+ /**
152
+ * Protcol used to request file (file://, http://, etc)
153
+ *
154
+ * @var string
155
+ */
156
+ private $protocol;
157
+
158
+ /**
159
+ * HTTP context created with stream_context_create()
160
+ * Will be used for file_get_contents
161
+ *
162
+ * @var resource
163
+ */
164
+ private $httpContext;
165
+
166
+ /**
167
+ * Timestamp of the script start time
168
+ *
169
+ * @var int
170
+ */
171
+ private $startTime = null;
172
+
173
+ /**
174
+ * The system's locale
175
+ *
176
+ * @var string
177
+ */
178
+ private $systemLocale = null;
179
+
180
+ /**
181
+ * Tells if the system's locale is the C standard one
182
+ *
183
+ * @var bool
184
+ */
185
+ private $localeStandard = false;
186
+
187
+ /**
188
+ * The default view of the PDF in the viewer
189
+ *
190
+ * @var string
191
+ */
192
+ private $defaultView = "Fit";
193
+
194
+ /**
195
+ * The default view options of the PDF in the viewer
196
+ *
197
+ * @var array
198
+ */
199
+ private $defaultViewOptions = array();
200
+
201
+ /**
202
+ * Tells wether the DOM document is in quirksmode (experimental)
203
+ *
204
+ * @var bool
205
+ */
206
+ private $quirksmode = false;
207
+
208
+ /**
209
+ * Protocol whitelist
210
+ *
211
+ * Protocols and PHP wrappers allowed in URLs. Full support is not
212
+ * guarantee for the protocols/wrappers contained in this array.
213
+ *
214
+ * @var array
215
+ */
216
+ private $allowedProtocols = array(null, "", "file://", "http://", "https://");
217
+
218
+ /**
219
+ * Local file extension whitelist
220
+ *
221
+ * File extensions supported by dompdf for local files.
222
+ *
223
+ * @var array
224
+ */
225
+ private $allowedLocalFileExtensions = array("htm", "html");
226
+
227
+ /**
228
+ * @var array
229
+ */
230
+ private $messages = array();
231
+
232
+ /**
233
+ * @var Options
234
+ */
235
+ private $options;
236
+
237
+ /**
238
+ * @var FontMetrics
239
+ */
240
+ private $fontMetrics;
241
+
242
+ /**
243
+ * The list of built-in fonts
244
+ *
245
+ * @var array
246
+ * @deprecated
247
+ */
248
+ public static $native_fonts = array(
249
+ "courier", "courier-bold", "courier-oblique", "courier-boldoblique",
250
+ "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique",
251
+ "times-roman", "times-bold", "times-italic", "times-bolditalic",
252
+ "symbol", "zapfdinbats"
253
+ );
254
+
255
+ /**
256
+ * The list of built-in fonts
257
+ *
258
+ * @var array
259
+ */
260
+ public static $nativeFonts = array(
261
+ "courier", "courier-bold", "courier-oblique", "courier-boldoblique",
262
+ "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique",
263
+ "times-roman", "times-bold", "times-italic", "times-bolditalic",
264
+ "symbol", "zapfdinbats"
265
+ );
266
+
267
+ /**
268
+ * Class constructor
269
+ *
270
+ * @param array|Options $options
271
+ */
272
+ public function __construct($options = null)
273
+ {
274
+ mb_internal_encoding('UTF-8');
275
+
276
+ if (isset($options) && $options instanceof Options) {
277
+ $this->setOptions($options);
278
+ } elseif (is_array($options)) {
279
+ $this->setOptions(new Options($options));
280
+ } else {
281
+ $this->setOptions(new Options());
282
+ }
283
+
284
+ $versionFile = realpath(__DIR__ . '/../VERSION');
285
+ if (file_exists($versionFile) && ($version = file_get_contents($versionFile)) !== false && $version !== '$Format:<%h>$') {
286
+ $this->version = sprintf('dompdf %s', $version);
287
+ }
288
+
289
+ $this->localeStandard = sprintf('%.1f', 1.0) == '1.0';
290
+ $this->saveLocale();
291
+ $this->paperSize = $this->options->getDefaultPaperSize();
292
+ $this->paperOrientation = $this->options->getDefaultPaperOrientation();
293
+
294
+ $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
295
+ $this->setFontMetrics(new FontMetrics($this->getCanvas(), $this->getOptions()));
296
+ $this->css = new Stylesheet($this);
297
+
298
+ $this->restoreLocale();
299
+ }
300
+
301
+ /**
302
+ * Save the system's locale configuration and
303
+ * set the right value for numeric formatting
304
+ */
305
+ private function saveLocale()
306
+ {
307
+ if ($this->localeStandard) {
308
+ return;
309
+ }
310
+
311
+ $this->systemLocale = setlocale(LC_NUMERIC, "0");
312
+ setlocale(LC_NUMERIC, "C");
313
+ }
314
+
315
+ /**
316
+ * Restore the system's locale configuration
317
+ */
318
+ private function restoreLocale()
319
+ {
320
+ if ($this->localeStandard) {
321
+ return;
322
+ }
323
+
324
+ setlocale(LC_NUMERIC, $this->systemLocale);
325
+ }
326
+
327
+ /**
328
+ * @param $file
329
+ * @deprecated
330
+ */
331
+ public function load_html_file($file)
332
+ {
333
+ $this->loadHtmlFile($file);
334
+ }
335
+
336
+ /**
337
+ * Loads an HTML file
338
+ * Parse errors are stored in the global array _dompdf_warnings.
339
+ *
340
+ * @param string $file a filename or url to load
341
+ *
342
+ * @throws Exception
343
+ */
344
+ public function loadHtmlFile($file)
345
+ {
346
+ $this->saveLocale();
347
+
348
+ if (!$this->protocol && !$this->baseHost && !$this->basePath) {
349
+ list($this->protocol, $this->baseHost, $this->basePath) = Helpers::explode_url($file);
350
+ }
351
+ $protocol = strtolower($this->protocol);
352
+
353
+ if ( !in_array($protocol, $this->allowedProtocols) ) {
354
+ throw new Exception("Permission denied on $file. The communication protocol is not supported.");
355
+ }
356
+
357
+ if (!$this->options->isRemoteEnabled() && ($protocol != "" && $protocol !== "file://")) {
358
+ throw new Exception("Remote file requested, but remote file download is disabled.");
359
+ }
360
+
361
+ if ($protocol == "" || $protocol === "file://") {
362
+ $realfile = realpath($file);
363
+
364
+ $chroot = realpath($this->options->getChroot());
365
+ if ($chroot && strpos($realfile, $chroot) !== 0) {
366
+ throw new Exception("Permission denied on $file. The file could not be found under the directory specified by Options::chroot.");
367
+ }
368
+
369
+ $ext = strtolower(pathinfo($realfile, PATHINFO_EXTENSION));
370
+ if (!in_array($ext, $this->allowedLocalFileExtensions)) {
371
+ throw new Exception("Permission denied on $file.");
372
+ }
373
+
374
+ if (!$realfile) {
375
+ throw new Exception("File '$file' not found.");
376
+ }
377
+
378
+ $file = $realfile;
379
+ }
380
+
381
+ list($contents, $http_response_header) = Helpers::getFileContent($file, $this->httpContext);
382
+ $encoding = 'UTF-8';
383
+
384
+ // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
385
+ if (isset($http_response_header)) {
386
+ foreach ($http_response_header as $_header) {
387
+ if (preg_match("@Content-Type:\s*[\w/]+;\s*?charset=([^\s]+)@i", $_header, $matches)) {
388
+ $encoding = strtoupper($matches[1]);
389
+ break;
390
+ }
391
+ }
392
+ }
393
+
394
+ $this->restoreLocale();
395
+
396
+ $this->loadHtml($contents, $encoding);
397
+ }
398
+
399
+ /**
400
+ * @param $str
401
+ * @param null $encoding
402
+ * @deprecated
403
+ */
404
+ public function load_html($str, $encoding = 'UTF-8')
405
+ {
406
+ $this->loadHtml($str, $encoding);
407
+ }
408
+
409
+ /**
410
+ * Loads an HTML string
411
+ * Parse errors are stored in the global array _dompdf_warnings.
412
+ * @todo use the $encoding variable
413
+ *
414
+ * @param string $str HTML text to load
415
+ * @param string $encoding Not used yet
416
+ */
417
+ public function loadHtml($str, $encoding = 'UTF-8')
418
+ {
419
+ $this->saveLocale();
420
+
421
+ // FIXME: Determine character encoding, switch to UTF8, update meta tag. Need better http/file stream encoding detection, currently relies on text or meta tag.
422
+ $known_encodings = mb_list_encodings();
423
+ mb_detect_order('auto');
424
+ if (($file_encoding = mb_detect_encoding($str, null, true)) === false) {
425
+ $file_encoding = "auto";
426
+ }
427
+ if (in_array(strtoupper($file_encoding), array('UTF-8','UTF8')) === false) {
428
+ $str = mb_convert_encoding($str, 'UTF-8', $file_encoding);
429
+ }
430
+
431
+ $metatags = array(
432
+ '@<meta\s+http-equiv="Content-Type"\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))?@i',
433
+ '@<meta\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))"?\s+http-equiv="Content-Type"@i',
434
+ '@<meta [^>]*charset\s*=\s*["\']?\s*([^"\' ]+)@i',
435
+ );
436
+ foreach ($metatags as $metatag) {
437
+ if (preg_match($metatag, $str, $matches)) {
438
+ if (isset($matches[1]) && in_array($matches[1], $known_encodings)) {
439
+ $document_encoding = $matches[1];
440
+ break;
441
+ }
442
+ }
443
+ }
444
+ if (isset($document_encoding) && in_array(strtoupper($document_encoding), array('UTF-8','UTF8')) === false) {
445
+ $str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str);
446
+ } elseif (isset($document_encoding) === false && strpos($str, '<head>') !== false) {
447
+ $str = str_replace('<head>', '<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">', $str);
448
+ } elseif (isset($document_encoding) === false) {
449
+ $str = '<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">' . $str;
450
+ }
451
+ //FIXME: since we're not using this just yet
452
+ $encoding = 'UTF-8';
453
+
454
+ // remove BOM mark from UTF-8, it's treated as document text by DOMDocument
455
+ // FIXME: roll this into the encoding detection using UTF-8/16/32 BOM (http://us2.php.net/manual/en/function.mb-detect-encoding.php#91051)?
456
+ if (substr($str, 0, 3) == chr(0xEF) . chr(0xBB) . chr(0xBF)) {
457
+ $str = substr($str, 3);
458
+ }
459
+
460
+ // Store parsing warnings as messages
461
+ set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
462
+
463
+ // @todo Take the quirksmode into account
464
+ // http://hsivonen.iki.fi/doctype/
465
+ // https://developer.mozilla.org/en/mozilla's_quirks_mode
466
+ $quirksmode = false;
467
+
468
+ if ($this->options->isHtml5ParserEnabled()) {
469
+ $tokenizer = new HTML5_Tokenizer($str);
470
+ $tokenizer->parse();
471
+ $doc = $tokenizer->save();
472
+
473
+ // Remove #text children nodes in nodes that shouldn't have
474
+ $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
475
+ foreach ($tag_names as $tag_name) {
476
+ $nodes = $doc->getElementsByTagName($tag_name);
477
+
478
+ foreach ($nodes as $node) {
479
+ self::removeTextNodes($node);
480
+ }
481
+ }
482
+
483
+ $quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS);
484
+ } else {
485
+ // loadHTML assumes ISO-8859-1 unless otherwise specified on the HTML document header.
486
+ // http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/ (see #4)
487
+ // http://stackoverflow.com/a/11310258/264628
488
+ $doc = new DOMDocument("1.0", $encoding);
489
+ $doc->preserveWhiteSpace = true;
490
+ $doc->loadHTML($str);
491
+ $doc->encoding = $encoding;
492
+
493
+ // Remove #text children nodes in nodes that shouldn't have
494
+ $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
495
+ foreach ($tag_names as $tag_name) {
496
+ $nodes = $doc->getElementsByTagName($tag_name);
497
+ foreach ($nodes as $node) {
498
+ self::removeTextNodes($node);
499
+ }
500
+ }
501
+
502
+ // If some text is before the doctype, we are in quirksmode
503
+ if (preg_match("/^(.+)<!doctype/i", ltrim($str), $matches)) {
504
+ $quirksmode = true;
505
+ } // If no doctype is provided, we are in quirksmode
506
+ elseif (!preg_match("/^<!doctype/i", ltrim($str), $matches)) {
507
+ $quirksmode = true;
508
+ } else {
509
+ // HTML5 <!DOCTYPE html>
510
+ if (!$doc->doctype->publicId && !$doc->doctype->systemId) {
511
+ $quirksmode = false;
512
+ }
513
+
514
+ // not XHTML
515
+ if (!preg_match("/xhtml/i", $doc->doctype->publicId)) {
516
+ $quirksmode = true;
517
+ }
518
+ }
519
+ }
520
+
521
+ $this->dom = $doc;
522
+ $this->quirksmode = $quirksmode;
523
+
524
+ $this->tree = new FrameTree($this->dom);
525
+
526
+ restore_error_handler();
527
+
528
+ $this->restoreLocale();
529
+ }
530
+
531
+ /**
532
+ * @param DOMNode $node
533
+ * @deprecated
534
+ */
535
+ public static function remove_text_nodes(DOMNode $node)
536
+ {
537
+ self::removeTextNodes($node);
538
+ }
539
+
540
+ /**
541
+ * @param DOMNode $node
542
+ */
543
+ public static function removeTextNodes(DOMNode $node)
544
+ {
545
+ $children = array();
546
+ for ($i = 0; $i < $node->childNodes->length; $i++) {
547
+ $child = $node->childNodes->item($i);
548
+ if ($child->nodeName === "#text") {
549
+ $children[] = $child;
550
+ }
551
+ }
552
+
553
+ foreach ($children as $child) {
554
+ $node->removeChild($child);
555
+ }
556
+ }
557
+
558
+ /**
559
+ * Builds the {@link FrameTree}, loads any CSS and applies the styles to
560
+ * the {@link FrameTree}
561
+ */
562
+ private function processHtml()
563
+ {
564
+ $this->tree->build_tree();
565
+
566
+ $this->css->load_css_file(Stylesheet::getDefaultStylesheet(), Stylesheet::ORIG_UA);
567
+
568
+ $acceptedmedia = Stylesheet::$ACCEPTED_GENERIC_MEDIA_TYPES;
569
+ $acceptedmedia[] = $this->options->getDefaultMediaType();
570
+
571
+ // <base href="" />
572
+ $base_nodes = $this->dom->getElementsByTagName("base");
573
+ if ($base_nodes->length && ($href = $base_nodes->item(0)->getAttribute("href"))) {
574
+ list($this->protocol, $this->baseHost, $this->basePath) = Helpers::explode_url($href);
575
+ }
576
+
577
+ // Set the base path of the Stylesheet to that of the file being processed
578
+ $this->css->set_protocol($this->protocol);
579
+ $this->css->set_host($this->baseHost);
580
+ $this->css->set_base_path($this->basePath);
581
+
582
+ // Get all the stylesheets so that they are processed in document order
583
+ $xpath = new DOMXPath($this->dom);
584
+ $stylesheets = $xpath->query("//*[name() = 'link' or name() = 'style']");
585
+
586
+ /** @var \DOMElement $tag */
587
+ foreach ($stylesheets as $tag) {
588
+ switch (strtolower($tag->nodeName)) {
589
+ // load <link rel="STYLESHEET" ... /> tags
590
+ case "link":
591
+ if (mb_strtolower(stripos($tag->getAttribute("rel"), "stylesheet") !== false) || // may be "appendix stylesheet"
592
+ mb_strtolower($tag->getAttribute("type")) === "text/css"
593
+ ) {
594
+ //Check if the css file is for an accepted media type
595
+ //media not given then always valid
596
+ $formedialist = preg_split("/[\s\n,]/", $tag->getAttribute("media"), -1, PREG_SPLIT_NO_EMPTY);
597
+ if (count($formedialist) > 0) {
598
+ $accept = false;
599
+ foreach ($formedialist as $type) {
600
+ if (in_array(mb_strtolower(trim($type)), $acceptedmedia)) {
601
+ $accept = true;
602
+ break;
603
+ }
604
+ }
605
+
606
+ if (!$accept) {
607
+ //found at least one mediatype, but none of the accepted ones
608
+ //Skip this css file.
609
+ continue;
610
+ }
611
+ }
612
+
613
+ $url = $tag->getAttribute("href");
614
+ $url = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $url);
615
+
616
+ $this->css->load_css_file($url, Stylesheet::ORIG_AUTHOR);
617
+ }
618
+ break;
619
+
620
+ // load <style> tags
621
+ case "style":
622
+ // Accept all <style> tags by default (note this is contrary to W3C
623
+ // HTML 4.0 spec:
624
+ // http://www.w3.org/TR/REC-html40/present/styles.html#adef-media
625
+ // which states that the default media type is 'screen'
626
+ if ($tag->hasAttributes() &&
627
+ ($media = $tag->getAttribute("media")) &&
628
+ !in_array($media, $acceptedmedia)
629
+ ) {
630
+ continue;
631
+ }
632
+
633
+ $css = "";
634
+ if ($tag->hasChildNodes()) {
635
+ $child = $tag->firstChild;
636
+ while ($child) {
637
+ $css .= $child->nodeValue; // Handle <style><!-- blah --></style>
638
+ $child = $child->nextSibling;
639
+ }
640
+ } else {
641
+ $css = $tag->nodeValue;
642
+ }
643
+
644
+ $this->css->load_css($css, Stylesheet::ORIG_AUTHOR);
645
+ break;
646
+ }
647
+ }
648
+ }
649
+
650
+ /**
651
+ * @param string $cacheId
652
+ * @deprecated
653
+ */
654
+ public function enable_caching($cacheId)
655
+ {
656
+ $this->enableCaching($cacheId);
657
+ }
658
+
659
+ /**
660
+ * Enable experimental caching capability
661
+ *
662
+ * @param string $cacheId
663
+ */
664
+ public function enableCaching($cacheId)
665
+ {
666
+ $this->cacheId = $cacheId;
667
+ }
668
+
669
+ /**
670
+ * @param string $value
671
+ * @return bool
672
+ * @deprecated
673
+ */
674
+ public function parse_default_view($value)
675
+ {
676
+ return $this->parseDefaultView($value);
677
+ }
678
+
679
+ /**
680
+ * @param string $value
681
+ * @return bool
682
+ */
683
+ public function parseDefaultView($value)
684
+ {
685
+ $valid = array("XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV");
686
+
687
+ $options = preg_split("/\s*,\s*/", trim($value));
688
+ $defaultView = array_shift($options);
689
+
690
+ if (!in_array($defaultView, $valid)) {
691
+ return false;
692
+ }
693
+
694
+ $this->setDefaultView($defaultView, $options);
695
+ return true;
696
+ }
697
+
698
+ /**
699
+ * Renders the HTML to PDF
700
+ */
701
+ public function render()
702
+ {
703
+ $this->saveLocale();
704
+ $options = $this->options;
705
+
706
+ $logOutputFile = $options->getLogOutputFile();
707
+ if ($logOutputFile) {
708
+ if (!file_exists($logOutputFile) && is_writable(dirname($logOutputFile))) {
709
+ touch($logOutputFile);
710
+ }
711
+
712
+ $this->startTime = microtime(true);
713
+ if (is_writable($logOutputFile)) {
714
+ ob_start();
715
+ }
716
+ }
717
+
718
+ $this->processHtml();
719
+
720
+ $this->css->apply_styles($this->tree);
721
+
722
+ // @page style rules : size, margins
723
+ $pageStyles = $this->css->get_page_styles();
724
+ $basePageStyle = $pageStyles["base"];
725
+ unset($pageStyles["base"]);
726
+
727
+ foreach ($pageStyles as $pageStyle) {
728
+ $pageStyle->inherit($basePageStyle);
729
+ }
730
+
731
+ $defaultOptionPaperSize = $this->getPaperSize($options->getDefaultPaperSize());
732
+ // If there is a CSS defined paper size compare to the paper size used to create the canvas to determine a
733
+ // recreation need
734
+ if (is_array($basePageStyle->size)) {
735
+ $basePageStyleSize = $basePageStyle->size;
736
+ $this->setPaper(array(0, 0, $basePageStyleSize[0], $basePageStyleSize[1]));
737
+ }
738
+
739
+ $paperSize = $this->getPaperSize();
740
+ if (
741
+ $defaultOptionPaperSize[2] !== $paperSize[2] ||
742
+ $defaultOptionPaperSize[3] !== $paperSize[3] ||
743
+ $options->getDefaultPaperOrientation() !== $this->paperOrientation
744
+ ) {
745
+ $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
746
+ $this->fontMetrics->setCanvas($this->getCanvas());
747
+ }
748
+
749
+ $canvas = $this->getCanvas();
750
+
751
+ if ($options->isFontSubsettingEnabled() && $canvas instanceof CPDF) {
752
+ foreach ($this->tree->get_frames() as $frame) {
753
+ $style = $frame->get_style();
754
+ $node = $frame->get_node();
755
+
756
+ // Handle text nodes
757
+ if ($node->nodeName === "#text") {
758
+ $chars = mb_strtoupper($node->nodeValue) . mb_strtolower($node->nodeValue);
759
+ $canvas->register_string_subset($style->font_family, $chars);
760
+ continue;
761
+ }
762
+
763
+ // Handle generated content (list items)
764
+ if ($style->display === "list-item") {
765
+ $chars = ListBullet::get_counter_chars($style->list_style_type);
766
+ $canvas->register_string_subset($style->font_family, $chars);
767
+ continue;
768
+ }
769
+
770
+ // Handle other generated content (pseudo elements)
771
+ // FIXME: This only captures the text of the stylesheet declaration,
772
+ // not the actual generated content, and forces all possible counter
773
+ // values. See notes in issue #750.
774
+ if ($frame->get_node()->nodeName == "dompdf_generated") {
775
+ // all possible counter values, just in case
776
+ $chars = ListBullet::get_counter_chars('decimal');
777
+ $canvas->register_string_subset($style->font_family, $chars);
778
+ $chars = ListBullet::get_counter_chars('upper-alpha');
779
+ $canvas->register_string_subset($style->font_family, $chars);
780
+ $chars = ListBullet::get_counter_chars('lower-alpha');
781
+ $canvas->register_string_subset($style->font_family, $chars);
782
+ $chars = ListBullet::get_counter_chars('lower-greek');
783
+ $canvas->register_string_subset($style->font_family, $chars);
784
+
785
+ // the hex-decoded text of the content property, duplicated from AbstrctFrameReflower::_parse_string
786
+ $decoded_string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/",
787
+ function ($matches) { return \Dompdf\Helpers::unichr(hexdec($matches[1])); },
788
+ $style->content);
789
+ $chars = mb_strtoupper($style->content) . mb_strtolower($style->content) . mb_strtoupper($decoded_string) . mb_strtolower($decoded_string);
790
+ $canvas->register_string_subset($style->font_family, $chars);
791
+ continue;
792
+ }
793
+ }
794
+ }
795
+
796
+ $root = null;
797
+
798
+ foreach ($this->tree->get_frames() as $frame) {
799
+ // Set up the root frame
800
+ if (is_null($root)) {
801
+ $root = Factory::decorate_root($this->tree->get_root(), $this);
802
+ continue;
803
+ }
804
+
805
+ // Create the appropriate decorators, reflowers & positioners.
806
+ Factory::decorate_frame($frame, $this, $root);
807
+ }
808
+
809
+ // Add meta information
810
+ $title = $this->dom->getElementsByTagName("title");
811
+ if ($title->length) {
812
+ $canvas->add_info("Title", trim($title->item(0)->nodeValue));
813
+ }
814
+
815
+ $metas = $this->dom->getElementsByTagName("meta");
816
+ $labels = array(
817
+ "author" => "Author",
818
+ "keywords" => "Keywords",
819
+ "description" => "Subject",
820
+ );
821
+ /** @var \DOMElement $meta */
822
+ foreach ($metas as $meta) {
823
+ $name = mb_strtolower($meta->getAttribute("name"));
824
+ $value = trim($meta->getAttribute("content"));
825
+
826
+ if (isset($labels[$name])) {
827
+ $canvas->add_info($labels[$name], $value);
828
+ continue;
829
+ }
830
+
831
+ if ($name === "dompdf.view" && $this->parseDefaultView($value)) {
832
+ $canvas->set_default_view($this->defaultView, $this->defaultViewOptions);
833
+ }
834
+ }
835
+
836
+ $root->set_containing_block(0, 0,$canvas->get_width(), $canvas->get_height());
837
+ $root->set_renderer(new Renderer($this));
838
+
839
+ // This is where the magic happens:
840
+ $root->reflow();
841
+
842
+ // Clean up cached images
843
+ Cache::clear();
844
+
845
+ global $_dompdf_warnings, $_dompdf_show_warnings;
846
+ if ($_dompdf_show_warnings && isset($_dompdf_warnings)) {
847
+ echo '<b>Dompdf Warnings</b><br><pre>';
848
+ foreach ($_dompdf_warnings as $msg) {
849
+ echo $msg . "\n";
850
+ }
851
+
852
+ if ($canvas instanceof CPDF) {
853
+ echo $canvas->get_cpdf()->messages;
854
+ }
855
+ echo '</pre>';
856
+ flush();
857
+ }
858
+
859
+ if ($logOutputFile && is_writable($logOutputFile)) {
860
+ $this->write_log();
861
+ ob_end_clean();
862
+ }
863
+
864
+ $this->restoreLocale();
865
+ }
866
+
867
+ /**
868
+ * Add meta information to the PDF after rendering
869
+ */
870
+ public function add_info($label, $value)
871
+ {
872
+ $canvas = $this->getCanvas();
873
+ if (!is_null($canvas)) {
874
+ $canvas->add_info($label, $value);
875
+ }
876
+ }
877
+
878
+ /**
879
+ * Writes the output buffer in the log file
880
+ *
881
+ * @return void
882
+ */
883
+ private function write_log()
884
+ {
885
+ $log_output_file = $this->getOptions()->getLogOutputFile();
886
+ if (!$log_output_file || !is_writable($log_output_file)) {
887
+ return;
888
+ }
889
+
890
+ $frames = Frame::$ID_COUNTER;
891
+ $memory = memory_get_peak_usage(true) / 1024;
892
+ $time = (microtime(true) - $this->startTime) * 1000;
893
+
894
+ $out = sprintf(
895
+ "<span style='color: #000' title='Frames'>%6d</span>" .
896
+ "<span style='color: #009' title='Memory'>%10.2f KB</span>" .
897
+ "<span style='color: #900' title='Time'>%10.2f ms</span>" .
898
+ "<span title='Quirksmode'> " .
899
+ ($this->quirksmode ? "<span style='color: #d00'> ON</span>" : "<span style='color: #0d0'>OFF</span>") .
900
+ "</span><br />", $frames, $memory, $time);
901
+
902
+ $out .= ob_get_contents();
903
+ ob_clean();
904
+
905
+ file_put_contents($log_output_file, $out);
906
+ }
907
+
908
+ /**
909
+ * Streams the PDF to the client
910
+ *
911
+ * The file will open a download dialog by default. The options
912
+ * parameter controls the output. Accepted options (array keys) are:
913
+ *
914
+ * 'Accept-Ranges' => 1 or 0 (=default): Send an 'Accept-Ranges:'
915
+ * HTTP header, see https://tools.ietf.org/html/rfc2616#section-14.5
916
+ * This header seems to have caused some problems, despite the fact
917
+ * that it is supposed to solve them, so I am leaving it off by default.
918
+ *
919
+ * 'compress' = > 1 (=default) or 0:
920
+ * Apply content stream compression
921
+ *
922
+ * 'Attachment' => 1 (=default) or 0:
923
+ * Set the 'Content-Disposition:' HTTP header to 'attachment'
924
+ * (thereby causing the browser to open a download dialog)
925
+ *
926
+ * @param string $filename the name of the streamed file
927
+ * @param array $options header options (see above)
928
+ */
929
+ public function stream($filename = 'document.pdf', $options = null)
930
+ {
931
+ $this->saveLocale();
932
+
933
+ $canvas = $this->getCanvas();
934
+ if (!is_null($canvas)) {
935
+ $canvas->stream($filename, $options);
936
+ }
937
+
938
+ $this->restoreLocale();
939
+ }
940
+
941
+ /**
942
+ * Returns the PDF as a string
943
+ *
944
+ * The file will open a download dialog by default. The options
945
+ * parameter controls the output. Accepted options are:
946
+ *
947
+ *
948
+ * 'compress' = > 1 or 0 - apply content stream compression, this is
949
+ * on (1) by default
950
+ *
951
+ *
952
+ * @param array $options options (see above)
953
+ *
954
+ * @return string
955
+ */
956
+ public function output($options = null)
957
+ {
958
+ $this->saveLocale();
959
+
960
+ $canvas = $this->getCanvas();
961
+ if (is_null($canvas)) {
962
+ return null;
963
+ }
964
+
965
+ $output = $canvas->output($options);
966
+
967
+ $this->restoreLocale();
968
+
969
+ return $output;
970
+ }
971
+
972
+ /**
973
+ * @return string
974
+ * @deprecated
975
+ */
976
+ public function output_html()
977
+ {
978
+ return $this->outputHtml();
979
+ }
980
+
981
+ /**
982
+ * Returns the underlying HTML document as a string
983
+ *
984
+ * @return string
985
+ */
986
+ public function outputHtml()
987
+ {
988
+ return $this->dom->saveHTML();
989
+ }
990
+
991
+ /**
992
+ * Get the dompdf option value
993
+ *
994
+ * @param string $key
995
+ * @return mixed
996
+ * @deprecated
997
+ */
998
+ public function get_option($key)
999
+ {
1000
+ return $this->options->get($key);
1001
+ }
1002
+
1003
+ /**
1004
+ * @param string $key
1005
+ * @param mixed $value
1006
+ * @return $this
1007
+ * @deprecated
1008
+ */
1009
+ public function set_option($key, $value)
1010
+ {
1011
+ $this->options->set($key, $value);
1012
+ return $this;
1013
+ }
1014
+
1015
+ /**
1016
+ * @param array $options
1017
+ * @return $this
1018
+ * @deprecated
1019
+ */
1020
+ public function set_options(array $options)
1021
+ {
1022
+ $this->options->set($options);
1023
+ return $this;
1024
+ }
1025
+
1026
+ /**
1027
+ * @param string $size
1028
+ * @param string $orientation
1029
+ * @deprecated
1030
+ */
1031
+ public function set_paper($size, $orientation = "portrait")
1032
+ {
1033
+ $this->setPaper($size, $orientation);
1034
+ }
1035
+
1036
+ /**
1037
+ * Sets the paper size & orientation
1038
+ *
1039
+ * @param string $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}
1040
+ * @param string $orientation 'portrait' or 'landscape'
1041
+ * @return $this
1042
+ */
1043
+ public function setPaper($size, $orientation = "portrait")
1044
+ {
1045
+ $this->paperSize = $size;
1046
+ $this->paperOrientation = $orientation;
1047
+ return $this;
1048
+ }
1049
+
1050
+ /**
1051
+ * Gets the paper size
1052
+ *
1053
+ * @param null|string|array $paperSize
1054
+ * @return \int[] A four-element integer array
1055
+ */
1056
+ public function getPaperSize($paperSize = null)
1057
+ {
1058
+ $size = $paperSize !== null ? $paperSize : $this->paperSize;
1059
+ if (is_array($size)) {
1060
+ return $size;
1061
+ } else if (isset(Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)])) {
1062
+ return Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)];
1063
+ } else {
1064
+ return Adapter\CPDF::$PAPER_SIZES["letter"];
1065
+ }
1066
+ }
1067
+
1068
+ /**
1069
+ * Gets the paper orientation
1070
+ *
1071
+ * @return string Either "portrait" or "landscape"
1072
+ */
1073
+ public function getPaperOrientation()
1074
+ {
1075
+ return $this->paperOrientation;
1076
+ }
1077
+
1078
+ /**
1079
+ * @param FrameTree $tree
1080
+ * @return $this
1081
+ */
1082
+ public function setTree(FrameTree $tree)
1083
+ {
1084
+ $this->tree = $tree;
1085
+ return $this;
1086
+ }
1087
+
1088
+ /**
1089
+ * @return FrameTree
1090
+ * @deprecated
1091
+ */
1092
+ public function get_tree()
1093
+ {
1094
+ return $this->getTree();
1095
+ }
1096
+
1097
+ /**
1098
+ * Returns the underlying {@link FrameTree} object
1099
+ *
1100
+ * @return FrameTree
1101
+ */
1102
+ public function getTree()
1103
+ {
1104
+ return $this->tree;
1105
+ }
1106
+
1107
+ /**
1108
+ * @param string $protocol
1109
+ * @return $this
1110
+ * @deprecated
1111
+ */
1112
+ public function set_protocol($protocol)
1113
+ {
1114
+ return $this->setProtocol($protocol);
1115
+ }
1116
+
1117
+ /**
1118
+ * Sets the protocol to use
1119
+ * FIXME validate these
1120
+ *
1121
+ * @param string $protocol
1122
+ * @return $this
1123
+ */
1124
+ public function setProtocol($protocol)
1125
+ {
1126
+ $this->protocol = $protocol;
1127
+ return $this;
1128
+ }
1129
+
1130
+ /**
1131
+ * @return string
1132
+ * @deprecated
1133
+ */
1134
+ public function get_protocol()
1135
+ {
1136
+ return $this->getProtocol();
1137
+ }
1138
+
1139
+ /**
1140
+ * Returns the protocol in use
1141
+ *
1142
+ * @return string
1143
+ */
1144
+ public function getProtocol()
1145
+ {
1146
+ return $this->protocol;
1147
+ }
1148
+
1149
+ /**
1150
+ * @param string $host
1151
+ * @deprecated
1152
+ */
1153
+ public function set_host($host)
1154
+ {
1155
+ $this->setBaseHost($host);
1156
+ }
1157
+
1158
+ /**
1159
+ * Sets the base hostname
1160
+ *
1161
+ * @param string $baseHost
1162
+ * @return $this
1163
+ */
1164
+ public function setBaseHost($baseHost)
1165
+ {
1166
+ $this->baseHost = $baseHost;
1167
+ return $this;
1168
+ }
1169
+
1170
+ /**
1171
+ * @return string
1172
+ * @deprecated
1173
+ */
1174
+ public function get_host()
1175
+ {
1176
+ return $this->getBaseHost();
1177
+ }
1178
+
1179
+ /**
1180
+ * Returns the base hostname
1181
+ *
1182
+ * @return string
1183
+ */
1184
+ public function getBaseHost()
1185
+ {
1186
+ return $this->baseHost;
1187
+ }
1188
+
1189
+ /**
1190
+ * Sets the base path
1191
+ *
1192
+ * @param string $path
1193
+ * @deprecated
1194
+ */
1195
+ public function set_base_path($path)
1196
+ {
1197
+ $this->setBasePath($path);
1198
+ }
1199
+
1200
+ /**
1201
+ * Sets the base path
1202
+ *
1203
+ * @param string $basePath
1204
+ * @return $this
1205
+ */
1206
+ public function setBasePath($basePath)
1207
+ {
1208
+ $this->basePath = $basePath;
1209
+ return $this;
1210
+ }
1211
+
1212
+ /**
1213
+ * @return string
1214
+ * @deprecated
1215
+ */
1216
+ public function get_base_path()
1217
+ {
1218
+ return $this->getBasePath();
1219
+ }
1220
+
1221
+ /**
1222
+ * Returns the base path
1223
+ *
1224
+ * @return string
1225
+ */
1226
+ public function getBasePath()
1227
+ {
1228
+ return $this->basePath;
1229
+ }
1230
+
1231
+ /**
1232
+ * @param string $default_view The default document view
1233
+ * @param array $options The view's options
1234
+ * @return $this
1235
+ * @deprecated
1236
+ */
1237
+ public function set_default_view($default_view, $options)
1238
+ {
1239
+ return $this->setDefaultView($default_view, $options);
1240
+ }
1241
+
1242
+ /**
1243
+ * Sets the default view
1244
+ *
1245
+ * @param string $defaultView The default document view
1246
+ * @param array $options The view's options
1247
+ * @return $this
1248
+ */
1249
+ public function setDefaultView($defaultView, $options)
1250
+ {
1251
+ $this->defaultView = $defaultView;
1252
+ $this->defaultViewOptions = $options;
1253
+ return $this;
1254
+ }
1255
+
1256
+ /**
1257
+ * @param resource $http_context
1258
+ * @return $this
1259
+ * @deprecated
1260
+ */
1261
+ public function set_http_context($http_context)
1262
+ {
1263
+ return $this->setHttpContext($http_context);
1264
+ }
1265
+
1266
+ /**
1267
+ * Sets the HTTP context
1268
+ *
1269
+ * @param resource $httpContext
1270
+ * @return $this
1271
+ */
1272
+ public function setHttpContext($httpContext)
1273
+ {
1274
+ $this->httpContext = $httpContext;
1275
+ return $this;
1276
+ }
1277
+
1278
+ /**
1279
+ * @return resource
1280
+ * @deprecated
1281
+ */
1282
+ public function get_http_context()
1283
+ {
1284
+ return $this->getHttpContext();
1285
+ }
1286
+
1287
+ /**
1288
+ * Returns the HTTP context
1289
+ *
1290
+ * @return resource
1291
+ */
1292
+ public function getHttpContext()
1293
+ {
1294
+ return $this->httpContext;
1295
+ }
1296
+
1297
+ /**
1298
+ * @param Canvas $canvas
1299
+ * @return $this
1300
+ */
1301
+ public function setCanvas(Canvas $canvas)
1302
+ {
1303
+ $this->canvas = $canvas;
1304
+ return $this;
1305
+ }
1306
+
1307
+ /**
1308
+ * @return Canvas
1309
+ * @deprecated
1310
+ */
1311
+ public function get_canvas()
1312
+ {
1313
+ return $this->getCanvas();
1314
+ }
1315
+
1316
+ /**
1317
+ * Return the underlying Canvas instance (e.g. Dompdf\Adapter\CPDF, Dompdf\Adapter\GD)
1318
+ *
1319
+ * @return Canvas
1320
+ */
1321
+ public function getCanvas()
1322
+ {
1323
+ return $this->canvas;
1324
+ }
1325
+
1326
+ /**
1327
+ * @param Stylesheet $css
1328
+ * @return $this
1329
+ */
1330
+ public function setCss(Stylesheet $css)
1331
+ {
1332
+ $this->css = $css;
1333
+ return $this;
1334
+ }
1335
+
1336
+ /**
1337
+ * @return Stylesheet
1338
+ * @deprecated
1339
+ */
1340
+ public function get_css()
1341
+ {
1342
+ return $this->getCss();
1343
+ }
1344
+
1345
+ /**
1346
+ * Returns the stylesheet
1347
+ *
1348
+ * @return Stylesheet
1349
+ */
1350
+ public function getCss()
1351
+ {
1352
+ return $this->css;
1353
+ }
1354
+
1355
+ /**
1356
+ * @param DOMDocument $dom
1357
+ * @return $this
1358
+ */
1359
+ public function setDom(DOMDocument $dom)
1360
+ {
1361
+ $this->dom = $dom;
1362
+ return $this;
1363
+ }
1364
+
1365
+ /**
1366
+ * @return DOMDocument
1367
+ * @deprecated
1368
+ */
1369
+ public function get_dom()
1370
+ {
1371
+ return $this->getDom();
1372
+ }
1373
+
1374
+ /**
1375
+ * @return DOMDocument
1376
+ */
1377
+ public function getDom()
1378
+ {
1379
+ return $this->dom;
1380
+ }
1381
+
1382
+ /**
1383
+ * @param Options $options
1384
+ * @return $this
1385
+ */
1386
+ public function setOptions(Options $options)
1387
+ {
1388
+ $this->options = $options;
1389
+ $fontMetrics = $this->getFontMetrics();
1390
+ if (isset($fontMetrics)) {
1391
+ $fontMetrics->setOptions($options);
1392
+ }
1393
+ return $this;
1394
+ }
1395
+
1396
+ /**
1397
+ * @return Options
1398
+ */
1399
+ public function getOptions()
1400
+ {
1401
+ return $this->options;
1402
+ }
1403
+
1404
+ /**
1405
+ * @return array
1406
+ * @deprecated
1407
+ */
1408
+ public function get_callbacks()
1409
+ {
1410
+ return $this->getCallbacks();
1411
+ }
1412
+
1413
+ /**
1414
+ * Returns the callbacks array
1415
+ *
1416
+ * @return array
1417
+ */
1418
+ public function getCallbacks()
1419
+ {
1420
+ return $this->callbacks;
1421
+ }
1422
+
1423
+ /**
1424
+ * @param array $callbacks the set of callbacks to set
1425
+ * @deprecated
1426
+ */
1427
+ public function set_callbacks($callbacks)
1428
+ {
1429
+ $this->setCallbacks($callbacks);
1430
+ }
1431
+
1432
+ /**
1433
+ * Sets callbacks for events like rendering of pages and elements.
1434
+ * The callbacks array contains arrays with 'event' set to 'begin_page',
1435
+ * 'end_page', 'begin_frame', or 'end_frame' and 'f' set to a function or
1436
+ * object plus method to be called.
1437
+ *
1438
+ * The function 'f' must take an array as argument, which contains info
1439
+ * about the event.
1440
+ *
1441
+ * @param array $callbacks the set of callbacks to set
1442
+ */
1443
+ public function setCallbacks($callbacks)
1444
+ {
1445
+ if (is_array($callbacks)) {
1446
+ $this->callbacks = array();
1447
+ foreach ($callbacks as $c) {
1448
+ if (is_array($c) && isset($c['event']) && isset($c['f'])) {
1449
+ $event = $c['event'];
1450
+ $f = $c['f'];
1451
+ if (is_callable($f) && is_string($event)) {
1452
+ $this->callbacks[$event][] = $f;
1453
+ }
1454
+ }
1455
+ }
1456
+ }
1457
+ }
1458
+
1459
+ /**
1460
+ * @return boolean
1461
+ * @deprecated
1462
+ */
1463
+ public function get_quirksmode()
1464
+ {
1465
+ return $this->getQuirksmode();
1466
+ }
1467
+
1468
+ /**
1469
+ * Get the quirks mode
1470
+ *
1471
+ * @return boolean true if quirks mode is active
1472
+ */
1473
+ public function getQuirksmode()
1474
+ {
1475
+ return $this->quirksmode;
1476
+ }
1477
+
1478
+ /**
1479
+ * @param FontMetrics $fontMetrics
1480
+ * @return $this
1481
+ */
1482
+ public function setFontMetrics(FontMetrics $fontMetrics)
1483
+ {
1484
+ $this->fontMetrics = $fontMetrics;
1485
+ return $this;
1486
+ }
1487
+
1488
+ /**
1489
+ * @return FontMetrics
1490
+ */
1491
+ public function getFontMetrics()
1492
+ {
1493
+ return $this->fontMetrics;
1494
+ }
1495
+
1496
+ /**
1497
+ * PHP5 overloaded getter
1498
+ * Along with {@link Dompdf::__set()} __get() provides access to all
1499
+ * properties directly. Typically __get() is not called directly outside
1500
+ * of this class.
1501
+ *
1502
+ * @param string $prop
1503
+ *
1504
+ * @throws Exception
1505
+ * @return mixed
1506
+ */
1507
+ function __get($prop)
1508
+ {
1509
+ switch ($prop)
1510
+ {
1511
+ case 'version' :
1512
+ return $this->version;
1513
+ default:
1514
+ throw new Exception( 'Invalid property: ' . $prop );
1515
+ }
1516
+ }
1517
+ }
woocommerce-pdf-invoices-packingslips.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
- * Version: 2.0.14
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
@@ -21,7 +21,7 @@ if ( !class_exists( 'WPO_WCPDF' ) ) :
21
 
22
  class WPO_WCPDF {
23
 
24
- public $version = '2.0.14';
25
  public $plugin_basename;
26
  public $legacy_mode;
27
 
3
  * Plugin Name: WooCommerce PDF Invoices & Packing Slips
4
  * Plugin URI: http://www.wpovernight.com
5
  * Description: Create, print & email PDF invoices & packing slips for WooCommerce orders.
6
+ * Version: 2.0.15
7
  * Author: Ewout Fernhout
8
  * Author URI: http://www.wpovernight.com
9
  * License: GPLv2 or later
21
 
22
  class WPO_WCPDF {
23
 
24
+ public $version = '2.0.15';
25
  public $plugin_basename;
26
  public $legacy_mode;
27