PdftotextExtractor.php
Pfad: src/Infrastructure/Rechnung/PdftotextExtractor.php
Ext: php
Größe: 1786 Bytes
Geändert: 2026-07-16 16:57:10+02
<?php
declare(strict_types=1);
namespace Demo\Infrastructure\Rechnung;
use Demo\Domain\Rechnung\ExtractedInvoiceData;
use Demo\Domain\Rechnung\TextExtractionPort;
use RuntimeException;
/**
* Extrahiert eingebetteten PDF-Text ueber Poppler.
*/
final class PdftotextExtractor implements TextExtractionPort
{
/** Bindet den Adapter an das Poppler-Binary. */
public function __construct(private readonly string $binary = 'pdftotext', private readonly ?InvoiceTextParser $parser = null)
{
}
/** Extrahiert und parst eine PDF-Datei. */
public function extract(string $pdfPath): ExtractedInvoiceData
{
if (!is_file($pdfPath)) {
throw new RuntimeException('PDF fuer Textextraktion fehlt');
}
[$status, $stdout, $stderr] = $this->run([$this->binary, '-layout', $pdfPath, '-']);
if ($status !== 0 || trim($stdout) === '') {
throw new RuntimeException('pdftotext fehlgeschlagen: ' . trim($stderr));
}
return ($this->parser ?? new InvoiceTextParser())->parse($stdout, 0.85);
}
/**
* @param list<string> $command Prozessargumente ohne Shell.
* @return array{int,string,string} Exitcode, stdout, stderr.
*/
private function run(array $command): array
{
$pipes = [];
$process = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
if (!is_resource($process)) {
throw new RuntimeException('pdftotext kann nicht gestartet werden');
}
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
return [proc_close($process), $stdout === false ? '' : $stdout, $stderr === false ? '' : $stderr];
}
}
Frühere Versionen
| Version | Zeitpunkt | Operation |
|---|---|---|
| 27 | 2026-07-16 19:01:40.81513+02 | UPDATE |