Перейти к содержимому

Справочник API Cloudflare

Пакет NextPDF\Cloudflare связывает PHP-приложение с отрисовкой на периферии. Ваш PHP-процесс хранит язык гипертекстовой разметки (HTML), а Cloudflare Worker запускает безголовый браузер. Пакет предоставляет HTML-рендерер на базе Worker (CloudflareHtmlRenderer) и возвращаемые им объекты-значения, слой защиты запросов для конечных точек отрисовки (ApiProtection), службу архивирования R2 для отрисованных файлов формата переносимого документа (PDF) (R2ArchiveManager) и вспомогательные средства транспорта с закреплением для усиления защиты TLS и DNS. Конфигурация хранится в трёх неизменяемых объектах (CloudflareRendererConfig, ApiProtectionConfig, R2ArchiveConfig).

Чтобы начать, создайте CloudflareRendererConfig, передайте его в CloudflareHtmlRenderer и вызовите render(). Этот вызов отправляет ваш HTML в Worker и возвращает CloudflareRenderResult с байтами PDF. Защита, архивирование и закрепление подключаются вокруг этого вызова.

Эти фрагменты покрывают рабочие сценарии, которые вы будете использовать чаще всего. Каждый из них самодостаточен, сверен с src/Cloudflare/ и читает секреты из окружения.

Отрисовка строки HTML в PDF на периферии каноническим вызовом:

<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use NextPDF\Cloudflare\CloudflareHtmlRenderer;
use NextPDF\Cloudflare\CloudflareRendererConfig;
$httpFactory = new HttpFactory();
$renderer = new CloudflareHtmlRenderer(
config: new CloudflareRendererConfig(
workerUrl: 'https://pdf-renderer.example.workers.dev/render',
apiToken: getenv('CF_PDF_TOKEN') ?: throw new RuntimeException('CF_PDF_TOKEN not set'),
),
httpClient: new Client(),
requestFactory: $httpFactory,
streamFactory: $httpFactory,
responseFactory: $httpFactory,
);
$result = $renderer->render('<h1>Hello from the edge</h1>', widthPt: 595.28);
if ($result->isValid()) {
file_put_contents('output.pdf', $result->pdfData);
}

Что он делает: отправляет HTML в Worker по защищённому протоколу передачи гипертекста (HTTPS) и записывает возвращённые байты PDF формата A4 на диск после того, как isValid() подтвердит, что это действительный PDF.

Архивирование отрисованного PDF в R2 и возврат недолговечной ссылки:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\R2ArchiveConfig;
use NextPDF\Cloudflare\R2ArchiveManager;
$archive = new R2ArchiveManager(
config: R2ArchiveConfig::fromArray([
'bucket_name' => 'pdf-archive',
'account_id' => getenv('CF_ACCOUNT_ID') ?: '',
'access_key_id' => getenv('R2_ACCESS_KEY_ID') ?: '',
'secret_access_key' => getenv('R2_SECRET_ACCESS_KEY') ?: '',
]),
httpClient: $httpClient, // PSR-18 ClientInterface
requestFactory: $requestFactory, // PSR-17 RequestFactoryInterface
streamFactory: $streamFactory, // PSR-17 StreamFactoryInterface
);
$upload = $archive->upload($result->pdfData, 'invoice-1234.pdf');
$signedUrl = $upload->isValid()
? $archive->generateSignedUrl($upload->key, expiresInSeconds: 600)
: null;

Что он делает: загружает байты PDF в ключ R2 с разбиением по дате и при успехе создаёт предварительно подписанный единый указатель ресурса (URL) на 10 минут для временной загрузки.

