Giter Site home page Giter Site logo

gotenberg-php's Introduction

Gotenberg PHP Logo

Gotenberg PHP

A PHP client for interacting with Gotenberg

Latest Version Total Downloads Continuous Integration https://codecov.io/gh/gotenberg/gotenberg


This package is a PHP client for Gotenberg, a developer-friendly API to interact with powerful tools like Chromium and LibreOffice for converting numerous document formats (HTML, Markdown, Word, Excel, etc.) into PDF files, and more!

⚠️

For Gotenberg 6.x, use thecodingmachine/gotenberg-php-client instead.

For Gotenberg 7.x, use version v1.1.8.

Quick Examples

You may convert a target URL to PDF and save it to a given directory:

use Gotenberg\Gotenberg;

// Converts a target URL to PDF and saves it to a given directory.
$filename = Gotenberg::save(
    Gotenberg::chromium($apiUrl)->pdf()->url('https://my.url'), 
    $pathToSavingDirectory
);

You may also convert Office documents and merge them:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

// Converts Office documents to PDF and merges them.
$response = Gotenberg::send(
    Gotenberg::libreOffice($apiUrl)
        ->merge()
        ->convert(
            Stream::path($pathToDocx),
            Stream::path($pathToXlsx)
        )
);

Requirement

This packages requires Gotenberg, a Docker-powered stateless API for PDF files.

See the installation guide for more information.

Installation

This package can be installed with Composer:

composer require gotenberg/gotenberg-php

We use PSR-7 HTTP message interfaces (i.e., RequestInterface and ResponseInterface) and the PSR-18 HTTP client interface (i.e., ClientInterface).

For the latter, you may need an adapter in order to use your favorite client library. Check the available adapters:

If you're not sure which adapter you should use, consider using the php-http/guzzle7-adapter:

composer require php-http/guzzle7-adapter

Usage

Send a request to the API

After having created the HTTP request (see below), you have two options:

  1. Get the response from the API and handle it according to your need.
  2. Save the resulting file to a given directory.

In the following examples, we assume the Gotenberg API is available at http://localhost:3000.

Get a response

You may use any HTTP client that is able to handle a PSR-7 RequestInterface to call the API:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->url('https://my.url');
    
$response = $client->sendRequest($request);

If you have a PSR-18 compatible HTTP client (see Installation), you may also use Gotenberg::send:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->url('https://my.url');

try {
    $response = Gotenberg::send($request);
    return $response;
} catch (GotenbergApiErrored $e) {
    // $e->getResponse();
}

This helper will parse the response and if it is not 2xx, it will throw an exception. That's especially useful if you wish to return the response directly to the browser.

You may also explicitly set the HTTP client:

use Gotenberg\Gotenberg;

$response = Gotenberg::send($request, $client);

Save the resulting file

If you have a PSR-18 compatible HTTP client (see Installation), you may use Gotenberg::save:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->url('https://my.url');
    
$filename = Gotenberg::save($request, '/path/to/saving/directory');

It returns the filename of the resulting file. By default, Gotenberg creates a UUID filename (i.e., 95cd9945-484f-4f89-8bdb-23dbdd0bdea9) with either a .zip or a .pdf file extension.

You may also explicitly set the HTTP client:

use Gotenberg\Gotenberg;

$response = Gotenberg::save($request, $pathToSavingDirectory, $client);

Filename

You may override the output filename with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->outputFilename('my_file')
    ->url('https://my.url');

Gotenberg will automatically add the correct file extension.

Trace or request ID

By default, Gotenberg creates a UUID trace that identifies a request in its logs. You may override its value thanks to:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->trace('debug')
    ->url('https://my.url');

It will set the header Gotenberg-Trace with your value. You may also override the default header name:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium('http://localhost:3000')
    ->pdf()
    ->trace('debug', 'Request-Id')
    ->url('https://my.url');

Please note that it should be the same value as defined by the --api-trace-header Gotenberg's property.

The response from Gotenberg will also contain the trace header. In case of error, both the Gotenberg::send and Gotenberg::save methods throw a GotenbergApiErroed exception that provides the following method for retrieving the trace:

use Gotenberg\Exceptions\GotenbergApiErrored;
use Gotenberg\Gotenberg;

