diff --git a/src/OrderDocumentPdfBuilderAbstract.php b/src/OrderDocumentPdfBuilderAbstract.php index 7d07e2e..5449f1c 100644 --- a/src/OrderDocumentPdfBuilderAbstract.php +++ b/src/OrderDocumentPdfBuilderAbstract.php @@ -83,6 +83,17 @@ public function saveDocument(string $toFilename) return $this; } + /** + * Returns the PDF as an inline file + * + * @param string $toFilename + * @return string + */ + public function saveDocumentInline(string $toFilename): string + { + return $this->pdfWriter->Output($toFilename, 'I'); + } + /** * Returns the PDF as a string * @@ -155,7 +166,7 @@ private function startCreatePdf(): void for ($pageNumber = 1; $pageNumber <= $pageCount; ++$pageNumber) { $pageContent = $this->pdfWriter->importPage($pageNumber, '/MediaBox'); $this->pdfWriter->AddPage(); - $this->pdfWriter->useTemplate($pageContent); + $this->pdfWriter->useTemplate($pageContent, 0, 0, null, null, true); } // Set PDF version 1.7 according to PDF/A-3 ISO 32000-1 diff --git a/src/OrderDocumentPdfReader.php b/src/OrderDocumentPdfReader.php index 81f85d3..270788e 100644 --- a/src/OrderDocumentPdfReader.php +++ b/src/OrderDocumentPdfReader.php @@ -9,11 +9,9 @@ namespace horstoeko\orderx; -use Exception; -use horstoeko\orderx\exception\OrderFileNotFoundException; -use horstoeko\orderx\exception\OrderNoValidAttachmentFoundInPdfException; -use JMS\Serializer\Exception\RuntimeException; use Smalot\PdfParser\Parser as PdfParser; +use horstoeko\orderx\exception\OrderFileNotFoundException; +use horstoeko\orderx\exception\OrderFileNotReadableException; /** * Class representing the document reader for incoming PDF/A-Documents with @@ -30,64 +28,137 @@ class OrderDocumentPdfReader /** * List of filenames which are possible in PDF */ - const ATTACHMENT_FILEAMES = ['order-x.xml']; + const ATTACHMENT_FILENAMES = ['order-x.xml']; /** * Load a PDF file (Order-X) * - * @param string $pdfFilename - * Contains a full-qualified filename which must exist and must be readable + * @param string $pdfFilename Contains a full-qualified filename which must exist and must be readable * @return null|OrderDocumentReader * @throws OrderFileNotFoundException * @throws Exception - * @throws RuntimeException - * @throws OrderNoValidAttachmentFoundInPdfException */ public static function readAndGuessFromFile(string $pdfFilename): ?OrderDocumentReader { if (!file_exists($pdfFilename)) { throw new OrderFileNotFoundException($pdfFilename); } - if (!is_readable($pdfFilename)) { + + $pdfContent = file_get_contents($pdfFilename); + + if ($pdfContent === false) { + throw new OrderFileNotReadableException($pdfFilename); + } + + return static::readAndGuessFromContent($pdfContent); + } + + /** + * Tries to load an attachment content from PDF and return a OrderDocumentReader + * If any erros occured or no attachments were found null is returned + * + * @param string $pdfContent String Containing the binary pdf data + * @return OrderDocumentReader|null + * @throws Exception + */ + public static function readAndGuessFromContent(string $pdfContent): ?OrderDocumentReader + { + $xmlContent = static::internalExtractXMLFromPdfContent($pdfContent); + + if (is_null($xmlContent)) { + return null; + } + + try { + return OrderDocumentReader::readAndGuessFromContent($xmlContent); + } catch (\Exception $e) { + return null; + } + } + + /** + * Returns a XML content from a PDF file + * + * @param string $pdfFilename + * Contains a full-qualified filename which must exist and must be readable + * @return string|null + * @throws OrderFileNotFoundException + * @throws OrderFileNotReadableException + * @throws Exception + */ + public static function getXmlFromFile(string $pdfFilename): ?string + { + if (!file_exists($pdfFilename)) { throw new OrderFileNotFoundException($pdfFilename); } + $pdfContent = file_get_contents($pdfFilename); + + if ($pdfContent === false) { + throw new OrderFileNotReadableException($pdfFilename); + } + + return static::getXmlFromContent($pdfContent); + } + + /** + * Returns a XML content from a PDF binary stream (string) + * + * @param string $pdfContent String Containing the binary pdf data + * @return string|null + * @throws Exception + */ + public static function getXmlFromContent(string $pdfContent): ?string + { + return static::internalExtractXMLFromPdfContent($pdfContent); + } + + /** + * Get the attachment content from XML. + * See the allowed filenames which are supported + * + * @param string $pdfContent + * @return null|string + * @throws Exception + */ + protected static function internalExtractXMLFromPdfContent(string $pdfContent): ?string + { $pdfParser = new PdfParser(); - $pdfParsed = $pdfParser->parseFile($pdfFilename); + $pdfParsed = $pdfParser->parseContent($pdfContent); $filespecs = $pdfParsed->getObjectsByType('Filespec'); $attachmentFound = false; $attachmentIndex = 0; $embeddedFileIndex = 0; - $orderDocument = null; + $returnValue = null; - foreach ($filespecs as $filespec) { - $filespecDetails = $filespec->getDetails(); - if (in_array($filespecDetails['F'], static::ATTACHMENT_FILEAMES)) { - $attachmentFound = true; - break; - } - $attachmentIndex++; - } - - if (true == $attachmentFound) { - /** - * @var array<\Smalot\PdfParser\PDFObject> - */ - $embeddedFiles = $pdfParsed->getObjectsByType('EmbeddedFile'); - foreach ($embeddedFiles as $embeddedFile) { - if ($attachmentIndex == $embeddedFileIndex) { - $orderDocument = OrderDocumentReader::readAndGuessFromContent($embeddedFile->getContent()); + try { + foreach ($filespecs as $filespec) { + $filespecDetails = $filespec->getDetails(); + if (in_array($filespecDetails['F'], static::ATTACHMENT_FILENAMES)) { + $attachmentFound = true; break; } - $embeddedFileIndex++; + $attachmentIndex++; } - } - if (is_null($orderDocument)) { - throw new OrderNoValidAttachmentFoundInPdfException(); + if (true == $attachmentFound) { + /** + * @var array<\Smalot\PdfParser\PDFObject> + */ + $embeddedFiles = $pdfParsed->getObjectsByType('EmbeddedFile'); + foreach ($embeddedFiles as $embeddedFile) { + if ($attachmentIndex == $embeddedFileIndex) { + $returnValue = $embeddedFile->getContent(); + break; + } + $embeddedFileIndex++; + } + } + } catch (\Exception $e) { + $returnValue = null; } - return $orderDocument; + return $returnValue; } } diff --git a/src/exception/OrderFileNotReadableException.php b/src/exception/OrderFileNotReadableException.php new file mode 100644 index 0000000..61adbdc --- /dev/null +++ b/src/exception/OrderFileNotReadableException.php @@ -0,0 +1,61 @@ + + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/horstoeko/orderx + */ +class OrderFileNotReadableException extends Exception +{ + /** + * The context of the type element + * + * @var string + */ + private $filePath = ""; + + /** + * Constructor + * + * @param string $filePath + */ + public function __construct(string $filePath) + { + $this->filePath = $filePath; + + parent::__construct($this->buildMessage()); + } + + /** + * @inheritDoc + */ + public function __toString() + { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + } + + /** + * Build the message + * + * @return string + */ + private function buildMessage(): string + { + return sprintf("The filer %s is not readable", $this->filePath); + } +} diff --git a/tests/testcases/OrderDocumentPdfReaderComfortTest.php b/tests/testcases/OrderDocumentPdfReaderComfortTest.php index 8f1494a..6986b73 100644 --- a/tests/testcases/OrderDocumentPdfReaderComfortTest.php +++ b/tests/testcases/OrderDocumentPdfReaderComfortTest.php @@ -24,8 +24,8 @@ public function testPdfReadNotExists(): void public function testPdfReadInvalid(): void { - $this->expectException(OrderNoValidAttachmentFoundInPdfException::class); self::$document = OrderDocumentPdfReader::readAndGuessFromFile(dirname(__FILE__) . '/../assets/reader-invalid.pdf'); + $this->assertNull(self::$document); } public function testPdfRead(): void diff --git a/tests/testcases/OrderDocumentPdfReaderExtendedTest.php b/tests/testcases/OrderDocumentPdfReaderExtendedTest.php index cf71e9b..74740e9 100644 --- a/tests/testcases/OrderDocumentPdfReaderExtendedTest.php +++ b/tests/testcases/OrderDocumentPdfReaderExtendedTest.php @@ -24,8 +24,8 @@ public function testPdfReadNotExists(): void public function testPdfReadInvalid(): void { - $this->expectException(OrderNoValidAttachmentFoundInPdfException::class); self::$document = OrderDocumentPdfReader::readAndGuessFromFile(dirname(__FILE__) . '/../assets/reader-invalid.pdf'); + $this->assertNull(self::$document); } public function testPdfRead(): void