workingDir = $dirStructure['workingDir']; $this->tempDir = $dirStructure['tempDir']; $this->pdfCacheDir = $dirStructure['pdfCacheDir']; $this->fontDir = $dirStructure['fontDir']; } public function getGenerator(array $mpdfConfig = []): \FluentPdf\Vendor\Mpdf\Mpdf { $uploadDir = wp_upload_dir(); $fluentPdfFontDir = $uploadDir['basedir'] . '/FLUENT_PDF_TEMPLATES/fonts'; $fontDirs = [$this->fontDir]; if (is_dir($fluentPdfFontDir)) { $fontDirs[] = $fluentPdfFontDir; } $defaults = [ 'fontDir' => $fontDirs, 'tempDir' => $this->tempDir, 'curlCaCertificate' => ABSPATH . WPINC . '/certificates/ca-bundle.crt', 'curlFollowLocation' => true, 'allow_output_buffering' => true, 'autoLangToFont' => true, 'autoScriptToLang' => true, 'useSubstitutions' => true, 'ignore_invalid_utf8' => true, 'setAutoTopMargin' => 'stretch', 'setAutoBottomMargin' => 'stretch', 'enableImports' => true, 'use_kwt' => true, 'keepColumns' => true, 'biDirectional' => true, 'showWatermarkText' => true, 'showWatermarkImage' => true, 'default_font' => 'dejavusans', ]; $mpdfConfig = wp_parse_args($mpdfConfig, $defaults); $mpdfConfig = apply_filters('fluent_cart/pdf_templates/mpdf_config', $mpdfConfig); return new \FluentPdf\Vendor\Mpdf\Mpdf($mpdfConfig); } public function getTempDirectory(): string { return $this->tempDir; } /** * Resolve same-site image URLs in HTML to local filesystem paths for mPDF. * * @param string $html * @return string */ public function prepareHtmlForPdf(string $html): string { if ($html === '') { return $html; } // Remove tags with empty src to prevent mPDF errors $html = preg_replace('/]*\bsrc\s*=\s*["\']["\'][^>]*>/i', '', $html) ?? $html; $upload_dir = wp_upload_dir(); $content_url = content_url(); $content_dir = WP_CONTENT_DIR; $home_host = wp_parse_url(home_url(), PHP_URL_HOST); $resolveUrl = function ($url) use ($upload_dir, $content_url, $content_dir, $home_host) { $url = trim($url); if ($url === '' || strpos($url, 'data:') === 0) { return null; } $url_host = wp_parse_url($url, PHP_URL_HOST); if ($url_host !== null && $url_host !== $home_host) { return null; } $path_part = wp_parse_url($url, PHP_URL_PATH); if ($path_part === null || $path_part === '') { return null; } if (!empty($upload_dir['baseurl']) && strpos($url, $upload_dir['baseurl']) === 0) { $local_path = $upload_dir['basedir'] . substr($path_part, strlen(wp_parse_url($upload_dir['baseurl'], PHP_URL_PATH))); $local_path = wp_normalize_path($local_path); if (file_exists($local_path) && is_readable($local_path)) { return $local_path; } return null; } if (!empty($content_url) && strpos($url, $content_url) === 0) { $content_path = wp_parse_url($content_url, PHP_URL_PATH); $local_path = $content_dir . substr($path_part, strlen($content_path)); $local_path = wp_normalize_path($local_path); if (file_exists($local_path) && is_readable($local_path)) { return $local_path; } return null; } return null; }; $html = preg_replace_callback( '/(]*\bsrc\s*=\s*["\'])([^"\']+)(["\'][^>]*>)|\b(url\s*\(\s*["\']?)([^"\')\s]+)(["\']?\s*\))/i', function ($m) use ($resolveUrl) { if ($m[1] !== '') { $resolved = $resolveUrl($m[2]); if ($resolved === null) { return $m[0]; } $dataUri = $this->flattenPngTransparency($resolved); return $dataUri !== null ? $m[1] . $dataUri . $m[3] : $m[1] . $resolved . $m[3]; } $resolved = $resolveUrl($m[5]); return $resolved !== null ? 'url(\'' . str_replace(["\\", "'"], ["\\\\", "\\'"], $resolved) . '\')' : $m[0]; }, $html ); return $html; } /** * If $path is a PNG with an alpha channel, composite it onto a white * canvas and return a base64 JPEG data URI. * * @param string $path * @return string|null */ private function flattenPngTransparency(string $path): ?string { if (!function_exists('imagecreatefrompng') || strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'png') { return null; } $src = @imagecreatefrompng($path); if (!$src) { return null; } $w = imagesx($src); $h = imagesy($src); $hasAlpha = false; for ($x = 0; $x < $w && !$hasAlpha; $x++) { for ($y = 0; $y < $h && !$hasAlpha; $y++) { if ((imagecolorat($src, $x, $y) >> 24) & 0x7F) { $hasAlpha = true; } } } if (!$hasAlpha) { imagedestroy($src); return null; } $canvas = imagecreatetruecolor($w, $h); $white = imagecolorallocate($canvas, 255, 255, 255); imagefill($canvas, 0, 0, $white); imagecopy($canvas, $src, 0, 0, 0, 0, $w, $h); imagedestroy($src); ob_start(); imagejpeg($canvas, null, 92); $jpeg = ob_get_clean(); imagedestroy($canvas); return 'data:image/jpeg;base64,' . base64_encode($jpeg); } }