try {
    $response = Gotenberg::send(
        Gotenberg::chromium('http://localhost:3000')
            ->pdf()
            ->url('https://my.url')
    );
} catch (GotenbergApiErrored $e) {
    $trace = $e->getGotenbergTrace();
    // Or if you override the header name:
    $trace = $e->getGotenbergTrace('Request-Id');
}

Chromium

The Chromium module interacts with the Chromium browser to convert HTML documents to PDF or capture screenshots.

Convert a target URL to PDF

See https://gotenberg.dev/docs/routes#url-into-pdf-route.

Converting a target URL to PDF is as simple as:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->url('https://my.url');

Convert an HTML document to PDF

See https://gotenberg.dev/docs/routes#html-file-into-pdf-route.

You may convert an HTML document with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->html(Stream::path('/path/to/file.html'));

Or with an HTML string:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->html(Stream::string('my.html', $someHtml));

Please note that it automatically sets the filename to index.html, as required by Gotenberg, whatever the value you're using with the Stream class.

You may also send additional files, like images, fonts, stylesheets, and so on. The only requirement is that their paths in the HTML DOM are on the root level.

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->assets(
        Stream::path('/path/to/my.css'),
        Stream::path('/path/to/my.js')
    )
    ->html(Stream::path('/path/to/file.html'));

Convert one or more markdown files to PDF

See https://gotenberg.dev/docs/routes#markdown-files-into-pdf-route.

You may convert markdown files with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->markdown(
        Stream::path('/path/to/my_wrapper.html'),
        Stream::path('/path/to/file.md')
    );

The first argument is a Stream with HTML content, for instance:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>My PDF</title>
  </head>
  <body>
    {{ toHTML "file.md" }}
  </body>
</html>

Here, there is a Go template function toHTML. Gotenberg will use it to convert a markdown file's content to HTML.

Like the HTML conversion, you may also send additional files, like images, fonts, stylesheets, and so on. The only requirement is that their paths in the HTML DOM are on the root level.

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->assets(
        Stream::path('/path/to/my.css'),
        Stream::path('/path/to/my.js')
    )
    ->markdown(
        Stream::path('/path/to/file.html'),
        Stream::path('/path/to/my.md'),
        Stream::path('/path/to/my2.md')
    );

Single page

You may print the entire content in one single page with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->singlePage()
    ->url('https://my.url');

Paper size

You may override the default paper size with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->paperSize($width, $height)
    ->url('https://my.url');

Examples of paper size (width x height, in inches):

  • Letter - 8.5 x 11 (default)
  • Legal - 8.5 x 14
  • Tabloid - 11 x 17
  • Ledger - 17 x 11
  • A0 - 33.1 x 46.8
  • A1 - 23.4 x 33.1
  • A2 - 16.54 x 23.4
  • A3 - 11.7 x 16.54
  • A4 - 8.27 x 11.7
  • A5 - 5.83 x 8.27
  • A6 - 4.13 x 5.83

Margins

You may override the default margins (i.e., 0.39):

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->margins($top, $bottom, $left, $right)
    ->url('https://my.url');

Prefer CSS page size

You may force page size as defined by CSS:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->preferCssPageSize()
    ->url('https://my.url');

Print the background graphics

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->printBackground()
    ->url('https://my.url');

You may also hide the default white background and allow generating PDFs with transparency with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->printBackground()
    ->omitBackground()
    ->url('https://my.url');

The rules regarding the printBackground and omitBackground form fields are the following:

  • If printBackground is set to false, no background is printed.
  • If printBackground is set to true:
    • If the HTML document has a background, that background is used.
    • If not:
      • If omitBackground is set to true, the default background is transparent.
      • If not, the default white background is used.

Landscape orientation

You may override the default portrait orientation with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->landscape()
    ->url('https://my.url');

Scale

You may override the default scale of the page rendering (i.e., 1.0) with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->scale(2.0)
    ->url('https://my.url');

Page ranges

You may set the page ranges to print, e.g., 1-5, 8, 11-13. Empty means all pages.

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->nativePageRanges('1-2')
    ->url('https://my.url');

Header and footer

You may add a header and/or a footer to each page of the PDF:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->header(Stream::path('/path/to/my_header.html'))
    ->footer(Stream::path('/path/to/my_footer.html'))
    ->url('https://my.url');

