İçeriğe geç

Üretimde kullanım — yerel yedek, telemetri, arşivleme, koruma

Bu sayfa, temel işleme akışının ötesindeki dört üretim konusunu kapsar: yerel yedek, kenar telemetrisi, Cloudflare R2 arşivlemesi ve gelen application programming interface (API) koruma katmanı. Her bölüm doğrulanmış sınıf davranışına dayanır.

Worker erişilemediğinde ve fallbackToLocal değeri true olduğunda, köprü işlemeyi yerel bir işleyiciye devreder. Bu işleyiciyi LocalRendererFactoryInterface üzerinden sağlayın. Köprü yerel işleyiciyi gecikmeli olarak oluşturur; bu nedenle fabrikanın create() metodu yalnızca yedek yolunda çalışır.

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\Contract\LocalRendererFactoryInterface;
use NextPDF\Cloudflare\Contract\LocalRendererInterface;
final class ArtisanLocalRendererFactory implements LocalRendererFactoryInterface
{
public function __construct(
private readonly \NextPDF\Artisan\ChromeHtmlRenderer $chrome,
) {}
public function create(): LocalRendererInterface
{
return new readonly class($this->chrome) implements LocalRendererInterface {
public function __construct(
private \NextPDF\Artisan\ChromeHtmlRenderer $chrome,
) {}
/** @param array<string, mixed> $options */
public function render(string $html, array $options = []): string
{
// Delegate to the local Chrome renderer; return raw PDF bytes.
return $this->chrome->renderToString($html, $options);
}
};
}
}

Fabrikayı işleyiciye bağlayın:

use NextPDF\Cloudflare\CloudflareHtmlRenderer;
$renderer = new CloudflareHtmlRenderer(
config: $config,
httpClient: $httpClient,
requestFactory: $httpFactory,
streamFactory: $httpFactory,
logger: $logger,
localRendererFactory: new ArtisanLocalRendererFactory($chrome),
responseFactory: $httpFactory,
);

Yedek yol çalıştığında, sonuçtaki renderLocation değeri sabit local dizgesidir ve heightPt değeri 0.0 olur. Yerel yol bir kenar konumu veya ölçülmüş yükseklik bildirmez. Köprü, istenen genişliği yerel işleyiciye widthPt seçenek anahtarı aracılığıyla iletir.

Doğrudan CloudflareHtmlRenderer sınıfından okunur:

DurumSonuç
Yapılandırma eksik, fallbackToLocal: falseCloudflareNotAvailableException
Yapılandırma eksik, fallbackToLocal: true, fabrika bağlanmışYerel işleme
Worker bir taşıma hatası fırlatır, yedek etkin, fabrika bağlanmışYerel işleme, günlüğe kaydedilir: önce warning, ardından info
Worker hata fırlatır, yedek etkin, Artisan kurulu, fabrika yokCloudflareNotAvailableException, eksik fabrikayı belirtir
Worker hata fırlatır, yedek etkin, Artisan kurulu değildirCloudflareNotAvailableException, eksik paketi belirtir
Worker bir Hypertext Transfer Protocol (HTTP) hatası ya da bozuk gövde döndürürCloudflareRenderException, asla yedeğe geçmez

Son satır kritiktir. Hata döndüren bir Worker, erişilebilirlik hatası değil, işleme hatası üretir. Köprü bunu yeniden fırlatır; böylece kodunuz bozuk bir işlemeyi erişilemeyen bir kenardan ayırt edebilir.

İkili yol üzerinden başarıyla tamamlanan her işleme, yanıt başlıklarından gelen telemetriyi içerir:

$result = $renderer->render($html);
$logger->info('edge render', [
'edge' => $result->renderLocation, // e.g. 'TPE', 'NRT'
'render_time_ms' => $result->renderTimeMs,
'content_px' => $result->contentHeightPx,
'pdf_bytes' => $result->size(),
]);

İşleyici renderLocation değerini CF-Ray yanıt başlığından okur ve son tireden sonraki bölümü alır. CF-Ray: 8abc123def456-TPE için konum TPE olur. Başlık yoksa konum boş bir dizgedir. JavaScript Object Notation (JSON) yanıt yolunda ise değer bunun yerine JSON renderLocation alanından gelir. Bu değerleri platform garantisi olarak değil, Worker’dan gelen gözlemlenebilirlik sinyalleri olarak değerlendirin.

R2ArchiveManager, Portable Document Format (PDF) baytlarını Amazon Simple Storage Service (S3) uyumlu API üzerinden Cloudflare R2’ye yükler ve istekleri Amazon Web Services (AWS) Signature V4 ile imzalar.

use NextPDF\Cloudflare\R2ArchiveConfig;
use NextPDF\Cloudflare\R2ArchiveManager;
$r2 = new R2ArchiveManager(
config: new R2ArchiveConfig(
bucketName: 'pdf-archive',
accountId: getenv('CF_ACCOUNT_ID') ?: '',
accessKeyId: getenv('R2_ACCESS_KEY_ID') ?: '',
secretAccessKey: getenv('R2_SECRET_ACCESS_KEY') ?: '',
pathPrefix: 'invoices/',
),
httpClient: $httpClient,
requestFactory: $httpFactory,
streamFactory: $httpFactory,
);
$upload = $r2->upload($result->pdfData, 'invoice-2026-0042.pdf', [
'tenant' => 'acme',
]);
if (!$upload->success) {
$logger->error('r2 upload failed', ['error' => $upload->error]);
}