Защита конечной точки отрисовки до начала затратной работы Worker:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\ApiKeyValidator;
use NextPDF\Cloudflare\ApiProtection;
use NextPDF\Cloudflare\ApiProtectionConfig;
$protection = new ApiProtection(
config: new ApiProtectionConfig(maxRequestsPerMinute: 30),
keyValidator: new ApiKeyValidator([getenv('RENDER_API_KEY') ?: '']),
);
$decision = $protection->checkRequest(
clientId: $clientIp,
payloadSize: strlen($html),
apiKey: $presentedApiKey,
);
if (!$decision->allowed) {
// Reject with 429 and rate-limit headers before any render call.
return [429, $decision->toHeaders(), $decision->denialReason];
}

Что он делает: проверяет ключ API и размер полезной нагрузки, контролирует ограничение частоты запросов для каждого клиента и возвращает единое решение с заголовками ответа, которые нужно добавить при отклонении запроса.

Эта таблица описывает основной интерфейс рендерера. Используйте её, когда создаёте конфигурацию, собираете рендерер или выполняете вызовы отрисовки и проверки доступности.

СимволПараметрыПоведение по умолчаниюВозвращаетИсключения или ошибкиПримечания
new CloudflareRendererConfig(string $workerUrl, string $apiToken, int $renderTimeout = 30, string $defaultCss = '', int $maxHtmlSize = 5000000, ?string $r2FontBucket = null, bool $fallbackToLocal = true, array $pinnedPublicKeys = [], array $backupPublicKeys = [])URL Worker, токен-носитель, тайм-аут, каскадные таблицы стилей (CSS), ограничение размера, необязательный бакет шрифтов R2, флаг резервного режима, наборы закреплений.Локальный резервный режим включён; закрепление отключено, если массивы закреплений пусты.CloudflareRendererConfigНе ожидаются.Храните токен API в секрете; предпочитайте URL Worker по HTTPS.
CloudflareRendererConfig::fromArray(array $config)worker_url, api_token, render_timeout, default_css, max_html_size, r2_font_bucket, fallback_to_local, массивы закреплений.Для отсутствующих необязательных ключей используются значения конструктора по умолчанию.CloudflareRendererConfigНе ожидаются.Используйте для конфигурационных массивов в стиле фреймворков.
CloudflareRendererConfig::isValid()нет.Требует непустой URL Worker и токен API.boolНе ожидаются.Недопустимая конфигурация вызывает в рендерере резервный режим или ошибку.
CloudflareRendererConfig::allPublicKeyPins()нет.Объединяет основные и резервные закрепления открытых ключей.list<string>Не ожидаются.Пустой список отключает закрепление.
new CloudflareHtmlRenderer(CloudflareRendererConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, ?LoggerInterface $logger = null, ?LocalRendererFactoryInterface $localRendererFactory = null, ?HtmlSecurityPolicyInterface $htmlSecurityPolicy = null, ?ResponseFactoryInterface $responseFactory = null)Конфигурация, зависимости HTTP по рекомендации стандартов PHP (PSR), необязательный логгер, необязательная фабрика локального резервного режима, необязательная политика HTML, необязательная фабрика ответов.Использует DefaultHtmlSecurityPolicy, если политика HTML не указана.CloudflareHtmlRendererОшибки связывания в контейнере.Фабрика ответов включает транспорт cURL с закреплением, когда это необходимо.
CloudflareHtmlRenderer::render(string $html, float $widthPt = 595.28, float $heightPt = 0, array $fontFiles = [])HTML, ширина страницы, высота страницы, файлы шрифтов в R2.Ширина A4, автоматическая высота, без файлов шрифтов.CloudflareRenderResultCloudflareNotAvailableException, CloudflareRenderException, ошибки проверки.Проверяет размер HTML и URL Worker перед сетевым input/output (I/O).
CloudflareHtmlRenderer::getHtmlSecurityPolicy()нет.Возвращает настроенную политику слоя разбора.HtmlSecurityPolicyInterfaceНе ожидаются.Используйте вместе с защитой конечной точки и проверкой URL Worker.
CloudflareHtmlRenderer::isAvailable()нет.Отправляет запрос HEAD в Worker, когда конфигурация допустима.boolВозвращает false при ошибках.Используйте для проверки готовности, а не как единственную защиту во время выполнения.

