我正在使用 Drupal 开发自定义模块。 我的模块需要让用户上传一个 PDF 文件,然后模块创建一个类型为:decision 的节点,并在 field_decision_text 中我想将 PDF 的内容放在 HTML 结构 中,以便我可以保留所有按原样格式化 PDF。
我尝试过一些库,例如 TCPDF 和 Dompdf,但没有成功。也许我没有正确使用它们。
所以基本上我创建了一个表单,用户在其中上传 PDF,然后当提交表单时,我运行此函数,将 PDF 的内容作为文本放入节点中。
public function submitForm(array &$form, FormStateInterface $form_state) {
// Get the uploaded file.
$file = $form_state->getValue('pdf_file');
// Validate the uploaded file.
$validators = [
'file_validate_extensions' => ['pdf'],
];
$new_file = file_save_upload('pdf_file', $validators);
if ($new_file) {
// Extract text from the PDF file.
$pdf_uri = $new_file[0]->getFileUri();
$pdf_content = \Drupal::service('file_system')->realpath($pdf_uri);
$parser = new \Smalot\PdfParser\Parser();
$pdf = $parser->parseFile($pdf_content);
$text = $pdf->getText();
// Create a new node and save the extracted text to the field.
$node = Node::create([
'type' => 'decision',
'title' => $new_file[0]->getFilename(), // Use the file name as the node title.
'field_attachment' => [
'target_id' => $new_file[0]->id(), // Attach the uploaded file to a file field.
],
'field_decision_text' => $text, // Save the extracted text to the field.
]);
// Save the node.
$node->save();
// Optionally, redirect the user to the created node.
$url = $node->toUrl();
$form_state->setRedirectUrl($url);
} else {
$form_state->setErrorByName('pdf_file', $this->t('Please upload a valid PDF file.'));
}
}
所以我有了我正在寻找的主要功能,我只需要以某种方式将 PDF 转换为 HTML,然后将其传递到节点字段中,但我不太确定如何进行。任何帮助将不胜感激。
这是我根据我用来与这些工具交互的其他一些代码组合而成的快速函数。一般来说,我是
proc_open
的忠实粉丝,因为您可以访问 stdOut 和 stdIn,有时命令程序会将错误信息写入其中一个或两个。
这个函数是纯 PHP 的,所以你应该能够在 Drupal、Symfony、WordPress 等中运行它,尽管你可能想要添加特定于平台的东西,比如日志记录。
您应该能够将
$pdf_content
传递给此函数,该函数将返回 PDF 的内容,或引发异常。
我将通过创建一个存储 stdErr 和 stdOut 以及命令的返回值的自定义异常来扩展它,但我将保留它。
如果遇到问题,请务必检查 stdErr。您可能会看到有关“命令 pdftohtml 不是命令”或类似内容的内容,在这种情况下,您可能需要提供二进制文件的绝对路径,或者可能需要调整权限。
function convertPdfToHtml(string $inputFileName): string
{
// Two ways to run this, the array version was added in 7.4 but might
// run into some platform weirdness, especially on Windows.
// You might also want to specify the absolute path to pdftohtml.
// You can either build a string and escape manually
//$cmd = 'pdftohtml';
//$cmd .= ' -i -s -noframes -stdout';
//$cmd .= ' '.escapeshellarg($inputFileName);
//$cmd .= ' '.escapeshellarg($tmpNameWithExtension);
// OR, you can use an array and it will be escaped for you
$cmd = [
'pdftohtml',
'-i',
'-s',
'-noframes',
'-stdout',
$inputFileName,
];
// Output streams to read errors
$descriptorspec = [
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];
// Handle high-level failure somehow
if (!$process = proc_open($cmd, $descriptorspec, $pipes)) {
throw new RuntimeException('Error');
}
// Get both stdOut and stdErr as strings, just in case we need to look at them
$stdOut = stream_get_contents($pipes[1]);
$stdErr = stream_get_contents($pipes[2]);
// Cleanup
fclose($pipes[1]);
fclose($pipes[2]);
// Check the return value
if ($return_value = proc_close($process)) {
// Exit code from https://www.xpdfreader.com/pdftohtml-man.html#EXIT%20CODES
$msg = match ($return_value) {
1 => 'Error opening a PDF file',
2 => 'Error opening an output file',
3 => 'Error related to PDF permissions',
98 => 'Out of memory',
99 => 'Other error',
default => 'Unknown return_value',
};
// Do something here
throw new RuntimeException($msg.PHP_EOL.$stdErr);
}
return $stdOut;
}