diff --git a/lib/tcpdf/CHANGELOG.TXT b/lib/tcpdf/CHANGELOG.TXT index efd3b52f2ee..4a845350ee0 100644 --- a/lib/tcpdf/CHANGELOG.TXT +++ b/lib/tcpdf/CHANGELOG.TXT @@ -1,10 +1,18 @@ -6.6.5 (2023-09-06) +6.7.5 (2024-04-20) + - Update GitHub actions + - fix: CSV-2024-22640 (#712) + +6.7.4 (2024-03-24) + - Upgrade tcpdf tag encryption algorithm. + - Fix regression issue #699. + - Fix security issue. + - [BREAKING CHANGE] The tcpdf HTML tag syntax has changed, see example_049.php. + - New K_ALLOWED_TCPDF_TAGS configuration constant to set the allowed methods for the tcdpf HTML tag. + - Raised minimum PHP version to PHP 5.5.0. + +6.6.5 (2023-09-02) - Fix corrupted file. - -6.6.4 (2023-09-06) - Fix GitHub automation tests. - -6.6.3 (2023-09-06) - Fix SPDX license ID (#591) - Fix warning "array offset on value of type null" (#620) - Improve the README about the status of this library (#589) diff --git a/lib/tcpdf/LICENSE.TXT b/lib/tcpdf/LICENSE.TXT index 072e73a7547..ec7968a7e22 100644 --- a/lib/tcpdf/LICENSE.TXT +++ b/lib/tcpdf/LICENSE.TXT @@ -7,7 +7,7 @@ published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - 2002-2023 Nicola Asuni - Tecnick.com LTD + 2002-2024 Nicola Asuni - Tecnick.com LTD ********************************************************************** ********************************************************************** diff --git a/lib/tcpdf/README.md b/lib/tcpdf/README.md index 39ea1c458ba..f59f663399c 100644 --- a/lib/tcpdf/README.md +++ b/lib/tcpdf/README.md @@ -6,7 +6,7 @@ * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2023 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2024 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF diff --git a/lib/tcpdf/composer.json b/lib/tcpdf/composer.json index 69944357bbd..e4244b2821f 100644 --- a/lib/tcpdf/composer.json +++ b/lib/tcpdf/composer.json @@ -12,7 +12,7 @@ "barcodes" ], "homepage": "http://www.tcpdf.org/", - "version": "6.6.5", + "version": "6.7.5", "license": "LGPL-3.0-or-later", "authors": [ { @@ -22,7 +22,7 @@ } ], "require": { - "php": ">=5.3.0" + "php": ">=5.5.0" }, "autoload": { "classmap": [ diff --git a/lib/tcpdf/config/tcpdf_config.php b/lib/tcpdf/config/tcpdf_config.php index 92317b121ef..9888a6778b0 100644 --- a/lib/tcpdf/config/tcpdf_config.php +++ b/lib/tcpdf/config/tcpdf_config.php @@ -212,6 +212,14 @@ define('K_THAI_TOPCHARS', true); */ define('K_TCPDF_CALLS_IN_HTML', false); +/** + * List of TCPDF methods that are allowed to be called using HTML syntax. + * Note: each method name must end with surrounded with | (pipe) character. + * The constant K_TCPDF_CALLS_IN_HTML must be set to true. + * IMPORTANT: For security reason, disable this feature if you are allowing user HTML content. + */ +define('K_ALLOWED_TCPDF_TAGS', ''); + /** * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. */ diff --git a/lib/tcpdf/include/tcpdf_colors.php b/lib/tcpdf/include/tcpdf_colors.php index 7f337f31a4b..5a51594c317 100644 --- a/lib/tcpdf/include/tcpdf_colors.php +++ b/lib/tcpdf/include/tcpdf_colors.php @@ -275,7 +275,7 @@ class TCPDF_COLORS { $color = strtolower($color); // check for javascript color array syntax if (strpos($color, '[') !== false) { - if (preg_match('/[\[][\"\'](t|g|rgb|cmyk)[\"\'][\,]?([0-9\.]*)[\,]?([0-9\.]*)[\,]?([0-9\.]*)[\,]?([0-9\.]*)[\]]/', $color, $m) > 0) { + if (preg_match('/[\[][\"\'](t|g|rgb|cmyk)[\"\'][\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\]]/', $color, $m) > 0) { $returncolor = array(); switch ($m[1]) { case 'cmyk': { diff --git a/lib/tcpdf/include/tcpdf_static.php b/lib/tcpdf/include/tcpdf_static.php index 46c23f41dcb..ff9a08f8346 100644 --- a/lib/tcpdf/include/tcpdf_static.php +++ b/lib/tcpdf/include/tcpdf_static.php @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.6.5'; + private static $tcpdf_version = '6.7.5'; /** * String alias for total number of pages. diff --git a/lib/tcpdf/readme_moodle.txt b/lib/tcpdf/readme_moodle.txt index 7a9bb1e1936..1109f9db2e0 100644 --- a/lib/tcpdf/readme_moodle.txt +++ b/lib/tcpdf/readme_moodle.txt @@ -12,6 +12,21 @@ 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. +2024/06/16 +---------- +Upgrade to tcpdf TCPDF 6.7.5 (MDL-81658) +by Daniel Ziegenbergg + +2023/10/23 +---------- +Upgrade to tcpdf TCPDF 6.6.5 (MDL-79665) +by Paul Holden + +2023/03/02 +---------- +Upgrade to tcpdf TCPDF 6.6.2 (MDL-76910) +by Paul Holden + 2022/09/27 ---------- Upgrade to tcpdf TCPDF 6.5.0 (MDL-75468) diff --git a/lib/tcpdf/tcpdf.php b/lib/tcpdf/tcpdf.php index cd0205129da..60f93c4169e 100644 --- a/lib/tcpdf/tcpdf.php +++ b/lib/tcpdf/tcpdf.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 6.6.5 + * @version 6.7.5 * @author Nicola Asuni - info@tecnick.com * @IgnoreAnnotation("protected") * @IgnoreAnnotation("public") @@ -838,6 +838,13 @@ class TCPDF { */ protected $file_id; + /** + * Internal secret used to encrypt data. + * @protected + * @since 6.7.5 (2024-03-21) + */ + protected $hash_key; + // --- bookmark --- /** @@ -1880,10 +1887,10 @@ class TCPDF { // 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)); + $this->hash_key = hash_hmac('sha256', TCPDF_STATIC::getRandomSeed($this->file_id), TCPDF_STATIC::getRandomSeed('TCPDF'), false); $this->font_obj_ids = array(); $this->page_obj_id = array(); $this->form_obj_id = array(); - // set pdf/a mode if ($pdfa != false) { $this->pdfa_mode = true; @@ -4427,7 +4434,7 @@ class TCPDF { $this->Error('Unknow font type: '.$type.''); } // set name if unset - if (!isset($name) OR empty($name)) { + if (empty($name)) { $name = $fontkey; } // create artificial font style variations if missing (only works with non-embedded fonts) @@ -4470,7 +4477,7 @@ class TCPDF { // we are inside an XObject template $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $this->numfonts; } - if (isset($diff) AND (!empty($diff))) { + if (!empty($diff)) { //Search existing encodings $d = 0; $nb = count($this->diffs); @@ -16389,6 +16396,53 @@ class TCPDF { * @since 3.2.000 (2008-06-20) */ protected function getHtmlDomArray($html) { + // set inheritable properties fot the first void element + // possible inheritable properties are: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, empty-cells, font, font-family, font-stretch, font-size, font-size-adjust, font-style, font-variant, font-weight, letter-spacing, line-height, list-style, list-style-image, list-style-position, list-style-type, orphans, page, page-break-inside, quotes, speak, speak-header, text-align, text-indent, text-transform, volume, white-space, widows, word-spacing + $dom = array( + array( + 'tag' => false, + 'block' => false, + 'value' => '', + 'parent' => 0, + 'hide' => false, + 'fontname' => $this->FontFamily, + 'fontstyle' => $this->FontStyle, + 'fontsize' => $this->FontSizePt, + 'font-stretch' => $this->font_stretching, + 'letter-spacing' => $this->font_spacing, + 'stroke' => $this->textstrokewidth, + 'fill' => (($this->textrendermode % 2) == 0), + 'clip' => ($this->textrendermode > 3), + 'line-height' => $this->cell_height_ratio, + 'bgcolor' => false, + 'fgcolor' => $this->fgcolor, // color + 'strokecolor' => $this->strokecolor, + 'align' => '', + 'listtype' => '', + 'text-indent' => 0, + 'text-transform' => '', + 'border' => array(), + 'dir' => $this->rtl?'rtl':'ltr', + 'width' => 0, + 'height' => 0, + 'x' => 0, + 'y' => 0, + 'w' => 0, + 'h' => 0, + 'l' => 0, + 't' => 0, + 'r' => 0, + 'b' => 0, + 'padding' => array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0), + 'margin' => array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0), + 'border-spacing' => array('H' => 0, 'V' => 0), + 'border-collapse' => 'separate', + ) + ); + + if(empty($html)) { + return $dom; + } // array of CSS styles ( selector => properties). $css = array(); // get CSS array defined at previous call @@ -16533,37 +16587,8 @@ class TCPDF { // count elements $maxel = count($a); $elkey = 0; - $key = 0; - // create an array of elements - $dom = array(); - $dom[$key] = array(); - // set inheritable properties fot the first void element - // possible inheritable properties are: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, empty-cells, font, font-family, font-stretch, font-size, font-size-adjust, font-style, font-variant, font-weight, letter-spacing, line-height, list-style, list-style-image, list-style-position, list-style-type, orphans, page, page-break-inside, quotes, speak, speak-header, text-align, text-indent, text-transform, volume, white-space, widows, word-spacing - $dom[$key]['tag'] = false; - $dom[$key]['block'] = false; - $dom[$key]['value'] = ''; - $dom[$key]['parent'] = 0; - $dom[$key]['hide'] = false; - $dom[$key]['fontname'] = $this->FontFamily; - $dom[$key]['fontstyle'] = $this->FontStyle; - $dom[$key]['fontsize'] = $this->FontSizePt; - $dom[$key]['font-stretch'] = $this->font_stretching; - $dom[$key]['letter-spacing'] = $this->font_spacing; - $dom[$key]['stroke'] = $this->textstrokewidth; - $dom[$key]['fill'] = (($this->textrendermode % 2) == 0); - $dom[$key]['clip'] = ($this->textrendermode > 3); - $dom[$key]['line-height'] = $this->cell_height_ratio; - $dom[$key]['bgcolor'] = false; - $dom[$key]['fgcolor'] = $this->fgcolor; // color - $dom[$key]['strokecolor'] = $this->strokecolor; - $dom[$key]['align'] = ''; - $dom[$key]['listtype'] = ''; - $dom[$key]['text-indent'] = 0; - $dom[$key]['text-transform'] = ''; - $dom[$key]['border'] = array(); - $dom[$key]['dir'] = $this->rtl?'rtl':'ltr'; $thead = false; // true when we are inside the THEAD tag - ++$key; + $key = 1; $level = array(); array_push($level, 0); // root while ($elkey < $maxel) { @@ -17200,41 +17225,59 @@ class TCPDF { } /** - * Return an hash code used to ensure that the serialized data has been generated by this TCPDF instance. - * @param string $data serialized data - * @return string - * @public static + * Calculates the hash value of the given data. + * + * @param string $data The data to be hashed. + * @return string The hashed value of the data. */ - protected function getHashForTCPDFtagParams($data) { - return md5(strlen($data).$this->file_id.$data); + protected function hashTCPDFtag($data) { + return hash_hmac('sha256', $data, $this->hash_key, false); } /** - * Serialize an array of parameters to be used with TCPDF tag in HTML code. - * @param array $data parameters array - * @return string containing serialized data + * Serialize data to be used with TCPDF tag in HTML code. + * @param string $method TCPDF method name + * @param array $params Method parameters + * @return string Serialized data * @public static */ - public function serializeTCPDFtagParameters($data) { + public function serializeTCPDFtag($method, $params=array()) { + $data = array('m' => $method, 'p' => $params); $encoded = urlencode(json_encode($data)); - return $this->getHashForTCPDFtagParams($encoded).$encoded; + $hash = $this->hashTCPDFtag($encoded); + return strlen($hash).'+'.$hash.'+'.$encoded; } /** - * Unserialize parameters to be used with TCPDF tag in HTML code. + * Unserialize data to be used with TCPDF tag in HTML code. * @param string $data serialized data * @return array containing unserialized data * @protected static */ - protected function unserializeTCPDFtagParameters($data) { - $hash = substr($data, 0, 32); - $encoded = substr($data, 32); - if ($hash != $this->getHashForTCPDFtagParams($encoded)) { + protected function unserializeTCPDFtag($data) { + $hpos = strpos($data, '+'); + $hlen = intval(substr($data, 0, $hpos)); + $hash = substr($data, $hpos + 1, $hlen); + $encoded = substr($data, $hpos + 2 + $hlen); + if ($hash != $this->hashTCPDFtag($encoded)) { $this->Error('Invalid parameters'); } return json_decode(urldecode($encoded), true); } + /** + * Check if a TCPDF tag is allowed + * @param string $method TCPDF method name + * @return boolean + * @protected + */ + protected function allowedTCPDFtag($method) { + if (defined('K_ALLOWED_TCPDF_TAGS')) { + return (strpos(K_ALLOWED_TCPDF_TAGS, '|'.$method.'|') !== false); + } + return false; + } + /** * Prints a cell (rectangular area) with optional borders, background color and html text string. * The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.
@@ -17248,8 +17291,7 @@ class TCPDF { * @param float|null $y upper-left corner Y coordinate * @param string $html html text to print. Default value: empty string. * @param mixed $border 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))) - * @param int $ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right (or left for RTL language)
  • 1: to the beginning of the next line
  • 2: below
-Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param int $ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right (or left for RTL language)
  • 1: to the beginning of the next line
  • 2: below
Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). * @param boolean $reseth if true reset the last cell height (default true). * @param string $align Allows to center or align the text. Possible values are:
  • L : left align
  • C : center
  • R : right align
  • '' : empty string : left for LTR or right for RTL
@@ -19510,17 +19552,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: case 'tcpdf': { if (defined('K_TCPDF_CALLS_IN_HTML') AND (K_TCPDF_CALLS_IN_HTML === true)) { // Special tag used to call TCPDF methods - if (isset($tag['attribute']['method'])) { - $tcpdf_method = $tag['attribute']['method']; - if (method_exists($this, $tcpdf_method)) { - if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) { - $params = $this->unserializeTCPDFtagParameters($tag['attribute']['params']); - call_user_func_array(array($this, $tcpdf_method), $params); - } else { - $this->$tcpdf_method(); - } - $this->newline = true; + // This tag is disabled by default by the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file. + // Please use this feature only if you are in control of the HTML content and you are sure that it does not contain any harmful code. + if (!empty($tag['attribute']['data'])) { + $tcpdf_tag_data = $this->unserializeTCPDFtag($tag['attribute']['data']); + if ($this->allowedTCPDFtag($tcpdf_tag_data['m'])) { + call_user_func_array(array($this, $tcpdf_tag_data['m']), $tcpdf_tag_data['p']); } + $this->newline = true; } } break; @@ -21867,25 +21906,23 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * @since 4.5.029 (2009-03-19) */ public function rollbackTransaction($self=false) { - if (isset($this->objcopy)) { - $objcopy = $this->objcopy; - $this->_destroy(true, true); - if ($self) { - $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; - } - /* The unique file_id should not be used during cleanup again */ - $this->file_id = NULL; - return $objcopy; + if (!isset($this->objcopy)) { + return $this; } - return $this; + $file_id = $this->file_id; + $objcopy = $this->objcopy; + $this->_destroy(true, true); + if ($self) { + $objvars = get_object_vars($objcopy); + foreach ($objvars as $key => $value) { + $this->$key = $value; + } + $objcopy->_destroy(true, true); + unset($objcopy); + return $this; + } + $this->file_id = $file_id; + return $objcopy; } // --- MULTI COLUMNS METHODS ----------------------- diff --git a/lib/tcpdf/tcpdf_autoconfig.php b/lib/tcpdf/tcpdf_autoconfig.php index 6ec9ce83bb8..2bcfccb82b7 100644 --- a/lib/tcpdf/tcpdf_autoconfig.php +++ b/lib/tcpdf/tcpdf_autoconfig.php @@ -228,6 +228,10 @@ if (!defined('K_TCPDF_CALLS_IN_HTML')) { define('K_TCPDF_CALLS_IN_HTML', false); } +if (!defined('K_ALLOWED_TCPDF_TAGS')) { + define('K_ALLOWED_TCPDF_TAGS', ''); +} + if (!defined('K_TCPDF_THROW_EXCEPTION_ERROR')) { define('K_TCPDF_THROW_EXCEPTION_ERROR', false); } diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index 62fa9f82985..05e5f576add 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -175,7 +175,7 @@ tcpdf TCPDF Class to generate PDF files - 6.6.5 + 6.7.5 LGPL 3.0-or-later https://github.com/tecnickcom/TCPDF