Please note that it automatically sets the filenames to header.html and footer.html, as required by Gotenberg, whatever the value you're using with the Stream class.

Wait delay

When the page relies on JavaScript for rendering, and you don't have access to the page's code, you may want to wait a certain amount of time (i.e., 1s, 2ms, etc.) to make sure Chromium has fully rendered the page you're trying to generate.

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->waitDelay('3s')
    ->url('https://my.url');

Wait for expression

You may also wait until a given JavaScript expression returns true:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->waitForExpression("window.globalVar === 'ready'")
    ->url('https://my.url');

Emulate media type

Some websites have dedicated CSS rules for print. Using screen allows you to force the "standard" CSS rules:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->emulateScreenMediaType()
    ->url('https://my.url');

You may also force the print media type with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->emulatePrintMediaType()
    ->url('https://my.url');

Cookies

You may add ccookies to store in the Chromium cookie jar:

use Gotenberg\Modules\ChromiumCookie;
use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->cookies([
        new ChromiumCookie(name: 'yummy_cookie', value: 'choco', domain: 'theyummycookie.com'),
        new ChromiumCookie(name: 'vanilla_cookie', value: 'vanilla', domain: 'theyummycookie.com', path: '/', secure: true, httpOnly: true, sameSite: 'Lax'),
    ])
    ->url('https://my.url');

Extra HTTP headers

You may add HTTP headers that Chromium will send when loading the HTML document:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->extraHttpHeaders([
        'My-Header-1' => 'My value',
        'My-Header-2' => 'My value'
    ])
    ->url('https://my.url');

Invalid HTTP status codes

You may force Gotenberg to return a 409 Conflict response if the HTTP status code from the main page is not acceptable:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->failOnHttpStatusCodes([499])
    ->url('https://my.url');

A X99 entry means every HTTP status codes between X00 and X99 (e.g., 499 means every HTTP status codes between 400 and 499).

Fail on console exceptions

You may force Gotenberg to return a 409 Conflict response if there are exceptions in the Chromium console:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->failOnConsoleExceptions()
    ->url('https://my.url');

Performance mode

Gotenberg, by default, waits for the network idle event to ensure that the majority of the page is rendered during conversion. However, this often significantly slows down the conversion process. Setting skipNetworkEventIdle form field to true can greatly enhance the conversion speed.

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->skipNetworkIdleEvent()
    ->url('https://my.url');

PDF/A & PDF/UA

See https://gotenberg.dev/docs/routes#pdfa-chromium.

You may set the PDF/A format and enable PDF/UA for the resulting PDF with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->pdfFormat('PDF/A-1a')
    ->pdfua()
    ->url('https://my.url');

Metadata

See https://gotenberg.dev/docs/routes#metadata-chromium.

You may set the metadata to write with:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->pdf()
    ->metadata(['Producer' => 'Gotenberg'])
    ->url('https://my.url');

Screenshots

You can capture full-page screenshots using the following three routes, which function similarly to their PDF equivalents:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->screenshot()
    ->png()
    ->optimizeForSpeed()
    ->url('https://my.url');
use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->screenshot()
    ->jpeg()
    ->quality(50)
    ->assets(
        Stream::path('/path/to/my.css'),
        Stream::path('/path/to/my.js')
    )
    ->html(Stream::path('/path/to/file.html'));
use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::chromium($apiUrl)
    ->screenshot()
    ->webp()
    ->markdown(
        Stream::path('/path/to/my_wrapper.html'),
        Stream::path('/path/to/file.md')
    );

LibreOffice

The LibreOffice module interacts with LibreOffice to convert documents to PDF, thanks to unoconv.

Convert documents to PDF

See https://gotenberg.dev/docs/routes#office-documents-into-pdfs-route.

Converting a document to PDF is as simple as:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->convert(Stream::path('/path/to/my.docx'));

If you send many documents, Gotenberg will return a ZIP archive with the PDFs:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->outputFilename('archive')
    ->convert(
        Stream::path('/path/to/my.docx'),
        Stream::path('/path/to/my.xlsx')
    );

// $filename = archive.zip
$filename = Gotenberg::save($request, $pathToSavingDirectory);

