update lock clucknut
All checks were successful
All checks were successful
This commit is contained in:
56
vendor/mpdf/mpdf/.github/workflows/snapshots.yml
vendored
Normal file
56
vendor/mpdf/mpdf/.github/workflows/snapshots.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
|
||||
|
||||
name: "Snapshot Tests"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "development"
|
||||
- "test"
|
||||
|
||||
jobs:
|
||||
|
||||
tests:
|
||||
|
||||
name: "Tests"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: Update sources and install ghostscript
|
||||
uses: awalsh128/cache-apt-pkgs-action@master
|
||||
with:
|
||||
packages: ghostscript
|
||||
version: 1.0
|
||||
refresh: true
|
||||
|
||||
- name: Change ImageMagick policy to allow pdf->png conversion.
|
||||
run: |
|
||||
sudo sed -i 's/none/read|write/' /etc/ImageMagick-6/policy.xml
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.5"
|
||||
extensions: "mbstring, gd, bcmath, bz2, imagick"
|
||||
tools: composer:v2
|
||||
ini-values: error_reporting=-1
|
||||
|
||||
- name: "Install dependencies"
|
||||
run: "composer install --no-interaction --no-progress"
|
||||
|
||||
- name: "Snapshot Tests"
|
||||
run: composer test -- --group=snapshot
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: "phpunit-artifact"
|
||||
path: tmp/artifacts/
|
||||
if-no-files-found: ignore
|
||||
3
vendor/mpdf/mpdf/CHANGELOG.md
vendored
3
vendor/mpdf/mpdf/CHANGELOG.md
vendored
@@ -7,6 +7,7 @@
|
||||
* Added support for `psr/http-message` v2 without dropping v1. (@markdorison, @apotek, @greg-1-anderson, @NigelCunningham #1907)
|
||||
* PHP 8.3 support in mPDF 8.2.1
|
||||
* Add support for `page-break-before: avoid;` and `page-break-after: avoid;` for tr elements inside tables
|
||||
* Add support for custom `AssetFetcher` via the service container (@splitbrain, #2165)
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
@@ -14,6 +15,8 @@
|
||||
* Replace character entities with characters when processing the `code` attribute in the `<barcode />` tag
|
||||
* Escape XML predefined entities in XMP metadata (Fix for #2090)
|
||||
* Enable Font Subsetting by Default (Fix for #1315)
|
||||
* Fix `TypeError` with non-numeric `rotate` values like `none` or `90deg` on tables (@derrabus, #2178)
|
||||
* Small change to better support list-style-type on list items within tables
|
||||
|
||||
mPDF 8.1.x
|
||||
===========================
|
||||
|
||||
12
vendor/mpdf/mpdf/composer.json
vendored
12
vendor/mpdf/mpdf/composer.json
vendored
@@ -38,12 +38,13 @@
|
||||
"squizlabs/php_codesniffer": "^3.5.0",
|
||||
"tracy/tracy": "~2.5",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Needed for generation of some types of barcodes",
|
||||
"ext-zlib": "Needed for compression of embedded resources, such as fonts",
|
||||
"ext-xml": "Needed mainly for SVG manipulation"
|
||||
},
|
||||
"ext-xml": "Needed mainly for SVG manipulation",
|
||||
"ext-imagick": "Needed if developing the Mpdf library"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mpdf\\": "src/"
|
||||
@@ -54,7 +55,9 @@
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Mpdf\\": "tests/Mpdf"
|
||||
"Mpdf\\": "tests/Mpdf",
|
||||
"Snapshots\\": "tests/Snapshots",
|
||||
"Issues\\": "tests/Issues"
|
||||
},
|
||||
"files": [
|
||||
"src/functions-dev.php"
|
||||
@@ -65,6 +68,7 @@
|
||||
"php -r \"chmod('./tmp', 0777);\""
|
||||
],
|
||||
"cs": "@php vendor/bin/phpcs --report-width=160 --standard=ruleset.xml --severity=1 --warning-severity=0 --extensions=php src utils tests",
|
||||
"cs:fix": "@php vendor/bin/phpcbf --standard=ruleset.xml --extensions=php src utils tests",
|
||||
"test": "@php vendor/bin/phpunit",
|
||||
"coverage": "@php vendor/bin/phpunit --coverage-text"
|
||||
},
|
||||
|
||||
16
vendor/mpdf/mpdf/phpstan-baseline.neon
vendored
16
vendor/mpdf/mpdf/phpstan-baseline.neon
vendored
@@ -36,18 +36,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Color/ColorSpaceRestrictor.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\+" between non\-empty\-string and 0 results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/CssManager.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$tag might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 1
|
||||
path: src/CssManager.php
|
||||
|
||||
-
|
||||
message: '#^Method Mpdf\\Mpdf\:\:GetJspacing\(\) invoked with 4 parameters, 5 required\.$#'
|
||||
identifier: arguments.count
|
||||
@@ -885,13 +873,13 @@ parameters:
|
||||
-
|
||||
message: '#^Offset int on array\{\} in isset\(\) does not exist\.$#'
|
||||
identifier: isset.offset
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/Otl.php
|
||||
|
||||
-
|
||||
message: '#^Offset int\<0, max\> on array\{\} in isset\(\) does not exist\.$#'
|
||||
identifier: isset.offset
|
||||
count: 4
|
||||
count: 1
|
||||
path: src/Otl.php
|
||||
|
||||
-
|
||||
|
||||
7
vendor/mpdf/mpdf/phpunit.xml
vendored
7
vendor/mpdf/mpdf/phpunit.xml
vendored
@@ -1,5 +1,6 @@
|
||||
<phpunit
|
||||
bootstrap="tests/bootstrap.php"
|
||||
cacheResultFile="tmp/.phpunit.result.cache"
|
||||
colors="true"
|
||||
backupGlobals="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="false">
|
||||
@@ -10,6 +11,12 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>snapshot</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
|
||||
2
vendor/mpdf/mpdf/src/AssetFetcher.php
vendored
2
vendor/mpdf/mpdf/src/AssetFetcher.php
vendored
@@ -10,7 +10,7 @@
|
||||
use Mpdf\PsrLogAwareTrait\PsrLogAwareTrait;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class AssetFetcher implements \Psr\Log\LoggerAwareInterface
|
||||
class AssetFetcher implements \Psr\Log\LoggerAwareInterface, \Mpdf\AssetFetcherInterface
|
||||
{
|
||||
|
||||
use PsrLogAwareTrait;
|
||||
|
||||
16
vendor/mpdf/mpdf/src/AssetFetcherInterface.php
vendored
Normal file
16
vendor/mpdf/mpdf/src/AssetFetcherInterface.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
interface AssetFetcherInterface
|
||||
{
|
||||
/**
|
||||
* Fetch data from a given path, either local or remote.
|
||||
*
|
||||
* @param string $path The path to fetch data from.
|
||||
* @param string|null $originalSrc The original source path, if applicable.
|
||||
* @return string The fetched data.
|
||||
* @throws \Mpdf\Exception\AssetFetchingException If fetching fails.
|
||||
*/
|
||||
public function fetchDataFromPath($path, $originalSrc = null);
|
||||
}
|
||||
76
vendor/mpdf/mpdf/src/Buffer.php
vendored
Normal file
76
vendor/mpdf/mpdf/src/Buffer.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class Buffer
|
||||
{
|
||||
|
||||
/** @var array<int, string> */
|
||||
private $contents = [];
|
||||
|
||||
/** @var int */
|
||||
private $length = 0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function append($content, $newLine = false)
|
||||
{
|
||||
if ($content === null || $content === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = (string) $content;
|
||||
$contentLength = strlen($content);
|
||||
|
||||
// Do not create an additional buffer entry if the content is relatively small.
|
||||
if ($newLine && $contentLength < 1000000) {
|
||||
$content .= "\n";
|
||||
++$contentLength;
|
||||
}
|
||||
|
||||
$this->contents[] = $content;
|
||||
$this->length += $contentLength;
|
||||
|
||||
if ($newLine && $contentLength >= 1000000) {
|
||||
$this->contents[] = "\n";
|
||||
++$this->length;
|
||||
}
|
||||
}
|
||||
|
||||
public function getLength()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
public function writeToFile($handle)
|
||||
{
|
||||
foreach ($this->contents as $content) {
|
||||
fwrite($handle, $content);
|
||||
}
|
||||
}
|
||||
|
||||
public function writeToOutput()
|
||||
{
|
||||
foreach ($this->contents as $content) {
|
||||
echo $content;
|
||||
}
|
||||
}
|
||||
|
||||
public function writeToString()
|
||||
{
|
||||
return implode('', $this->contents);
|
||||
}
|
||||
|
||||
public function getHash()
|
||||
{
|
||||
$hash = '';
|
||||
foreach ($this->contents as $content) {
|
||||
$hash = md5($hash.$content);
|
||||
}
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
}
|
||||
18
vendor/mpdf/mpdf/src/Cache.php
vendored
18
vendor/mpdf/mpdf/src/Cache.php
vendored
@@ -42,11 +42,25 @@ protected function createBasePath($basePath)
|
||||
|
||||
protected function createDirectory($basePath)
|
||||
{
|
||||
$permissions = $this->getPermission($this->getExistingParentDirectory($basePath));
|
||||
if (! mkdir($basePath, $permissions, true)) {
|
||||
$parentPath = $this->getExistingParentDirectory($basePath);
|
||||
$permissions = $this->getPermission($parentPath);
|
||||
if (!mkdir($basePath, $permissions, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Check if umask modified the permissions and reset any created directories */
|
||||
if (($permissions & ~umask()) !== $permissions) {
|
||||
$basePath = realpath($basePath);
|
||||
$folders = explode('/', substr($basePath, strlen($parentPath) + 1));
|
||||
for ($i = 1, $total = count($folders); $i <= $total; $i++) {
|
||||
$path = $parentPath . '/';
|
||||
$path .= implode('/', array_slice($folders, 0, $i));
|
||||
|
||||
chmod($path, $permissions);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
142
vendor/mpdf/mpdf/src/Css/BorderMerger.php
vendored
Normal file
142
vendor/mpdf/mpdf/src/Css/BorderMerger.php
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Exception\InvalidArgumentException;
|
||||
|
||||
class BorderMerger
|
||||
{
|
||||
/**
|
||||
* @var array<int> Border dominance levels for cell borders (top/right/bottom/left)
|
||||
*/
|
||||
private $borderDominance = [
|
||||
'T' => 0,
|
||||
'R' => 0,
|
||||
'B' => 0,
|
||||
'L' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* Merge borders into CSS properties.
|
||||
*
|
||||
* @param array $newProperties properties to merge from
|
||||
* @param array $cssProperties current CSS properties (passed by reference)
|
||||
* @return void
|
||||
*/
|
||||
public function mergeBorderProperties($newProperties, &$cssProperties)
|
||||
{
|
||||
foreach (['TOP', 'RIGHT', 'BOTTOM', 'LEFT'] as $side) {
|
||||
$this->mergeSideBorder($side, $newProperties, $cssProperties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge border properties for a specific side.
|
||||
*
|
||||
* Helper method for mergeBorderProperties to handle merging of individual side properties
|
||||
* (style, width, color) into the shorthand border property.
|
||||
*
|
||||
* @param string $side Side to merge (TOP, RIGHT, BOTTOM, LEFT)
|
||||
* @param array $properties Source border properties
|
||||
* @param array $cssProperties Target CSS properties (passed by reference)
|
||||
* @return void
|
||||
*/
|
||||
protected function mergeSideBorder($side, $properties, &$cssProperties)
|
||||
{
|
||||
// Merges $a['BORDER-TOP-STYLE'] to $cssProperties['BORDER-TOP'] etc.
|
||||
$defaults = [
|
||||
'WIDTH' => '0px',
|
||||
'STYLE' => 'none',
|
||||
'COLOR' => '#000000'
|
||||
];
|
||||
|
||||
$borderKey = 'BORDER-' . $side;
|
||||
$currentBorder = isset($cssProperties[$borderKey]) ? trim($cssProperties[$borderKey]) : '';
|
||||
|
||||
foreach (['STYLE', 'WIDTH', 'COLOR'] as $el) {
|
||||
$propertyKey = $borderKey . '-' . $el;
|
||||
if (!isset($properties[$propertyKey])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = trim($properties[$propertyKey]);
|
||||
if ($currentBorder) {
|
||||
// Update existing border value
|
||||
if ($el === 'STYLE') {
|
||||
$cssProperties[$borderKey] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 ' . $value . ' \\3', $currentBorder);
|
||||
} elseif ($el === 'WIDTH') {
|
||||
$cssProperties[$borderKey] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', $value . ' \\2 \\3', $currentBorder);
|
||||
} else { // COLOR
|
||||
$cssProperties[$borderKey] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 \\2 ' . $value, $currentBorder);
|
||||
}
|
||||
|
||||
$currentBorder = $cssProperties[$borderKey]; // Update current border for next iteration
|
||||
} else {
|
||||
// Build new border from scratch with defaults
|
||||
if (!isset($borderParts)) {
|
||||
$borderParts = $defaults;
|
||||
}
|
||||
|
||||
$borderParts[$el] = $value;
|
||||
$cssProperties[$borderKey] = $borderParts['WIDTH'] . ' ' . $borderParts['STYLE'] . ' ' . $borderParts['COLOR'];
|
||||
$currentBorder = $cssProperties[$borderKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set border dominance level for table cells.
|
||||
*
|
||||
* Used in table rendering to determine which cell borders take
|
||||
* precedence when cells share borders.
|
||||
*
|
||||
* @param array $prop CSS properties containing border definitions
|
||||
* @param int $val Dominance level value
|
||||
* @return void
|
||||
*/
|
||||
public function setDominanceFromProperties($prop, $val)
|
||||
{
|
||||
if (!empty($prop['BORDER-TOP'])) {
|
||||
$this->setBorderDominance('T', $val);
|
||||
}
|
||||
|
||||
if (!empty($prop['BORDER-RIGHT'])) {
|
||||
$this->setBorderDominance('R', $val);
|
||||
}
|
||||
|
||||
if (!empty($prop['BORDER-BOTTOM'])) {
|
||||
$this->setBorderDominance('B', $val);
|
||||
}
|
||||
|
||||
if (!empty($prop['BORDER-LEFT'])) {
|
||||
$this->setBorderDominance('L', $val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set border dominance level for a specific side.
|
||||
*
|
||||
* @param string $side T|R|B|L
|
||||
* @param int $val Dominance value
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setBorderDominance($side, $val)
|
||||
{
|
||||
if (!isset($this->borderDominance[$side])) {
|
||||
throw new InvalidArgumentException('Invalid border dominance value:' . $side);
|
||||
}
|
||||
|
||||
$this->borderDominance[$side] = (int) $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get border dominance level for a specific side.
|
||||
*
|
||||
* @param string $side T|R|B|L
|
||||
* @return int Dominance value
|
||||
*/
|
||||
public function getBorderDominance($side)
|
||||
{
|
||||
return isset($this->borderDominance[$side]) ? $this->borderDominance[$side] : 0;
|
||||
}
|
||||
}
|
||||
47
vendor/mpdf/mpdf/src/Css/CommentParser.php
vendored
Normal file
47
vendor/mpdf/mpdf/src/Css/CommentParser.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
class CommentParser
|
||||
{
|
||||
/**
|
||||
* Remove mPDF-specific and general HTML comments from content.
|
||||
*
|
||||
* Removes <!--mpdf and mpdf--> markers and all HTML comments.
|
||||
*
|
||||
* @param string $html HTML content to clean
|
||||
* @return string HTML with comments removed
|
||||
*/
|
||||
public function removeHtmlComments($html)
|
||||
{
|
||||
$html = preg_replace('/<!--mpdf/i', '', $html);
|
||||
$html = preg_replace('/mpdf-->/i', '', $html);
|
||||
$html = preg_replace('/<!--.*?-->/s', ' ', $html);
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove HTML and CSS comments from style blocks.
|
||||
*
|
||||
* Removes both HTML comments (<!-- -->) and CSS comments from
|
||||
* <style> tag contents while preserving the structure.
|
||||
*
|
||||
* @param string $html HTML content with style tags
|
||||
* @return string HTML with cleaned style blocks
|
||||
*/
|
||||
public function removeCommentsFromStyleBlocks($html)
|
||||
{
|
||||
preg_match_all('/<style.*?>(.*?)<\/style>/si', $html, $m);
|
||||
if (count($m[1]) === 0) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
foreach ($m[1] as $style) {
|
||||
$sub = str_replace(['<!--', '-->'], ' ', $style);
|
||||
$sub = '>' . preg_replace('|/\*.*?\*/|s', ' ', $sub) . '</style>';
|
||||
$html = str_replace('>' . $style . '</style>', $sub, $html);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
184
vendor/mpdf/mpdf/src/Css/CssLoader.php
vendored
Normal file
184
vendor/mpdf/mpdf/src/Css/CssLoader.php
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\AssetFetcher;
|
||||
use Mpdf\Cache;
|
||||
use Mpdf\Exception\AssetFetchingException;
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\MpdfException;
|
||||
use Mpdf\Utils\Path;
|
||||
|
||||
class CssLoader
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var AssetFetcher
|
||||
*/
|
||||
private $assetFetcher;
|
||||
|
||||
/**
|
||||
* @var Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
public function __construct(Mpdf $mpdf, AssetFetcher $assetFetcher, Cache $cache)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->assetFetcher = $assetFetcher;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and return the CSS from $path
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
* @throws MpdfException If asset fetching issue, is through when $mpdf->debug = true
|
||||
*/
|
||||
public function loadStylesheet($path)
|
||||
{
|
||||
$path = preg_replace('/\.css\?.*$/', '.css', $path);
|
||||
|
||||
try {
|
||||
$data = $this->assetFetcher->fetchDataFromPath($path);
|
||||
if (!$data) {
|
||||
$path = !$this->mpdf->basepathIsLocal ? Path::normalizeLocalFilePath($path) : $path;
|
||||
$data = $this->assetFetcher->fetchDataFromPath($path);
|
||||
}
|
||||
} catch (AssetFetchingException $e) {
|
||||
$data = ''; // do nothing
|
||||
if ($this->mpdf->debug) {
|
||||
throw new MpdfException($e->getMessage(), 0, E_ERROR, null, null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract external stylesheet URLs from HTML.
|
||||
*
|
||||
* Finds all external CSS file references including:
|
||||
* - <link rel="stylesheet" href="...">
|
||||
* - <link href="..." rel="stylesheet">
|
||||
* - @import url(...)
|
||||
* - @import "..."
|
||||
*
|
||||
* @param string $html HTML content to scan
|
||||
* @return array Array of CSS file URLs
|
||||
*/
|
||||
public function extractExternalStylesheetUrls($html)
|
||||
{
|
||||
$cssUrls = [];
|
||||
|
||||
// <link rel="stylesheet" href="...">
|
||||
if (preg_match_all('/<link[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^>"\']*)["\'].*?>/si', $html, $cxt)) {
|
||||
$cssUrls = $cxt[1];
|
||||
}
|
||||
|
||||
// <link href="..." rel="stylesheet">
|
||||
if (preg_match_all('/<link[^>]*href=["\']([^>"\']*)["\'][^>]*?rel=["\']stylesheet["\'].*?>/si', $html, $cxt)) {
|
||||
$cssUrls = array_merge($cssUrls, $cxt[1]);
|
||||
}
|
||||
|
||||
// @import url(...)
|
||||
if (preg_match_all('/@import url\([\'\"]{0,1}(\S*?\.css(\?[^\s\'\"]+)?)[\'\"]{0,1}\)\;?/si', $html, $cxt)) {
|
||||
$cssUrls = array_merge($cssUrls, $cxt[1]);
|
||||
}
|
||||
|
||||
// @import "..."
|
||||
if (preg_match_all('/@import (?!url)[\'\"]{0,1}(\S*?\.css(\?[^\s\'\"]+)?)[\'\"]{0,1}\;?/si', $html, $cxt)) {
|
||||
$cssUrls = array_merge($cssUrls, $cxt[1]);
|
||||
}
|
||||
|
||||
return $cssUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate embedded @import stylesheets in other stylesheets and fix url paths
|
||||
* (including background-images) relative to stylesheet
|
||||
*
|
||||
* @param string $stylesheetCss
|
||||
* @param string $path
|
||||
* @param array $externalCss
|
||||
* @param int $externalCssCount
|
||||
* @return string
|
||||
*/
|
||||
public function processExternalCssImports($stylesheetCss, $path, &$externalCss, &$externalCssCount)
|
||||
{
|
||||
$css = '';
|
||||
|
||||
$cssBasePath = preg_replace('/\/[^\/]*$/', '', $path) . '/';
|
||||
if (preg_match_all('/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si', $stylesheetCss, $cxtem)) {
|
||||
foreach ($cxtem[1] as $cxtembedded) {
|
||||
// path is relative to original stylesheet!!
|
||||
$externalCss[] = Path::relativeToAbsolutePath($cxtembedded, $cssBasePath);
|
||||
$externalCssCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$css .= ' ' . $this->resolveBackgroundUrls($stylesheetCss, $cssBasePath);
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve background image URLs in CSS.
|
||||
*
|
||||
* Converts relative URLs to absolute paths using Path::relativeToAbsolute.
|
||||
* Skips data URIs which are already absolute.
|
||||
*
|
||||
* @param string $cssStr CSS string potentially containing background URLs
|
||||
* @param string|null $basePath Optional base path for resolving relative URLs
|
||||
* @return string CSS string with resolved URLs
|
||||
*/
|
||||
public function resolveBackgroundUrls($cssStr, $basePath = null)
|
||||
{
|
||||
if (!preg_match_all('/(background[^;]*url\s*\(\s*[\'"]{0,1})([^)\'"]*)([\'"]{0,1}\s*\))/si', $cssStr, $cxtem)) {
|
||||
return $cssStr;
|
||||
}
|
||||
|
||||
$basePath = $basePath ?: $this->mpdf->basepath;
|
||||
|
||||
foreach ($cxtem[0] as $i => $value) {
|
||||
$embedded = $cxtem[2][$i];
|
||||
if (!preg_match('/^data:image/i', $embedded)) {
|
||||
$newPath = Path::relativeToAbsolutePath($embedded, $basePath);
|
||||
$cssStr = str_replace($cxtem[0][$i], ($cxtem[1][$i] . $newPath . $cxtem[3][$i]), $cssStr);
|
||||
}
|
||||
}
|
||||
|
||||
return $cssStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process data URI images in CSS.
|
||||
*
|
||||
* Converts data URI images to temporary files for processing.
|
||||
* Example: url(data:image/png;base64,...) becomes url("tempfile.png")
|
||||
*
|
||||
* @param string $cssStr CSS string potentially containing data URIs
|
||||
* @return string CSS string with data URIs replaced by temp file references
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function processDataUriImages($cssStr)
|
||||
{
|
||||
preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*?)\))/si", $cssStr, $idata);
|
||||
if (count($idata[0]) === 0) {
|
||||
return $cssStr;
|
||||
}
|
||||
|
||||
foreach ($idata[0] as $i => $value) {
|
||||
$file = $this->cache->write('_tempCSSidata' . random_int(1, 10000) . '_' . $i . '.' . $idata[2][$i], base64_decode($idata[3][$i]));
|
||||
$cssStr = str_replace($idata[0][$i], 'url("' . $file . '")', $cssStr);
|
||||
}
|
||||
|
||||
return $cssStr;
|
||||
}
|
||||
}
|
||||
1060
vendor/mpdf/mpdf/src/Css/CssMerger.php
vendored
Normal file
1060
vendor/mpdf/mpdf/src/Css/CssMerger.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
374
vendor/mpdf/mpdf/src/Css/CssParser.php
vendored
Normal file
374
vendor/mpdf/mpdf/src/Css/CssParser.php
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Utils\Arrays;
|
||||
use Mpdf\Utils\Path;
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\Cache;
|
||||
use Mpdf\SizeConverter;
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\AssetFetcher;
|
||||
|
||||
class CssParser
|
||||
{
|
||||
/**
|
||||
* @var Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var CssLoader
|
||||
*/
|
||||
private $cssLoader;
|
||||
|
||||
/**
|
||||
* @var MediaQueryProcessor
|
||||
*/
|
||||
private $mediaQueryProcessor;
|
||||
|
||||
/**
|
||||
* @var CommentParser
|
||||
*/
|
||||
private $commentParser;
|
||||
|
||||
/**
|
||||
* @var InlineStyleParser
|
||||
*/
|
||||
private $inlineStyleParser;
|
||||
|
||||
/**
|
||||
* @var SelectorParser
|
||||
*/
|
||||
private $selectorParser;
|
||||
|
||||
/**
|
||||
* @var NormalizeProperties
|
||||
*/
|
||||
private $normalizeProperties;
|
||||
|
||||
/**
|
||||
* @var ShadowParser
|
||||
*/
|
||||
private $shadowParser;
|
||||
|
||||
/**
|
||||
* CSS for simple selectors.
|
||||
*
|
||||
* Stores CSS properties for simple selectors (depth 1).
|
||||
* Format:
|
||||
* [
|
||||
* 'P' => [
|
||||
* 'COLOR' => '#FF0000',
|
||||
* 'FONT-SIZE' => '12pt',
|
||||
* ],
|
||||
* 'CLASS>>MYCLASS' => [
|
||||
* 'BORDER' => '1px solid black',
|
||||
* ],
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $css = [];
|
||||
|
||||
/**
|
||||
* CSS for cascaded selectors.
|
||||
*
|
||||
* Stores CSS properties for nested/cascaded selectors (depth > 1).
|
||||
* Format is a nested array mirroring the selector hierarchy.
|
||||
* Example for "DIV.myclass P":
|
||||
* [
|
||||
* 'DIV' => [
|
||||
* 'CLASS>>MYCLASS' => [
|
||||
* 'P' => [
|
||||
* 'COLOR' => '#0000FF',
|
||||
* 'depth' => 3
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cascadeCSS = [];
|
||||
|
||||
/**
|
||||
* @var array An index used to filter redundant class names before passing to Arrays::allUniqueSortedCombinations
|
||||
*/
|
||||
private $usedClassNames = [];
|
||||
|
||||
/**
|
||||
* @var int Maximum number of classes found in a single selector
|
||||
*/
|
||||
private $maxClassDepth = 1;
|
||||
|
||||
public function __construct(
|
||||
Mpdf $mpdf,
|
||||
Cache $cache,
|
||||
SizeConverter $sizeConverter,
|
||||
ColorConverter $colorConverter,
|
||||
AssetFetcher $assetFetcher
|
||||
) {
|
||||
$this->mpdf = $mpdf;
|
||||
$this->normalizeProperties = new NormalizeProperties($mpdf, $sizeConverter, $colorConverter);
|
||||
$this->cssLoader = new CssLoader($mpdf, $assetFetcher, $cache);
|
||||
$this->mediaQueryProcessor = new MediaQueryProcessor($mpdf);
|
||||
$this->commentParser = new CommentParser();
|
||||
$this->inlineStyleParser = new InlineStyleParser($this->normalizeProperties);
|
||||
$this->selectorParser = new SelectorParser($mpdf);
|
||||
$this->shadowParser = new ShadowParser($mpdf, $sizeConverter, $colorConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse CSS from HTML content.
|
||||
*
|
||||
* @param string $html HTML content containing CSS
|
||||
* @return string
|
||||
*/
|
||||
public function parse($html)
|
||||
{
|
||||
$this->css = [];
|
||||
$this->cascadeCSS = [];
|
||||
|
||||
$ind = 0;
|
||||
$css = '';
|
||||
|
||||
$html = $this->mediaQueryProcessor->filterByMediaQuery($html, '/<style[^>]*media=["\']([^"\'>]*)["\'].*?<\/style>/is');
|
||||
$html = $this->mediaQueryProcessor->filterByMediaQuery($html, '/<link[^>]*media=["\']([^"\'>]*)["\'].*?>/is');
|
||||
$html = $this->commentParser->removeCommentsFromStyleBlocks($html);
|
||||
$html = $this->commentParser->removeHtmlComments($html);
|
||||
|
||||
$externalCss = $this->cssLoader->extractExternalStylesheetUrls($html);
|
||||
$externalCssCount = count($externalCss);
|
||||
while ($externalCssCount) {
|
||||
$path = htmlspecialchars_decode($externalCss[$ind]);
|
||||
$path = Path::relativeToAbsolutePath($path, $this->mpdf->basepath);
|
||||
if (strpos($path, '//') === false) { // mPDF 5.7.3
|
||||
$path = preg_replace('/\.css\?.*$/', '.css', $path);
|
||||
}
|
||||
|
||||
$stylesheetCss = $this->cssLoader->loadStylesheet($path);
|
||||
if ($stylesheetCss) {
|
||||
$css .= $this->cssLoader->processExternalCssImports($stylesheetCss, $path, $externalCss, $externalCssCount);
|
||||
}
|
||||
|
||||
$externalCssCount--;
|
||||
$ind++;
|
||||
}
|
||||
|
||||
// CSS as <style> in HTML document
|
||||
$regexp = '/<style.*?>(.*?)<\/style>/si';
|
||||
if (preg_match_all($regexp, $html, $cssBlock)) {
|
||||
$css .= ' ' . $this->cssLoader->resolveBackgroundUrls(implode(' ', $cssBlock[1]));
|
||||
}
|
||||
|
||||
$css = preg_replace('|/\*.*?\*/|s', ' ', $css);
|
||||
$css = preg_replace('/[\s\n\r\t\f]/s', ' ', $css);
|
||||
$css = $this->mediaQueryProcessor->processMediaQueries($css);
|
||||
$css = $this->cssLoader->processDataUriImages($css);
|
||||
$css = preg_replace('/(<\!\-\-|\-\->)/s', ' ', $css);
|
||||
$css = $this->inlineStyleParser->processUrlsInCss($css);
|
||||
|
||||
$this->processCssString($css);
|
||||
|
||||
// Remove CSS (tags and content), if any (it can be <style> or <style type="txt/css">)
|
||||
$html = preg_replace('/<style.*?>(.*?)<\/style>/si', '', $html);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCss()
|
||||
{
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCascadeCss()
|
||||
{
|
||||
return $this->cascadeCSS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getUsedClassNames()
|
||||
{
|
||||
return array_keys($this->usedClassNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxClassDepth()
|
||||
{
|
||||
return $this->maxClassDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $css
|
||||
* @return void
|
||||
*/
|
||||
private function processCssString($css)
|
||||
{
|
||||
preg_match_all('/(.*?)\{(.*?)\}/', $css, $styles);
|
||||
$count = count($styles[1]);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$classProperties = $this->parseCssProperties($styles[2][$i]);
|
||||
$tagName = strtoupper(trim($styles[1][$i]));
|
||||
|
||||
$tags = explode(',', $tagName);
|
||||
foreach ($tags as $tag) {
|
||||
$this->processCssSelector($tag, $classProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a CSS selector.
|
||||
*
|
||||
* @param string $selector Selector string
|
||||
* @param array $classProperties CSS properties
|
||||
* @return void
|
||||
*/
|
||||
private function processCssSelector($selector, $classProperties)
|
||||
{
|
||||
// store classes in an index for faster lookups
|
||||
if (strpos($selector, '.') !== false && preg_match_all('/\.([a-zA-Z0-9_\-]+)/', $selector, $matches)) {
|
||||
foreach ($matches[1] as $className) {
|
||||
$this->usedClassNames[$className] = true;
|
||||
}
|
||||
|
||||
$classCount = count($matches[1]);
|
||||
if ($classCount > $this->maxClassDepth) {
|
||||
$this->maxClassDepth = $classCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/NTH-CHILD\((\s*(([\-+]?\d*)N(\s*[\-+]\s*\d+)?|[\-+]?\d+|ODD|EVEN)\s*)\)/', $selector, $m)) {
|
||||
$selector = preg_replace('/NTH-CHILD\(.*\)/', 'NTH-CHILD(' . str_replace(' ', '', $m[1]) . ')', $selector);
|
||||
}
|
||||
|
||||
$tags = preg_split('/\s+/', trim($selector));
|
||||
$level = count($tags);
|
||||
if (trim($tags[0]) === '@PAGE') {
|
||||
$tag = $this->selectorParser->parsePageSelector($tags);
|
||||
if ($tag && isset($this->css[$tag])) {
|
||||
$this->css[$tag] = Arrays::uniqueRecursiveMerge($this->css[$tag], $classProperties);
|
||||
} elseif ($tag) {
|
||||
$this->css[$tag] = $classProperties;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($level === 1) {
|
||||
$tag = $this->selectorParser->parseSimpleSelector($tags);
|
||||
if ($tag && isset($this->css[$tag])) {
|
||||
$this->css[$tag] = Arrays::uniqueRecursiveMerge($this->css[$tag], $classProperties);
|
||||
} elseif ($tag) {
|
||||
$this->css[$tag] = $classProperties;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$cascade = $this->selectorParser->parseCascadedSelector($tags);
|
||||
if (empty($cascade)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cascadeCSS = &$this->cascadeCSS;
|
||||
foreach ($cascade as $tag) {
|
||||
$cascadeCSS = &$cascadeCSS[$tag];
|
||||
}
|
||||
|
||||
$cascadeCSS = Arrays::uniqueRecursiveMerge($cascadeCSS, $classProperties);
|
||||
$cascadeCSS['depth'] = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CSS property string into an array.
|
||||
*
|
||||
* @param string $rawStyles CSS style string (e.g. "color: red; font-size: 12px")
|
||||
* @return array Associative array of CSS properties
|
||||
*/
|
||||
public function parseCssProperties($rawStyles)
|
||||
{
|
||||
$classProperties = [];
|
||||
$styles = explode(';', trim($rawStyles));
|
||||
|
||||
foreach ($styles as $style) {
|
||||
if (empty(trim($style))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')"
|
||||
$tmp = explode(':', $style, 2);
|
||||
$property = strtoupper(trim($tmp[0]));
|
||||
$value = isset($tmp[1]) ? $tmp[1] : '';
|
||||
|
||||
$value = str_replace('%ZZ', ';', $value); // restore URL placeholder
|
||||
$value = preg_replace('/\s*!important/i', '', $value);
|
||||
$value = trim($value);
|
||||
|
||||
if (empty($property) || strlen($value) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignores -webkit-gradient so doesn't override -moz-
|
||||
if (($property === 'BACKGROUND-IMAGE' || $property === 'BACKGROUND') &&
|
||||
stripos($value, '-webkit-gradient') !== false
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classProperties[$property] = $value;
|
||||
}
|
||||
|
||||
return $this->normalizeProperties->normalize($classProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse inline CSS style attribute.
|
||||
*
|
||||
* @param string $html CSS string from style attribute
|
||||
* @return array Parsed CSS properties
|
||||
*/
|
||||
public function parseInlineCss($html)
|
||||
{
|
||||
return $this->inlineStyleParser->parse($html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse box-shadow CSS property.
|
||||
*
|
||||
* Converts box-shadow CSS property string into array format used internally.
|
||||
* Handles multiple shadows, inset shadows, blur, spread, and colors.
|
||||
*
|
||||
* @param string $value Box-shadow property value
|
||||
* @return array Array of shadow definitions
|
||||
*/
|
||||
public function parseBoxShadow($value)
|
||||
{
|
||||
return $this->shadowParser->parseBoxShadow($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse text-shadow CSS property.
|
||||
*
|
||||
* Converts text-shadow CSS property string into array format used internally.
|
||||
* Handles multiple shadows, blur, and colors.
|
||||
*
|
||||
* @param string $value Text-shadow property value
|
||||
* @return array Array of text shadow definitions
|
||||
*/
|
||||
public function parseTextShadow($value)
|
||||
{
|
||||
return $this->shadowParser->parseTextShadow($value);
|
||||
}
|
||||
}
|
||||
189
vendor/mpdf/mpdf/src/Css/InlinePropertyConverter.php
vendored
Normal file
189
vendor/mpdf/mpdf/src/Css/InlinePropertyConverter.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Color\ColorConverter;
|
||||
|
||||
class InlinePropertyConverter
|
||||
{
|
||||
/**
|
||||
* @var ColorConverter
|
||||
*/
|
||||
private $colorConverter;
|
||||
|
||||
public function __construct(ColorConverter $colorConverter)
|
||||
{
|
||||
$this->colorConverter = $colorConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert inline properties back to CSS.
|
||||
*
|
||||
* Transforms internal inline property format (used in TextVars) back into
|
||||
* CSS property array. Used for property inheritance and cascading.
|
||||
*
|
||||
* @param array $properties Inline properties array
|
||||
* @return array Converted CSS properties
|
||||
*/
|
||||
public function convert($properties)
|
||||
{
|
||||
$css = [];
|
||||
|
||||
if (!empty($properties['family'])) {
|
||||
$css['FONT-FAMILY'] = $properties['family'];
|
||||
}
|
||||
|
||||
if (!empty($properties['I'])) {
|
||||
$css['FONT-STYLE'] = 'italic';
|
||||
}
|
||||
|
||||
if (!empty($properties['sizePt'])) {
|
||||
$css['FONT-SIZE'] = $properties['sizePt'] . 'pt';
|
||||
}
|
||||
|
||||
if (!empty($properties['B'])) {
|
||||
$css['FONT-WEIGHT'] = 'bold';
|
||||
}
|
||||
|
||||
if (!empty($properties['colorarray'])) {
|
||||
$css['COLOR'] = $this->colorConverter->colAtoString($properties['colorarray']);
|
||||
}
|
||||
|
||||
if (!empty($properties['lSpacingCSS'])) {
|
||||
$css['LETTER-SPACING'] = $properties['lSpacingCSS'];
|
||||
}
|
||||
|
||||
if (!empty($properties['wSpacingCSS'])) {
|
||||
$css['WORD-SPACING'] = $properties['wSpacingCSS'];
|
||||
}
|
||||
|
||||
if (!empty($properties['textparam'])) {
|
||||
if (isset($properties['textparam']['hyphens'])) {
|
||||
$hyphens = (int) $properties['textparam']['hyphens'];
|
||||
switch ($hyphens) {
|
||||
case 1:
|
||||
$css['HYPHENS'] = 'auto';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$css['HYPHENS'] = 'none';
|
||||
break;
|
||||
|
||||
default:
|
||||
$css['HYPHENS'] = 'manual';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($properties['textparam']['outline-s']) && !$properties['textparam']['outline-s']) {
|
||||
$css['TEXT-OUTLINE'] = 'none';
|
||||
}
|
||||
|
||||
if (!empty($properties['textparam']['outline-COLOR'])) {
|
||||
$css['TEXT-OUTLINE-COLOR'] = $this->colorConverter->colAtoString($properties['textparam']['outline-COLOR']);
|
||||
}
|
||||
|
||||
if (!empty($properties['textparam']['outline-WIDTH'])) {
|
||||
$css['TEXT-OUTLINE-WIDTH'] = $properties['textparam']['outline-WIDTH'] . 'mm';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($properties['textvar'])) {
|
||||
// CSS says text-decoration is not inherited, but IE7 does??
|
||||
if ($properties['textvar'] & TextVars::FD_LINETHROUGH) {
|
||||
if ($properties['textvar'] & TextVars::FD_UNDERLINE) {
|
||||
$css['TEXT-DECORATION'] = 'underline line-through';
|
||||
} else {
|
||||
$css['TEXT-DECORATION'] = 'line-through';
|
||||
}
|
||||
} elseif ($properties['textvar'] & TextVars::FD_UNDERLINE) {
|
||||
$css['TEXT-DECORATION'] = 'underline';
|
||||
} else {
|
||||
$css['TEXT-DECORATION'] = 'none';
|
||||
}
|
||||
|
||||
if ($properties['textvar'] & TextVars::FA_SUPERSCRIPT) {
|
||||
$css['VERTICAL-ALIGN'] = 'super';
|
||||
} elseif ($properties['textvar'] & TextVars::FA_SUBSCRIPT) {
|
||||
$css['VERTICAL-ALIGN'] = 'sub';
|
||||
} else {
|
||||
$css['VERTICAL-ALIGN'] = 'baseline';
|
||||
}
|
||||
|
||||
if ($properties['textvar'] & TextVars::FT_CAPITALIZE) {
|
||||
$css['TEXT-TRANSFORM'] = 'capitalize';
|
||||
} elseif ($properties['textvar'] & TextVars::FT_UPPERCASE) {
|
||||
$css['TEXT-TRANSFORM'] = 'uppercase';
|
||||
} elseif ($properties['textvar'] & TextVars::FT_LOWERCASE) {
|
||||
$css['TEXT-TRANSFORM'] = 'lowercase';
|
||||
} else {
|
||||
$css['TEXT-TRANSFORM'] = 'none';
|
||||
}
|
||||
|
||||
if ($properties['textvar'] & TextVars::FC_KERNING) {
|
||||
$css['FONT-KERNING'] = 'normal';
|
||||
} else {
|
||||
$css['FONT-KERNING'] = 'none';
|
||||
} // ignore 'auto' as default already applied
|
||||
|
||||
if ($properties['textvar'] & TextVars::FA_SUPERSCRIPT) {
|
||||
$css['FONT-VARIANT-POSITION'] = 'super';
|
||||
} elseif ($properties['textvar'] & TextVars::FA_SUBSCRIPT) {
|
||||
$css['FONT-VARIANT-POSITION'] = 'sub';
|
||||
} else {
|
||||
$css['FONT-VARIANT-POSITION'] = 'normal';
|
||||
}
|
||||
|
||||
if ($properties['textvar'] & TextVars::FC_SMALLCAPS) {
|
||||
$css['FONT-VARIANT-CAPS'] = 'small-caps';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($properties['fontLanguageOverride'])) {
|
||||
if ($properties['fontLanguageOverride']) {
|
||||
$css['FONT-LANGUAGE-OVERRIDE'] = $properties['fontLanguageOverride'];
|
||||
} else {
|
||||
$css['FONT-LANGUAGE-OVERRIDE'] = 'normal';
|
||||
}
|
||||
}
|
||||
|
||||
// All the variations of font-variant-* we are going to set as font-feature-settings...
|
||||
if (!empty($properties['OTLtags'])) {
|
||||
$fontFeature = [];
|
||||
if (!empty($properties['OTLtags']['Minus'])) {
|
||||
$f = preg_split('/\s+/', trim($properties['OTLtags']['Minus']));
|
||||
foreach ($f as $ff) {
|
||||
$fontFeature[] = "'" . $ff . "' 0";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($properties['OTLtags']['FFMinus'])) {
|
||||
$f = preg_split('/\s+/', trim($properties['OTLtags']['FFMinus']));
|
||||
foreach ($f as $ff) {
|
||||
$fontFeature[] = "'" . $ff . "' 0";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($properties['OTLtags']['Plus'])) {
|
||||
$f = preg_split('/\s+/', trim($properties['OTLtags']['Plus']));
|
||||
foreach ($f as $ff) {
|
||||
$fontFeature[] = "'" . $ff . "' 1";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($properties['OTLtags']['FFPlus'])) { // May contain numeric value e.g. salt4
|
||||
$f = preg_split('/\s+/', trim($properties['OTLtags']['FFPlus']));
|
||||
foreach ($f as $ff) {
|
||||
if (strlen($ff) > 4) {
|
||||
$fontFeature[] = "'" . substr($ff, 0, 4) . "' " . substr($ff, 4);
|
||||
} else {
|
||||
$fontFeature[] = "'" . $ff . "' 1";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$css['FONT-FEATURE-SETTINGS'] = implode(', ', $fontFeature);
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
}
|
||||
103
vendor/mpdf/mpdf/src/Css/InlineStyleParser.php
vendored
Normal file
103
vendor/mpdf/mpdf/src/Css/InlineStyleParser.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
class InlineStyleParser
|
||||
{
|
||||
/**
|
||||
* @var NormalizeProperties
|
||||
*/
|
||||
private $normalizeProperties;
|
||||
|
||||
public function __construct(NormalizeProperties $normalizeProperties)
|
||||
{
|
||||
$this->normalizeProperties = $normalizeProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse inline CSS style attribute.
|
||||
*
|
||||
* Parses a CSS string from an HTML style attribute and returns
|
||||
* an array of CSS properties.
|
||||
*
|
||||
* @param string $html CSS string from style attribute
|
||||
* @return array Parsed CSS properties
|
||||
*/
|
||||
public function parse($html)
|
||||
{
|
||||
$html = htmlspecialchars_decode($html); // mPDF 5.7.4 URLs
|
||||
// mPDF 5.7.4 URLs
|
||||
// Characters "(", ")", and ";" in url() e.g. background-image, cause problems parsing the CSS string
|
||||
// URLencode ( and ), but change ";" to a code which can be converted back after parsing (so as not to confuse ;
|
||||
// with a segment delimiter in the URI)
|
||||
$html = $this->processUrlsInCss($html);
|
||||
|
||||
// Fix incomplete CSS code
|
||||
$size = strlen($html) - 1;
|
||||
if (substr($html, $size, 1) !== ';') {
|
||||
$html .= ';';
|
||||
}
|
||||
|
||||
// Make CSS[Name-of-the-class] = array(key => value)
|
||||
$regexp = '|\\s*?(\\S+?):(.+?);|i';
|
||||
preg_match_all($regexp, $html, $styleinfo);
|
||||
$properties = $styleinfo[1];
|
||||
$values = $styleinfo[2];
|
||||
|
||||
// Array-properties and Array-values must have the SAME SIZE!
|
||||
$classproperties = [];
|
||||
$properties_count = count($properties);
|
||||
for ($i = 0; $i < $properties_count; $i++) {
|
||||
|
||||
// Ignores -webkit-gradient so doesn't override -moz-
|
||||
if ((strtoupper($properties[$i]) === 'BACKGROUND-IMAGE' || strtoupper($properties[$i]) === 'BACKGROUND') && false !== stripos($values[$i], '-webkit-gradient')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[$i] = str_replace('%ZZ', ';', $values[$i]); // mPDF 5.7.4 URLs
|
||||
$classproperties[strtoupper($properties[$i])] = trim($values[$i]);
|
||||
}
|
||||
|
||||
return $this->normalizeProperties->normalize($classproperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process URLs in CSS strings by encoding special characters.
|
||||
*
|
||||
* Characters "(", ")", and ";" in url() can cause problems parsing CSS.
|
||||
* This method URLencodes ( and ), and temporarily encodes ";" to prevent
|
||||
* confusion with CSS segment delimiters.
|
||||
*
|
||||
* @param string $css CSS string containing url() references
|
||||
* @return string CSS string with processed URLs
|
||||
*/
|
||||
public function processUrlsInCss($css)
|
||||
{
|
||||
if (strpos($css, 'url(') === false) {
|
||||
return $css;
|
||||
}
|
||||
|
||||
// Process urls with double quotes
|
||||
preg_match_all('/url\(\"(.*?)\"\)/', $css, $m);
|
||||
foreach ($m[1] as $i => $url) {
|
||||
$tmp = str_replace(['(', ')', ';'], ['%28', '%29', '%ZZ'], $m[1][$i]);
|
||||
$css = str_replace($m[0][$i], 'url(\'' . $tmp . '\')', $css);
|
||||
}
|
||||
|
||||
// Process urls with single quotes
|
||||
preg_match_all('/url\(\'(.*?)\'\)/', $css, $m);
|
||||
foreach ($m[1] as $i => $url) {
|
||||
$tmp = str_replace(['(', ')', ';'], ['%28', '%29', '%ZZ'], $m[1][$i]);
|
||||
$css = str_replace($m[0][$i], 'url(\'' . $tmp . '\')', $css);
|
||||
}
|
||||
|
||||
// Process urls without quotes
|
||||
preg_match_all('/url\(([^\'\"].*?[^\'\"])\)/', $css, $m);
|
||||
foreach ($m[1] as $i => $url) {
|
||||
$tmp = str_replace(['(', ')', ';'], ['%28', '%29', '%ZZ'], $m[1][$i]);
|
||||
$css = str_replace($m[0][$i], 'url(\'' . $tmp . '\')', $css);
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
}
|
||||
66
vendor/mpdf/mpdf/src/Css/MediaQueryProcessor.php
vendored
Normal file
66
vendor/mpdf/mpdf/src/Css/MediaQueryProcessor.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class MediaQueryProcessor
|
||||
{
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter HTML elements by media query.
|
||||
*
|
||||
* Removes elements (style or link tags) that don't match the configured media type.
|
||||
*
|
||||
* @param string $html HTML content to filter
|
||||
* @param string $pattern Regex pattern to match elements
|
||||
* @return string Filtered HTML
|
||||
*/
|
||||
public function filterByMediaQuery($html, $pattern)
|
||||
{
|
||||
preg_match_all($pattern, $html, $m);
|
||||
foreach ($m[0] as $i => $url) {
|
||||
if (!$this->mpdf->CSSselectMedia || !preg_match('/(' . trim($this->mpdf->CSSselectMedia) . '|all)/i', $m[1][$i])) {
|
||||
$html = str_replace($m[0][$i], '', $html);
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process @media queries in CSS.
|
||||
*
|
||||
* Filters or unwraps @media blocks based on configured media type.
|
||||
* If media doesn't match CSSselectMedia, the entire block is removed.
|
||||
* If it matches, the contents are unwrapped.
|
||||
*
|
||||
* @param string $cssStr CSS string potentially containing @media rules
|
||||
* @return string CSS string with media queries processed
|
||||
*/
|
||||
public function processMediaQueries($cssStr)
|
||||
{
|
||||
if (!preg_match('/@media/', $cssStr)) {
|
||||
return $cssStr;
|
||||
}
|
||||
|
||||
preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is', $cssStr, $m);
|
||||
foreach ($m[0] as $i => $value) {
|
||||
if ($this->mpdf->CSSselectMedia && !preg_match('/(' . trim($this->mpdf->CSSselectMedia) . '|all)/i', $m[1][$i])) {
|
||||
$cssStr = str_replace($m[0][$i], '', $cssStr);
|
||||
} else {
|
||||
$cssStr = str_replace($m[0][$i], ' ' . $m[2][$i] . ' ', $cssStr);
|
||||
}
|
||||
}
|
||||
|
||||
return $cssStr;
|
||||
}
|
||||
}
|
||||
1004
vendor/mpdf/mpdf/src/Css/NormalizeProperties.php
vendored
Normal file
1004
vendor/mpdf/mpdf/src/Css/NormalizeProperties.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
225
vendor/mpdf/mpdf/src/Css/SelectorParser.php
vendored
Normal file
225
vendor/mpdf/mpdf/src/Css/SelectorParser.php
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class SelectorParser
|
||||
{
|
||||
/**
|
||||
* @var Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse @PAGE selector.
|
||||
*
|
||||
* @param array $tags Selector tags array
|
||||
* @return string Matches tag
|
||||
*/
|
||||
public function parsePageSelector($tags)
|
||||
{
|
||||
$level = count($tags);
|
||||
$t = '';
|
||||
$t2 = '';
|
||||
$t3 = '';
|
||||
|
||||
if (isset($tags[0])) {
|
||||
$t = trim($tags[0]);
|
||||
}
|
||||
|
||||
if (isset($tags[1])) {
|
||||
$t2 = trim($tags[1]);
|
||||
}
|
||||
|
||||
if (isset($tags[2])) {
|
||||
$t3 = trim($tags[2]);
|
||||
}
|
||||
|
||||
$tag = '';
|
||||
if ($level === 1) {
|
||||
$tag = $t;
|
||||
} elseif ($level === 2 && preg_match('/^[:](.*)$/', $t2, $m)) {
|
||||
$tag = $t . '>>PSEUDO>>' . $m[1];
|
||||
if ($m[1] === 'LEFT' || $m[1] === 'RIGHT') {
|
||||
$this->mpdf->mirrorMargins = true;
|
||||
}
|
||||
} elseif ($level === 2) {
|
||||
$tag = $t . '>>NAMED>>' . $t2;
|
||||
} elseif ($level === 3 && preg_match('/^[:](.*)$/', $t3, $m)) {
|
||||
$tag = $t . '>>NAMED>>' . $t2 . '>>PSEUDO>>' . $m[1];
|
||||
if ($m[1] === 'LEFT' || $m[1] === 'RIGHT') {
|
||||
$this->mpdf->mirrorMargins = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse simple selector (depth 1).
|
||||
*
|
||||
* @param array $tags Selector tags array
|
||||
* @return string|null Parsed tag key or null if invalid
|
||||
*/
|
||||
public function parseSimpleSelector($tags)
|
||||
{
|
||||
$t = isset($tags[0]) ? trim($tags[0]) : '';
|
||||
if (empty($t)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tag = '';
|
||||
if (preg_match('/^[.](.*)$/', $t, $m)) {
|
||||
$classes = explode('.', $m[1]);
|
||||
sort($classes);
|
||||
$tag = 'CLASS>>' . implode('.', $classes);
|
||||
} elseif (preg_match('/^[#](.*)$/', $t, $m)) {
|
||||
$tag = 'ID>>' . $m[1];
|
||||
} elseif (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
|
||||
$tag = 'LANG>>' . strtolower($m[1]);
|
||||
} elseif (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = 'LANG>>' . strtolower($m[1]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[.](.*)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$classes = explode('.', $m[2]);
|
||||
sort($classes);
|
||||
$tag = $m[1] . '>>CLASS>>' . implode('.', $classes);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\s*:NTH-CHILD\((.*)\)$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>SELECTORNTHCHILD>>' . $m[2];
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[#](.*)$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>ID>>' . $m[2];
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . '):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')$/', $t)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = $t;
|
||||
}
|
||||
|
||||
return $tag ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse cascaded selector (depth > 1).
|
||||
*
|
||||
* @param array $tags Selector tags array
|
||||
* @return array Array of tag levels for cascade
|
||||
*/
|
||||
public function parseCascadedSelector($tags)
|
||||
{
|
||||
$tmp = [];
|
||||
$level = count($tags);
|
||||
|
||||
for ($n = 0; $n < $level; $n++) {
|
||||
$tag = '';
|
||||
$t = isset($tags[$n]) ? trim($tags[$n]) : '';
|
||||
if (empty($t)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/^[.](.*)$/', $t, $m)) {
|
||||
$classes = explode('.', $m[1]);
|
||||
sort($classes);
|
||||
$tag = 'CLASS>>' . join('.', $classes);
|
||||
} elseif (preg_match('/^[#](.*)$/', $t, $m)) {
|
||||
$tag = 'ID>>' . $m[1];
|
||||
} elseif (preg_match('/^\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
|
||||
$tag = 'LANG>>' . strtolower($m[1]);
|
||||
} elseif (preg_match('/^:LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = 'LANG>>' . strtolower($m[1]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[.](.*)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$classes = explode('.', $m[2]);
|
||||
sort($classes);
|
||||
$tag = $m[1] . '>>CLASS>>' . join('.', $classes);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\s*:NTH-CHILD\((.*)\)$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>SELECTORNTHCHILD>>' . $m[2];
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')[#](.*)$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>ID>>' . $m[2];
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')\[LANG=[\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\]$/', $t, $m)) {
|
||||
$tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . '):LANG\([\'\"]{0,1}([A-Z\-]{2,11})[\'\"]{0,1}\)$/', $t, $m)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = $m[1] . '>>LANG>>' . strtolower($m[2]);
|
||||
} elseif (preg_match('/^(' . $this->mpdf->allowedCSStags . ')$/', $t)) { // mPDF 6 Special case for lang as attribute selector
|
||||
$tag = $t;
|
||||
}
|
||||
|
||||
if (!$tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
$tmp[] = $tag;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate nth-child CSS selector.
|
||||
*
|
||||
* Determines if a given element index matches an nth-child selector formula.
|
||||
* Supports formulas like "2n+1", "odd", "even", or specific numbers.
|
||||
*
|
||||
* @param array $nthComponents Formula components from preg_match (e.g. 2N+1 split into a preg_match array))
|
||||
* @param int $index Current element index (e.g row or column number)
|
||||
* @return bool True if element matches the nth-child selector
|
||||
*/
|
||||
public function matchesNthChild($nthComponents, $index)
|
||||
{
|
||||
++$index;
|
||||
$select = false;
|
||||
|
||||
$numOfComponents = count($nthComponents);
|
||||
if ($nthComponents[0] === 'ODD') {
|
||||
$a = 2;
|
||||
$b = 1;
|
||||
} elseif ($nthComponents[0] === 'EVEN') {
|
||||
$a = 2;
|
||||
$b = 0;
|
||||
} elseif ($numOfComponents === 2) {
|
||||
$a = 0;
|
||||
$b = $nthComponents[1] + 0;
|
||||
} // e.g. (+6)
|
||||
elseif ($numOfComponents === 3) { // e.g. (2N)
|
||||
if ($nthComponents[2] === '') {
|
||||
$a = 1;
|
||||
} elseif ($nthComponents[2] === '-') {
|
||||
$a = -1;
|
||||
} else {
|
||||
$a = $nthComponents[2] + 0;
|
||||
}
|
||||
$b = 0;
|
||||
} elseif ($numOfComponents === 4) { // e.g. (2N+6)
|
||||
if ($nthComponents[2] === '') {
|
||||
$a = 1;
|
||||
} elseif ($nthComponents[2] === '-') {
|
||||
$a = -1;
|
||||
} else {
|
||||
$a = $nthComponents[2] + 0;
|
||||
}
|
||||
$b = $nthComponents[3] + 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($a > 0) {
|
||||
if (((($index % $a) - $b) % $a) === 0 && $index >= $b) {
|
||||
$select = true;
|
||||
}
|
||||
} elseif ($a === 0) {
|
||||
if ($index === $b) {
|
||||
$select = true;
|
||||
}
|
||||
} else { // if ($a<0)
|
||||
if (((($index % $a) - $b) % $a) === 0 && $index <= $b) {
|
||||
$select = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $select;
|
||||
}
|
||||
}
|
||||
281
vendor/mpdf/mpdf/src/Css/ShadowParser.php
vendored
Normal file
281
vendor/mpdf/mpdf/src/Css/ShadowParser.php
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\SizeConverter;
|
||||
|
||||
class ShadowParser
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var SizeConverter
|
||||
*/
|
||||
private $sizeConverter;
|
||||
|
||||
/**
|
||||
* @var ColorConverter
|
||||
*/
|
||||
private $colorConverter;
|
||||
|
||||
public function __construct(Mpdf $mpdf, SizeConverter $sizeConverter, ColorConverter $colorConverter)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->sizeConverter = $sizeConverter;
|
||||
$this->colorConverter = $colorConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize shadow colors.
|
||||
*
|
||||
* Replaces commas in color functions (rgb, hsl, etc.) with placeholders
|
||||
* to prevent splitting multiple shadows on those commas.
|
||||
*
|
||||
* @param string $value Shadow property value
|
||||
* @return string Normalized shadow property value
|
||||
*/
|
||||
public function normalizeShadowColors($value)
|
||||
{
|
||||
$c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/', $value, $x); // mPDF 5.6.05
|
||||
for ($i = 0; $i < $c; $i++) {
|
||||
$col = preg_replace('/,\s/', '*', $x[0][$i]);
|
||||
$value = str_replace($x[0][$i], $col, $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse box-shadow CSS property.
|
||||
*
|
||||
* Converts box-shadow CSS property string into array format used internally.
|
||||
* Handles multiple shadows, inset shadows, blur, spread, and colors.
|
||||
*
|
||||
* @param string $value Box-shadow property value
|
||||
* @return array Array of shadow definitions
|
||||
*/
|
||||
public function parseBoxShadow($value)
|
||||
{
|
||||
$sh = [];
|
||||
$ss = explode(',', $this->normalizeShadowColors($value));
|
||||
foreach ($ss as $s) {
|
||||
$boxShadow = $this->parseSingleBoxShadow($s);
|
||||
if ($boxShadow) {
|
||||
array_unshift($sh, $boxShadow);
|
||||
}
|
||||
}
|
||||
|
||||
return $sh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single box-shadow definition.
|
||||
*
|
||||
* Helper method for setCSSboxshadow to parse individual shadow components
|
||||
* (inset, x, y, blur, spread, color).
|
||||
*
|
||||
* @param string $s Shadow definition string
|
||||
* @return array|null Parsed shadow array or null if invalid
|
||||
*/
|
||||
protected function parseSingleBoxShadow($s)
|
||||
{
|
||||
$boxShadow = [
|
||||
'inset' => false,
|
||||
'blur' => 0,
|
||||
'spread' => 0
|
||||
];
|
||||
|
||||
if (stripos($s, 'inset') !== false) {
|
||||
$boxShadow['inset'] = true;
|
||||
$s = preg_replace('/\s*inset\s*/', '', $s);
|
||||
}
|
||||
|
||||
$p = explode(' ', trim($s));
|
||||
if (isset($p[0])) {
|
||||
$parentWidth = 0;
|
||||
if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'])) {
|
||||
$parentWidth = isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width']);
|
||||
} elseif (isset($this->mpdf->blk[0]['inner_width'])) {
|
||||
$parentWidth = $this->mpdf->blk[0]['inner_width'];
|
||||
}
|
||||
|
||||
$boxShadow['x'] = $this->sizeConverter->convert(
|
||||
trim($p[0]),
|
||||
$parentWidth,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($p[1])) {
|
||||
$parentWidth = 0;
|
||||
if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'])) {
|
||||
$parentWidth = isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width']);
|
||||
} elseif (isset($this->mpdf->blk[0]['inner_width'])) {
|
||||
$parentWidth = $this->mpdf->blk[0]['inner_width'];
|
||||
}
|
||||
|
||||
$boxShadow['y'] = $this->sizeConverter->convert(
|
||||
trim($p[1]),
|
||||
$parentWidth,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if (isset($p[2])) {
|
||||
if (preg_match('/^\s*[\.\-0-9]/', $p[2])) {
|
||||
$parentWidth = 0;
|
||||
if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'])) {
|
||||
$parentWidth = isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width']);
|
||||
} elseif (isset($this->mpdf->blk[0]['inner_width'])) {
|
||||
$parentWidth = $this->mpdf->blk[0]['inner_width'];
|
||||
}
|
||||
|
||||
$boxShadow['blur'] = $this->sizeConverter->convert(
|
||||
trim($p[2]),
|
||||
$parentWidth,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
$boxShadow['col'] = $this->colorConverter->convert(
|
||||
preg_replace('/\*/', ',', $p[2]),
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($p[3])) {
|
||||
if (preg_match('/^\s*[\.\-0-9]/', $p[3])) {
|
||||
$parentWidth = 0;
|
||||
if (isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width'])) {
|
||||
$parentWidth = isset($this->mpdf->blk[$this->mpdf->blklvl - 1]['inner_width']);
|
||||
} elseif (isset($this->mpdf->blk[0]['inner_width'])) {
|
||||
$parentWidth = $this->mpdf->blk[0]['inner_width'];
|
||||
}
|
||||
|
||||
$boxShadow['spread'] = $this->sizeConverter->convert(
|
||||
trim($p[3]),
|
||||
$parentWidth,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
$boxShadow['col'] = $this->colorConverter->convert(
|
||||
preg_replace('/\*/', ',', $p[3]),
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($p[4])) {
|
||||
$boxShadow['col'] = $this->colorConverter->convert(
|
||||
preg_replace('/\*/', ',', $p[4]),
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($boxShadow['col'])) {
|
||||
$boxShadow['col'] = $this->colorConverter->convert('#888888', $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
|
||||
return isset($boxShadow['y']) ? $boxShadow : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse text-shadow CSS property.
|
||||
*
|
||||
* Converts text-shadow CSS property string into array format used internally.
|
||||
* Handles multiple shadows, blur, and colors.
|
||||
*
|
||||
* @param string $value Text-shadow property value
|
||||
* @return array Array of text shadow definitions
|
||||
*/
|
||||
public function parseTextShadow($value)
|
||||
{
|
||||
$sh = [];
|
||||
$ss = explode(',', $this->normalizeShadowColors($value));
|
||||
|
||||
foreach ($ss as $s) {
|
||||
$textShadow = $this->parseSingleTextShadow($s);
|
||||
if ($textShadow) {
|
||||
array_unshift($sh, $textShadow);
|
||||
}
|
||||
}
|
||||
|
||||
return $sh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single text-shadow definition.
|
||||
*
|
||||
* Helper method for setCSStextshadow to parse individual shadow components
|
||||
* (x, y, blur, color).
|
||||
*
|
||||
* @param string $s Shadow definition string
|
||||
* @return array|null Parsed shadow array or null if invalid
|
||||
*/
|
||||
protected function parseSingleTextShadow($s)
|
||||
{
|
||||
$textShadow = ['blur' => 0];
|
||||
$p = explode(' ', trim($s));
|
||||
|
||||
if (isset($p[0])) {
|
||||
$textShadow['x'] = $this->sizeConverter->convert(
|
||||
trim($p[0]),
|
||||
$this->mpdf->FontSize,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($p[1])) {
|
||||
$textShadow['y'] = $this->sizeConverter->convert(
|
||||
trim($p[1]),
|
||||
$this->mpdf->FontSize,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($p[2])) {
|
||||
if (preg_match('/^\s*[\.\-0-9]/', $p[2])) {
|
||||
$textShadow['blur'] = $this->sizeConverter->convert(
|
||||
trim($p[2]),
|
||||
isset($this->mpdf->blk[$this->mpdf->blklvl]['inner_width']) ? $this->mpdf->blk[$this->mpdf->blklvl]['inner_width'] : 0,
|
||||
$this->mpdf->FontSize,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
$textShadow['col'] = $this->colorConverter->convert(
|
||||
preg_replace('/\*/', ',', $p[2]),
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($p[3])) {
|
||||
$textShadow['col'] = $this->colorConverter->convert(
|
||||
preg_replace('/\*/', ',', $p[3]),
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($textShadow['col'])) {
|
||||
$textShadow['col'] = $this->colorConverter->convert(
|
||||
'#888888',
|
||||
$this->mpdf->PDFAXwarnings
|
||||
);
|
||||
}
|
||||
|
||||
return isset($textShadow['y']) ? $textShadow : null;
|
||||
}
|
||||
}
|
||||
2427
vendor/mpdf/mpdf/src/CssManager.php
vendored
2427
vendor/mpdf/mpdf/src/CssManager.php
vendored
File diff suppressed because it is too large
Load Diff
6
vendor/mpdf/mpdf/src/FpdiTrait.php
vendored
6
vendor/mpdf/mpdf/src/FpdiTrait.php
vendored
@@ -332,11 +332,7 @@ public function getImportedPages()
|
||||
|
||||
protected function _put($s, $newLine = true)
|
||||
{
|
||||
if ($newLine) {
|
||||
$this->buffer .= $s . "\n";
|
||||
} else {
|
||||
$this->buffer .= $s;
|
||||
}
|
||||
$this->buffer->append($s, $newLine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
vendor/mpdf/mpdf/src/Image/Svg.php
vendored
2
vendor/mpdf/mpdf/src/Image/Svg.php
vendored
@@ -278,7 +278,7 @@ function svgImage($attribs)
|
||||
$orig_srcpath = '';
|
||||
if (trim($srcpath) != '' && substr($srcpath, 0, 4) == 'var:') {
|
||||
$orig_srcpath = $srcpath;
|
||||
$srcpath = $this->mpdf->GetFullPath($srcpath);
|
||||
$this->mpdf->GetFullPath($srcpath);
|
||||
}
|
||||
|
||||
// Image file (does not allow vector images i.e. WMF/SVG)
|
||||
|
||||
114
vendor/mpdf/mpdf/src/Mpdf.php
vendored
114
vendor/mpdf/mpdf/src/Mpdf.php
vendored
@@ -15,6 +15,7 @@
|
||||
use Mpdf\Utils\Arrays;
|
||||
use Mpdf\Utils\NumericString;
|
||||
use Mpdf\Utils\UtfString;
|
||||
use Mpdf\Utils\Path;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
|
||||
use FpdiTrait;
|
||||
use MpdfPsrLogAwareTrait;
|
||||
|
||||
const VERSION = '8.2.7';
|
||||
const VERSION = '8.3.1';
|
||||
|
||||
const SCALE = 72 / 25.4;
|
||||
|
||||
@@ -332,10 +333,6 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
|
||||
var $lastblocklevelchange;
|
||||
var $nestedtablejustfinished;
|
||||
var $linebreakjustfinished;
|
||||
var $cell_border_dominance_L;
|
||||
var $cell_border_dominance_R;
|
||||
var $cell_border_dominance_T;
|
||||
var $cell_border_dominance_B;
|
||||
var $table_keep_together;
|
||||
var $plainCell_properties;
|
||||
var $shrin_k1;
|
||||
@@ -851,6 +848,10 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
|
||||
*/
|
||||
private $cssManager;
|
||||
|
||||
/**
|
||||
* @var ShadowParser
|
||||
private $shadowParser;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Gradient
|
||||
*/
|
||||
@@ -1109,7 +1110,7 @@ public function __construct(array $config = [], $container = null)
|
||||
$this->BMPonly = [];
|
||||
$this->page = 0;
|
||||
$this->n = 2;
|
||||
$this->buffer = '';
|
||||
$this->buffer = new Buffer();
|
||||
$this->objectbuffer = [];
|
||||
$this->pages = [];
|
||||
$this->OrientationChanges = [];
|
||||
@@ -9554,7 +9555,7 @@ function Output($name = '', $dest = '')
|
||||
|
||||
$this->logger->debug(sprintf('Compiled in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
|
||||
$this->logger->debug(sprintf('Peak Memory usage %s MB', number_format(memory_get_peak_usage(true) / (1024 * 1024), 2)), ['context' => LogContext::STATISTICS]);
|
||||
$this->logger->debug(sprintf('PDF file size %s kB', number_format(strlen($this->buffer) / 1024)), ['context' => LogContext::STATISTICS]);
|
||||
$this->logger->debug(sprintf('PDF file size %s kB', number_format($this->buffer->getLength() / 1024)), ['context' => LogContext::STATISTICS]);
|
||||
$this->logger->debug(sprintf('%d fonts used', count($this->fonts)), ['context' => LogContext::STATISTICS]);
|
||||
|
||||
if (is_bool($dest)) {
|
||||
@@ -9591,7 +9592,7 @@ function Output($name = '', $dest = '')
|
||||
|
||||
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
|
||||
// don't use length if server using compression
|
||||
header('Content-Length: ' . strlen($this->buffer));
|
||||
header('Content-Length: ' . $this->buffer->getLength());
|
||||
}
|
||||
|
||||
header('Content-disposition: inline; filename="' . $name . '"');
|
||||
@@ -9602,7 +9603,7 @@ function Output($name = '', $dest = '')
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
}
|
||||
|
||||
echo $this->buffer;
|
||||
$this->buffer->writeToOutput();
|
||||
|
||||
break;
|
||||
|
||||
@@ -9623,12 +9624,12 @@ function Output($name = '', $dest = '')
|
||||
|
||||
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
|
||||
// don't use length if server using compression
|
||||
header('Content-Length: ' . strlen($this->buffer));
|
||||
header('Content-Length: ' . $this->buffer->getLength());
|
||||
}
|
||||
|
||||
header('Content-Disposition: attachment; filename="' . $name . '"');
|
||||
|
||||
echo $this->buffer;
|
||||
$this->buffer->writeToOutput();
|
||||
|
||||
break;
|
||||
|
||||
@@ -9639,14 +9640,15 @@ function Output($name = '', $dest = '')
|
||||
throw new \Mpdf\MpdfException(sprintf('Unable to create output file %s', $name));
|
||||
}
|
||||
|
||||
fwrite($f, $this->buffer, strlen($this->buffer));
|
||||
$this->buffer->writeToFile($f);
|
||||
|
||||
fclose($f);
|
||||
|
||||
break;
|
||||
|
||||
case Destination::STRING_RETURN:
|
||||
$this->cache->clearOld();
|
||||
return $this->buffer;
|
||||
return $this->buffer->writeToString();
|
||||
|
||||
default:
|
||||
throw new \Mpdf\MpdfException(sprintf('Incorrect output destination %s', $dest));
|
||||
@@ -10110,7 +10112,7 @@ function _enddoc()
|
||||
$this->writer->write('endobj');
|
||||
|
||||
// Cross-ref
|
||||
$o = strlen($this->buffer);
|
||||
$o = $this->buffer->getLength();
|
||||
$this->writer->write('xref');
|
||||
$this->writer->write('0 ' . ($this->n + 1));
|
||||
$this->writer->write('0000000000 65535 f ');
|
||||
@@ -10129,7 +10131,7 @@ function _enddoc()
|
||||
$this->writer->write('startxref');
|
||||
$this->writer->write($o);
|
||||
|
||||
$this->buffer .= '%%EOF';
|
||||
$this->buffer->append('%%EOF');
|
||||
$this->state = 3;
|
||||
}
|
||||
|
||||
@@ -11535,84 +11537,8 @@ function SetBasePath($str = '')
|
||||
|
||||
public function GetFullPath(&$path, $basepath = '')
|
||||
{
|
||||
// @todo make return, remove reference
|
||||
|
||||
// When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
|
||||
if (!$basepath) {
|
||||
$basepath = $this->basepath;
|
||||
}
|
||||
|
||||
// Fix path value
|
||||
$path = str_replace("\\", '/', $path); // If on Windows
|
||||
|
||||
// mPDF 5.7.2
|
||||
if (strpos($path, '//') === 0) {
|
||||
$scheme = parse_url($basepath, PHP_URL_SCHEME);
|
||||
$scheme = $scheme ?: 'http';
|
||||
$path = $scheme . ':' . $path;
|
||||
}
|
||||
|
||||
$path = preg_replace('|^./|', '', $path); // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
|
||||
|
||||
if (strpos($path, '#') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip schemes not supported by installed stream wrappers
|
||||
$wrappers = stream_get_wrappers();
|
||||
$pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
|
||||
if (preg_match($pattern, $path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($path, '../') === 0) { // It is a relative link
|
||||
|
||||
$backtrackamount = substr_count($path, '../');
|
||||
$maxbacktrack = substr_count($basepath, '/') - 3;
|
||||
$filepath = str_replace('../', '', $path);
|
||||
$path = $basepath;
|
||||
|
||||
// If it is an invalid relative link, then make it go to directory root
|
||||
if ($backtrackamount > $maxbacktrack) {
|
||||
$backtrackamount = $maxbacktrack;
|
||||
}
|
||||
|
||||
// Backtrack some directories
|
||||
for ($i = 0; $i < $backtrackamount + 1; $i++) {
|
||||
$path = substr($path, 0, strrpos($path, "/"));
|
||||
}
|
||||
|
||||
$path .= '/' . $filepath; // Make it an absolute path
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ((strpos($path, ":/") === false || strpos($path, ":/") > 10) && !@is_file($path)) { // It is a local link. Ignore potential file errors
|
||||
|
||||
if (strpos($path, '/') === 0) {
|
||||
|
||||
$tr = parse_url($basepath);
|
||||
|
||||
// mPDF 5.7.2
|
||||
$root = '';
|
||||
if (!empty($tr['scheme'])) {
|
||||
$root .= $tr['scheme'] . '://';
|
||||
}
|
||||
|
||||
$root .= isset($tr['host']) ? $tr['host'] : '';
|
||||
$root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3
|
||||
|
||||
$path = $root . $path;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
$path = $basepath . $path;
|
||||
}
|
||||
|
||||
// Do nothing if it is an Absolute Link
|
||||
$basepath = !empty($basepath) ? $basepath : $this->basepath;
|
||||
$path = Path::relativeToAbsolutePath($path, $basepath);
|
||||
}
|
||||
|
||||
function docPageNum($num = 0, $extras = false)
|
||||
@@ -13347,7 +13273,7 @@ function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $c
|
||||
}
|
||||
$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
|
||||
if ($zproperties) {
|
||||
$properties = $this->cssManager->array_merge_recursive_unique($properties, $zproperties);
|
||||
$properties = Arrays::uniqueRecursiveMerge($properties, $zproperties);
|
||||
}
|
||||
|
||||
if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
|
||||
|
||||
12
vendor/mpdf/mpdf/src/PageBox.php
vendored
12
vendor/mpdf/mpdf/src/PageBox.php
vendored
@@ -17,6 +17,9 @@ public function __construct()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
@@ -27,12 +30,18 @@ public function offsetSet($offset, $value)
|
||||
$this->container[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
@@ -43,6 +52,9 @@ public function offsetUnset($offset)
|
||||
$this->container[$offset] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
|
||||
32
vendor/mpdf/mpdf/src/ServiceFactory.php
vendored
32
vendor/mpdf/mpdf/src/ServiceFactory.php
vendored
@@ -5,6 +5,14 @@
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\Color\ColorModeConverter;
|
||||
use Mpdf\Color\ColorSpaceRestrictor;
|
||||
use Mpdf\Css\BorderMerger;
|
||||
use Mpdf\Css\CssMerger;
|
||||
use Mpdf\Css\CssParser;
|
||||
use Mpdf\Css\InlinePropertyConverter;
|
||||
use Mpdf\Css\InlineStyleParser;
|
||||
use Mpdf\Css\NormalizeProperties;
|
||||
use Mpdf\Css\SelectorParser;
|
||||
use Mpdf\Css\ShadowParser;
|
||||
use Mpdf\File\LocalContentLoader;
|
||||
use Mpdf\Fonts\FontCache;
|
||||
use Mpdf\Fonts\FontFileFinder;
|
||||
@@ -81,9 +89,29 @@ public function getServices(
|
||||
? $this->container->get('localContentLoader')
|
||||
: new LocalContentLoader();
|
||||
|
||||
$assetFetcher = new AssetFetcher($mpdf, $localContentLoader, $httpClient, $logger);
|
||||
$assetFetcher = $this->container && $this->container->has('assetFetcher')
|
||||
? $this->container->get('assetFetcher')
|
||||
: new AssetFetcher($mpdf, $localContentLoader, $httpClient, $logger);
|
||||
|
||||
$cssManager = new CssManager($mpdf, $cache, $sizeConverter, $colorConverter, $assetFetcher);
|
||||
$normalizeProperties = new NormalizeProperties($mpdf, $sizeConverter, $colorConverter);
|
||||
$selectorParser = new SelectorParser($mpdf);
|
||||
$inlineStyleParser = new InlineStyleParser($normalizeProperties);
|
||||
$inlinePropertyConverter = new InlinePropertyConverter($colorConverter);
|
||||
$borderMerger = new BorderMerger();
|
||||
|
||||
$cssParser = new CssParser($mpdf, $cache, $sizeConverter, $colorConverter, $assetFetcher);
|
||||
|
||||
$cssMerger = new CssMerger(
|
||||
$mpdf,
|
||||
$normalizeProperties,
|
||||
$inlineStyleParser,
|
||||
$selectorParser,
|
||||
$inlinePropertyConverter,
|
||||
$colorConverter,
|
||||
$borderMerger
|
||||
);
|
||||
|
||||
$cssManager = new CssManager($cssParser, $cssMerger);
|
||||
|
||||
$otl = new Otl($mpdf, $fontCache);
|
||||
|
||||
|
||||
2
vendor/mpdf/mpdf/src/SizeConverter.php
vendored
2
vendor/mpdf/mpdf/src/SizeConverter.php
vendored
@@ -42,7 +42,7 @@ public function __construct($dpi, $defaultFontSize, Mpdf $mpdf, LoggerInterface
|
||||
*/
|
||||
public function convert($size = 5, $maxsize = 0, $fontsize = false, $usefontsize = true)
|
||||
{
|
||||
$size = trim(strtolower($size));
|
||||
$size = trim(strtolower((string) $size));
|
||||
$res = preg_match('/^(?P<size>[-0-9.,]+([eE]\-?[0-9]+)?)?(?P<unit>[%a-z-]+)?$/', $size, $parts);
|
||||
if (!$res) {
|
||||
// ignore definition
|
||||
|
||||
182
vendor/mpdf/mpdf/src/Tag/BlockTag.php
vendored
182
vendor/mpdf/mpdf/src/Tag/BlockTag.php
vendored
@@ -3,6 +3,9 @@
|
||||
namespace Mpdf\Tag;
|
||||
|
||||
use Mpdf\Conversion\DecToAlpha;
|
||||
use Mpdf\Conversion\DecToCjk;
|
||||
use Mpdf\Conversion\DecToHebrew;
|
||||
use Mpdf\Conversion\DecToOther;
|
||||
use Mpdf\Conversion\DecToRoman;
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\Utils\Arrays;
|
||||
@@ -155,6 +158,34 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
$this->mpdf->listtype[$this->mpdf->listlvl] = 'square';
|
||||
}
|
||||
}
|
||||
|
||||
// Override with HTML TYPE attribute (lower specificity than CSS)
|
||||
if (!empty($attr['TYPE'])) {
|
||||
$listtype = $attr['TYPE'];
|
||||
switch ($listtype) {
|
||||
case 'A':
|
||||
$listtype = 'upper-latin';
|
||||
break;
|
||||
case 'a':
|
||||
$listtype = 'lower-latin';
|
||||
break;
|
||||
case 'I':
|
||||
$listtype = 'upper-roman';
|
||||
break;
|
||||
case 'i':
|
||||
$listtype = 'lower-roman';
|
||||
break;
|
||||
case '1':
|
||||
$listtype = 'decimal';
|
||||
break;
|
||||
}
|
||||
$this->mpdf->listtype[$this->mpdf->listlvl] = $listtype;
|
||||
}
|
||||
|
||||
// Override with CSS list-style-type if specified (highest specificity)
|
||||
if (!empty($properties['LIST-STYLE-TYPE'])) {
|
||||
$this->mpdf->listtype[$this->mpdf->listlvl] = strtolower($properties['LIST-STYLE-TYPE']);
|
||||
}
|
||||
}
|
||||
|
||||
// mPDF 6 Lists - in Tables
|
||||
@@ -170,54 +201,161 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
//if in table - output here as a tabletextbuffer
|
||||
//position:inside OR position:outside (always output in table as position:inside)
|
||||
|
||||
$currentListType = $this->mpdf->listtype[$this->mpdf->listlvl];
|
||||
|
||||
// Allow individual LI to override list type via HTML TYPE attribute
|
||||
if (!empty($attr['TYPE'])) {
|
||||
$liType = $attr['TYPE'];
|
||||
switch ($liType) {
|
||||
case 'A':
|
||||
$liType = 'upper-latin';
|
||||
break;
|
||||
case 'a':
|
||||
$liType = 'lower-latin';
|
||||
break;
|
||||
case 'I':
|
||||
$liType = 'upper-roman';
|
||||
break;
|
||||
case 'i':
|
||||
$liType = 'lower-roman';
|
||||
break;
|
||||
case '1':
|
||||
$liType = 'decimal';
|
||||
break;
|
||||
}
|
||||
$currentListType = $liType;
|
||||
}
|
||||
|
||||
// Allow individual LI to override list type via CSS (highest specificity)
|
||||
if (!empty($properties['LIST-STYLE-TYPE'])) {
|
||||
$currentListType = strtolower($properties['LIST-STYLE-TYPE']);
|
||||
}
|
||||
|
||||
$decToAlpha = new DecToAlpha();
|
||||
$decToRoman = new DecToRoman();
|
||||
$counter = $this->mpdf->listcounter[$this->mpdf->listlvl];
|
||||
$list_item_color = '';
|
||||
|
||||
switch ($this->mpdf->listtype[$this->mpdf->listlvl]) {
|
||||
switch ($currentListType) {
|
||||
case 'upper-alpha':
|
||||
case 'upper-latin':
|
||||
case 'A':
|
||||
$blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
|
||||
$blt = $decToAlpha->convert($counter) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'lower-alpha':
|
||||
case 'lower-latin':
|
||||
case 'a':
|
||||
$blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl], false) . $this->mpdf->list_number_suffix;
|
||||
$blt = $decToAlpha->convert($counter, false) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'upper-roman':
|
||||
case 'I':
|
||||
$blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
|
||||
$blt = $decToRoman->convert($counter) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'lower-roman':
|
||||
case 'i':
|
||||
$blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
|
||||
$blt = $decToRoman->convert($counter, false) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'decimal':
|
||||
case '1':
|
||||
$blt = $this->mpdf->listcounter[$this->mpdf->listlvl] . $this->mpdf->list_number_suffix;
|
||||
$blt = $counter . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'hebrew':
|
||||
$decToHebrew = new DecToHebrew();
|
||||
$blt = $decToHebrew->convert($counter) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'cjk-decimal':
|
||||
$decToCjk = new DecToCjk();
|
||||
$blt = $decToCjk->convert($counter) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'arabic-indic':
|
||||
case 'bengali':
|
||||
case 'cambodian':
|
||||
case 'devanagari':
|
||||
case 'gujarati':
|
||||
case 'gurmukhi':
|
||||
case 'kannada':
|
||||
case 'khmer':
|
||||
case 'lao':
|
||||
case 'malayalam':
|
||||
case 'myanmar':
|
||||
case 'oriya':
|
||||
case 'persian':
|
||||
case 'tamil':
|
||||
case 'telugu':
|
||||
case 'thai':
|
||||
case 'urdu':
|
||||
$decToOther = new DecToOther($this->mpdf);
|
||||
$cp = $decToOther->getCodePage($currentListType);
|
||||
$blt = $decToOther->convert($counter, $cp, true) . $this->mpdf->list_number_suffix;
|
||||
break;
|
||||
case 'disc':
|
||||
$blt = '-';
|
||||
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
|
||||
$blt = "\xe2\x80\xa2"; // U+2022 BULLET
|
||||
}
|
||||
break;
|
||||
case 'circle':
|
||||
$blt = '-';
|
||||
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9900)) {
|
||||
$blt = "\xe2\x9a\xac"; // U+26AC
|
||||
}
|
||||
break;
|
||||
case 'square':
|
||||
$blt = '-';
|
||||
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9642)) {
|
||||
$blt = "\xe2\x96\xaa"; // U+25AA
|
||||
}
|
||||
break;
|
||||
case 'none':
|
||||
$blt = '';
|
||||
break;
|
||||
default:
|
||||
$blt = '-';
|
||||
if ($this->mpdf->listlvl % 3 == 1 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
|
||||
$blt = "\xe2\x80\xa2";
|
||||
} // •
|
||||
elseif ($this->mpdf->listlvl % 3 == 2 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9900)) {
|
||||
$blt = "\xe2\x9a\xac";
|
||||
} // ⚬
|
||||
elseif ($this->mpdf->listlvl % 3 == 0 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9642)) {
|
||||
$blt = "\xe2\x96\xaa";
|
||||
} // ▪
|
||||
if (preg_match('/U\+([a-fA-F0-9]+)/i', $currentListType, $m)) {
|
||||
$blt = '-';
|
||||
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], hexdec($m[1]))) {
|
||||
$blt = UtfString::codeHex2utf($m[1]);
|
||||
}
|
||||
if (preg_match('/rgb\(.*?\)/', $currentListType, $cm)) {
|
||||
$list_item_color = $this->colorConverter->convert($cm[0], $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
} else {
|
||||
$blt = '-';
|
||||
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
|
||||
$blt = "\xe2\x80\xa2";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// change to spaces
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$ls = str_repeat(chr(160) . chr(160), ($this->mpdf->listlvl - 1) * 2) . $blt . ' ';
|
||||
} else {
|
||||
$ls = str_repeat("\xc2\xa0\xc2\xa0", ($this->mpdf->listlvl - 1) * 2) . $blt . ' ';
|
||||
if ($currentListType !== 'none') {
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$indent = str_repeat(chr(160) . chr(160), ($this->mpdf->listlvl - 1) * 2);
|
||||
} else {
|
||||
$indent = str_repeat("\xc2\xa0\xc2\xa0", ($this->mpdf->listlvl - 1) * 2);
|
||||
}
|
||||
|
||||
if (!empty($list_item_color)) {
|
||||
// Write indentation without color
|
||||
if ($indent !== '') {
|
||||
$this->mpdf->_saveCellTextBuffer($indent);
|
||||
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($indent);
|
||||
}
|
||||
// Write marker with color
|
||||
$save_colorarray = $this->mpdf->colorarray;
|
||||
$this->mpdf->colorarray = $list_item_color;
|
||||
$this->mpdf->_saveCellTextBuffer($blt);
|
||||
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($blt);
|
||||
$this->mpdf->colorarray = $save_colorarray;
|
||||
// Write trailing space without color
|
||||
$this->mpdf->_saveCellTextBuffer(' ');
|
||||
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth(' ');
|
||||
} else {
|
||||
$ls = $indent . $blt . ' ';
|
||||
$this->mpdf->_saveCellTextBuffer($ls);
|
||||
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($ls);
|
||||
}
|
||||
}
|
||||
$this->mpdf->_saveCellTextBuffer($ls);
|
||||
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($ls);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
28
vendor/mpdf/mpdf/src/Tag/Table.php
vendored
28
vendor/mpdf/mpdf/src/Tag/Table.php
vendored
@@ -212,7 +212,7 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
}
|
||||
}
|
||||
if (!empty($properties['ROTATE']) && $this->mpdf->tableLevel == 1) {
|
||||
$this->mpdf->table_rotate = $properties['ROTATE'];
|
||||
$this->mpdf->table_rotate = $this->parseTableRotate($properties['ROTATE']);
|
||||
}
|
||||
if (isset($properties['TOPNTAIL'])) {
|
||||
$table['topntail'] = $properties['TOPNTAIL'];
|
||||
@@ -496,7 +496,7 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
}
|
||||
}
|
||||
if (isset($attr['ROTATE']) && $this->mpdf->tableLevel == 1) {
|
||||
$this->mpdf->table_rotate = $attr['ROTATE'];
|
||||
$this->mpdf->table_rotate = $this->parseTableRotate($attr['ROTATE']);
|
||||
}
|
||||
|
||||
//++++++++++++++++++++++++++++
|
||||
@@ -1278,4 +1278,28 @@ private function tbsqrt($val, $iteration = 3)
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rotate
|
||||
* @return int
|
||||
*/
|
||||
private function parseTableRotate($rotate)
|
||||
{
|
||||
if (1 !== preg_match('/^(-?[0-9]+)(?:deg)?$/', $rotate, $matches)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$rotationDegrees = (int) $matches[1] % 360;
|
||||
if ($rotationDegrees > 180) {
|
||||
$rotationDegrees -= 360;
|
||||
} elseif ($rotationDegrees < -180) {
|
||||
$rotationDegrees += 360;
|
||||
}
|
||||
|
||||
// Only 90 and -90 are supported
|
||||
if ($rotationDegrees !== 90 && $rotationDegrees !== -90) {
|
||||
$rotationDegrees = 0;
|
||||
}
|
||||
|
||||
return $rotationDegrees;
|
||||
}
|
||||
}
|
||||
|
||||
27
vendor/mpdf/mpdf/src/Tag/Td.php
vendored
27
vendor/mpdf/mpdf/src/Tag/Td.php
vendored
@@ -4,6 +4,7 @@
|
||||
|
||||
use Mpdf\Css\Border;
|
||||
use Mpdf\Css\TextVars;
|
||||
use Mpdf\Utils\Arrays;
|
||||
use Mpdf\Utils\UtfString;
|
||||
|
||||
class Td extends Tag
|
||||
@@ -167,14 +168,14 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
$c['R'] = $this->mpdf->trow_text_rotate;
|
||||
}
|
||||
|
||||
$this->mpdf->cell_border_dominance_L = 0;
|
||||
$this->mpdf->cell_border_dominance_R = 0;
|
||||
$this->mpdf->cell_border_dominance_T = 0;
|
||||
$this->mpdf->cell_border_dominance_B = 0;
|
||||
$this->cssManager->setBorderDominance('L', 0);
|
||||
$this->cssManager->setBorderDominance('R', 0);
|
||||
$this->cssManager->setBorderDominance('T', 0);
|
||||
$this->cssManager->setBorderDominance('B', 0);
|
||||
|
||||
$properties = $this->cssManager->MergeCSS('TABLE', $tag, $attr);
|
||||
|
||||
$properties = $this->cssManager->array_merge_recursive_unique($this->mpdf->base_table_properties, $properties);
|
||||
$properties = Arrays::uniqueRecursiveMerge($this->mpdf->base_table_properties, $properties);
|
||||
|
||||
$this->mpdf->Reset(); // mPDF 6 ?????????????????????
|
||||
|
||||
@@ -282,10 +283,10 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
$c['border_details']['L'] = $bord;
|
||||
$c['border_details']['T'] = $bord;
|
||||
$c['border_details']['B'] = $bord;
|
||||
$c['border_details']['L']['dom'] = $this->mpdf->cell_border_dominance_L;
|
||||
$c['border_details']['R']['dom'] = $this->mpdf->cell_border_dominance_R;
|
||||
$c['border_details']['T']['dom'] = $this->mpdf->cell_border_dominance_T;
|
||||
$c['border_details']['B']['dom'] = $this->mpdf->cell_border_dominance_B;
|
||||
$c['border_details']['L']['dom'] = $this->cssManager->getBorderDominance('L');
|
||||
$c['border_details']['R']['dom'] = $this->cssManager->getBorderDominance('R');
|
||||
$c['border_details']['T']['dom'] = $this->cssManager->getBorderDominance('T');
|
||||
$c['border_details']['B']['dom'] = $this->cssManager->getBorderDominance('B');
|
||||
} elseif ($this->mpdf->simpleTables && $this->mpdf->row == 0 && $this->mpdf->col == 0) {
|
||||
$table['simple']['border'] = Border::ALL;
|
||||
$table['simple']['border_details']['R'] = $bord;
|
||||
@@ -299,22 +300,22 @@ public function open($attr, &$ahtml, &$ihtml)
|
||||
if (!empty($properties['BORDER-RIGHT'])) {
|
||||
$c['border_details']['R'] = $this->mpdf->border_details($properties['BORDER-RIGHT']);
|
||||
$this->mpdf->setBorder($c['border'], Border::RIGHT, $c['border_details']['R']['s']);
|
||||
$c['border_details']['R']['dom'] = $this->mpdf->cell_border_dominance_R;
|
||||
$c['border_details']['R']['dom'] = $this->cssManager->getBorderDominance('R');
|
||||
}
|
||||
if (!empty($properties['BORDER-LEFT'])) {
|
||||
$c['border_details']['L'] = $this->mpdf->border_details($properties['BORDER-LEFT']);
|
||||
$this->mpdf->setBorder($c['border'], Border::LEFT, $c['border_details']['L']['s']);
|
||||
$c['border_details']['L']['dom'] = $this->mpdf->cell_border_dominance_L;
|
||||
$c['border_details']['L']['dom'] = $this->cssManager->getBorderDominance('L');
|
||||
}
|
||||
if (!empty($properties['BORDER-BOTTOM'])) {
|
||||
$c['border_details']['B'] = $this->mpdf->border_details($properties['BORDER-BOTTOM']);
|
||||
$this->mpdf->setBorder($c['border'], Border::BOTTOM, $c['border_details']['B']['s']);
|
||||
$c['border_details']['B']['dom'] = $this->mpdf->cell_border_dominance_B;
|
||||
$c['border_details']['B']['dom'] = $this->cssManager->getBorderDominance('B');
|
||||
}
|
||||
if (!empty($properties['BORDER-TOP'])) {
|
||||
$c['border_details']['T'] = $this->mpdf->border_details($properties['BORDER-TOP']);
|
||||
$this->mpdf->setBorder($c['border'], Border::TOP, $c['border_details']['T']['s']);
|
||||
$c['border_details']['T']['dom'] = $this->mpdf->cell_border_dominance_T;
|
||||
$c['border_details']['T']['dom'] = $this->cssManager->getBorderDominance('T');
|
||||
}
|
||||
} elseif ($this->mpdf->simpleTables && $this->mpdf->row == 0 && $this->mpdf->col == 0) {
|
||||
if (!empty($properties['BORDER-LEFT'])) {
|
||||
|
||||
31
vendor/mpdf/mpdf/src/Utils/Arrays.php
vendored
31
vendor/mpdf/mpdf/src/Utils/Arrays.php
vendored
@@ -29,9 +29,10 @@ public static function get($array, $key, $default = null)
|
||||
* [one, two]
|
||||
* ]
|
||||
* @param array $array
|
||||
* @param int|null $maxSize Max depth of the combinations
|
||||
* @return array
|
||||
*/
|
||||
public static function allUniqueSortedCombinations($array)
|
||||
public static function allUniqueSortedCombinations($array, $maxSize = null)
|
||||
{
|
||||
$input = array_unique($array);
|
||||
if (count($input) <= 1) {
|
||||
@@ -46,6 +47,9 @@ public static function allUniqueSortedCombinations($array)
|
||||
|
||||
$n = count($input);
|
||||
for ($k = 2; $k <= $n; $k++) {
|
||||
if ($maxSize && $k > $maxSize) {
|
||||
break;
|
||||
}
|
||||
$combinations = array_merge($combinations, self::combinations($input, $k));
|
||||
}
|
||||
|
||||
@@ -97,4 +101,29 @@ public static function combinations($array, $k)
|
||||
|
||||
return $combinations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge arrays recursively, appending integer-like keys and merge string keys.
|
||||
*
|
||||
* @param array ...$arrays Arrays to merge
|
||||
* @return array Merged array
|
||||
*/
|
||||
public static function uniqueRecursiveMerge(...$arrays)
|
||||
{
|
||||
$results = array_shift($arrays);
|
||||
|
||||
foreach ($arrays as $array) {
|
||||
foreach ($array as $key => $value) {
|
||||
if ((string) $key === (string) ((int) $key)) {
|
||||
$results[] = $value;
|
||||
} elseif (is_array($value) && isset($results[$key]) && is_array($results[$key])) {
|
||||
$results[$key] = self::uniqueRecursiveMerge($results[$key], $value);
|
||||
} else {
|
||||
$results[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
||||
117
vendor/mpdf/mpdf/src/Utils/Path.php
vendored
Normal file
117
vendor/mpdf/mpdf/src/Utils/Path.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Mpdf\Utils;
|
||||
|
||||
class Path
|
||||
{
|
||||
/**
|
||||
* Convert a relative path to an absolute path
|
||||
*
|
||||
* @param string $relPath
|
||||
* @param string $basePath The absolute path to prefix to the relative path (can be a path or URL)
|
||||
* @return string
|
||||
*/
|
||||
public static function relativeToAbsolutePath($relPath, $basePath)
|
||||
{
|
||||
// Fix Windows paths
|
||||
$relPath = str_replace("\\", '/', $relPath);
|
||||
|
||||
// mPDF 5.7.2
|
||||
if (strpos($relPath, '//') === 0) {
|
||||
$scheme = parse_url($basePath, PHP_URL_SCHEME);
|
||||
$scheme = $scheme ?: 'http';
|
||||
$relPath = $scheme . ':' . $relPath;
|
||||
}
|
||||
|
||||
// Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
|
||||
$relPath = preg_replace('|^./|', '', $relPath);
|
||||
if (strpos($relPath, '#') === 0) {
|
||||
return $relPath;
|
||||
}
|
||||
|
||||
// Skip schemes not supported by installed stream wrappers
|
||||
$wrappers = stream_get_wrappers();
|
||||
$pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
|
||||
if (preg_match($pattern, $relPath)) {
|
||||
return $relPath;
|
||||
}
|
||||
|
||||
// It is a relative link
|
||||
if (strpos($relPath, '../') === 0) {
|
||||
$backtrackamount = substr_count($relPath, '../');
|
||||
$maxbacktrack = substr_count($basePath, '/') - 3;
|
||||
$filepath = str_replace('../', '', $relPath);
|
||||
$relPath = $basePath;
|
||||
|
||||
// If it is an invalid relative link, then make it go to directory root
|
||||
if ($backtrackamount > $maxbacktrack) {
|
||||
$backtrackamount = $maxbacktrack;
|
||||
}
|
||||
|
||||
// Backtrack some directories
|
||||
for ($i = 0; $i < $backtrackamount + 1; $i++) {
|
||||
$relPath = substr($relPath, 0, strrpos($relPath, "/"));
|
||||
}
|
||||
|
||||
// Make it an absolute path
|
||||
$relPath .= '/' . $filepath;
|
||||
|
||||
return $relPath;
|
||||
}
|
||||
|
||||
// It is a local link. Ignore potential file errors
|
||||
if ((strpos($relPath, ":/") === false || strpos($relPath, ":/") > 10) &&
|
||||
!@is_file($relPath)
|
||||
) {
|
||||
|
||||
if (strpos($relPath, '/') !== 0) {
|
||||
return $basePath . $relPath;
|
||||
}
|
||||
|
||||
$tr = parse_url($basePath);
|
||||
|
||||
// mPDF 5.7.2
|
||||
$root = '';
|
||||
if (!empty($tr['scheme'])) {
|
||||
$root .= $tr['scheme'] . '://';
|
||||
}
|
||||
|
||||
$root .= !empty($tr['host']) ? $tr['host'] : '';
|
||||
$root .= !empty($tr['port']) ? ':' . $tr['port'] : ''; // mPDF 5.7.3
|
||||
|
||||
$relPath = $root . $relPath;
|
||||
}
|
||||
|
||||
return $relPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize file path for local file system access.
|
||||
*
|
||||
* Converts URLs to local file paths when the base path is local.
|
||||
* Handles DOCUMENT_ROOT and relative paths.
|
||||
*
|
||||
* @param string $path File path or URL
|
||||
* @return string Normalized path
|
||||
*/
|
||||
public static function normalizeLocalFilePath($path)
|
||||
{
|
||||
$tr = parse_url($path);
|
||||
$lp = __FILE__;
|
||||
$ap = realpath($lp);
|
||||
$ap = str_replace("\\", '/', $ap);
|
||||
$docroot = substr($ap, 0, strpos($ap, $lp));
|
||||
|
||||
// WriteHTML parses all paths to full URLs; may be local file name
|
||||
// DOCUMENT_ROOT is not returned on IIS
|
||||
if (!empty($tr['scheme']) && !empty($tr['host']) && !empty($_SERVER['DOCUMENT_ROOT'])) {
|
||||
return $_SERVER['DOCUMENT_ROOT'] . $tr['path'];
|
||||
}
|
||||
|
||||
if ($docroot) {
|
||||
return $docroot . $tr['path'];
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
4
vendor/mpdf/mpdf/src/Writer/BaseWriter.php
vendored
4
vendor/mpdf/mpdf/src/Writer/BaseWriter.php
vendored
@@ -32,7 +32,7 @@ public function write($s, $ln = true)
|
||||
if ($this->mpdf->state === 2) {
|
||||
$this->endPage($s, $ln);
|
||||
} else {
|
||||
$this->mpdf->buffer .= $s . ($ln ? "\n" : '');
|
||||
$this->mpdf->buffer->append($s, $ln);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public function object($obj_id = false, $onlynewobj = false)
|
||||
|
||||
// Begin a new object
|
||||
if (!$onlynewobj) {
|
||||
$this->mpdf->offsets[$obj_id] = strlen($this->mpdf->buffer);
|
||||
$this->mpdf->offsets[$obj_id] = $this->mpdf->buffer->getLength();
|
||||
$this->write($obj_id . ' 0 obj');
|
||||
$this->mpdf->currentObjectNumber = $obj_id; // for later use with encryption
|
||||
}
|
||||
|
||||
@@ -801,7 +801,7 @@ public function writeTrailer() // _puttrailer
|
||||
$this->writer->write('/Encrypt ' . $this->mpdf->enc_obj_id . ' 0 R');
|
||||
$this->writer->write('/ID [<' . $this->protection->getUniqid() . '> <' . $this->protection->getUniqid() . '>]');
|
||||
} else {
|
||||
$uniqid = md5(time() . $this->mpdf->buffer);
|
||||
$uniqid = md5(time() . $this->mpdf->buffer->getHash());
|
||||
$this->writer->write('/ID [<' . $uniqid . '> <' . $uniqid . '>]');
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/mpdf/mpdf/src/Writer/PageWriter.php
vendored
2
vendor/mpdf/mpdf/src/Writer/PageWriter.php
vendored
@@ -265,7 +265,7 @@ public function writePages() // _putpages
|
||||
$this->metadataWriter->writeAnnotations(); // mPDF 5.7.2
|
||||
|
||||
// Pages root
|
||||
$this->mpdf->offsets[1] = strlen($this->mpdf->buffer);
|
||||
$this->mpdf->offsets[1] = $this->mpdf->buffer->getLength();
|
||||
$this->writer->write('1 0 obj');
|
||||
$this->writer->write('<</Type /Pages');
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ public function writeResources() // _putresources
|
||||
$this->backgroundWriter->writePatterns();
|
||||
|
||||
// Resource dictionary
|
||||
$this->mpdf->offsets[2] = strlen($this->mpdf->buffer);
|
||||
$this->mpdf->offsets[2] = $this->mpdf->buffer->getLength();
|
||||
$this->writer->write('2 0 obj');
|
||||
$this->writer->write('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user