Справочник 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, автоматическая высота, без файлов шрифтов. | CloudflareRenderResult | CloudflareNotAvailableException, 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. | CloudflareRenderResult | CloudflareRenderException при сбойном или недопустимом выводе 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
Заголовок раздела «Защита API»Используйте эту таблицу, когда защищаете конечную точку отрисовки: проверяете ключ 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 | Не ожидаются. | Используется при начале нового окна. |
Архив R2
Заголовок раздела «Архив R2»Используйте эту таблицу, когда храните отрисованные 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. | R2ArchiveConfig | InvalidArgumentException при недопустимых именах бакетов. | Относитесь к учётным данным как к конфигурации, содержащей секреты. |
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 возвращают структурированные результаты успеха или ошибки; обрабатывайте оба пути.