Объекты-значения рендерера и безопасность

Заголовок раздела «Объекты-значения рендерера и безопасность»

Используйте эту таблицу для объектов-значений запроса и результата (CloudflareRenderResult, CloudflareRenderPayload) и статических проверок транспортного уровня, которые проверяют HTML, URL Worker и закрепления DNS перед сетевым вводом-выводом.

СимволПараметрыПоведение по умолчаниюВозвращаетИсключения или ошибкиПримечания
new CloudflareRenderResult(string $pdfData, float $widthPt, float $heightPt, float $contentHeightPx = 0.0, string $renderLocation = '', float $renderTimeMs = 0.0)Байты PDF, ширина, высота, измеренная высота содержимого, расположение на периферии, время отрисовки.Метаданные пусты, когда Worker их не сообщает.CloudflareRenderResultНе ожидаются.Обычно возвращается из CloudflareResponseParser::parse().
CloudflareRenderResult::isValid()нет.Проверяет наличие непустых байтов PDF, начинающихся с заголовка PDF.boolНе ожидаются.Используйте перед архивированием или передачей байтов на другой слой.
CloudflareRenderResult::size()нет.Подсчитывает отрисованные байты PDF.intНе ожидаются.Передавайте в логику квот и аудита.
new CloudflareRenderPayload(string $html, float $widthPt, float $heightPt = 0, string $defaultCss = '', ?string $r2FontBucket = null, array $fontFiles = [])HTML, размер, CSS, необязательный бакет шрифтов R2, список файлов шрифтов.Автоматическая высота, без CSS по умолчанию, без бакета шрифтов R2, без файлов шрифтов.CloudflareRenderPayloadНе ожидаются.Объект-значение полезной нагрузки запроса.
CloudflareRenderPayload::toJson()нет.Сериализует HTML, размер, CSS и ссылки на шрифты в нотацию объектов JavaScript (JSON) для Worker.stringОшибки кодирования JSON.Низкоуровневый API полезной нагрузки запроса.
CloudflareResponseParser::parse(ResponseInterface $response, float $requestedWidthPt)Ответ Worker и запрошенная ширина.Принимает двоичные ответы PDF и структурированные ответы JSON.CloudflareRenderResultCloudflareRenderException при сбойном или недопустимом выводе Worker.Центральный анализатор, который использует рендерер.
CloudflareSecurityPolicy::validate(string $html, int $maxSize)Входной HTML и ограничение размера.Применяет политику пакета для входного HTML.voidИсключение проверки.Выполняйте проверки недоверенного ввода за пределами границы Worker.
CloudflareSecurityPolicy::validateWorkerUrl(string $url)URL Worker (адрес назначения).Разбирает и проверяет место назначения.arrayИсключение проверки.Блокирует небезопасные формы конечных точек перед сетевым вводом-выводом.
CloudflareSecurityPolicy::assertPinsStillValid(string $host, array $pinnedIps)Хост и список закреплённых IP.Проверяет ожидаемые закрепления DNS.voidИсключение проверки, если закрепления устарели или недопустимы.Используйте при эксплуатационных проверках для развёртываний с закреплением.

Используйте эту таблицу, когда защищаете конечную точку отрисовки: проверяете ключ API, контролируете размер полезной нагрузки и ограничения частоты, а также работаете с объектами результата и заголовков, которые они формируют.

