From 3b1de08da5b2ffdf3770142e44d81508a6683102 Mon Sep 17 00:00:00 2001 From: David Matamoros Date: Tue, 20 Apr 2021 11:53:54 +0200 Subject: [PATCH] MDL-70902 libraries: upgrade to version 6.4.1 of TCPDF --- lib/tcpdf/composer.json | 2 +- lib/tcpdf/fonts/freefont-20120503/CREDITS | 2 +- lib/tcpdf/include/barcodes/pdf417.php | 2 +- lib/tcpdf/include/barcodes/qrcode.php | 3 +- lib/tcpdf/include/tcpdf_colors.php | 2 +- lib/tcpdf/include/tcpdf_fonts.php | 18 +- lib/tcpdf/include/tcpdf_images.php | 5 +- lib/tcpdf/include/tcpdf_static.php | 32 ++- lib/tcpdf/readme_moodle.txt | 5 + lib/tcpdf/tcpdf.php | 238 ++++++++++++++++------ lib/tcpdf/tcpdf_barcodes_1d.php | 8 +- lib/thirdpartylibs.xml | 2 +- 12 files changed, 223 insertions(+), 96 deletions(-) diff --git a/lib/tcpdf/composer.json b/lib/tcpdf/composer.json index 2299c976477..efa82296df3 100644 --- a/lib/tcpdf/composer.json +++ b/lib/tcpdf/composer.json @@ -1,6 +1,6 @@ { "name": "tecnickcom/tcpdf", - "version": "6.3.5", + "version": "6.4.1", "homepage": "http://www.tcpdf.org/", "type": "library", "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", diff --git a/lib/tcpdf/fonts/freefont-20120503/CREDITS b/lib/tcpdf/fonts/freefont-20120503/CREDITS index 06d280e934d..f4430ecf937 100644 --- a/lib/tcpdf/fonts/freefont-20120503/CREDITS +++ b/lib/tcpdf/fonts/freefont-20120503/CREDITS @@ -357,7 +357,7 @@ please contact mssridhar AT vsnl.com. Noah Levitt found out that the Sinhalese fonts available on the site are released under GNU GPL, or, -precisely, "Public Domain under GNU Licence Produced by DMS +precisely, "Public Domain under GNU Licence Produced by DMS Electronics for The Sri Lanka Tipitaka Project" (taken from the font comment), and took the effort of recoding the font to Unicode. diff --git a/lib/tcpdf/include/barcodes/pdf417.php b/lib/tcpdf/include/barcodes/pdf417.php index 9a58a21f673..65381dc8db6 100644 --- a/lib/tcpdf/include/barcodes/pdf417.php +++ b/lib/tcpdf/include/barcodes/pdf417.php @@ -740,6 +740,7 @@ class PDF417 { * @protected */ protected function getErrorCorrectionLevel($ecl, $numcw) { + $maxecl = 8; // starting error level // check for automatic levels if (($ecl < 0) OR ($ecl > 8)) { if ($numcw < 41) { @@ -755,7 +756,6 @@ class PDF417 { } } // get maximum correction level - $maxecl = 8; // starting error level $maxerrsize = (928 - $numcw); // available codewords for error while ($maxecl > 0) { $errsize = (2 << $ecl); diff --git a/lib/tcpdf/include/barcodes/qrcode.php b/lib/tcpdf/include/barcodes/qrcode.php index 7ef2759fd6f..a9a21246f57 100644 --- a/lib/tcpdf/include/barcodes/qrcode.php +++ b/lib/tcpdf/include/barcodes/qrcode.php @@ -1386,6 +1386,7 @@ class QRcode { $p += 2; } $this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr)); + $run = $p; return $run; } @@ -1455,7 +1456,7 @@ class QRcode { break; } case QR_MODE_KJ: { - if ($hint == QR_MODE_KJ) { + if ($this->hint == QR_MODE_KJ) { $length = $this->eatKanji(); } else { $length = $this->eat8(); diff --git a/lib/tcpdf/include/tcpdf_colors.php b/lib/tcpdf/include/tcpdf_colors.php index 27fb7afd192..f9fc3fcb727 100644 --- a/lib/tcpdf/include/tcpdf_colors.php +++ b/lib/tcpdf/include/tcpdf_colors.php @@ -449,7 +449,7 @@ class TCPDF_COLORS { } if (!in_array($color, self::$jscolor)) { // default transparent color - $color = $jscolor[0]; + $color = self::$jscolor[0]; } return 'color.'.$color; } diff --git a/lib/tcpdf/include/tcpdf_fonts.php b/lib/tcpdf/include/tcpdf_fonts.php index 218fb6df1e5..bd1cc775100 100644 --- a/lib/tcpdf/include/tcpdf_fonts.php +++ b/lib/tcpdf/include/tcpdf_fonts.php @@ -557,6 +557,7 @@ class TCPDF_FONTS { $numGlyphs = TCPDF_STATIC::_getUSHORT($font, $offset); // ---------- get CIDToGIDMap ---------- $ctg = array(); + $c = 0; foreach ($encodingTables as $enctable) { // get only specified Platform ID and Encoding ID if (($enctable['platformID'] == $platid) AND ($enctable['encodingID'] == $encid)) { @@ -956,6 +957,7 @@ class TCPDF_FONTS { // sfnt version must be 0x00010000 for TrueType version 1.0. return $font; } + $c = 0; $offset += 4; // get number of tables $numTables = TCPDF_STATIC::_getUSHORT($font, $offset); @@ -1883,7 +1885,7 @@ class TCPDF_FONTS { * Converts UTF-8 character to integer value.
* Uses the getUniord() method if the value is not cached. * @param $uch (string) character string to process. - * @return integer Unicode value + * @return int Unicode value * @public static */ public static function uniord($uch) { @@ -1922,7 +1924,7 @@ class TCPDF_FONTS { * --------------------------------------------------------------------- * * @param $uch (string) character string to process. - * @return integer Unicode value + * @return int Unicode value * @author Nicola Asuni * @public static */ @@ -1995,7 +1997,7 @@ class TCPDF_FONTS { * @author Nicola Asuni * @public static */ - public static function UTF8StringToArray($str, $isunicode=true, &$currentfont) { + public static function UTF8StringToArray($str, $isunicode, &$currentfont) { if ($isunicode) { // requires PCRE unicode support turned on $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY); @@ -2021,7 +2023,7 @@ class TCPDF_FONTS { * @since 3.2.000 (2008-06-23) * @public static */ - public static function UTF8ToLatin1($str, $isunicode=true, &$currentfont) { + public static function UTF8ToLatin1($str, $isunicode, &$currentfont) { $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values return self::UTF8ArrToLatin1($unicode); } @@ -2037,7 +2039,7 @@ class TCPDF_FONTS { * @since 1.53.0.TC005 (2005-01-05) * @public static */ - public static function UTF8ToUTF16BE($str, $setbom=false, $isunicode=true, &$currentfont) { + public static function UTF8ToUTF16BE($str, $setbom, $isunicode, &$currentfont) { if (!$isunicode) { return $str; // string is not in unicode } @@ -2057,7 +2059,7 @@ class TCPDF_FONTS { * @since 2.1.000 (2008-01-08) * @public static */ - public static function utf8StrRev($str, $setbom=false, $forcertl=false, $isunicode=true, &$currentfont) { + public static function utf8StrRev($str, $setbom, $forcertl, $isunicode, &$currentfont) { return self::utf8StrArrRev(self::UTF8StringToArray($str, $isunicode, $currentfont), $str, $setbom, $forcertl, $isunicode, $currentfont); } @@ -2074,7 +2076,7 @@ class TCPDF_FONTS { * @since 4.9.000 (2010-03-27) * @public static */ - public static function utf8StrArrRev($arr, $str='', $setbom=false, $forcertl=false, $isunicode=true, &$currentfont) { + public static function utf8StrArrRev($arr, $str, $setbom, $forcertl, $isunicode, &$currentfont) { return self::arrUTF8ToUTF16BE(self::utf8Bidi($arr, $str, $forcertl, $isunicode, $currentfont), $setbom); } @@ -2090,7 +2092,7 @@ class TCPDF_FONTS { * @since 2.4.000 (2008-03-06) * @public static */ - public static function utf8Bidi($ta, $str='', $forcertl=false, $isunicode=true, &$currentfont) { + public static function utf8Bidi($ta, $str, $forcertl, $isunicode, &$currentfont) { // paragraph embedding level $pel = 0; // max level diff --git a/lib/tcpdf/include/tcpdf_images.php b/lib/tcpdf/include/tcpdf_images.php index 5e504f2101c..a3d61b8fe80 100644 --- a/lib/tcpdf/include/tcpdf_images.php +++ b/lib/tcpdf/include/tcpdf_images.php @@ -77,10 +77,7 @@ class TCPDF_IMAGES { } } if (empty($type)) { - $fileinfo = pathinfo($imgfile); - if (isset($fileinfo['extension']) AND (!TCPDF_STATIC::empty_string($fileinfo['extension']))) { - $type = strtolower(trim($fileinfo['extension'])); - } + $type = strtolower(trim(pathinfo(parse_url($imgfile, PHP_URL_PATH), PATHINFO_EXTENSION))); } if ($type == 'jpg') { $type = 'jpeg'; diff --git a/lib/tcpdf/include/tcpdf_static.php b/lib/tcpdf/include/tcpdf_static.php index 6d7897cf6a8..e13060b7341 100644 --- a/lib/tcpdf/include/tcpdf_static.php +++ b/lib/tcpdf/include/tcpdf_static.php @@ -276,7 +276,7 @@ class TCPDF_STATIC { /** * Determine whether a string is empty. * @param $str (string) string to be checked - * @return boolean true if string is empty + * @return bool true if string is empty * @since 4.5.044 (2009-04-16) * @public static */ @@ -1136,7 +1136,7 @@ class TCPDF_STATIC { * @see setHtmlVSpace() * @public static */ - public static function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='', &$tagvspaces) { + public static function fixHTMLCode($html, $default_css, $tagvs, $tidy_options, &$tagvspaces) { // configure parameters for HTML Tidy if ($tidy_options === '') { $tidy_options = array ( @@ -1440,6 +1440,10 @@ class TCPDF_STATIC { */ public static function intToRoman($number) { $roman = ''; + if ($number >= 4000) { + // do not represent numbers above 4000 in Roman numerals + return strval($number); + } while ($number >= 1000) { $roman .= 'M'; $number -= 1000; @@ -1808,8 +1812,8 @@ class TCPDF_STATIC { /** * Wrapper to use fopen only with local files * @param filename (string) Name of the file to open - * @param $mode (string) - * @return Returns a file pointer resource on success, or FALSE on error. + * @param $mode (string) + * @return Returns a file pointer resource on success, or FALSE on error. * @public static */ public static function fopenLocal($filename, $mode) { @@ -1842,6 +1846,10 @@ class TCPDF_STATIC { curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); + curl_setopt($crs, CURLOPT_MAXREDIRS, 5); + if (defined('CURLOPT_PROTOCOLS')) { + curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); + } curl_exec($crs); $code = curl_getinfo($crs, CURLINFO_HTTP_CODE); curl_close($crs); @@ -1859,7 +1867,7 @@ class TCPDF_STATIC { public static function encodeUrlQuery($url) { $urlData = parse_url($url); if (isset($urlData['query']) && $urlData['query']) { - $urlQueryData = []; + $urlQueryData = array(); parse_str(urldecode($urlData['query']), $urlQueryData); $updatedUrl = $urlData['scheme'] . '://' . $urlData['host'] . $urlData['path'] . '?' . http_build_query($urlQueryData); } else { @@ -1872,8 +1880,8 @@ class TCPDF_STATIC { * Wrapper for file_exists. * Checks whether a file or directory exists. * Only allows some protocols and local files. - * @param filename (string) Path to the file or directory. - * @return Returns TRUE if the file or directory specified by filename exists; FALSE otherwise. + * @param filename (string) Path to the file or directory. + * @return Returns TRUE if the file or directory specified by filename exists; FALSE otherwise. * @public static */ public static function file_exists($filename) { @@ -1890,7 +1898,7 @@ class TCPDF_STATIC { * Reads entire file into a string. * The file can be also an URL. * @param $file (string) Name of the file or URL to read. - * @return The function returns the read data or FALSE on failure. + * @return The function returns the read data or FALSE on failure. * @author Nicola Asuni * @since 6.0.025 * @public static @@ -1973,6 +1981,10 @@ class TCPDF_STATIC { curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); + curl_setopt($crs, CURLOPT_MAXREDIRS, 5); + if (defined('CURLOPT_PROTOCOLS')) { + curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); + } $ret = curl_exec($crs); curl_close($crs); if ($ret !== false) { @@ -2120,7 +2132,7 @@ class TCPDF_STATIC { return $a['i']; } - + /** * Array of page formats * measures are calculated in this way: (inches * 72) or (millimeters * 72 / 25.4) @@ -2507,7 +2519,7 @@ class TCPDF_STATIC { * @since 5.0.010 (2010-05-17) * @public static */ - public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points=false, $k, $pagedim=array()) { + public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points, $k, $pagedim=array()) { if (!isset($pagedim[$page])) { // initialize array $pagedim[$page] = array(); diff --git a/lib/tcpdf/readme_moodle.txt b/lib/tcpdf/readme_moodle.txt index 3b22ec9231c..974371cb766 100644 --- a/lib/tcpdf/readme_moodle.txt +++ b/lib/tcpdf/readme_moodle.txt @@ -12,6 +12,11 @@ Important A new version of the libray is being developed @ https://github.com/tecnickcom/tc-lib-pdf . Check periodically when it's ready and if it's a drop-in replacement for the legacy tcpdf one. +2021/04/20 +---------- +Upgrade to tcpdf TCPDF 6.4.1 (MDL-70902) +by David Matamoros + 2021/02/11 ---------- Reduce PDF metadata disclosure (MDL-70735) diff --git a/lib/tcpdf/tcpdf.php b/lib/tcpdf/tcpdf.php index 8b7d8122361..7a6cb50f022 100644 --- a/lib/tcpdf/tcpdf.php +++ b/lib/tcpdf/tcpdf.php @@ -773,13 +773,6 @@ class TCPDF { */ protected $encoding = 'UTF-8'; - /** - * PHP internal encoding. - * @protected - * @since 1.53.0.TC016 - */ - protected $internal_encoding; - /** * Boolean flag to indicate if the document language is Right-To-Left. * @protected @@ -1832,6 +1825,23 @@ class TCPDF { */ protected $gdgammacache = array(); + /** + * Cache array for file content + * @protected + * @var array + * @sinde 6.3.5 (2020-09-28) + */ + protected $fileContentCache = array(); + + /** + * Whether to allow local file path in image html tags, when prefixed with file:// + * + * @var bool + * @protected + * @since 6.4 (2020-07-23) + */ + protected $allowLocalFiles = false; + //------------------------------------------------------------ // METHODS //------------------------------------------------------------ @@ -1840,8 +1850,6 @@ class TCPDF { * This is the class constructor. * It allows to set up the page format, the orientation and the measure unit used in all the methods (except for the font sizes). * - * IMPORTANT: Please note that this method sets the mb_internal_encoding to ASCII, so if you are using the mbstring module functions with TCPDF you need to correctly set/unset the mb_internal_encoding when needed. - * * @param $orientation (string) page orientation. Possible values are (case insensitive):
  • P or Portrait (default)
  • L or Landscape
  • '' (empty string) for automatic orientation
* @param $unit (string) User measure unit. Possible values are:
  • pt: point
  • mm: millimeter (default)
  • cm: centimeter
  • in: inch

A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). @@ -1853,11 +1861,6 @@ class TCPDF { * @see getPageSizeFromFormat(), setPageFormat() */ public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) { - /* Set internal character encoding to ASCII */ - if (function_exists('mb_internal_encoding') AND mb_internal_encoding()) { - $this->internal_encoding = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } // set file ID for trailer $serformat = (is_array($format) ? json_encode($format) : $format); $this->file_id = md5(TCPDF_STATIC::getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding)); @@ -2728,7 +2731,7 @@ class TCPDF { /** * Adjust the internal Cell padding array to take account of the line width. * @param $brd (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
  • 0: no border (default)
  • 1: frame
or a string containing some or all of the following characters (in any order):
  • L: left
  • T: top
  • R: right
  • B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @return array of adjustments + * @return void|array of adjustments * @public * @since 5.9.000 (2010-10-03) */ @@ -2744,7 +2747,11 @@ class TCPDF { $newbrd[$brd[$i]] = true; } $brd = $newbrd; - } elseif (($brd === 1) OR ($brd === true) OR (is_numeric($brd) AND (intval($brd) > 0))) { + } elseif ( + ($brd === 1) + || ($brd === true) + || (is_numeric($brd) && ((int)$brd > 0)) + ) { $brd = array('LRTB' => true); } if (!is_array($brd)) { @@ -2762,7 +2769,7 @@ class TCPDF { // process borders foreach ($brd as $border => $style) { $line_width = $this->LineWidth; - if (is_array($style) AND isset($style['width'])) { + if (is_array($style) && isset($style['width'])) { // get border width $line_width = $style['width']; } @@ -2783,20 +2790,43 @@ class TCPDF { } } // correct internal cell padding if required to avoid overlap between text and lines - if ((strpos($border,'T') !== false) AND ($this->cell_padding['T'] < $adj)) { + if ( + is_numeric($this->cell_padding['T']) + && ($this->cell_padding['T'] < $adj) + && (strpos($border, 'T') !== false) + ) { $this->cell_padding['T'] = $adj; } - if ((strpos($border,'R') !== false) AND ($this->cell_padding['R'] < $adj)) { + if ( + is_numeric($this->cell_padding['R']) + && ($this->cell_padding['R'] < $adj) + && (strpos($border, 'R') !== false) + ) { $this->cell_padding['R'] = $adj; } - if ((strpos($border,'B') !== false) AND ($this->cell_padding['B'] < $adj)) { + if ( + is_numeric($this->cell_padding['B']) + && ($this->cell_padding['B'] < $adj) + && (strpos($border, 'B') !== false) + ) { $this->cell_padding['B'] = $adj; } - if ((strpos($border,'L') !== false) AND ($this->cell_padding['L'] < $adj)) { + if ( + is_numeric($this->cell_padding['L']) + && ($this->cell_padding['L'] < $adj) + && (strpos($border, 'L') !== false) + ) { $this->cell_padding['L'] = $adj; } + } - return array('T' => ($this->cell_padding['T'] - $cp['T']), 'R' => ($this->cell_padding['R'] - $cp['R']), 'B' => ($this->cell_padding['B'] - $cp['B']), 'L' => ($this->cell_padding['L'] - $cp['L'])); + + return array( + 'T' => ($this->cell_padding['T'] - $cp['T']), + 'R' => ($this->cell_padding['R'] - $cp['R']), + 'B' => ($this->cell_padding['B'] - $cp['B']), + 'L' => ($this->cell_padding['L'] - $cp['L']), + ); } /** @@ -2935,6 +2965,18 @@ class TCPDF { $this->creator = $creator; } + /** + * Whether to allow local file path in image html tags, when prefixed with file:// + * + * @param $allowLocalFiles bool true, when local files should be allowed. Otherwise false. + * @public + * @since 6.4 + */ + public function SetAllowLocalFiles($allowLocalFiles) { + $this->allowLocalFiles = (bool) $allowLocalFiles; + } + + /** * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true. * @param $msg (string) The error message @@ -4863,7 +4905,7 @@ class TCPDF { } reset($this->embeddedfiles); foreach ($this->embeddedfiles as $filename => $filedata) { - $data = TCPDF_STATIC::fileGetContents($filedata['file']); + $data = $this->getCachedFileContents($filedata['file']); if ($data !== FALSE) { $rawsize = strlen($data); if ($rawsize > 0) { @@ -6489,7 +6531,7 @@ class TCPDF { // *** very slow *** $l = $this->GetArrStringWidth(TCPDF_FONTS::utf8Bidi(array_slice($chars, $j, ($i - $j)), '', $this->tmprtl, $this->isunicode, $this->CurrentFont)); } else { - $l += $this->GetCharWidth($c); + $l += $this->GetCharWidth($c, ($i+1 < $nb)); } if (($l > $wmax) OR (($c == 173) AND (($l + $tmp_shy_replacement_width) >= $wmax))) { if (($c == 173) AND (($l + $tmp_shy_replacement_width) > $wmax)) { @@ -6866,6 +6908,12 @@ class TCPDF { list($x, $y) = $this->checkPageRegions($h, $x, $y); $exurl = ''; // external streams $imsize = FALSE; + + // Make sure the file variable is not empty or null because accessing $file[0] later + // results in error when running PHP 7.4 + if (empty($file)) { + return false; + } // check if we are passing an image as file or string if ($file[0] === '@') { // image from string @@ -6877,18 +6925,14 @@ class TCPDF { $exurl = $file; } // check if file exist and it is valid - if (!@TCPDF_STATIC::file_exists($file)) { + if (!@$this->fileExists($file)) { return false; } - if (($imsize = @getimagesize($file)) === FALSE) { - if (in_array($file, $this->imagekeys)) { - // get existing image data - $info = $this->getImageBuffer($file); - $imsize = array($info['w'], $info['h']); - } elseif (strpos($file, '__tcpdf_'.$this->file_id.'_img') === FALSE) { - $imgdata = TCPDF_STATIC::fileGetContents($file); - } - } + if (false !== $info = $this->getImageBuffer($file)) { + $imsize = array($info['w'], $info['h']); + } elseif (($imsize = @getimagesize($file)) === FALSE && strpos($file, '__tcpdf_'.$this->file_id.'_img') === FALSE){ + $imgdata = $this->getCachedFileContents($file); + } } if (!empty($imgdata)) { // copy image to cache @@ -7093,7 +7137,7 @@ class TCPDF { $svgimg = substr($file, 1); } else { // get SVG file content - $svgimg = TCPDF_STATIC::fileGetContents($file); + $svgimg = $this->getCachedFileContents($file); } if ($svgimg !== FALSE) { // get width and height @@ -7178,7 +7222,7 @@ class TCPDF { } else { $ximg = $x; } - + if ($ismask OR $hidden) { // image is not displayed return $info['i']; @@ -7767,14 +7811,10 @@ class TCPDF { * @since 4.5.016 (2009-02-24) */ public function _destroy($destroyall=false, $preserve_objcopy=false) { - // restore internal encoding - if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) { - mb_internal_encoding($this->internal_encoding); - } if (isset(self::$cleaned_ids[$this->file_id])) { $destroyall = false; } - if ($destroyall AND !$preserve_objcopy) { + if ($destroyall AND !$preserve_objcopy && isset($this->file_id)) { self::$cleaned_ids[$this->file_id] = true; // remove all temporary files if ($handle = @opendir(K_PATH_CACHE)) { @@ -7787,7 +7827,7 @@ class TCPDF { } if (isset($this->imagekeys)) { foreach($this->imagekeys as $file) { - if (strpos($file, K_PATH_CACHE) === 0) { + if (strpos($file, K_PATH_CACHE) === 0 && TCPDF_STATIC::file_exists($file)) { @unlink($file); } } @@ -7795,7 +7835,6 @@ class TCPDF { } $preserve = array( 'file_id', - 'internal_encoding', 'state', 'bufferlen', 'buffer', @@ -14909,7 +14948,7 @@ class TCPDF { if ($file[0] === '@') { // image from string $data = substr($file, 1); } else { // EPS/AI file - $data = TCPDF_STATIC::fileGetContents($file); + $data = $this->getCachedFileContents($file); } if ($data === FALSE) { $this->Error('EPS file not found: '.$file); @@ -15511,7 +15550,7 @@ class TCPDF { $this->y = $y + $vpadding + $barh; $cellpadding = $this->cell_padding; $this->SetCellPadding(0); - $this->Cell($txtwidth, '', $label, 0, 0, 'C', false, '', $style['stretchtext'], false, 'T', 'T'); + $this->Cell($txtwidth, 0, $label, 0, 0, 'C', false, '', $style['stretchtext'], false, 'T', 'T'); $this->cell_padding = $cellpadding; } // restore original direction @@ -16328,7 +16367,7 @@ class TCPDF { $type = array(); if (preg_match('/href[\s]*=[\s]*"([^"]*)"/', $link, $type) > 0) { // read CSS data file - $cssdata = TCPDF_STATIC::fileGetContents(trim($type[1])); + $cssdata = $this->getCachedFileContents(trim($type[1])); if (($cssdata !== FALSE) AND (strlen($cssdata) > 0)) { $css = array_merge($css, TCPDF_STATIC::extractCSSproperties($cssdata)); } @@ -16354,7 +16393,7 @@ class TCPDF { // create a special tag to contain the CSS array (used for table content) $csstagarray = ''.htmlentities(json_encode($css)).''; // remove head and style blocks - $html = preg_replace('/]*)>(.*?)<\/head>/siU', '', $html); + $html = preg_replace('/]*)>(.*)?<\/head>/siU', '', $html); $html = preg_replace('/]*)>([^\<]*)<\/style>/isU', '', $html); // define block tags $blocktags = array('blockquote','br','dd','dl','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','pre','ul','tcpdf','table','tr','td'); @@ -16549,7 +16588,11 @@ class TCPDF { $dom[($dom[$key]['parent'])]['content'] = str_replace('', '', $dom[($dom[$key]['parent'])]['content']); } // store header rows on a new table - if (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['thead'] === true)) { + if ( + ($dom[$key]['value'] === 'tr') + && !empty($dom[($dom[$key]['parent'])]['thead']) + && ($dom[($dom[$key]['parent'])]['thead'] === true) + ) { if (TCPDF_STATIC::empty_string($dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'])) { $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] = $csstagarray.$a[$dom[($dom[($dom[$key]['parent'])]['parent'])]['elkey']]; } @@ -16979,10 +17022,20 @@ class TCPDF { // rows on thead block are printed as a separate table } else { $dom[$key]['thead'] = false; + $parent = $dom[$key]['parent']; + + if (!isset($dom[$parent]['rows'])) { + $dom[$parent]['rows'] = 0; + } // store the number of rows on table element - ++$dom[($dom[$key]['parent'])]['rows']; + ++$dom[$parent]['rows']; + + if (!isset($dom[$parent]['trids'])) { + $dom[$parent]['trids'] = array(); + } + // store the TR elements IDs on table element - array_push($dom[($dom[$key]['parent'])]['trids'], $key); + array_push($dom[$parent]['trids'], $key); } } if (($dom[$key]['value'] == 'th') OR ($dom[$key]['value'] == 'td')) { @@ -18865,7 +18918,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $prevlinewidth = $this->GetLineWidth(); $this->SetLineWidth($hrHeight); - $this->Line($x, $y, $x + $hrWidth, $y); + + $lineStyle = array( + 'color' => $tag['fgcolor'], + 'cap' => $tag['style']['cap'], + 'join' => $tag['style']['join'], + 'dash' => $tag['style']['dash'], + 'phase' => $tag['style']['phase'], + ); + + $lineStyle = array_filter($lineStyle); + + $this->Line($x, $y, $x + $hrWidth, $y, $lineStyle); $this->SetLineWidth($prevlinewidth); $this->addHTMLVertSpace(max($hbc, ($hrHeight / 2)), 0, $cell, !isset($dom[($key + 1)])); break; @@ -18885,7 +18949,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // data stream $imgsrc = '@'.base64_decode(substr($imgsrc, 1)); $type = ''; - } else { + } elseif ( $this->allowLocalFiles && substr($imgsrc, 0, 7) === 'file://') { + // get image type from a local file path + $imgsrc = substr($imgsrc, 7); + $type = TCPDF_IMAGES::getImageFileType($imgsrc); + } else { if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) { // fix image path $findroot = strpos($imgsrc, $_SERVER['DOCUMENT_ROOT']); @@ -19807,7 +19875,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } if (!$in_table_head) { // we are not inside a thead section - $this->cell_padding = $table_el['old_cell_padding']; + $this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : null; // reset row height $this->resetLastH(); if (($this->page == ($this->numpages - 1)) AND ($this->pageopen[$this->numpages])) { @@ -21717,6 +21785,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: public function commitTransaction() { if (isset($this->objcopy)) { $this->objcopy->_destroy(true, true); + /* The unique file_id should not be used during cleanup again */ + $this->objcopy->file_id = NULL; unset($this->objcopy); } } @@ -21730,14 +21800,22 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: */ public function rollbackTransaction($self=false) { if (isset($this->objcopy)) { + $objcopy = $this->objcopy; $this->_destroy(true, true); if ($self) { - $objvars = get_object_vars($this->objcopy); + $objvars = get_object_vars($objcopy); foreach ($objvars as $key => $value) { $this->$key = $value; } + $objcopy->_destroy(true, true); + /* The unique file_id should not be used during cleanup again */ + $objcopy->file_id = NULL; + unset($objcopy); + return $this; } - return $this->objcopy; + /* The unique file_id should not be used during cleanup again */ + $this->file_id = NULL; + return $objcopy; } return $this; } @@ -22776,7 +22854,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $svgdata = substr($file, 1); } else { // SVG file $this->svgdir = dirname($file); - $svgdata = TCPDF_STATIC::fileGetContents($file); + $svgdata = $this->getCachedFileContents($file); } if ($svgdata === FALSE) { $this->Error('SVG file not found: '.$file); @@ -22986,22 +23064,26 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $f = ($this->h - $oy) * $this->k * (1 - $svgscale_y); $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y))); // creates a new XML parser to be used by the other XML functions - $this->parser = xml_parser_create('UTF-8'); + $parser = xml_parser_create('UTF-8'); // the following function allows to use parser inside object - xml_set_object($this->parser, $this); + xml_set_object($parser, $this); // disable case-folding for this XML parser - xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); // sets the element handler functions for the XML parser - xml_set_element_handler($this->parser, 'startSVGElementHandler', 'endSVGElementHandler'); + xml_set_element_handler($parser, 'startSVGElementHandler', 'endSVGElementHandler'); // sets the character data handler function for the XML parser - xml_set_character_data_handler($this->parser, 'segSVGContentHandler'); + xml_set_character_data_handler($parser, 'segSVGContentHandler'); // start parsing an XML document - if (!xml_parse($this->parser, $svgdata)) { - $error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser)); + if (!xml_parse($parser, $svgdata)) { + $error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)); $this->Error($error_message); } // free this XML parser - xml_parser_free($this->parser); + xml_parser_free($parser); + + // >= PHP 7.0.0 "explicitly unset the reference to parser to avoid memory leaks" + unset($parser); + // restore previous graphic state $this->_out($this->epsmarker.'Q'); // restore graphic vars @@ -23418,6 +23500,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $paths = array(); $d = preg_replace('/([0-9ACHLMQSTVZ])([\-\+])/si', '\\1 \\2', $d); + $d = preg_replace('/(\.[0-9]+)(\.)/s', '\\1 \\2', $d); preg_match_all('/([ACHLMQSTVZ])[\s]*([^ACHLMQSTVZ\"]*)/si', $d, $paths, PREG_SET_ORDER); $x = 0; $y = 0; @@ -24571,6 +24654,33 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // --- END SVG METHODS ----------------------------------------------------- + /** + * Keeps files in memory, so it doesn't need to downloaded everytime in a loop + * @param string $file + * @return string + */ + protected function getCachedFileContents($file) + { + if (!isset($this->fileContentCache[$file])) { + $this->fileContentCache[$file] = TCPDF_STATIC::fileGetContents($file); + } + return $this->fileContentCache[$file]; + } + + /** + * Avoid multiple calls to an external server to see if a file exists + * @param string $file + * @return bool + */ + protected function fileExists($file) + { + if (isset($this->fileContentCache[$file]) || false !== $this->getImageBuffer($file)) { + return true; + } + + return TCPDF_STATIC::file_exists($file); + } + } // END OF TCPDF CLASS //============================================================+ diff --git a/lib/tcpdf/tcpdf_barcodes_1d.php b/lib/tcpdf/tcpdf_barcodes_1d.php index 78bfc5b5bf4..2b94afca7b3 100644 --- a/lib/tcpdf/tcpdf_barcodes_1d.php +++ b/lib/tcpdf/tcpdf_barcodes_1d.php @@ -938,7 +938,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; @@ -1271,7 +1271,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; } @@ -1856,7 +1856,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; @@ -1947,7 +1947,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index 185be1cb2d4..da0e308580b 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -116,7 +116,7 @@ tcpdf TCPDF LGPL - 6.3.5 + 6.4.1 3.0-only