CakePhp 3.x、TCPDF、htmlspecialchars

CakePhp 3.x, TCPDF, htmlspecialchars

我已经按照文档安装了插件 "CakePDF":https://github.com/FriendsOfCake/CakePdf

现在我想构建第一个 PDF,但出现以下错误:

这是我在bootstrap.php中的配置:

Configure::write('CakePdf', [
    'engine' => 'CakePdf.Tcpdf',
    'margin' => [
        'bottom' => 15,
        'left' => 50,
        'right' => 30,
        'top' => 45
    ],
    'download' => true,
    'encoding' => 'UTF-8'
]);

我编写的唯一代码是模板中的以下代码:

$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);

这是 functions.php 中第 68 行的代码:

function h($text, $double = true, $charset = null)
    {
        if (is_string($text)) {
            //optimize for strings
        } elseif (is_array($text)) {
            $texts = [];
            foreach ($text as $k => $t) {
                $texts[$k] = h($t, $double, $charset);
            }
            return $texts;
        } elseif (is_object($text)) {
            if (method_exists($text, '__toString')) {
                $text = (string)$text;
            } else {
                $text = '(object)' . get_class($text);
            }
        } elseif (is_bool($text)) {
            return $text;
        }

        static $defaultCharset = false;
        if ($defaultCharset === false) {
            $defaultCharset = mb_internal_encoding();
            if ($defaultCharset === null) {
                $defaultCharset = 'UTF-8';
            }
        }
        if (is_string($double)) {
            $charset = $double;
        }
        return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, ($charset) ? $charset : $defaultCharset, $double);
    }

我非常困惑,找不到任何解决方案。有人有想法吗?

我想,我找到了罪魁祸首。 TCPDF 的构造方法将 mb_internal_encoding 设置为 ASCII。 (tcpdf.php 第 1838 行)

我在评论中发现了一个提示:Please note that this method sets the mb_internal_encoding to ASCII, so if you are using the mbstring module functions with TCPDF you need to correctly set/unset the mb_internal_encoding when needed.

但现在我需要有关如何正确使用 tcpdf 和 mb_internal_encoding 的建议(没有 cake 或 tcpdf 的问题)。

抱歉提问,我绝对是初学者。 ;)

如您所想,问题 is/was TCPDF class 与 mb_internal_encoding() 混淆,后者在 CakePHPs h() 函数中用于确定应用程序默认值编码,以防没有明确的编码作为参数传递。

我不是 TCPDF 专家,很久没用过它了,但是快速浏览一下当前的源代码,我很难理解为什么它会乱用内部编码,因为库使用的唯一 mb_* 函数是 mb_convert_encoding(),其中传递了两个编码参数,因此根本没有使用内部编码。话虽如此,我会将此作为 bug/issue 报告给 TCPDF 开发人员。

无论如何,您遇到这个问题只是因为您使用 CakePDF 的方式不对。无需手动创建 PDF 引擎实例,这就是 CakePDF 自动为您完成的,这几乎是插件的全部要点,它抽象了 PDF 创建,因此您只需要在中构建适当的 HTML你的视图模板。这样,您还可以避免当前遇到的 TCPDF 编码问题,因为在创建 PDF 引擎实例 之前 呈现视图模板。

tl;博士

长话短说,只在视图模板中构建 HTML,如果您确实需要访问 PDF 引擎实例,因为您需要做的事情只能通过这种方式实现,那么 CakePDF 不是您要找的插件。

在尝试查找和调试相同错误一个多小时后,我在使用 TCPDF 后将值重置为 UTF-8 - 一切正常之前:

$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);

///...create, save, display your pdf

// Reset the encoding forced from tcpdf
mb_internal_encoding('UTF-8');

我也试过在 new TCPDF 调用后直接重置它,一切都很好。我不知道这次重置会出什么问题 :) 我的 PDF 在此之后看起来仍然一样,但电子邮件会再次发送。

通过扩展 TCPDF class 放回初始编码,并使用新的 class:

class TCPDF_repaired extends TCPDF{
    public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) {
        parent::__construct($orientation, $unit, $format, $unicode, $encoding, $diskcache, $pdfa);
        mb_internal_encoding($this->internal_encoding);
    }
};