СимволПараметрыПоведение по умолчаниюВозвращаетИсключения или ошибкиПримечания
new ApiProtection(ApiProtectionConfig $config, ?ApiKeyValidator $keyValidator = null, ?Closure $clock = null)Конфигурация защиты, необязательный валидатор ключей, необязательные часы.Использует системное время, если часы не указаны.ApiProtectionНе ожидаются.Внедряйте детерминированные часы в тестах.
ApiProtection::checkRequest(string $clientId, int $payloadSize, string $apiKey = '')Идентификатор клиента, размер полезной нагрузки, необязательный ключ API.Пустой ключ API допустим только тогда, когда конфигурация не требует ключей.ApiProtectionResultНе ожидаются.Проверяет ключ API и размер, затем применяет ограничения частоты.
ApiProtection::getRateLimit(string $clientId)Идентификатор клиента.Не регистрирует запрос.RateLimitResultНе ожидаются.Используйте, чтобы добавить заголовки ограничения частоты.
new ApiKeyValidator(array $validKeys = [])Список допустимых ключей в открытом виде.Пустой список отклоняет все ключи.ApiKeyValidatorНе ожидаются.Храните секреты вне кода и подставляйте через конфигурацию.
ApiKeyValidator::validate(string $key)Необработанный ключ.Сравнивает с настроенными ключами в открытом виде с использованием логики, устойчивой к временным атакам.boolНе ожидаются.Параметр конфиденциален; не записывайте необработанные ключи в журнал.
ApiKeyValidator::addKey(string $key)Необработанный ключ.Добавляет хешированный ключ в новый экземпляр валидатора.selfНе ожидаются.Считайте возвращённый экземпляр обновлённым валидатором.
ApiKeyValidator::revokeKey(string $key)Необработанный ключ.Удаляет соответствующий хеш из нового экземпляра валидатора.selfНе ожидаются.Считайте возвращённый экземпляр обновлённым валидатором.
ApiKeyValidator::hashKey(string $key)Необработанный ключ.Формирует хранимое представление хеша.stringНе ожидаются.Не раскрывайте хеши в журналах или ответах клиенту.
ApiKeyValidator::validateHashed(string $key, array $hashedKeys)Необработанный ключ и кандидатные хеши.Сравнивает с переданными хешами за постоянное время.boolНе ожидаются.Низкоуровневое вспомогательное средство для пользовательских хранилищ ключей.
new ApiProtectionConfig(int $maxRequestsPerMinute = 60, int $maxRequestsPerHour = 1000, int $maxPayloadSizeBytes = 10485760, array $allowedOrigins = [], bool $requireApiKey = true, string $apiKeyHeader = 'X-Api-Key', int $rateLimitWindowSeconds = 60)Ограничения запросов, ограничение полезной нагрузки, разрешённые источники, требование ключа API, имя заголовка, длина окна.60/minute, 1000/hour, полезная нагрузка 10 MiB, требуется ключ API.ApiProtectionConfigНе ожидаются.Создавайте напрямую в тестах или подставляйте через fromArray().
ApiProtectionConfig::fromArray(array $data)max_requests_per_minute, max_requests_per_hour, max_payload_size_bytes, allowed_origins, require_api_key, api_key_header, rate_limit_window_seconds.Для отсутствующих ключей используются значения конструктора по умолчанию.ApiProtectionConfigНе ожидаются.Используйте для подстановки конфигурации фреймворка.
ApiProtectionConfig::isValid()нет.Требует положительных ограничений и согласованных значений размера и окна.boolНе ожидаются.Проверяйте перед предоставлением конечной точки.
new ApiProtectionResult(bool $allowed, string $denialReason = '', ?RateLimitResult $rateLimit = null)Решение, причина отказа, необязательный результат ограничения частоты.Пустая причина отказа и отсутствие результата ограничения частоты.ApiProtectionResultНе ожидаются.Возвращается из ApiProtection::checkRequest().
ApiProtectionResult::toHeaders()нет.Выдаёт заголовки ограничения частоты, когда есть данные о частоте.array<string, string>Не ожидаются.Добавляйте к ответам Worker или фреймворка.
new RateLimitResult(bool $allowed, int $remainingRequests, int $retryAfterSeconds, string $clientId)Решение, оставшееся количество, задержка повтора, идентификатор клиента (ID).Без значений по умолчанию.RateLimitResultНе ожидаются.Неизменяемый результат для одной проверки.
RateLimitResult::toHeaders()нет.Выдаёт заголовки остатка лимита и сброса.array<string, string>Не ожидаются.Используйте для наблюдаемости и замедления клиента.
new RateLimitEntry(string $clientId, int $requestCount = 0, int $windowStart = 0, int $hourlyCount = 0, int $hourlyWindowStart = 0)ID клиента и изменяемые счётчики.Счётчики начинаются с нуля.RateLimitEntryНе ожидаются.Объект отслеживания в памяти.
RateLimitEntry::increment()нет.Увеличивает счётчик в памяти для одного client/window.voidНе ожидаются.Низкоуровневое вспомогательное средство, используемое ApiProtection.
RateLimitEntry::isExpired(int $windowSeconds)Длина окна в секундах.Сравнивает с текущим временем.boolНе ожидаются.Вспомогательное средство истечения срока во время выполнения.
RateLimitEntry::isExpiredAt(int $now, int $windowSeconds)Значение часов и длина окна.Сравнивает с переданным значением часов.boolНе ожидаются.Детерминированное вспомогательное средство для тестов.
RateLimitEntry::reset()нет.Сбрасывает счётчик и время начала окна.voidНе ожидаются.Используется при начале нового окна.

