PHP
Именованные аргументы, понятные исключения, повторы при перегрузке. Без сторонних зависимостей — нужно только расширение curl.
| Пакет | Версии PHP | Зависимости |
|---|---|---|
pdfapi/pdfapi | 8.2+ | ext-curl |
Установка#
composer require pdfapi/pdfapiКлюч берётся из переменной окружения PDFAPI_KEY — выпустите его в кабинете:
export PDFAPI_KEY=pdf_live_...Первый PDF#
use PdfApi\Client;
$client = new Client(); // ключ из PDFAPI_KEY
$pdf = $client->html('<h1>Счёт №42</h1>', marginTop: '20mm');
$pdf->save('invoice.pdf');
echo $pdf->pages, ' стр., осталось ', $pdf->quota?->remaining;Методы#
| Метод | Что делает |
|---|---|
html($html, ...параметры) | HTML → PDF |
url($url, ...параметры) | публичная страница по адресу → PDF. Тариф Premium и выше; адрес — полный, с https:// |
markdown($text, ...параметры) | Markdown → PDF. Тариф Premium и выше |
office($path, $landscape = null) | docx, xlsx, pptx с диска → PDF. Тариф Premium и выше |
officeFromString($data, $filename, $landscape = null) | то же из памяти |
convert(array $body) | POST /v1/convert с телом как есть |
me() | тариф, расход и остаток страниц — GET /v1/me |
У каждого метода есть timeout: — секунд на этот вызов.
Параметры страницы#
Именованные аргументы, все необязательные. Что они значат — в разделе Параметры страницы.
| Параметр | Пример | По умолчанию |
|---|---|---|
landscape | true | false |
paperWidth, paperHeight | '8.27in', '297mm' | A4 |
marginTop, marginBottom, marginLeft, marginRight | '20mm' | '0.39in' |
waitDelay | '2s', '500ms', до 10 секунд | '0s' |
$pdf = $client->url('https://example.com/report', landscape: true, waitDelay: '1s');Размер — число и единица pt, px, in, mm, cm или pc без пробела. '20' и '20 mm' вызовут InvalidArgumentException сразу, без запроса к API.
Документы Office#
$pdf = $client->office('report.docx'); // с диска
$pdf = $client->officeFromString($data, 'table.xlsx', landscape: true); // из памяти — имя с расширениемФайл — до 3,7 МБ: в base64 он вырастает на треть, а тело запроса ограничено 5 МБ. Библиотека проверяет, что файл — настоящий ZIP-архив, поэтому старый .doc или PDF, переименованный в .docx, отклоняется до отправки.
Результат#
Result:
content— байты PDF, строка;pages— сколько страниц списано;quota—Quotaс полямиlimit,usedиremainingпосле этой конвертации;save($path)— записать в файл и вернуть путь.
save пишет атомарно: сначала во временный файл рядом, потом переименовывает поверх. Оборвётся запись или кончится место — останется прежний файл, а не обрезанный PDF.
Аккаунт и квота#
$me = $client->me();
echo "{$me->plan}: осталось {$me->pagesRemaining} из {$me->pagesLimit}, обнулится ",
$me->periodEnd?->format(DATE_ATOM) ?? 'неизвестно когда', "\n";Account: userId, plan, periodStart, periodEnd (DateTimeImmutable в UTC или null), pagesUsed, pagesLimit, pagesRemaining, requestsPerSecond, burst. Запрос страниц не тратит. Как встроить проверку в cron — в руководстве Контроль квоты.
Ошибки#
Все ошибки API — наследники PdfApi\Exception\PdfApiException с полями errorCode, status и сообщением по-русски.
use PdfApi\Exception\{QuotaExceededException, RateLimitException, RenderException, PdfApiException};
try {
$pdf = $client->html($html);
} catch (QuotaExceededException $e) {
// страницы кончились
} catch (RateLimitException $e) {
sleep((int) ceil($e->retryAfter ?? 1));
} catch (RenderException $e) { // и RenderTimeoutException тоже
// разметка не отрендерилась
} catch (PdfApiException $e) {
error_log("{$e->errorCode} {$e->status}: {$e->getMessage()}");
}| Исключение | Когда |
|---|---|
AuthenticationException | 401: ключа нет, он неверный или отозван |
PermissionDeniedException | 403: почта не подтверждена или формат недоступен на тарифе |
QuotaExceededException | 402: страницы периода кончились или документ больше остатка |
InvalidRequestException | 400: неверный параметр или адрес во внутреннюю сеть (errorCode === 'url_not_allowed') |
PayloadTooLargeException | 413: тело больше 5 МБ; наследник InvalidRequestException |
RateLimitException | 429: слишком часто; retryAfter — через сколько секунд можно снова |
RenderException | 502: документ не отрендерился |
RenderTimeoutException | 504: рендер дольше 30 секунд; наследник RenderException |
UnavailableException | 503: рендер временно недоступен |
ApiConnectionException | нет связи с API |
ApiTimeoutException | API не ответил за таймаут; наследник ApiConnectionException |
Неверные аргументы — пустой HTML, адрес без https://, файл .pdf вместо .docx — \InvalidArgumentException до запроса; лимит частоты на них не тратится. Все коды API — в разделе Ошибки и повторы.
Повторы#
Библиотека сама повторяет запрос, когда это безопасно, — по умолчанию до двух раз (maxRetries):
- 429 — через
Retry-After, но не дольше минуты; - 503 или нет соединения — первый повтор примерно через 0,5 секунды, второй — примерно через 1 секунду.
После таймаута результат может быть уже сохранён. Повтор с тем же Idempotency-Key и телом запроса защищает от повторного списания на обновлённом сервере. Без этого ключа повтор считается новой конвертацией. Подробнее.
Настройки клиента#
$client = new Client(
apiKey: 'pdf_live_...', // иначе PDFAPI_KEY
baseUrl: 'https://pdfapi.ru/api', // иначе PDFAPI_BASE_URL
timeout: 40.0, // секунд на запрос
maxRetries: 2,
transport: $myTransport, // свой PdfApi\Http\Transport: прокси, PSR-18
);- Неверные настройки — таймаут не больше нуля или отрицательное число повторов —
\InvalidArgumentExceptionсразу. - Ключ не утекает — его нет в
var_dumpиprint_rклиента, а в трассировках исключений он помечен#[\SensitiveParameter].
PDF в веб-приложении#
PDF уже в памяти — отдавайте байты, на диск сохранять незачем:
return response($pdf->content, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="invoice.pdf"',
]);Данные пользователя в HTML — только через htmlspecialchars или шаблоны с автоэкранированием (Blade, Twig), иначе это HTML-инъекция в документ — см. Безопасность и данные.
Примеры#
В папке examples/ библиотеки; запуск — composer install && PDFAPI_KEY=pdf_live_... php examples/<файл>.
| Файл | Что показывает |
|---|---|
invoice.php | счёт из HTML-шаблона с экранированием данных |
from-url.php | страница по адресу, альбомная, с ожиданием скриптов |
office.php | docx, xlsx или pptx в PDF рядом с исходным файлом |
batch.php | пачка документов по очереди — при 429 библиотека подождёт сама |
quota.php | остаток страниц для cron: код выхода 2 при нехватке |
web.php | отдача PDF без фреймворка: php -S 127.0.0.1:8000 examples/web.php |