You may also merge them into one unique PDF:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->merge()
    ->outputFilename('merged')
    ->convert(
        Stream::path('/path/to/my.docx'),
        Stream::path('/path/to/my.xlsx')
    );

// $filename = merged.pdf
$filename = Gotenberg::save($request, $pathToSavingDirectory);

Please note that the merging order is determined by the order of the arguments.

Landscape orientation

You may override the default portrait orientation with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->landscape()
    ->convert(Stream::path('/path/to/my.docx'));

Page ranges

You may set the page ranges to print, e.g., 1-4. Empty means all pages.

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->nativePageRanges('1-2')
    ->convert(Stream::path('/path/to/my.docx'));

⚠️ The page ranges are applied to all files independently.

Export form fields

You may set whether to export the form fields or to use the inputted/selected content of the fields:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->exportFormFields(false)
    ->convert(Stream::path('/path/to/my.docx'));

Single page sheets

You may set whether to render the entire spreadsheet as a single page:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->singlePageSheets()
    ->convert(Stream::path('/path/to/my.xlsx'));

PDF/A & PDF/UA

See https://gotenberg.dev/docs/routes#pdfa-libreoffice.

You may set the PDF/A format and enable PDF/UA for the resulting PDF(s) with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->pdfa('PDF/A-1a')
    ->pdfua()
    ->convert(Stream::path('/path/to/my.docx'));

Metadata

See https://gotenberg.dev/docs/routes#metadata-libreoffice.

You may set the metadata to write with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::libreOffice($apiUrl)
    ->metadata(['Producer' => 'Gotenberg'])
    ->convert(Stream::path('/path/to/my.docx'));

PDF Engines

The PDF Engines module gathers all engines that can manipulate PDF files.

Merge PDFs

See https://gotenberg.dev/docs/routes#merge-pdfs-route.

Merging PDFs is as simple as:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->merge(
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf')
    );

Please note that the merging order is determined by the order of the arguments.

You may also set the PDF/A format and enable PDF/UA for the resulting PDF with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->pdfa('PDF/A-1a')
    ->pdfua()
    ->merge(
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf'),
        Stream::path('/path/to/my3.pdf')
    );

You may also set the metadata to write with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->metadata(['Producer' => 'Gotenberg'])
    ->merge(
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf'),
        Stream::path('/path/to/my3.pdf')
    );

Convert to a specific PDF format

See https://gotenberg.dev/docs/routes#convert-into-pdfa-route.

You may convert a PDF to a specific PDF/A format and enable PDF/UA with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->pdfua()
    ->convert(
        'PDF/A-1a'
        Stream::path('/path/to/my.pdf')
    );

If you send many PDFs, Gotenberg will return a ZIP archive with the PDFs:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->outputFilename('archive')
    ->convert(
        'PDF/A-1a',
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf'),
        Stream::path('/path/to/my3.pdf')
    );

// $filename = archive.zip
$filename = Gotenberg::save($request, $pathToSavingDirectory);

Read PDF metadata

See https://gotenberg.dev/docs/routes#read-pdf-metadata-route

⚠️ You cannot use the Gotenberg::save method if you're using this feature.

You may retrieve one or more PDFs metadata with:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->readMetadata(
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf')
    );

This request returns a JSON formatted response with the structure filename => metadata.

Write PDF metadata

See https://gotenberg.dev/docs/routes#write-pdf-metadata-route

You may write specified metadata to one or more PDFs:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->writeMetadata(
        [ 'Producer' => 'Gotenberg' ],
        Stream::path('/path/to/my.pdf')
    );

If you send many PDFs, Gotenberg will return a ZIP archive with the PDFs:

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->outputFilename('archive')
    ->writeMetadata(
        [ 'Producer' => 'Gotenberg' ],
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf'),
        Stream::path('/path/to/my3.pdf')
    );

// $filename = archive.zip
$filename = Gotenberg::save($request, $pathToSavingDirectory);

Webhook

The Webhook module is a Gotenberg middleware that sends the API responses to callbacks.

⚠️ You cannot use the Gotenberg::save method if you're using the webhook feature.

For instance:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->webhook('https://my.webhook.url', 'https://my.webhook.error.url')
    ->pdf()
    ->url('https://my.url'); 