Используйте эту таблицу, когда храните отрисованные PDF в Cloudflare R2: служба архивирования, её конфигурация и типы ключей объектов, а также результат загрузки, который нужно проверить перед выдачей URL.

СимволПараметрыПоведение по умолчаниюВозвращаетИсключения или ошибкиПримечания
new R2ArchiveManager(R2ArchiveConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory)Конфигурация R2, HTTP-фабрики и клиент PSR factories/client.При создании сетевой вызов не выполняется.R2ArchiveManagerОшибки связывания в контейнере.Основная служба архивирования.
R2ArchiveManager::upload(string $pdfData, string $filename, array $metadata = [])Необработанные байты PDF, исходное имя файла, строковые метаданные.Пустые метаданные; ключ с разбиением по дате.R2UploadResultВозвращает неуспешный результат при сбое конфигурации, размера, HTTP или транспорта.Не выбрасывает исключение при обычном сбое загрузки.
R2ArchiveManager::generateSignedUrl(string $key, int $expiresInSeconds = 3600)Ключ объекта и время жизни URL (TTL).Подписанный URL на один час.stringОшибки подписи из-за недопустимой конфигурации.Используйте короткие значения TTL для конфиденциальных PDF.
R2ArchiveManager::buildObjectKey(string $filename)Исходное имя файла.Использует настроенный префикс пути и текущую дату.R2ObjectKeyНе ожидаются.Используйте для предсказуемого разбиения архива.
R2ArchiveManager::createPutRequest(R2ObjectKey $key, string $data, array $metadata = [])Ключ объекта, необработанные байты, метаданные.Подписывает запрос PUT.RequestInterfaceОшибки построения запроса.Низкоуровневый API для пользовательских транспортов.
new R2ArchiveConfig(string $bucketName, string $accountId, string $accessKeyId, string $secretAccessKey, string $endpoint = '', string $pathPrefix = 'pdfs/', int $maxFileSizeBytes = 104857600)Бакет, ID учётной записи, учётные данные, переопределение конечной точки, префикс ключа, максимальный размер объекта.Производная конечная точка, префикс pdfs/, максимальный размер объекта 100 MiB.R2ArchiveConfigInvalidArgumentException при недопустимых именах бакетов.Относитесь к учётным данным как к конфигурации, содержащей секреты.
R2ArchiveConfig::fromArray(array $data)ID учётной записи, бакет, учётные данные, префикс пути, переопределение конечной точки, максимальный размер.Для отсутствующих значений используются значения конструктора по умолчанию.R2ArchiveConfigНедопустимое имя бакета, если оно указано.Используйте для подстановки конфигурации приложения.
R2ArchiveConfig::isValid()нет.Требует непустых учётной записи, бакета, ключа доступа и секретного ключа.boolНе ожидаются.Недопустимая конфигурация приводит к сбою загрузок со структурированными результатами.
R2ArchiveConfig::getEndpoint()нет.Использует явную конечную точку или выводит конечную точку Cloudflare R2 из ID учётной записи.stringНе ожидаются.Используется для построения подписанного запроса.
new R2ObjectKey(string $key, string $bucket)Полный ключ объекта и бакет.Без нормализации.R2ObjectKeyНе ожидаются.Обычно создаётся через R2ObjectKey::generate().
R2ObjectKey::generate(string $prefix, string $filename, ?DateTimeInterface $date = null)Префикс, исходное имя файла, необязательная дата.Очищенный ключ объекта с разбиением по дате.R2ObjectKeyНе ожидаются.Внедряйте дату в тестах для детерминированных ключей.
R2ObjectKey::fullPath()нет.Объединяет путь раздела и имя файла объекта.stringНе ожидаются.Сохраняйте это значение как ключ объекта.
new R2UploadResult(bool $success, string $key, string $etag = '', int $size = 0, string $error = '')Флаг успеха, ключ объекта, тег сущности (ETag), размер в байтах, сообщение об ошибке.Пустой ETag, нулевой размер, пустая ошибка.R2UploadResultНе ожидаются.Возвращается из R2ArchiveManager::upload().
R2UploadResult::isValid()нет.Допустим, когда загрузка прошла успешно и присутствуют ключ и ETag.boolНе ожидаются.Проверяйте перед предоставлением URL.
R2UploadResult::publicUrl(string $customDomain = '')Необязательный пользовательский публичный домен.Возвращает голый ключ объекта, когда пользовательский домен не указан.stringНе ожидаются.Избегайте публичных URL для конфиденциальных документов, если это не разрешено политикой.

