You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用wkhtmltopdf+Laravel生成PDF时标题特殊字符显示异常

问题:Laravel中wkhtmltopdf生产环境PDF标题丢失特殊字符

本地环境下,用wkhtmltopdf生成的PDF在浏览器标签页的标题能正常显示变音符号等特殊字符,保存时的文件名也正常;但生产环境中,浏览器标签页的PDF标题会丢失所有特殊字符(比如"können"变成"knnen"),不过保存文件名仍正常。

两端环境均使用wkhtmltopdf 0.12.6 (with patched qt),已在HTML中添加UTF-8编码meta标签,wkhtmltopdf配置也指定了encoding => 'utf-8',本地正常但生产环境问题依旧。

相关代码

Controller.php

<?php

/**
 * @todo
 */
public function pdf($regionCode, $langCode, Model $model)
{
    $locale = LocalisationServiceProvider::getLocale($regionCode, $langCode);

    $pdfFileName = $this->buildPdfFileName($model->id, $locale);

    if (Storage::disk('root')->exists('public/storage/wkhtmltopdf/' . $pdfFileName)) {
        return response()->file(public_path('/storage/wkhtmltopdf/' . $pdfFileName));
    }

    $view = view('model.pdf', compact('model', 'locale'));
    $viewRendered = $view->render();

    $pdf = new Pdf([
        'binary' => env('WKHTMLTOPDF_BINARY_PATH'),
        'ignoreWarnings' => ('production' === env('APP_ENV')),
        'disable-smart-shrinking',
        'title' => $model->title . ' - Site.pdf',
        'encoding' => 'utf-8',
    ]);

    $pdf->addPage($viewRendered);

    if (!$pdf->saveAs(public_path('/storage/wkhtmltopdf/' . $pdfFileName))) {
        $error = $pdf->getError();
        // @todo log
        return response('An error occured', 500);
    }

    if (!$pdf->send($model->title . ' - Site.pdf', true)) {
        $error = $pdf->getError();
        return response('An error occured', 500);
    }
}

/**
 * @todo
 */
public function buildPdfFileName($id, $locale)
{
    return 'foobar_' . $id . '_' . $locale . '.pdf';
}

pdf.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="canvas" class="position-relative">

            @hasSection('header')
                <header id="header">
                    @yield('header')
                </header>
            @endif

            @hasSection('main')
                <main role="main" id="main-content">
                    @yield('main')
                </main>
            @endif

        </div>
    </body>
</html>

注:buildPdfFileName仅用于本地存储的PDF内部文件名,与标题/保存文件名无关。

解决方案

1. 检查生产环境系统区域编码

生产环境的系统区域设置可能不是UTF-8,导致wkhtmltopdf处理字符串时丢失特殊字符。执行以下命令查看并设置:

# 查看当前区域设置
locale
# 设置为UTF-8编码的区域(以英文为例,可根据实际语言调整)
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

如果是服务器常驻进程(如PHP-FPM),需要重启进程让设置生效。

2. 显式确保标题字符串为UTF-8编码

生产环境中,字符串可能存在编码转换问题,显式转换标题为UTF-8:

$title = mb_convert_encoding($model->title . ' - Site.pdf', 'UTF-8', 'auto');

$pdf = new Pdf([
    // 其他配置...
    'title' => $title,
    'encoding' => 'utf-8',
]);

// send方法也使用转换后的标题
if (!$pdf->send($title, true)) {
    // ...
}

3. 在HTML模板中添加标签 <a class="header-anchor" href="#_3-在html模板中添加标签" aria-hidden="true">#</a></h3> <p>让wkhtmltopdf从HTML内容中读取标题,而非依赖配置参数,避免编码传递问题:<br> 修改<code>pdf.blade.php</code>的<head>部分:</p> <pre class="hljs"><code class="language-html volc-pre-code"><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta charset="UTF-8"> <title>{{ $model->title }} - Site.pdf</title> </head> </code></pre> <p>同时可以移除wkhtmltopdf配置中的<code>'title'</code>参数,让工具自动读取HTML的title。</p> <h3 id="_4-手动设置响应头的content-disposition">4. 手动设置响应头的Content-Disposition <a class="header-anchor" href="#_4-手动设置响应头的content-disposition" aria-hidden="true">#</a></h3> <p>当使用<code>response()->file</code>返回已生成的PDF时,确保响应头中的文件名和标题都正确编码:</p> <pre class="hljs"><code class="language-php volc-pre-code">if (Storage::disk('root')->exists('public/storage/wkhtmltopdf/' . $pdfFileName)) { $title = $model->title . ' - Site.pdf'; // 编码文件名,支持UTF-8 $encodedFileName = rawurlencode($title); return response()->file(public_path('/storage/wkhtmltopdf/' . $pdfFileName), [ 'Content-Disposition' => "inline; filename*=UTF-8''{$encodedFileName}; filename=\"{$encodedFileName}\"", 'Content-Type' => 'application/pdf', ]); } </code></pre> <p>内容的提问来源于stack exchange,提问作者Alex</p>

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 23:27:57