You may also override the default HTTP method (POST) that Gotenberg will use to call the webhooks:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->webhook('https://my.webhook.url', 'https://my.webhook.error.url')
    ->webhookMethod('PATCH')
    ->webhookErrorMethod('PUT')
    ->pdf()
    ->url('https://my.url');

You may also tell Gotenberg to add extra HTTP headers that it will send alongside the request to the webhooks:

use Gotenberg\Gotenberg;

$request = Gotenberg::chromium($apiUrl)
    ->webhook('https://my.webhook.url', 'https://my.webhook.error.url')
    ->webhookExtraHttpHeaders([
        'My-Header-1' => 'My value',
        'My-Header-2' => 'My value'    
    ])
    ->pdf()
    ->url('https://my.url');

gotenberg-php's People

Contributors

alexskrypnyk avatar changingterry avatar dependabot[bot] avatar dontfreakout avatar gulien avatar rreynier avatar vidschofelix avatar yanbuatois avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gotenberg-php's Issues

Wrong merge order if > 26 files

refs #9

your Index class produces something like

A B C D E F ... AA AB AC ...

except when sorting, AB comes before B, so it is sorted wrongly.

I recommend deleting your Index class and using something like this (untested):

    public function merge(Stream $pdf1, Stream $pdf2, Stream ...$pdfs): RequestInterface
    {
        foreach ([$pdf1, $pdf2, ...$pdfs] as $pdf) {
            $this->formFile(hrtime(true) . '_' . $pdf->getFilename(), $pdf->getStream());
        }

        $this->endpoint = '/forms/pdfengines/merge';

        return $this->request();
    }

Upload Merged File to S3

How can we upload merged file to S3 without storing it to local storage.
Here is my code.

`$array=[Stream::path($file_name),Stream::path($file_name),Stream::path($file_name)];

$request = Gotenberg::libreOffice("https://demo.gotenberg.dev")
->outputFilename('merged')
->merge()
->convert(...$array)`

Laravel 8

Does it works with Laravel 8?

I tried to install and use it, but I got the error below:

TypeError
Symfony\Component\HttpFoundation\Response::setContent(): Argument #1 ($content) must be of type ?string, Nyholm\Psr7\Request given, called in ../vendor/laravel/framework/src/Illuminate/Http/Response.php on line 72 

Content of ->html(Stream::string('index.html', $html)) is not added to PDF when header and/or footer are added to each page of the PDF

If I add a header and/or footer to each page of the PDF, the main content between header and footer is missing
when using the string() method of Stream class:
->html(Stream::string('index.html', $html));

If I use the path() method of the Stream class instead, it works:
->html(Stream::path('/var/www/html/public/test.html'));

When I comment out header() and footer() chained methods,
->html(Stream::string('index.html', $html));
is also working.

Is this a bug or am I missing something?

This is my test script:

<?php

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

require_once "vendor/autoload.php";

//$html = file_get_contents('/var/www/html/public/test.html');

$chromium = Gotenberg::chromium('http://gotenberg:3000')
    //->pdf() // uncomment for gotenberg/gotenberg-php ^2.0; Same results on version 2.0.0
    ->header(Stream::path('http://nginx:80/header/de'))
    ->footer(Stream::path('http://nginx:80/footer/de'))


    // With this, main content will not be printed to PDF if header() and/or footer() are also chained;
    // If header() and footer() are commented out, main content is printed correctly to PDF
    //->html(Stream::string('index.html', $html));


    // with this, main content is ALWAYS printed correctly to PDF
    ->html(Stream::path('/var/www/html/public/test.html'));

$response = Gotenberg::send($chromium);
file_put_contents('/var/www/html/public/test.pdf', $response->getBody()->getContents());

echo "done.\n";

Error when passing associative array to merge function

I'm getting an error when trying to pass an associative array to the merge call.

There are actually two errors I'm getting, the first happens when trying to pass it like normal with argument unpacking:

   $streams = array_map(
        fn($long_url) => Stream::path($long_url),
        $keyed_array_of_urls
    );

    $request = Gotenberg::pdfEngines($apiUrl)
        ->outputFilename('requested-name')
        ->merge(
            ...$streams
        );

The error I get is: Too few arguments to function Gotenberg\Modules\PdfEngines::merge(), 0 passed

