Gotenberg で Office 文書を PDF に変換する
Gotenberg ブリッジは Office 文書を PDF に変換します。文書を HTTPS 経由で Gotenberg マイクロサービスへ送信し、PDF のバイト列を返します。イミュータブルな GotenbergConfig でサービスを記述し、PSR-18 クライアントと PSR-17 ファクトリーを GotenbergBridge に組み込みます。さらに、ヘルスチェックでサービスをプローブしてから、ディスク上のファイルまたはメモリ内のバイト列を変換します。このガイドでは、ファイル拡張子によるフォーマット検出、ヘルスプローブ、型付きの失敗コントラクト、NextPDF の後処理への引き渡しを扱います。
前提条件は次のとおりです。
- NextPDF コアと
nextpdf/gotenbergがインストールされていること。 - Gotenberg サービスに HTTPS 経由で到達できること。ブリッジは、リクエストがプロセス外へ出る前に、素の
http://URL を拒否します。 - PSR-18 クライアントと、PSR-17 のリクエストファクトリーおよびストリームファクトリーがインストールされていること。DNS と TLS のピンニングを使う場合は、PSR-17 レスポンスファクトリーも指定します。
- 入力が、認識される 6 つの Office フォーマットのいずれかであること。
.docx、.xlsx、.pptx、.odt、.ods、または.odpです。ブリッジは、それ以外の拡張子をValueErrorで拒否します。
このページは how-to ガイドです。実行可能な完全なプログラムについては、Gotenberg クイックスタートを参照してください。
インストール
「インストール」という見出しのセクションブリッジ、PSR-18 クライアント、PSR-17 ファクトリーをインストールします。
composer require nextpdf/gotenberg guzzlehttp/guzzleHTTPS 経由で到達可能な Gotenberg サービスを実行し、ベアラートークンはシークレットマネージャーまたは注入された環境値から取得します。ブリッジは環境変数を読み取らず、HTTP クライアントも構築しません。どちらも呼び出し側で用意してください。
概念の概要
「概念の概要」という見出しのセクションGotenbergBridge::convertFile() はディスク上のパスを受け取ります。トラバーサルを防ぐためにパスを正規化し、ファイル拡張子をサポートされるフォーマットにマッピングし、サイズとファイル名を検査してから、<apiUrl>/forms/libreoffice/convert にマルチパートリクエストを送信します。convertString() は、すでに保持しているバイト列に対して同じ処理を行います。拡張子を検出できるよう、元のファイル名を使用します。
フォーマットは拡張子で検出されます。ブリッジは .docx、.xlsx、.pptx、.odt、.ods、.odp をそれぞれのフォーマットにマッピングし、それ以外はネットワーク通信が発生する前に ValueError で拒否します。結果オブジェクトは、検出されたソースフォーマットを enum 値として公開します。
ブリッジの処理は、検証を伴う単一の同期 HTTP ラウンドトリップです。リトライ、キューイング、キャッシュ、レート制限は行いません。これらはブリッジを取り巻くアプリケーション側の責務です。各変換は、自分で運用していてもプロセス内では制御できないサービスへのリモート呼び出しとして扱い、その遅延と失敗を見込んで設計してください。
ブリッジは失敗を型付き例外として明示し、部分的な結果や未検証の結果を返すことはありません。
- ステータスコードが
200以外、Content-Typeにapplication/pdfを含まない、またはボディが%PDFで始まらない場合は、いずれもGotenbergConvertExceptionを送出します。ブリッジは、3 つのチェックすべてに合格した場合にのみ結果を返します。 - ネットワーク障害やタイムアウトを含む PSR-18 クライアントの失敗は、元の例外を原因として
GotenbergConvertExceptionにラップされます。 - 検証の失敗(非 HTTPS の URL、プライベートまたは予約済みアドレス、サイズ超過の入力、安全でないファイル名)では、ネットワーク通信が発生する前に
RuntimeExceptionを送出します。 - 認識されないファイル拡張子では、ネットワーク通信が発生する前に
ValueErrorを送出します。
API サーフェス
「API サーフェス」という見出しのセクション// Configuration (final readonly):new GotenbergConfig( string $apiUrl, // required, must be HTTPS int $timeout = 30, // hard transfer timeout, seconds int $maxFileSize = 52_428_800, // 50 MiB string $apiKey = '', // #[SensitiveParameter]; Bearer when non-empty list<string> $pinnedPublicKeys = [], // sha256/<base64> list<string> $backupPublicKeys = [],)GotenbergConfig::fromArray(array $config): selfGotenbergConfig::isValid(): bool
// The bridge:new GotenbergBridge( GotenbergConfig $config, ClientInterface $httpClient, // PSR-18 RequestFactoryInterface $requestFactory, // PSR-17 StreamFactoryInterface $streamFactory, // PSR-17 ?LoggerInterface $logger = null, // PSR-3 ?HtmlSecurityPolicyInterface $htmlSecurityPolicy = null, ?ResponseFactoryInterface $responseFactory = null, // enables pinned transport)GotenbergBridge::isAvailable(): boolGotenbergBridge::convertFile(string $path): GotenbergConvertResultGotenbergBridge::convertString(string $bytes, string $originalFilename): GotenbergConvertResult結果オブジェクトは、pdfData、sourceFormat enum、isValid()(ボディが空でなく %PDF で始まる場合に true)、および size() を公開します。フィールドの完全なリファレンス、fromArray() のキーマップ、トランスポート選択のルールについては、「関連項目」からリンクしている Gotenberg 設定ページを参照してください。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクションサービス設定を記述し、ブリッジを組み込み、プローブしてから、1 つのファイルを変換します。
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Gotenberg\GotenbergBridge;use NextPDF\Gotenberg\GotenbergConfig;use NextPDF\Gotenberg\GotenbergConvertException;
$config = new GotenbergConfig( apiUrl: 'https://gotenberg.example.com', timeout: 60, apiKey: getenv('GOTENBERG_TOKEN') ?: '',);
$bridge = new GotenbergBridge( config: $config, httpClient: $httpClient, // your PSR-18 client requestFactory: $requestFactory, // your PSR-17 factory streamFactory: $streamFactory, // your PSR-17 factory responseFactory: $responseFactory, // enables the pinned transport);
// Probe before converting. The probe validates the URL with no network// traffic, then sends a HEAD to <apiUrl>/health.if (!$bridge->isAvailable()) { throw new RuntimeException('Gotenberg is not reachable.');}
try { $result = $bridge->convertFile('/path/to/report.docx');} catch (GotenbergConvertException $exception) { // Bad config, HTTP failure, non-200, wrong Content-Type, or non-PDF body. throw $exception;}
if (!$result->isValid()) { throw new RuntimeException('Result is not a valid PDF.');}
file_put_contents('/path/to/report.pdf', $result->pdfData);クラスは NextPDF\Gotenberg\GotenbergConfig です(上の行では、コードでインポートすべき正確な名前空間を使用しています)。isAvailable() は、空、非 HTTPS、プライベートアドレスの URL、およびあらゆるネットワークエラーに対して false を返し、例外を送出することはありません。500 未満のステータスが /health から返る場合は、利用可能であることを意味します。
コードサンプル — 本番環境
「コードサンプル — 本番環境」という見出しのセクション本番環境の変換では、各失敗の種類を個別にキャッチし、適切な条件下でのみリトライし、呼び出し側で並行数を制限します。以下の catch の順序は網羅的です。
<?php
declare(strict_types=1);
use NextPDF\Gotenberg\GotenbergBridge;use NextPDF\Gotenberg\GotenbergConvertException;use Psr\Log\LoggerInterface;use RuntimeException;use ValueError;
final readonly class OfficeConverter{ public function __construct( private GotenbergBridge $bridge, private LoggerInterface $logger, ) {}
public function convert(string $path): string { try { $result = $this->bridge->convertFile($path); } catch (GotenbergConvertException $exception) { // Transport, non-200, wrong Content-Type, or non-PDF body. // Retry only on transport-level or 502/503/504 causes, with // bounded exponential backoff and jitter — never blind retries. $this->logger->error('gotenberg.convert.failed', [ 'path' => basename($path), 'exception' => $exception::class, ]); throw $exception; } catch (ValueError $exception) { // Extension is not one of the six recognized Office formats. $this->logger->warning('gotenberg.convert.unsupported_format', [ 'path' => basename($path), ]); throw $exception; } catch (RuntimeException $exception) { // Non-HTTPS URL, private address, oversized input, or unsafe name. $this->logger->error('gotenberg.convert.rejected', [ 'path' => basename($path), 'exception' => $exception::class, ]); throw $exception; }
if (!$result->isValid()) { throw new RuntimeException('Gotenberg returned an invalid PDF body.'); }
return $result->pdfData; }}リトライは、トランスポートレベルの GotenbergConvertException(ラップされた PSR-18 クライアント例外)と、冪等なサーバーエラー(502、503、504)の場合にのみ行ってください。400 系のレスポンスは、通常は入力が誤っていることを意味するため、リトライしても同様に失敗します。試行回数の合計と総実時間の上限を設けてください。実行中の変換の数は、Gotenberg のデプロイが維持できる処理能力に合わせて制限してください。ブリッジ自体はステートレスで、多数のワーカーから安全に使用できますが、サービスの変換能力には限りがあります。
エッジケースと落とし穴
「エッジケースと落とし穴」という見出しのセクション- フォーマットは拡張子で検出されます。
.docxを.txtにリネームするとValueErrorで拒否され、.txtを.docxにリネームすると Gotenberg に送信され、そこで失敗します。アップロードを受け付ける際は、名前ではなく実際のフォーマットを信頼対象にしてください。 fromArray()は意図的に寛容です。 不正な入力は、黙ってデフォルト値に置き換えます。URL の欠落が、変換ごとの例外としてではなく設定エラーとして早期に表面化するよう、ブートパスでソース配列を検証してください。- サイズの上限はプロセス内で強制されます。
maxFileSize(デフォルト 50 MiB)はリクエストが送信される前にチェックされるため、サイズ超過のファイルがサービスの処理能力を消費することはありません。対象ドキュメントに必要な範囲に合わせて上限を引き下げてください。上限が小さいほど、より安価なサービス拒否対策になります。 - プローブは無料ではありません。
isAvailable()は、変換のたびにではなく、レディネスエンドポイントまたはヘルスエンドポイントから呼び出してください。変換ごとに実行すると、利点がないままサービスへのリクエストレートが 2 倍になります。 - プロセス内キャッシュはありません。 同じドキュメントを繰り返し変換する場合は、入力のコンテンツハッシュをキーとして、結果の PDF をアプリケーション側でキャッシュしてください。
renderTimeMsは自分で設定するものです。 結果のタイミングフィールドは、統合側が計測して設定しない限り0.0です。その数値が必要な場合は、呼び出し時間を自分で計測してください。
パフォーマンス
「パフォーマンス」という見出しのセクションリクエスト中、1 回の変換は Gotenberg 側で 1 つの接続と 1 つの LibreOffice ワーカーを占有し、Office 変換は瞬時には完了しません。timeout は、実際のドキュメントで計測した変換レイテンシをもとに、余裕を持たせて設定してください。プロセスが強制終了される前にブリッジが先にタイムアウトし、型付きの例外が得られるよう、上流のゲートウェイや PHP の max_execution_time よりも小さく保ってください。サービスの処理能力に合わせてサイズを調整したキュー、セマフォ、またはワーカープールで並行数を制限してください。プロセス内キャッシュはありません。同じ入力を繰り返し変換する場合は、アプリケーション側でキャッシュを追加してください。
セキュリティに関する注意事項
「セキュリティに関する注意事項」という見出しのセクション- 送信前の HTTPS とアドレスの検査。 ブリッジは、リクエストがプロセス外へ出る前に、非 HTTPS の URL と、プライベートまたは予約済みのアドレス空間に resolve(解決)される宛先を拒否します。リトライ時の各呼び出しでもその検証を再実行するため、リトライによって SSRF ガードを回避することはできません。
- リクエスト時のピン留めされたトランスポート。 レスポンスファクトリーとピンを指定した場合(または解決済みの IP セットがある場合)、ブリッジは接続を解決済みのアドレスにバインドし、SPKI ピンニングを強制し、ピアとホストを検証し、タイムアウトを適用し、リダイレクトの追従を無効にします。証明書のローテーションの前に、バックアップ用のピンを設定してください。
- アップロードで宣言されたコンテンツタイプを信頼しないでください。 ユーザーのアップロードを受け付ける際は、実際のファイルタイプを自分で検証してください。拡張子からフォーマットへのマッピングはルーティング判断であり、真正性のチェックではありません。
- シークレットは秘匿化され、イミュータブルです。
apiKeyは#[SensitiveParameter]を持ち、設定はfinal readonlyです。トークンはシークレットマネージャーから取得し、決してコミットしないでください。変換ログのエントリには、URL、ファイル名、フォーマット、コンテンツ長が含まれますが、ファイルの内容やトークンは決して含まれません。 - 空の
catchブロックは決して書かないでください。 各例では、特定の型をキャッチし、コンテキスト付きでログを記録します。
セキュリティとデプロイモデルの全体像については、Gotenberg のセキュリティと運用のページを参照してください。PSR-18 のトランスポートコントラクトと、コンテンツタイプを信頼しないというガイダンスは、上流の本番利用ページの該当する条項に紐付けられています。
このガイド自体は、規範的な標準への主張を行いません。ブリッジの PSR-18 トランスポートの挙動(クライアントは、レスポンスを送信またはパースできない場合にのみ例外を送出し、4xx/5xx は通常の戻り値です)、ファイルアップロードの検証ガイダンス、TLS ピンニングのモデルは、上流の Gotenberg 本番利用ページおよび設定ページで、PSR-18、OWASP、RFC 7469 に紐付けられています。このクックブックページは使い方を再掲し、それらの引用は該当ページに委ねます。ブリッジは PDF のバイト列を生成して、そこで終了します。署名、PDF/A プロファイル、透かしは NextPDF の後処理に関する事項であり、商用エディションの機能であって、このブリッジの一部ではありません。
- コントローラーから生成した PDF を返す — 変換した PDF を HTTP レスポンスとして返します。
- Gotenberg クイックスタート — 実行可能な完全な変換プログラム。
- Gotenberg 設定 — すべてのフィールド、
fromArray()のマッピング、トランスポートの選択。 - Gotenberg 本番利用 — シークレット、タイムアウト、リトライ、並行性、後処理の境界。