
本文介绍如何在 Drupal 自定义模块中,通过调用系统级工具 pdftohtml 将上传的 PDF 文件精准转换为保留排版结构的 HTML,并存入 field_decision_text 字段,避免纯文本解析导致的格式丢失。
本文介绍如何在 drupal 自定义模块中,通过调用系统级工具 `pdftohtml` 将上传的 pdf 文件精准转换为保留排版结构的 html,并存入 `field_decision_text` 字段,避免纯文本解析导致的格式丢失。
在 Drupal 中直接将 PDF 渲染为 HTML 并非 PHP 原生能力,TCPDF 和 Dompdf 等库主要用于「PDF 生成」而非「PDF 解析」,因此无法满足从 PDF 提取带样式 HTML 的需求。真正可行的方案是借助成熟的命令行工具 pdftohtml(Xpdf 工具集的一部分),它能将 PDF 转换为语义化 HTML(含内联 CSS、div 布局、字体声明等),最大程度还原原始排版。
✅ 前置依赖:安装 pdftohtml
确保服务器已安装 pdftohtml(非 PHP 扩展):
# Ubuntu/Debian sudo apt-get install xpdf # CentOS/RHEL sudo yum install xpdf # macOS (Homebrew) brew install xpdf
验证安装:
pdftohtml -v # 应输出版本信息,如:pdftohtml version 4.04
✅ 核心转换函数(安全、可调试、符合 Drupal 8+/9+ PSR-4 规范)
将以下函数放入您的模块服务类或工具类中(推荐 src/Utility/PdfToHtmlConverter.php):
<?php namespace Drupal\your_module\Utility;
use RuntimeException;
class PdfToHtmlConverter {
/**
* Converts a local PDF file to HTML using the system pdftohtml binary.
*
* @param string $pdfFilePath Absolute path to the PDF file on disk.
* @return string HTML content with embedded styles and structure.
* @throws RuntimeException If conversion fails or binary is missing.
*/
public static function convert(string $pdfFilePath): string {
// Use array syntax for automatic shell escaping (PHP 7.4+, safer than string concat).
$cmd = [
'pdftohtml',
'-i', // ignore images (optional; omit if you need img tags)
'-s', // generate single HTML file (not split by pages)
'-noframes', // avoid <frameset> — better for Drupal WYSIWYG compatibility
'-stdout', // output HTML to stdout (no temp files)
$pdfFilePath,
];
$descriptorspec = [
1 => ['pipe', 'w'], // stdout → capture HTML
2 => ['pipe', 'w'], // stderr → capture errors
];
$process = proc_open($cmd, $descriptorspec, $pipes);
if (!$process) {
throw new RuntimeException('Failed to launch pdftohtml process.');
}
$html = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$returnCode = proc_close($process);
if ($returnCode !== 0) {
$errorMap = [
1 => 'Error opening PDF file',
2 => 'Error writing output',
3 => 'PDF permissions error',
98 => 'Out of memory',
99 => 'General conversion error',
];
$message = $errorMap[$returnCode] ?? "pdftohtml exited with code {$returnCode}";
throw new RuntimeException("{$message}. Stderr: {$stderr}");
}
// Optional: sanitize output (remove DOCTYPE, html/body tags if field expects fragment)
$html = preg_replace('/^^>]*>\s*]*>\s*]*>\s*|\s*\s*\s*$/is', '', $html);
return trim($html);
}
}
✅ 集成到表单提交逻辑(替换原 submitForm 方法)
在您的表单类 submitForm() 中,替换原有文本提取逻辑,改用 HTML 转换:
use Drupal\your_module\Utility\PdfToHtmlConverter;
use Drupal\node\Entity\Node;
public function submitForm(array &$form, FormStateInterface $form_state) {
$file = $form_state->getValue('pdf_file');
$validators = ['file_validate_extensions' => ['pdf']];
$files = file_save_upload('pdf_file', $validators);
if (!empty($files)) {
$uploaded_file = $files[0];
$pdf_uri = $uploaded_file->getFileUri();
$pdf_path = \Drupal::service('file_system')->realpath($pdf_uri);
try {
// ✅ Convert PDF → HTML (preserves fonts, tables, spacing, headings)
$html_content = PdfToHtmlConverter::convert($pdf_path);
// Create node with HTML in formatted text field
$node = Node::create([
'type' => 'decision',
'title' => $uploaded_file->getFilename(),
'field_attachment' => [
'target_id' => $uploaded_file->id(),
],
'field_decision_text' => [
'value' => $html_content,
'format' => 'full_html', // ⚠️ Ensure this format allows <div>, <style>, etc.
],
]);
$node->save();
$form_state->setRedirectUrl($node->toUrl());
} catch (\Exception $e) {
$this->messenger()->addError(t('PDF to HTML conversion failed: @msg', ['@msg' => $e->getMessage()]));
$form_state->setRebuild(TRUE);
}
} else {
$form_state->setErrorByName('pdf_file', $this->t('Please upload a valid PDF file.'));
}
}<h3>⚠️ 关键注意事项<ul><li><strong>文本格式配置:确保 <code>field_decision_text 字段的「文本处理」设置为 <code>full_html 或自定义允许 <code><div><span><style> 等标签的格式,否则 HTML 将被过滤。<li><strong>权限与路径:<code>pdftohtml 必须对 Web 服务器用户(如 <code>www-data)可执行;若报 <code>command not found,请改用绝对路径(如 <code>/usr/bin/pdftohtml)。<li><strong>安全性提醒:仅对可信来源的 PDF 使用此功能;生产环境建议添加文件大小限制(<code>file_validate_size)和超时控制(<code>proc_open 可配合 <code>stream_set_timeout)。<li><strong>替代方案提示:若无法安装系统工具,可考虑 <a href="https://www.php.cn/link/bee8b66bf9167983003870d045f2acb1" rel="nofollow" target="_blank">pdf2htmlEX(更现代,支持 CSS3/HTML5),调用方式类似,仅需替换命令名与参数。<p>通过该方案,您将获得结构完整、样式内联、语义清晰的 HTML 内容,完美嵌入 Drupal 节点字段,真正实现「PDF 原样复刻为网页内容」的目标。
</style>
</div>前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