So to remedy that and match the function signature, I use array_shift() to match:

    $request = Gotenberg::pdfEngines($apiUrl)
        ->outputFilename('requested-name')
        ->merge(
            array_shift$streams),
            array_shift$streams),
            ...$streams
        );

This gives me the error message: Unsupported operand types: string + int from vendor/gotenberg/gotenberg-php/src/Modules/PdfEngines.php:41

I'm currently getting around this by simply using array_values() and not passing an associative array.

    $request = Gotenberg::pdfEngines($apiUrl)
        ->outputFilename('requested-name')
        ->merge(
            ...array_values($streams)
        );

Just thought it might be worth bringing to your attention. Thanks for all the hard work!

not working php:8.3.4

php:8.3.4
gotenberg:8.3.0
Executing the following code always returns:code=405, message=Method Not Allowed
$request = Gotenberg::libreOffice("http://gotenberg:3000") ->convert(Stream::path(BASE_PATH . '/storage/pdf/2023.docx')); Gotenberg::save($request, BASE_PATH . '/storage');

Docker logs
{"level":"error","ts":1712074302.3096998,"logger":"api","msg":"code=405, message=Method Not Allowed","trace":"86ea7b13-eeb4-4cb6-b208-b6eca9267db6","remote_ip":"172.19.0.3","host":"gotenberg:3000","uri":"/forms/libreoffice/convert","method":"PUT","path":"/forms/libreoffice/convert","referer":"","user_agent":"GuzzleHttp/7","status":405,"latency":58400,"latency_human":"58.4µs","bytes_in":0,"bytes_out":18}

[Support] GuzzleHttp\Psr7\Stream vs Gotenberg\Stream

Greetings!

I am sorry to pollute your ticket stream with a support request. 😞

✅ I have successfully implemented the gotenberg (v7) docker image and this library into my Symfony-based project.
✅ I have successfully "merged" its use with FlySystem via the OneupFlysystemBundle
✅ I am successfully producing merged pdfs from sources of html & office docs and storing them to AWS/S3 via the AwsS3 Flysystem adapter!

So all, in all, I am quite happy with the end product. I have one kludgy bit however, which I wondered if you might assist me.

Flysystem works well with Streams. But not directly with your Stream class. Therefore I end up doing something like this several times in my project:

    use Gotenberg\Stream;
    use GuzzleHttp\Psr7\Stream as Psr7Stream;

        ....

        $streams = [];
        foreach ($mountPaths as $mountPath) {
            $psr7Stream = new Psr7Stream($this->mountManager->readStream($mountPath));
            $streams[] = new Stream('file.pdf', $psr7Stream);
        }
        $request = $this->gotenberg->pdfEngines()
            ->outputFilename($destination)
            ->merge(...$streams);

(my gotenberg instance above is simply a wrapper of yours in order to include other services with DI)

You can see the gymnastics I am doing to first create the Psr7Stream (readStream returns a resource), then secondly create an instead of Stream.

Is there a cleaner way to do this? Can I create a Gotenberg/Stream directly from a resource or handle this differently?

Secondly, I'd like to write a stream directly from the response. Currently I do this:

        $response = $this->send($request, $client);
        ...
        $this->mountManager->write($mountPath.$filename, $response->getBody()->getContents());

I'd prefer to use Flysystem's writeStream method here if possible, Is it possible to get a Stream from the response?


As I said, I apologize in advance for the support request. I'm sure you're rolling your eyes at my stupidity 🙄 🤣 . Thanks in advance! 🙇

Custom header and footer no rendered.

Hi,

I can't figure out what I am do wrong when setting header and footer, or if this is a bug.
PHP is in version 8.2.12
Gotenberg docker version 8.3.0

If I do not set them, nothing in pdf file. --> ok
If I set them to "", default browser values. --> ok

