N°8637 - Alerts from dependabot, vulnerable libraries

* Update twig/twig from 3.16.0 to 3.21.1

* Update tecnickcom/tcpdf from 6.7.5 to 6.10.0

* Correct font folder case failing on linux server

* Suppress documentation generator from project in favor of the online version

* Update symfony/http-foundation from 6.4.2 to 6.4.14
Update symfony/runtime from 6.4.0 to 6.4.24
This commit is contained in:
Benjamin Dalsass
2025-09-09 16:15:21 +02:00
committed by GitHub
parent 901f8f2a7b
commit bb8a09d8e2
300 changed files with 5958 additions and 10353 deletions

View File

@@ -1,13 +1,13 @@
<?php
//============================================================+
// File name : tcpdf.php
// Version : 6.7.5
// Version : 6.10.0
// Begin : 2002-08-03
// Last Update : 2024-03-18
// Last Update : 2025-05-27
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
// -------------------------------------------------------------------
// Copyright (C) 2002-2024 Nicola Asuni - Tecnick.com LTD
// Copyright (C) 2002-2025 Nicola Asuni - Tecnick.com LTD
//
// This file is part of TCPDF software library.
//
@@ -104,7 +104,7 @@
* Tools to encode your unicode fonts are on fonts/utils directory.</p>
* @package com.tecnick.tcpdf
* @author Nicola Asuni
* @version 6.6.5
* @version 6.10.0
*/
// TCPDF configuration
@@ -128,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php');
* TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br>
* @package com.tecnick.tcpdf
* @brief PHP class for generating PDF documents without requiring external extensions.
* @version 6.7.5
* @version 6.10.0
* @author Nicola Asuni - info@tecnick.com
* @IgnoreAnnotation("protected")
* @IgnoreAnnotation("public")
@@ -1810,6 +1810,13 @@ class TCPDF {
*/
protected $custom_xmp_rdf = '';
/**
* Custom XMP RDF pdfaextension data.
* @protected
* @since 6.9.0 (2025-02-11)
*/
protected $custom_xmp_rdf_pdfaExtension = '';
/**
* Overprint mode array.
* (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
@@ -3007,6 +3014,7 @@ class TCPDF {
public function Error($msg) {
// unset all class variables
$this->_destroy(true);
$msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
if (defined('K_TCPDF_THROW_EXCEPTION_ERROR') AND !K_TCPDF_THROW_EXCEPTION_ERROR) {
die('<strong>TCPDF ERROR: </strong>'.$msg);
} else {
@@ -4931,6 +4939,32 @@ class TCPDF {
}
}
/**
* Embed the attached files.
* @since 6.9.000 (2025-02-11)
* @public
*/
public function EmbedFile($opt) {
if (!$this->pdfa_mode || ($this->pdfa_mode && $this->pdfa_version == 3)) {
if ((($opt['Subtype'] == 'FileAttachment')) AND (!TCPDF_STATIC::empty_string($opt['FS']))
AND (@TCPDF_STATIC::file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) {
$this->embeddedfiles[basename($opt['FS'])] = array('f' => ++$this->n, 'n' => ++$this->n, 'file' => $opt['FS']);
}
}
}
/**
* Embed the attached files.
* @since 6.9.000 (2025-02-11)
* @public
*/
public function EmbedFileFromString($filename, $content) {
if (!$this->pdfa_mode || ($this->pdfa_mode && $this->pdfa_version == 3)) {
$this->embeddedfiles[$filename] = array('f' => ++$this->n, 'n' => ++$this->n, 'content' => $content );
}
}
/**
* Embedd the attached files.
* @since 4.4.000 (2008-12-07)
@@ -4944,7 +4978,12 @@ class TCPDF {
}
reset($this->embeddedfiles);
foreach ($this->embeddedfiles as $filename => $filedata) {
$data = $this->getCachedFileContents($filedata['file']);
$data = false;
if (isset($filedata['file']) && !empty($filedata['file'])) {
$data = $this->getCachedFileContents($filedata['file']);
} elseif ($filedata['content'] && !empty($filedata['content'])) {
$data = $filedata['content'];
}
if ($data !== FALSE) {
$rawsize = strlen($data);
if ($rawsize > 0) {
@@ -6988,7 +7027,7 @@ class TCPDF {
unset($imgdata);
$imsize = @getimagesize($file);
if ($imsize === FALSE) {
unlink($file);
$this->_unlink($file);
$file = $original_file;
}
}
@@ -7221,7 +7260,7 @@ class TCPDF {
$tempname = TCPDF_STATIC::getObjFilename('img', $this->file_id);
$img->writeImage($tempname);
$info = TCPDF_IMAGES::_parsejpeg($tempname);
unlink($tempname);
$this->_unlink($tempname);
$img->destroy();
} catch(Exception $e) {
$info = false;
@@ -7857,15 +7896,16 @@ class TCPDF {
if ($handle = @opendir(K_PATH_CACHE)) {
while ( false !== ( $file_name = readdir( $handle ) ) ) {
if (strpos($file_name, '__tcpdf_'.$this->file_id.'_') === 0) {
unlink(K_PATH_CACHE.$file_name);
$this->_unlink(K_PATH_CACHE.$file_name);
}
}
closedir($handle);
}
if (isset($this->imagekeys)) {
foreach($this->imagekeys as $file) {
if (strpos($file, K_PATH_CACHE) === 0 && TCPDF_STATIC::file_exists($file)) {
@unlink($file);
if ((strpos($file, K_PATH_CACHE.'__tcpdf_'.$this->file_id.'_') === 0)
&& TCPDF_STATIC::file_exists($file)) {
$this->_unlink($file);
}
}
}
@@ -8164,7 +8204,7 @@ class TCPDF {
* @since 5.0.010 (2010-05-17)
*/
protected function _getannotsrefs($n) {
if (!(isset($this->PageAnnots[$n]) OR ($this->sign AND isset($this->signature_data['cert_type'])))) {
if (!(isset($this->PageAnnots[$n]) OR count($this->empty_signature_appearance)>0 OR ($this->sign AND isset($this->signature_data['cert_type'])))) {
return '';
}
$out = ' /Annots [';
@@ -8310,15 +8350,15 @@ class TCPDF {
break;
}
case 'locked': {
$fval += 1 << 8;
$fval += 1 << 7;
break;
}
case 'togglenoview': {
$fval += 1 << 9;
$fval += 1 << 8;
break;
}
case 'lockedcontents': {
$fval += 1 << 10;
$fval += 1 << 9;
break;
}
default: {
@@ -8532,7 +8572,7 @@ class TCPDF {
}
case 'freetext': {
if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
$annots .= ' /DA ('.$pl['opt']['da'].')';
$annots .= ' /DA '.$this->_datastring($pl['opt']['da']);
}
if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
$annots .= ' /Q '.intval($pl['opt']['q']);
@@ -8789,7 +8829,7 @@ class TCPDF {
$annots .= ' /AA << '.$pl['opt']['aa'].' >>';
}
if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
$annots .= ' /DA ('.$pl['opt']['da'].')';
$annots .= ' /DA '.$this->_datastring($pl['opt']['da']);
}
if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
$annots .= ' /Q '.intval($pl['opt']['q']);
@@ -9628,6 +9668,17 @@ class TCPDF {
$this->custom_xmp_rdf = $xmp;
}
/**
* Set additional XMP data to be added to the default XMP data for PDF/A extensions.
* IMPORTANT: This data is added as-is without controls, so you have to validate your data before using this method!
* @param string $xmp Custom XMP RDF data.
* @since 6.9.0 (2025-02-14)
* @public
*/
public function setExtraXMPPdfaextension($xmp) {
$this->custom_xmp_rdf_pdfaExtension = $xmp;
}
/**
* Put XMP data object and return ID.
* @return int The object ID.
@@ -9762,6 +9813,7 @@ class TCPDF {
$xmp .= "\t\t\t\t\t\t\t".'</rdf:Seq>'."\n";
$xmp .= "\t\t\t\t\t\t".'</pdfaSchema:property>'."\n";
$xmp .= "\t\t\t\t\t".'</rdf:li>'."\n";
$xmp .= $this->custom_xmp_rdf_pdfaExtension;
$xmp .= "\t\t\t\t".'</rdf:Bag>'."\n";
$xmp .= "\t\t\t".'</pdfaExtension:schemas>'."\n";
$xmp .= "\t\t".'</rdf:Description>'."\n";
@@ -9800,7 +9852,11 @@ class TCPDF {
}
// start catalog
$oid = $this->_newobj();
$out = '<< /Type /Catalog';
$out = '<< ';
if (!empty($this->efnames)) {
$out .= ' /AF [ '. implode(' ', $this->efnames) .' ]';
}
$out .= ' /Type /Catalog';
$out .= ' /Version /'.$this->PDFVersion;
//$out .= ' /Extensions <<>>';
$out .= ' /Pages 1 0 R';
@@ -9939,7 +9995,7 @@ class TCPDF {
$out .= ' >> >>';
}
$font = $this->getFontBuffer((($this->pdfa_mode) ? 'pdfa' : '') .'helvetica');
$out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)';
$out .= ' /DA ' . $this->_datastring('/F'.$font['i'].' 0 Tf 0 g');
$out .= ' /Q '.(($this->rtl)?'2':'0');
//$out .= ' /XFA ';
$out .= ' >>';
@@ -11046,7 +11102,7 @@ class TCPDF {
$this->encryptdata['V'] = 4;
$this->encryptdata['Length'] = 128;
$this->encryptdata['CF']['CFM'] = 'AESV2';
$this->encryptdata['CF']['Length'] = 128;
$this->encryptdata['CF']['Length'] = 16;
if ($this->encryptdata['pubkey']) {
$this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
$this->encryptdata['Recipients'] = array();
@@ -11057,7 +11113,7 @@ class TCPDF {
$this->encryptdata['V'] = 5;
$this->encryptdata['Length'] = 256;
$this->encryptdata['CF']['CFM'] = 'AESV3';
$this->encryptdata['CF']['Length'] = 256;
$this->encryptdata['CF']['Length'] = 32;
if ($this->encryptdata['pubkey']) {
$this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
$this->encryptdata['Recipients'] = array();
@@ -13936,8 +13992,8 @@ class TCPDF {
* @since 3.0.000 (2008-03-27)
*/
protected function addExtGState($parms) {
if ($this->pdfa_mode || $this->pdfa_version >= 2) {
// transparencies are not allowed in PDF/A mode
if (($this->pdfa_mode && $this->pdfa_version < 2) || ($this->state != 2)) {
// transparency is not allowed in PDF/A-1 mode
return;
}
// check if this ExtGState already exist
@@ -16440,7 +16496,7 @@ class TCPDF {
)
);
if(empty($html)) {
if($html === '' || $html === null) {
return $dom;
}
// array of CSS styles ( selector => properties).
@@ -17259,7 +17315,7 @@ class TCPDF {
$hlen = intval(substr($data, 0, $hpos));
$hash = substr($data, $hpos + 1, $hlen);
$encoded = substr($data, $hpos + 2 + $hlen);
if ($hash != $this->hashTCPDFtag($encoded)) {
if (!hash_equals( $this->hashTCPDFtag($encoded), $hash)) {
$this->Error('Invalid parameters');
}
return json_decode(urldecode($encoded), true);
@@ -17425,6 +17481,9 @@ class TCPDF {
}
}
if ($key == $maxel) break;
if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND !empty($dom[$key]['attribute']['id'])) {
$this->setDestination($dom[$key]['attribute']['id']);
}
if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) {
// check for pagebreak
if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) {
@@ -18867,6 +18926,29 @@ class TCPDF {
unset($dom);
}
/**
* Check if the path is relative.
* @param string $path path to check
* @return boolean true if the path is relative
* @protected
* @since 6.9.1
*/
protected function isRelativePath($path) {
return (strpos(str_ireplace('%2E', '.', $this->unhtmlentities($path)), '..') !== false);
}
/**
* Check if it contains a non-allowed external protocol.
* @param string $path path to check
* @return boolean true if the protocol is not allowed.
* @protected
* @since 6.9.3
*/
protected function hasExtForbiddenProtocol($path) {
return ((strpos($path, '://') !== false)
&& (preg_match('|^https?://|', $path) !== 1));
}
/**
* Process opening tags.
* @param array $dom html dom array
@@ -19010,29 +19092,29 @@ class TCPDF {
$this->setLineWidth($hrHeight);
$lineStyle = array();
if (isset($tag['fgcolor'])) {
$lineStyle['color'] = $tag['fgcolor'];
}
if (isset($tag['fgcolor'])) {
$lineStyle['color'] = $tag['fgcolor'];
}
if (isset($tag['fgcolor'])) {
$lineStyle['color'] = $tag['fgcolor'];
}
if (isset($tag['fgcolor'])) {
$lineStyle['color'] = $tag['fgcolor'];
}
if (isset($tag['style']['cap'])) {
$lineStyle['cap'] = $tag['style']['cap'];
}
if (isset($tag['style']['cap'])) {
$lineStyle['cap'] = $tag['style']['cap'];
}
if (isset($tag['style']['join'])) {
$lineStyle['join'] = $tag['style']['join'];
}
if (isset($tag['style']['join'])) {
$lineStyle['join'] = $tag['style']['join'];
}
if (isset($tag['style']['dash'])) {
$lineStyle['dash'] = $tag['style']['dash'];
}
if (isset($tag['style']['dash'])) {
$lineStyle['dash'] = $tag['style']['dash'];
}
if (isset($tag['style']['phase'])) {
$lineStyle['phase'] = $tag['style']['phase'];
}
if (isset($tag['style']['phase'])) {
$lineStyle['phase'] = $tag['style']['phase'];
}
$lineStyle = array_filter($lineStyle);
@@ -19055,15 +19137,20 @@ class TCPDF {
if ($imgsrc[0] === '@') {
// data stream
$imgsrc = '@'.base64_decode(substr($imgsrc, 1));
$type = '';
$type = preg_match('/<svg\s+[^>]*[^>]*>.*<\/svg>/is', $imgsrc) ? 'svg' : '';
} else if (preg_match('@^data:image/([^;]*);base64,(.*)@', $imgsrc, $reg)) {
$imgsrc = '@'.base64_decode($reg[2]);
$type = $reg[1];
} elseif ($this->isRelativePath($imgsrc)) {
// accessing parent folders is not allowed
break;
} 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 {
// get image type from a local file path
$imgsrc = substr($imgsrc, 7);
$type = TCPDF_IMAGES::getImageFileType($imgsrc);
} elseif ($this->hasExtForbiddenProtocol($imgsrc)) {
break;
} else {
if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
// fix image path
$findroot = strpos($imgsrc, $_SERVER['DOCUMENT_ROOT']);
@@ -19121,7 +19208,7 @@ class TCPDF {
$imglink = '';
if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) {
$imglink = $this->HREF['url'];
if ($imglink[0] == '#') {
if ($imglink[0] == '#' AND isset($imglink[1]) AND is_numeric($imglink[1])) {
// convert url to internal link
$lnkdata = explode(',', $imglink);
if (isset($lnkdata[0])) {
@@ -19982,7 +20069,7 @@ class TCPDF {
}
}
if (!$in_table_head) { // we are not inside a thead section
$this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : null;
$this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
// reset row height
$this->resetLastH();
if (($this->page == ($this->numpages - 1)) AND ($this->pageopen[$this->numpages])) {
@@ -23170,14 +23257,12 @@ class TCPDF {
$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
$parser = xml_parser_create('UTF-8');
// the following function allows to use parser inside object
xml_set_object($parser, $this);
// disable case-folding for this XML parser
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
// sets the element handler functions for the XML parser
xml_set_element_handler($parser, 'startSVGElementHandler', 'endSVGElementHandler');
xml_set_element_handler($parser, [$this, 'startSVGElementHandler'], [$this, 'endSVGElementHandler']);
// sets the character data handler function for the XML parser
xml_set_character_data_handler($parser, 'segSVGContentHandler');
xml_set_character_data_handler($parser, [$this, 'segSVGContentHandler']);
// start parsing an XML document
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));
@@ -23327,7 +23412,7 @@ class TCPDF {
$text_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['text-color'], $this->spot_colors);
$this->setTextColorArray($text_color);
// clip
if (preg_match('/rect\(([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)\)/si', $svgstyle['clip'], $regs)) {
if (preg_match('/rect\(([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)\)/si', $svgstyle['clip'], $regs)) {
$top = (isset($regs[1])?$this->getHTMLUnitToUnits($regs[1], 0, $this->svgunit, false):0);
$right = (isset($regs[2])?$this->getHTMLUnitToUnits($regs[2], 0, $this->svgunit, false):0);
$bottom = (isset($regs[3])?$this->getHTMLUnitToUnits($regs[3], 0, $this->svgunit, false):0);
@@ -23444,13 +23529,15 @@ class TCPDF {
$cy -= $h;
}
$this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), ($cy * $this->k)));
if (count($gradient['stops']) > 1) {
$this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false);
if ((is_array($gradient['stops']) || $gradient['stops'] instanceof Countable) && count($gradient['stops']) > 1) {
$this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops']);
}
} elseif ($svgstyle['fill'] != 'none') {
$fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['fill'], $this->spot_colors);
if ($svgstyle['fill-opacity'] != 1) {
$this->setAlpha($this->alpha['CA'], 'Normal', $svgstyle['fill-opacity'], false);
} elseif (preg_match('/rgba\(\d+%?,\s*\d+%?,\s*\d+%?,\s*(\d+(?:\.\d+)?)\)/i', $svgstyle['fill'], $rgba_matches)) {
$this->setAlpha($this->alpha['CA'], 'Normal', $rgba_matches[1], false);
}
$this->setFillColorArray($fill_color);
if ($svgstyle['fill-rule'] == 'evenodd') {
@@ -23484,7 +23571,7 @@ class TCPDF {
if (preg_match('/font-family[\s]*:[\s]*([^\;\"]*)/si', $svgstyle['font'], $regs)) {
$font_family = $this->getFontFamilyName($regs[1]);
} else {
$font_family = $svgstyle['font-family'];
$font_family = $this->getFontFamilyName($svgstyle['font-family']);
}
if (preg_match('/font-size[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
$font_size = trim($regs[1]);
@@ -23639,7 +23726,8 @@ class TCPDF {
$params = array();
if (isset($val[2])) {
// get curve parameters
$rawparams = preg_split('/([\,\s]+)/si', trim($val[2]));
preg_match_all('/-?\d*\.?\d+/', trim($val[2]), $matches);
$rawparams = $matches[0];
$params = array();
foreach ($rawparams as $ck => $cp) {
$params[$ck] = $this->getHTMLUnitToUnits($cp, 0, $this->svgunit, false);
@@ -24464,6 +24552,9 @@ class TCPDF {
$img = '@'.base64_decode(substr($img, strlen($m[0])));
} else {
// fix image path
if ($this->isRelativePath($img) || $this->hasExtForbiddenProtocol($img)) {
break;
}
if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) {
// replace relative path with full server path
$img = $this->svgdir.'/'.$img;
@@ -24784,6 +24875,20 @@ class TCPDF {
return TCPDF_STATIC::file_exists($file);
}
/**
* Wrapper for unlink with disabled protocols.
* @param string $file
* @return bool
*/
protected function _unlink($file)
{
if ((strpos($file, '://') !== false) && ((substr($file, 0, 7) !== 'file://') || (!$this->allowLocalFiles))) {
// forbidden protocol
return false;
}
return @unlink($file);
}
} // END OF TCPDF CLASS
//============================================================+