Davranış, R2ArchiveManager ve R2ObjectKey üzerinden doğrulanır:

  • Nesne anahtarı tarihe göre bölümlere ayrılır: <pathPrefix><Y>/<m>/<d>/<sanitized-filename>, örneğin invoices/2026/05/18/invoice-2026-0042.pdf.
  • Dosya adı temizlenir: basename() yol geçişini kaldırır; ardından boş baytlar ve denetim karakterleri (\x00\x1f, \x7f) çıkarılır. Boş bir sonuç document.pdf olur.
  • Özel meta veriler x-amz-meta-<lowercased-key> başlıkları olarak gönderilir ve V4 imzalı başlık kümesine dahil edilir.
  • Boyutu maxFileSizeBytes değerinden (varsayılan 104857600) büyük olan dosyalar, herhangi bir istek yapılmadan önce reddedilir; döndürülen R2UploadResult nesnesinde success: false bulunur.
  • R2UploadResult::isValid() metodu geçerli sonuç için success, boş olmayan bir key ve boş olmayan bir etag gerektirir.
$url = $r2->generateSignedUrl('invoices/2026/05/18/invoice-2026-0042.pdf', 900);

generateSignedUrl(), AWS Signature V4 sorgu imzası taşıyan bir GET URL’si oluşturur; bu URL’de denetlediğiniz bir X-Amz-Expires değeri (varsayılan 3600 saniye) bulunur. Kanonik istek, UNSIGNED-PAYLOAD içerik karması işaretçisini kullanır. Sorgu imzası taşıyan bir okuma URL’si bu biçimi kullanır; çünkü gövde, imzalı isteğin bir parçası değildir. Bu açıklama, R2ArchiveManager sınıfından okunduğu hâliyle paketin uygulanmış imzalama davranışını anlatır. AWS Signature Version 4’ü, bir standards development organization (SDO) standardı değil, Amazon’un hizmet belgeleri tanımlar; bu nedenle burada normatif bir madde sabitlenmemiştir. Nesne erişim anahtarları #[SensitiveParameter] ile işaretlidir; bunları günlüklerin dışında tutun.

R2UploadResult::publicUrl($customDomain), bir etki alanı sağlamadığınızda yalın anahtarı, sağladığınızda ise https://<domain>/<key> biçimini döndürür. Sağlanan etki alanında şema yoksa, bir Hypertext Transfer Protocol Secure (HTTPS) şeması ekler. Özel bir paketi herkese açık hâle getirmez; bu, R2 paketi yapılandırması olarak kalır.

ApiProtection, Worker’ın önündeki bir PHP ağ geçidine ulaşan işleme isteklerine uyguladığınız katmandır. Denetimleri sabit bir sırayla yapar: önce API anahtarı, ardından yük boyutu, ardından hız sınırı.

use NextPDF\Cloudflare\ApiKeyValidator;
use NextPDF\Cloudflare\ApiProtection;
use NextPDF\Cloudflare\ApiProtectionConfig;
$protection = new ApiProtection(
config: new ApiProtectionConfig(
maxRequestsPerMinute: 30,
maxRequestsPerHour: 500,
maxPayloadSizeBytes: 5_000_000,
requireApiKey: true,
),
keyValidator: new ApiKeyValidator([getenv('GATEWAY_API_KEY') ?: '']),
);
$decision = $protection->checkRequest(
clientId: $clientIp,
payloadSize: strlen($requestBody),
apiKey: $request->getHeaderLine('X-Api-Key'),
);
if (!$decision->allowed) {
http_response_code(429);
foreach ($decision->toHeaders() as $name => $value) {
header("{$name}: {$value}");
}
echo $decision->denialReason;
exit;
}

Doğrulanan davranış:

  • Sıra şöyledir: API anahtarı → yük boyutu → hız sınırı. İlk başarısız denetim, belirli bir denialReason ile akışı kısa devreye uğratır.
  • ApiKeyValidator::validate(), zamanlama açısından güvenli karşılaştırma için hash_equals() kullanır ve boş bir anahtarı reddeder. validateHashed(), statik anahtar depolaması için Secure Hash Algorithm 256-bit (SHA-256) karmalarıyla karşılaştırır. Anahtar parametreleri #[SensitiveParameter] taşır.
  • Hız sınırı deposu işlem başına bellek içindedir. Dakika başına bir pencereyi (rateLimitWindowSeconds, varsayılan 60) ve saat başına bir pencereyi (sabit 3600 saniye) izler. Worker’lar veya yeniden başlatmalar arasında kalıcı değildir. Sınırları işlemler arasında paylaşmak için bu katmanın önüne paylaşılan bir depo yerleştirin.
  • ApiProtectionResult::toHeaders(), her zaman X-Content-Type-Options: nosniff ve X-Frame-Options: DENY ekler ve hız sınırı başlıklarını (X-RateLimit-Remaining, X-RateLimit-Reset ve reddedildiğinde ek olarak Retry-After) birleştirir.

Bu köprü PDF’leri imzalamaz. Bir üretim imzalama hattı oluşturmak için kenarda işleyin, ardından döndürülen baytları imzalama motoruyla imzalayın:

  1. render()CloudflareRenderResult::$pdfData.
  2. Döndürülen $pdfData değerini nextpdf/core paketine (veya PDF Advanced Electronic Signatures (PAdES) B-B imzalama için NextPDF Pro’ya) verin. Uzun vadeli doğrulama profilleri bir Enterprise yeteneğidir; bu çekirdek köprü bu yeteneklerden hiçbirini sağladığını iddia etmez.

İmzalama adımını kendi işleminizde tutun; böylece imzalama anahtarı asla kenar sınırını geçmez.

  • /integrations/cloudflare/security-and-operations/ — sabitleme, server-side request forgery (SSRF) savunması, gizli anahtar döndürme ve operasyonel başvuru kılavuzu.
  • /integrations/cloudflare/troubleshooting/ — arıza modu kataloğu.
  • /integrations/cloudflare/configuration/ — tüm alanlar ve varsayılanlar.