$req->header(Stream::string($rootDir."header.html", "")); 
$req->footer(Stream::string($rootDir."footer.html', ""));

image

If I set anything else, nothing appears.

$req = Gotenberg::chromium('http://gotenberg:3000')->pdf();
$req->outputFilename('test');
$req->header(Stream::string($rootDir.'header.html', '<html><head></head><body>HEADER</body></html>'));
$req->footer(Stream::string($rootDir.'footer.html', '<html><head></head><body>FOOTER</body></html>'));
$req = $req->html(Stream::string($rootDir.'html.html', '<html><head></head><body>CONTENT '.date('Y-m-d H:i:s').'</body></html>'));
$res = Gotenberg::save($req, $rootDir);

image

Merge of long urls pointing to PDFs failing

I have a situation where I have files sitting in an S3/GCS bucket and need to merge certain files from that bucket. Since cloud storage isn't treated the same as local storage by gotenberg, we use temporary URLs from the bucket to merge certain files together. These temporary URLs are very long (sometimes 400+ characters) and this seems to cause an error with the gotenberg API.

    $streams = collect($long_urls)->map(
        fn($long_url) => Stream::path($long_url)
    );

    $request = Gotenberg::pdfEngines($apiUrl)
        ->outputFilename('requested-name')
        ->merge(
            ...$streams
        );

When I run this code with the long urls, I get a Gotenberg\Exceptions\GotenbergApiErroed error and if I check the gotenberg docker container, it says

{
   "level":"error",
   "ts":1641567947.0926168,
   "logger":"api",
   "msg":"create request context: copy to disk: create local file: open /tmp/aabf345b-68eb-457a-bbcb-728cc3813e1f/0_2021%20AR%20Help%20Manual%2010-27-2021.pdf?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQPF2CX2ONHXT3XG3%2F20220107%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220107T150546Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Signature=75620efd0a5e1c3520c398d50ea51c434b200e9785d830ddc350c14dbe714b4a: file name too long",
   "trace":"2aa4913a-534a-41af-911b-90296e43adc7",
   "remote_ip":"172.18.0.8",
   "host":"gotenberg:3000",
   "uri":"/forms/pdfengines/merge",
   "method":"POST",
   "path":"/forms/pdfengines/merge",
   "referer":"",
   "user_agent":"Symfony HttpClient/Curl",
   "status":500,
   "latency":5535083,
   "latency_human":"5.535083ms",
   "bytes_in":3083724,
   "bytes_out":21
}

I'm not sure if this is because of code changes between gotenberg/gotenberg 6 => 7 or from thecodingmachine/gotenberg => gotenberg/gotenberg-php but was wondering if I could get some help.

Laravel Sail Internal URLs not working 8.2.0

I'm having an issue on 8.2.0 (Maybe related to gotenberg/gotenberg#403?)

Using Laravel + Sail on WSL2

docker-compose.yml
    gotenberg:
        image: gotenberg/gotenberg:8
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${FORWARD_GOTENBERG_PORT:-3000}:3000'
        volumes:
            - './public/fonts:/usr/local/share/fonts'
        command:
            - "gotenberg"
            - "--log-level=debug"
        networks:
            - sail

ive made a static page at /sample which literally says just "Hello, World!"

from inside the gotenberg container curl http://laravel.test/sample works fine

I can run the following from inside the laravel app container (not the gotenberg container)

curl \
--request POST http://gotenberg:3000/forms/chromium/convert/url \
--form url=http://laravel.test/sample \
-o my.pdf

it works fine, my.pdf appears in the project root. with the words "Hello, World!" on it.

But from the application when I run (gotenberg/gotenberg-php)

$request = Gotenberg::chromium(config('gotenberg.url'))
                            ->pdf()
                            ->failOnConsoleExceptions()
                            ->outputFilename('my-custom-pdf')
                            ->url('http://laravel.test:80/sample');

        $response = Gotenberg::send($request);

        return $response
            ->withHeader('Content-Type', 'application/pdf')
            ->withHeader('Content-Disposition', 'inline; filename="generated.pdf"');

I keep getting:

ypa-filament-app-gotenberg-1  | {"level":"error","ts":1709274087.9005635,"logger":"api","msg":"convert URL to PDF: conv
ert to PDF: context deadline exceeded","trace":"efa04a81-fb5a-4cfe-abb3-80e0d6e81a00","remote_ip":"172.23.0.8","host":"
gotenberg:3000","uri":"/forms/chromium/convert/url","method":"POST","path":"/forms/chromium/convert/url","referer":"","
user_agent":"GuzzleHttp/7","status":503,"latency":30000270232,"latency_human":"30.000270232s","bytes_in":316,"bytes_out":19}

P.S. if i call ->html(Stream::string('sample', view('sample')->render())) though it does work. its only url() thats the problem. But if I have any images in the view the same timeout happens. The image urls also are something like 'http://localhost/img/example.jpg' and I don't think the Gotenberg container can resolve localhost so I'm not even sure what the correct implementation is.

Been fighting this all day. Please help 🙏

Request times out, while testing locally

My Php code
$request = Gotenberg::chromium('http://127.0.0.1:3000') ->url("http://host.docker.internal:8000/invoice/view");
$response = Gotenberg::send($request);
OS is ubuntu 22.
Docker container was started using docker run --rm --add-host host.docker.internal:host-gateway -p 3000:3000 gotenberg/gotenberg:7

Was able to successfully curl from within the docker instance by following the commands
docker exec -it <hash> bash; curl "http://host.docker.internal:8001/invoice/view"

Docker logs
"
{"level":"error","ts":1704128572.4625182,"logger":"api","msg":"convert URL to PDF: convert to PDF: context deadline exceeded","trace":"ba64d68d-0eb2-4834-831a-8db4d8415904","remote_ip":"172.17.0.1","host":"127.0.0.1:3000","uri":"/forms/chromium/convert/url","method":"POST","path":"/forms/chromium/convert/url","referer":"","user_agent":"GuzzleHttp/7","status":503,"latency":30001594641,"latency_human":"30.001594641s","bytes_in":203,"bytes_out":19}
"

How to loop to merge pdf

Sorry for a newbies question,

I want to merge pdf with pdfengine merge I have a loop for that based on the number of document to get.

I think to use this function :

use Gotenberg\Gotenberg;
use Gotenberg\Stream;

$request = Gotenberg::pdfEngines($apiUrl)
    ->merge(
        Stream::path('/path/to/my.pdf'),
        Stream::path('/path/to/my2.pdf')
    );

How can I loop to add Stream::path ?

Thanks for your feedback.

Best regards

How to handle large file conversion (4gb)

Hello,

Thanks for the wonderful library. How to handle large file conversion?
I can see you have already used stream but i still get internal 500 error.

Any suggestions?

Disable Footer entirely rather than show the temporary filename?

If there is an empty footer or header I would expect it to be empty. What is happening here?

To resolve issues like puppeteer/puppeteer#2089 we need to generate separate PDF:s and then merge. Some pages should not have footer or header, while others should.

        $this->gotenbergChromium = Gotenberg::chromium($this->baseUri)
            // No margins, but many pages will define using @page css rules
            ->margins(0, 0, 0, 0)
            // A4 in inches
            ->paperSize(8.275, 11.7)
            ->preferCssPageSize()
            ->printBackground();

Then later:

        foreach ($documents as $document) {
            if ($document->showFooter()) {
                $this->gotenbergChromium->footer(
                    Stream::string('footer.html', $document->renderFooterHtml())
                );
            } else {
                $this->gotenbergChromium->footer(
                    Stream::string('footer.html', '')
                );
            }

            // Add main content
            // Save PDF content
            // Merge multiple pages
        }

Result:
image

unexpected 'array' (T_ARRAY), expecting function (T_FUNCTION) or const (T_CONST) in MultipartFormDataModule.php on line 20

Hi,

I've tried to convert an HTML page into a PDF but I already got the same error:

"unexpected 'array' (T_ARRAY), expecting function (T_FUNCTION) or const (T_CONST) in MultipartFormDataModule.php on line 20"

and i don't understand why.

Here is my PHP code:

  <?php
    require 'vendor/autoload.php';
    use Gotenberg\Gotenberg;
    use Gotenberg\Stream;
    $apiUrl = "http://localhost:3000";
    $request = Gotenberg::chromium($apiUrl)->html(Stream::path('etiquette.html'));
    ?>

I've tried with other method as:

use Gotenberg\Gotenberg;

   // Converts a target URL to PDF and saves it to a given directory.
    $filename = Gotenberg::save(
    Gotenberg::chromium($apiUrl)->url('https://my.url'), 
    $pathToSavingDirectory
);

but I've got the same result.

Have you got any idea about why I've got this error please?

Thanks

Tag version

Hi,

The recent tag does not follow the semver structure like old tags. Plus the tag version jumped from 1.1 to 1.18

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.