Используйте эту таблицу только для низкоуровневого связывания: закрепление на уровне cURL по интернет-протоколу (IP) и по SubjectPublicKeyInfo (SPKI), а также контракты локального рендерера, которые используются как резервный путь, когда Worker недоступен.

СимволПараметрыПоведение по умолчаниюВозвращаетИсключения или ошибкиПримечания
new PinnedCurlTransport(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory, array $pinnedIps = [], array $pinnedPublicKeys = [], int $timeoutSeconds = 30)Фабрики PSR-17, закреплённые IP, закреплённые открытые ключи, тайм-аут.Без закреплений и с тайм-аутом 30 секунд.PinnedCurlTransportНе ожидаются.Используйте только тогда, когда требуется закрепление на уровне cURL.
PinnedCurlTransport::sendRequest(RequestInterface $request)Запрос PSR-7.Отправляет через cURL с настроенным тайм-аутом и средствами управления закреплением.ResponseInterfaceТранспортные исключения PSR-18.Используйте только тогда, когда HTTP-клиенты фреймворка не могут обеспечить такую же политику закрепления.
PinnedCurlTransport::buildCurlOptions(RequestInterface $request, string $host, int $port)Запрос, целевой хост, целевой порт.Формирует массив параметров cURL, используемый sendRequest().arrayОшибки недопустимого запроса или конфигурации закреплений.Низкоуровневая точка для тестов и диагностики.
LocalRendererInterface::render(string $html, array $options = [])HTML и параметры рендерера.Только контракт; реализация задаёт значения по умолчанию.stringОшибки отрисовки, зависящие от реализации.Используется как локальный резервный вариант, когда отрисовка через Worker недоступна.
LocalRendererFactoryInterface::create()нет.Создаёт реализацию локального рендерера.LocalRendererInterfaceОшибки фабрики или зависимостей.Выносит создание резервного рендерера за пределы CloudflareHtmlRenderer.
  • Относитесь к URL Worker как к сетевой границе. Проверяйте место назначения, размер и аутентификацию перед отрисовкой.
  • Используйте результаты защиты API как выводы политики, а не как механизм управления потоком через исключения.
  • Загрузки в R2 возвращают структурированные результаты успеха или ошибки; обрабатывайте оба пути.