picsi / sideolclient
Sideol Engine 的 PHP 客户端
Requires
- php: ^7.4|^8.0|^8.1|^8.2
- ext-json: *
- guzzlehttp/psr7: ^2.1
- php-http/discovery: ^1.14
- psr/http-client: ^1.0
- psr/http-message: ^1.0
Requires (Dev)
- doctrine/coding-standard: ^9.0
- pestphp/pest: ^1.21
- phpstan/phpstan: ^1.2
- squizlabs/php_codesniffer: ^3.6
README
Sideol PHP 客户端
用于与 Sideol Engine 交互的 PHP 客户端
此包是 Sideol 的 PHP 客户端,API 用于与 Chromium 和 LibreOffice 等强大的工具交互,可以将多种文档格式(HTML、Markdown、Word、Excel 等)转换为 PDF 文件,等等!
快速示例
可以将目标 URL 转换为 PDF 并将其保存到指定的目录
use Picsi\Sideolclient\Sideol; // Converts a target URL to PDF and saves it to a given directory. $filename = Sideol::save( Sideol::chromium($apiUrl)->url('https://my.url'), $pathToSavingDirectory );
还可以将 Office 文档进行转换和合并
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; // Converts Office documents to PDF and merges them. $response = Sideol::send( Sideol::libreOffice($apiUrl) ->merge() ->convert( Stream::path($pathToDocx), Stream::path($pathToXlsx) ) );
要求
此包需要Sideol,一个用于 PDF 文件的基于 Docker 的无状态 API
安装
此包不能使用 Composer 安装,它是一个私有仓库。一旦您下载了仓库,您可以使用以下设置使用 Composer 安装它。
{
"repositories": [
{
"type" : "path",
"url" : "./sidoelclient"
}
],
"require": {
"picsi/sideolclient" : "*"
},
}
我使用 PSR-7 HTTP 消息接口(即 RequestInterface
和 ResponseInterface
)以及 PSR-18 HTTP 客户端接口(即 ClientInterface
)。对于后者,您可能需要一个适配器才能使用您喜欢的客户端库。查看可用的适配器
如果您不确定应该使用哪个适配器,请考虑使用 php-http/guzzle7-adapter
composer require php-http/guzzle7-adapter
用法
向 API 发送请求
在创建了 HTTP 请求(见下文)后,您有两个选项
- 从 API 获取响应并根据您的需求处理它。
- 将结果文件保存到指定的目录。
在以下示例中,我们假设 Sideol Engine API 可在 https://:3000 上找到。
获取响应
您可以使用任何能够处理 PSR-7 RequestInterface
的 HTTP 客户端调用 API
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->url('https://my.url'); $response = $client->sendRequest($request);
如果您有一个兼容 PSR-18 的 HTTP 客户端(见 安装),您也可以使用 Sideol::send
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->url('https://my.url'); try { $response = Sideol::send($request); return $response; } catch (SideolApiError $e) { // $e->getResponse(); }
此助手将解析响应,如果它不是 2xx,则抛出异常。如果您希望直接将响应返回给浏览器,这特别有用。
您还可以显式设置 HTTP 客户端
use Picsi\Sideolclient\Sideol; $response = Sideol::send($request, $client);
保存结果文件
如果您有一个兼容 PSR-18 的 HTTP 客户端(见 安装),您可以使用 Sideol::save
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->url('https://my.url'); $filename = Sideol::save($request, '/path/to/saving/directory');
它返回结果文件的名称。默认情况下,Sideol 创建一个 UUID 文件名(例如,36a1558b-02a5-4a45-a950-2f8f8fd7f644
),具有 .zip
或 .pdf
文件扩展名。
您还可以显式设置 HTTP 客户端
use Picsi\Sideolclient\Sideol; $response = Sideol::save($request, $pathToSavingDirectory, $client);
文件名
您可以使用以下方法覆盖输出文件名
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->outputFilename('my_file') ->url('https://my.url');
Sideol 将自动添加正确的文件扩展名。
跟踪或请求 ID
默认情况下,Sideol 创建一个 UUID 跟踪,用于在其日志中标识一个请求。您可以使用以下方法覆盖其值
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->trace('debug') ->url('https://my.url');
它将使用您的值设置 Sideol-Trace
标头。您还可以覆盖默认的标头名称
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium('https://:3000') ->trace('debug', 'Request-Id') ->url('https://my.url');
请注意,它应该与由 Sideol 的 --api-trace-header
属性定义的值相同。
Sideol 的响应还将包含跟踪标头。如果发生错误,则 Sideol::send
和 Sideol::save
方法都会抛出 SideolApiError
异常,该异常提供了以下方法来检索跟踪
use Picsi\Sideolclient\Exceptions\SideolApiError; use Picsi\Sideolclient\Sideol; try { $response = Sideol::send( Sideol::chromium('https://:3000') ->url('https://my.url') ); } catch (SideolApiError $e) { $trace = $e->getSideolTrace(); // Or if you override the header name: $trace = $e->getSideolTrace('Request-Id'); }
Chromium
Chromium模块与Chromium浏览器交互,用于将HTML文档转换为PDF。
将目标URL转换为PDF
请参阅https://khairu-aqsara.net/sideol/docs/modules/chromium#url。
将目标URL转换为PDF非常简单
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->url('https://my.url');
由于提供了$extraLinkTags和$extraScriptTags参数,您可以使用它们注入<link>
和<script>
HTML元素
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Modules\ChromiumExtraLinkTag; use Picsi\Sideolclient\Modules\ChromiumExtraScriptTag; $request = Sideol::chromium($apiUrl)->url('https://my.url', [ new ChromiumExtraLinkTag('https://my.css'), ], [ new ChromiumExtraScriptTag('https://my.js'), ], );
请注意,Sideol将根据参数的顺序添加<link>
和<script>
元素。
将HTML文档转换为PDF
请参阅https://khairu-aqsara.net/sideol/docs/modules/chromium#html。
您可以使用以下方式转换HTML文档
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->html(Stream::path('/path/to/file.html'));
或使用HTML字符串
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->html(Stream::string('my.html', $someHtml));
请注意,它将自动将文件名设置为index.html
,这是Sideol的要求,无论您使用的是Stream
类的哪个值。
您还可以发送其他文件,如图像、字体、样式表等。唯一的要求是它们在HTML DOM中的路径位于根级别。
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->assets( Stream::path('/path/to/my.css'), Stream::path('/path/to/my.js') ) ->html(Stream::path('/path/to/file.html'));
将一个或多个Markdown文件转换为PDF
请参阅https://khairu-aqsara.net/sideol/docs/modules/chromium#markdown。
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->markdown( Stream::path('/path/to/my_wrapper.html'), Stream::path('/path/to/file.md') );
第一个参数是一个包含HTML内容的Stream
,例如
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My PDF</title> </head> <body> {{ toHTML "file.md" }} </body> </html>
这里有一个Go模板函数toHTML
。Sideol将使用它将Markdown文件的内容转换为HTML。
就像HTML转换一样,您也可以发送其他文件,如图像、字体、样式表等。唯一的要求是它们在HTML DOM中的路径位于根级别。
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->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') );
纸张大小
您可以使用以下方式覆盖默认纸张大小
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->paperSize($width, $height) ->url('https://my.url');
纸张大小示例(宽度 x 高度,以英寸为单位)
Letter
- 8.5 x 11(默认)Legal
- 8.5 x 14Tabloid
- 11 x 17Ledger
- 17 x 11A0
- 33.1 x 46.8A1
- 23.4 x 33.1A2
- 16.54 x 23.4A3
- 11.7 x 16.54A4
- 8.27 x 11.7A5
- 5.83 x 8.27A6
- 4.13 x 5.83
边距
您可以覆盖默认边距(即0.39
英寸)
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->margins($top, $bottom, $left, $right) ->url('https://my.url');
优先CSS页面大小
您可以将页面大小强制为CSS中定义的大小
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->preferCssPageSize() ->url('https://my.url');
打印背景图形
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->printBackground() ->url('https://my.url');
您还可以隐藏默认的白色背景,并使用以下方式生成具有透明度的PDF
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->printBackground() ->omitBackground() ->url('https://my.url');
关于printBackground
和omitBackground
表单字段的规则如下
- 如果将
printBackground
设置为false,则不打印背景。 - 如果将
printBackground
设置为true- 如果HTML文档有背景,则使用该背景。
- 如果没有
- 如果将
omitBackground
设置为true,则默认背景是透明的。 - 如果没有,则使用默认的白色背景。
- 如果将
横向排版
您可以使用以下方式覆盖默认的纵向排版
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->landscape() ->url('https://my.url');
缩放
您可以使用以下方式覆盖页面渲染的默认缩放(即1.0
)
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->scale(2.0) ->url('https://my.url');
页面范围
您可以设置要打印的页面范围,例如1-5, 8, 11-13
。空值表示所有页面。
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->nativePageRanges('1-2') ->url('https://my.url');
页眉和页脚
您可以为PDF的每一页添加页眉和/或页脚
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::chromium($apiUrl) ->header(Stream::path('/path/to/my_header.html')) ->footer(Stream::path('/path/to/my_footer.html')) ->margins(1, 1, 0.39, 0.39) ->url('https://my.url');
请注意,它将自动将文件名设置为header.html
和footer.html
,这是Sideol的要求,无论您使用的是Stream
类的哪个值。每个都必须是一个完整的HTML文档
<html> <head> <style> body { font-size: 8rem; margin: 4rem auto; } </style> </head> <body> <p><span class="pageNumber"></span> of <span class="totalPages"></span></p> </body> </html>
以下类允许您注入打印值
date
- 格式化的打印日期。title
- 文档标题。url
- 文档位置。pageNumber
- 当前页码。totalPages
- 文档的总页数。
⚠️ 确保以下条件:
- 顶部和底部的边距足够大(即,
->margins(1, 1, 0.39, 0.39)
) - 字体大小足够大。
⚠️ 存在一些限制
- 没有JavaScript。
- CSS属性与HTML文档中的属性独立。
- 页脚CSS属性会覆盖标题中的属性;
- 仅加载Docker镜像中安装的字体 - 请参阅字体章节。
- 图像仅使用base64编码的源工作 - 即,
data:image/png;base64, iVBORw0K....
background-color
和颜色CSS
属性需要一个额外的-webkit-print-color-adjust: exact
CSS属性才能工作。- 不加载资源(例如,CSS文件、脚本、字体等)。
- 背景表单字段不适用。
等待延迟
当页面依赖于JavaScript进行渲染,并且您无法访问页面的代码时,您可能需要等待一段时间(例如,1s
,2ms
等),以确保Chromium已完全渲染您试图生成的页面。
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->waitDelay('3s') ->url('https://my.url');
等待表达式
您还可以等待直到指定的JavaScript表达式返回true
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->waitForExpression("window.status === 'ready'") ->url('https://my.url');
用户代理
您可以使用Sideol覆盖默认的User-Agent
头
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1") ->url('https://my.url');
额外的HTTP头
您可以在加载HTML文档时添加Chromium将发送的HTTP头
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->extraHttpHeaders([ 'My-Header-1' => 'My value', 'My-Header-2' => 'My value' ]) ->url('https://my.url');
在控制台异常时失败
如果Chromium控制台中存在异常,您可以将Sideol强制返回409 Conflict
响应
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->failOnConsoleExceptions() ->url('https://my.url');
模拟媒体类型
一些网站有针对打印的专用CSS规则。使用screen
允许您强制使用“标准”CSS规则
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->emulateScreenMediaType() ->url('https://my.url');
您还可以使用以下方法强制使用print
媒体类型:
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->emulatePrintMediaType() ->url('https://my.url');
PDF格式
请参阅https://khairu-aqsara.net/sidoel/docs/modules/pdf-engines#engines。
您可以使用以下方法设置结果的PDF格式:
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->pdfFormat('PDF/A-1a') ->url('https://my.url');
LibreOffice
LibreOffice模块通过unoconv与LibreOffice交互,将文档转换为PDF。
将文档转换为PDF
请参阅https://khairu-aqsara.net/sideol/docs/modules/libreoffice#route。将文档转换为PDF非常简单,只需
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->convert(Stream::path('/path/to/my.docx'));
如果您发送许多文档,Sideol将返回包含PDF的ZIP存档
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->outputFilename('archive') ->convert( Stream::path('/path/to/my.docx'), Stream::path('/path/to/my.xlsx') ); // $filename = archive.zip $filename = Sideol::save($request, $pathToSavingDirectory);
您也可以将它们合并为一个唯一的PDF
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->merge() ->outputFilename('merged') ->convert( Stream::path('/path/to/my.docx'), Stream::path('/path/to/my.xlsx') ); // $filename = merged.pdf $filename = Sideol::save($request, $pathToSavingDirectory);
请注意,合并顺序由参数的顺序确定。
横向排版
您可以使用以下方式覆盖默认的纵向排版
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->landscape() ->convert(Stream::path('/path/to/my.docx'));
页面范围
您可以设置要打印的页面范围,例如,1-4
。为空表示所有页面。
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->nativePageRanges('1-2') ->convert(Stream::path('/path/to/my.docx'));
⚠️ 页面范围独立应用于所有文件。
PDF格式
请参阅https://khairu-aqsara.net/sideol/docs/modules/pdf-engines#engines。
您可以使用以下方法设置结果的PDF(s)格式:
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->pdfFormat('PDF/A-1a') ->convert(Stream::path('/path/to/my.docx'));
您还可以明确告诉Sideol使用unoconv将结果的PDF(s)转换为PDF格式
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::libreOffice($apiUrl) ->nativePdfFormat('PDF/A-1a') ->convert(Stream::path('/path/to/my.docx'));
⚠️ 您不能设置两个属性,否则Sideol将返回400 Bad Request
响应。
PDF 引擎
PDF引擎模块收集了所有可以操作PDF文件的工具。
合并PDF
请参阅https://khairu-aqsara.net/sideol/docs/modules/pdf-engines#merge。
合并PDF非常简单,只需
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::pdfEngines($apiUrl) ->merge( Stream::path('/path/to/my.pdf'), Stream::path('/path/to/my2.pdf') );
请注意,合并顺序由参数的顺序确定。
您也可以使用以下方法设置结果的PDF(s)格式:
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::pdfEngines($apiUrl) ->pdfFormat('PDF/A-1a') ->merge( Stream::path('/path/to/my.pdf'), Stream::path('/path/to/my2.pdf'), Stream::path('/path/to/my3.pdf') );
转换为特定的PDF格式
请参阅https://khairu-aqsara.net/sideol/docs/modules/pdf-engines#convert。
您可以使用以下方式将PDF转换为特定的PDF格式
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::pdfEngines($apiUrl) ->convert( 'PDF/A-1a' Stream::path('/path/to/my.pdf') );
如果您发送许多PDF文件,Sideol将返回一个包含PDF文件的ZIP存档
use Picsi\Sideolclient\Sideol; use Picsi\Sideolclient\Stream; $request = Sideol::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 = Sideol::save($request, $pathToSavingDirectory);
Webhook
Webhook模块是Sideol中间件,用于将API响应发送到回调。
⚠️ 如果您使用Webhook功能,则不能使用Sideol::save
方法。例如
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->webhook('https://my.webhook.url', 'https://my.webhook.error.url') ->url('https://my.url');
您还可以覆盖Sideol用于调用webhook的默认HTTP方法(POST
)
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->webhook('https://my.webhook.url', 'https://my.webhook.error.url') ->webhookMethod('PATCH') ->webhookErrorMethod('PUT') ->url('https://my.url');
您还可以指示Sideol在请求webhook时添加额外的HTTP头信息
use Picsi\Sideolclient\Sideol; $request = Sideol::chromium($apiUrl) ->webhook('https://my.webhook.url', 'https://my.webhook.error.url') ->webhookExtraHttpHeaders([ 'My-Header-1' => 'My value', 'My-Header-2' => 'My value' ]) ->url('https://my.url');