diff --git a/.env.example.complete b/.env.example.complete index 124296818..b4beb60cc 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -325,6 +325,14 @@ FILE_UPLOAD_SIZE_LIMIT=50 # Can be 'a4' or 'letter'. EXPORT_PAGE_SIZE=a4 +# Export PDF Command +# Set a command which can be used to convert a HTML file into a PDF file. +# When false this will not be used. +# String values represent the command to be called for conversion. +# Supports '{input_html_path}' and '{output_pdf_path}' placeholder values. +# Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}" +EXPORT_PDF_COMMAND=false + # Set path to wkhtmltopdf binary for PDF generation. # Can be 'false' or a path path like: '/home/bins/wkhtmltopdf' # When false, BookStack will attempt to find a wkhtmltopdf in the application diff --git a/app/Config/app.php b/app/Config/app.php index dda787f3f..67f31159f 100644 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -116,7 +116,6 @@ return [ // Application Service Providers 'providers' => ServiceProvider::defaultProviders()->merge([ // Third party service providers - Barryvdh\DomPDF\ServiceProvider::class, Barryvdh\Snappy\ServiceProvider::class, SocialiteProviders\Manager\ServiceProvider::class, diff --git a/app/Config/dompdf.php b/app/Config/exports.php similarity index 88% rename from app/Config/dompdf.php rename to app/Config/exports.php index 09dd91bcc..63cc2419d 100644 --- a/app/Config/dompdf.php +++ b/app/Config/exports.php @@ -1,23 +1,56 @@ 'A4', + 'letter' => 'Letter', +]; + $dompdfPaperSizeMap = [ 'a4' => 'a4', 'letter' => 'letter', ]; +$exportPageSize = env('EXPORT_PAGE_SIZE', 'a4'); + return [ - 'show_warnings' => false, // Throw an Exception on warnings from dompdf + // Set a command which can be used to convert a HTML file into a PDF file. + // When false this will not be used. + // String values represent the command to be called for conversion. + // Supports '{input_html_path}' and '{output_pdf_path}' placeholder values. + // Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}" + 'pdf_command' => env('EXPORT_PDF_COMMAND', false), - 'options' => [ + // 2024-04: Snappy/WKHTMLtoPDF now considered deprecated in regard to BookStack support. + 'snappy' => [ + 'pdf' => [ + 'enabled' => true, + 'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false), + 'timeout' => false, + 'options' => [ + 'outline' => true, + 'page-size' => $snappyPaperSizeMap[$exportPageSize] ?? 'A4', + ], + 'env' => [], + ], + 'image' => [ + 'enabled' => false, + 'binary' => '/usr/local/bin/wkhtmltoimage', + 'timeout' => false, + 'options' => [], + 'env' => [], + ], + ], + + 'dompdf' => [ /** * The location of the DOMPDF font directory. * @@ -101,7 +134,7 @@ return [ /** * Whether to enable font subsetting or not. */ - 'enable_fontsubsetting' => false, + 'enable_font_subsetting' => false, /** * The PDF rendering backend to use. @@ -165,7 +198,7 @@ return [ * * @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.) */ - 'default_paper_size' => $dompdfPaperSizeMap[env('EXPORT_PAGE_SIZE', 'a4')] ?? 'a4', + 'default_paper_size' => $dompdfPaperSizeMap[$exportPageSize] ?? 'a4', /** * The default paper orientation. @@ -268,15 +301,6 @@ return [ */ 'font_height_ratio' => 1.1, - /** - * Enable CSS float. - * - * Allows people to disabled CSS float support - * - * @var bool - */ - 'enable_css_float' => true, - /** * Use the HTML5 Lib parser. * @@ -286,5 +310,4 @@ return [ */ 'enable_html5_parser' => true, ], - ]; diff --git a/app/Config/snappy.php b/app/Config/snappy.php deleted file mode 100644 index a87ce805f..000000000 --- a/app/Config/snappy.php +++ /dev/null @@ -1,34 +0,0 @@ - 'A4', - 'letter' => 'Letter', -]; - -return [ - 'pdf' => [ - 'enabled' => true, - 'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false), - 'timeout' => false, - 'options' => [ - 'outline' => true, - 'page-size' => $snappyPaperSizeMap[env('EXPORT_PAGE_SIZE', 'a4')] ?? 'A4', - ], - 'env' => [], - ], - 'image' => [ - 'enabled' => false, - 'binary' => '/usr/local/bin/wkhtmltoimage', - 'timeout' => false, - 'options' => [], - 'env' => [], - ], -]; diff --git a/app/Entities/Tools/PdfGenerator.php b/app/Entities/Tools/PdfGenerator.php index d0c9158a9..7502c10ff 100644 --- a/app/Entities/Tools/PdfGenerator.php +++ b/app/Entities/Tools/PdfGenerator.php @@ -2,27 +2,32 @@ namespace BookStack\Entities\Tools; -use Barryvdh\DomPDF\Facade\Pdf as DomPDF; use Barryvdh\Snappy\Facades\SnappyPdf; +use Dompdf\Dompdf; class PdfGenerator { const ENGINE_DOMPDF = 'dompdf'; const ENGINE_WKHTML = 'wkhtml'; + const ENGINE_COMMAND = 'command'; /** * Generate PDF content from the given HTML content. */ public function fromHtml(string $html): string { - if ($this->getActiveEngine() === self::ENGINE_WKHTML) { + $engine = $this->getActiveEngine(); + + if ($engine === self::ENGINE_WKHTML) { $pdf = SnappyPDF::loadHTML($html); $pdf->setOption('print-media-type', true); - } else { - $pdf = DomPDF::loadHTML($html); + return $pdf->output(); + } else if ($engine === self::ENGINE_COMMAND) { + // TODO - Support PDF command + return ''; } - return $pdf->output(); + return $this->renderUsingDomPdf($html); } /** @@ -31,8 +36,45 @@ class PdfGenerator */ public function getActiveEngine(): string { - $useWKHTML = config('snappy.pdf.binary') !== false && config('app.allow_untrusted_server_fetching') === true; + $wkhtmlBinaryPath = config('snappy.pdf.binary'); + if (file_exists(base_path('wkhtmltopdf'))) { + $wkhtmlBinaryPath = base_path('wkhtmltopdf'); + } - return $useWKHTML ? self::ENGINE_WKHTML : self::ENGINE_DOMPDF; + if (is_string($wkhtmlBinaryPath) && config('app.allow_untrusted_server_fetching') === true) { + return self::ENGINE_WKHTML; + } + + return self::ENGINE_DOMPDF; + } + + protected function renderUsingDomPdf(string $html): string + { + $options = config('exports.dompdf'); + $domPdf = new Dompdf($options); + $domPdf->setBasePath(base_path('public')); + + $domPdf->loadHTML($this->convertEntities($html)); + $domPdf->render(); + + return (string) $domPdf->output(); + } + + /** + * Taken from https://github.com/barryvdh/laravel-dompdf/blob/v2.1.1/src/PDF.php + * Copyright (c) 2021 barryvdh, MIT License + * https://github.com/barryvdh/laravel-dompdf/blob/v2.1.1/LICENSE + */ + protected function convertEntities(string $subject): string + { + $entities = [ + '€' => '€', + '£' => '£', + ]; + + foreach ($entities as $search => $replace) { + $subject = str_replace($search, $replace, $subject); + } + return $subject; } } diff --git a/composer.json b/composer.json index b22c7b44d..94f64ec72 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ "ext-mbstring": "*", "ext-xml": "*", "bacon/bacon-qr-code": "^2.0", - "barryvdh/laravel-dompdf": "^2.0", "barryvdh/laravel-snappy": "^1.0", "doctrine/dbal": "^3.5", + "dompdf/dompdf": "^2.0", "guzzlehttp/guzzle": "^7.4", "intervention/image": "^3.5", "laravel/framework": "^10.10", diff --git a/composer.lock b/composer.lock index 24c2215dd..657a5a7fb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ccfc07d0ecc580962915a0457f0466a7", + "content-hash": "c0c5a3169cb23d9ab8e34324202d4c37", "packages": [ { "name": "aws/aws-crt-php", @@ -209,83 +209,6 @@ }, "time": "2022-12-07T17:46:57+00:00" }, - { - "name": "barryvdh/laravel-dompdf", - "version": "v2.1.1", - "source": { - "type": "git", - "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "cb37868365f9b937039d316727a1fced1e87b31c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/cb37868365f9b937039d316727a1fced1e87b31c", - "reference": "cb37868365f9b937039d316727a1fced1e87b31c", - "shasum": "" - }, - "require": { - "dompdf/dompdf": "^2.0.3", - "illuminate/support": "^6|^7|^8|^9|^10|^11", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "larastan/larastan": "^1.0|^2.7.0", - "orchestra/testbench": "^4|^5|^6|^7|^8|^9", - "phpro/grumphp": "^1 || ^2.5", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - }, - "laravel": { - "providers": [ - "Barryvdh\\DomPDF\\ServiceProvider" - ], - "aliases": { - "Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf", - "PDF": "Barryvdh\\DomPDF\\Facade\\Pdf" - } - } - }, - "autoload": { - "psr-4": { - "Barryvdh\\DomPDF\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "description": "A DOMPDF Wrapper for Laravel", - "keywords": [ - "dompdf", - "laravel", - "pdf" - ], - "support": { - "issues": "https://github.com/barryvdh/laravel-dompdf/issues", - "source": "https://github.com/barryvdh/laravel-dompdf/tree/v2.1.1" - }, - "funding": [ - { - "url": "https://fruitcake.nl", - "type": "custom" - }, - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2024-03-15T12:48:39+00:00" - }, { "name": "barryvdh/laravel-snappy", "version": "v1.0.3", @@ -1127,16 +1050,16 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.4", + "version": "v2.0.7", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" + "reference": "ab0123052b42ad0867348f25df8c228f1ece8f14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/ab0123052b42ad0867348f25df8c228f1ece8f14", + "reference": "ab0123052b42ad0867348f25df8c228f1ece8f14", "shasum": "" }, "require": { @@ -1144,7 +1067,7 @@ "ext-mbstring": "*", "masterminds/html5": "^2.0", "phenx/php-font-lib": ">=0.5.4 <1.0.0", - "phenx/php-svg-lib": ">=0.3.3 <1.0.0", + "phenx/php-svg-lib": ">=0.5.2 <1.0.0", "php": "^7.1 || ^8.0" }, "require-dev": { @@ -1183,9 +1106,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" + "source": "https://github.com/dompdf/dompdf/tree/v2.0.7" }, - "time": "2023-12-12T20:19:39+00:00" + "time": "2024-04-15T12:40:33+00:00" }, { "name": "dragonmantank/cron-expression", @@ -4067,16 +3990,16 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.5.3", + "version": "0.5.4", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "0e46722c154726a5f9ac218197ccc28adba16fcf" + "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/0e46722c154726a5f9ac218197ccc28adba16fcf", - "reference": "0e46722c154726a5f9ac218197ccc28adba16fcf", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691", + "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691", "shasum": "" }, "require": { @@ -4107,9 +4030,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.3" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4" }, - "time": "2024-02-23T20:39:24+00:00" + "time": "2024-04-08T12:52:34+00:00" }, { "name": "phpoption/phpoption", diff --git a/readme.md b/readme.md index 17e1a05f6..5adcc06bb 100644 --- a/readme.md +++ b/readme.md @@ -142,7 +142,6 @@ Note: This is not an exhaustive list of all libraries and projects that would be * [Google Material Icons](https://github.com/google/material-design-icons) - _[Apache-2.0](https://github.com/google/material-design-icons/blob/master/LICENSE)_ * [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists) - _[MIT](https://github.com/markdown-it/markdown-it/blob/master/LICENSE) and [ISC](https://github.com/revin/markdown-it-task-lists/blob/master/LICENSE)_ * [Dompdf](https://github.com/dompdf/dompdf) - _[LGPL v2.1](https://github.com/dompdf/dompdf/blob/master/LICENSE.LGPL)_ -* [BarryVD/Dompdf](https://github.com/barryvdh/laravel-dompdf) - _[MIT](https://github.com/barryvdh/laravel-dompdf/blob/master/LICENSE)_ * [BarryVD/Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy) - _[MIT](https://github.com/barryvdh/laravel-snappy/blob/master/LICENSE)_ * [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html) - _[LGPL v3.0](https://github.com/wkhtmltopdf/wkhtmltopdf/blob/master/LICENSE)_ * [diagrams.net](https://github.com/jgraph/drawio) - _[Embedded Version Terms](https://www.diagrams.net/trust/) / [Source Project - Apache-2.0](https://github.com/jgraph/drawio/blob/dev/LICENSE)_