Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: use fallback to get page dimension #4459

Merged
merged 1 commit into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/Helper/ConfigureCheckHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
use JsonSerializable;

/**
* @method ConfigureCheckHelper setSuccessMessage(string $value)
* @method ConfigureCheckHelper setInfoMessage(string $value)
* @method ConfigureCheckHelper setErrorMessage(string $value)
* @method ConfigureCheckHelper setStatus(string $value)
* @method string getStatus()
* @method ConfigureCheckHelper setMessage(string $value)
Expand Down
51 changes: 46 additions & 5 deletions lib/Service/Install/ConfigureCheckService.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@ public function checkSign(): array {
}

public function checkPoppler(): array {
$return = $this->checkPdfSig();
$return = array_merge($return, $this->checkPdfinfo());
return $return;
}

public function checkPdfSig(): array {
if (shell_exec('which pdfsig') === null) {
return [
(new ConfigureCheckHelper())
->setInfoMessage('Poppler utils not installed')
->setResource('poppler-utils')
->setResource('pdfsig')
->setTip('Install the package poppler-utils at your operational system to be possible get more details about validation of signatures.'),
];
}
Expand All @@ -80,17 +86,17 @@ public function checkPoppler(): array {
if (!$version) {
return [
(new ConfigureCheckHelper())
->setInfoMessage('Fail to retrieve pdfsig version')
->setResource('poppler-utils')
->setErrorMessage('Fail to retrieve pdfsig version')
->setResource('pdfsig')
->setTip("The command <pdfsig -v> executed by PHP haven't any output."),
];
}
$version = preg_match('/pdfsig version (?<version>.*)/', $version, $matches);
if (!$version) {
return [
(new ConfigureCheckHelper())
->setInfoMessage('Fail to retrieve pdfsig version')
->setResource('poppler-utils')
->setErrorMessage('Fail to retrieve pdfsig version')
->setResource('pdfsig')
->setTip("This is a poppler-utils dependency and wasn't possible to parse the output of command pdfsig -v"),
];
}
Expand All @@ -100,6 +106,41 @@ public function checkPoppler(): array {
];
}

public function checkPdfinfo(): array {
if (shell_exec('which pdfinfo') === null) {
return [
(new ConfigureCheckHelper())
->setInfoMessage('Poppler utils not installed')
->setResource('pdfinfo')
->setTip('Install the package poppler-utils at your operational system have a fallback to fetch page dimensions.'),
];
}
// The output of this command go to STDERR and shell_exec get the STDOUT
// With 2>&1 the STRERR is redirected to STDOUT
$version = shell_exec('pdfinfo -v 2>&1');
if (!$version) {
return [
(new ConfigureCheckHelper())
->setErrorMessage('Fail to retrieve pdfinfo version')
->setResource('pdfinfo')
->setTip("The command <pdfinfo -v> executed by PHP haven't any output."),
];
}
$version = preg_match('/pdfinfo version (?<version>.*)/', $version, $matches);
if (!$version) {
return [
(new ConfigureCheckHelper())
->setErrorMessage('Fail to retrieve pdfinfo version')
->setResource('pdfinfo')
->setTip("This is a poppler-utils dependency and wasn't possible to parse the output of command pdfinfo -v"),
];
}
return [(new ConfigureCheckHelper())
->setSuccessMessage('pdfinfo version: ' . $matches['version'])
->setResource('pdfinfo')
];
}

/**
* Check all requirements to use JSignPdf
*
Expand Down
66 changes: 56 additions & 10 deletions lib/Service/PdfParserService.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,19 @@ public function setFile(File|string $file): self {
return $this;
}

private function getContent(): string {
if (!$this->content) {
throw new LibresignException('File not defined to be parsed.');
}
return $this->content;
}

private function getDocument(): Document {
if (!$this->document) {
if (!$this->content) {
throw new LibresignException('File not defined to be parsed.');
}
$content = $this->getContent();
try {
$parser = new \Smalot\PdfParser\Parser();
$this->document = $parser->parseContent($this->content);
$this->document = $parser->parseContent($content);
return $this->document;
} catch (\Throwable $th) {
if ($th->getMessage() === 'Secured pdf file are currently not supported.') {
Expand All @@ -67,6 +72,13 @@ private function getDocument(): Document {
* @psalm-return array{p: int, d?: non-empty-list<array{w: mixed, h: mixed}>}
*/
public function getPageDimensions(): array {
if ($return = $this->getPageDimensionsWithPdfInfo()) {
return $return;
}
return $this->getPageDimensionsWithSmalotPdfParser();
}

private function getPageDimensionsWithSmalotPdfParser(): array {
$document = $this->getDocument();
$pages = $document->getPages();
$output = [
Expand All @@ -78,15 +90,49 @@ public function getPageDimensions(): array {
$pages = $document->getObjectsByType('Pages');
$details = reset($pages)->getHeader()->getDetails();
}
$widthAndHeight = [
'w' => $details['MediaBox'][2],
'h' => $details['MediaBox'][3]
];
if (!is_numeric($widthAndHeight['w']) || !is_numeric($widthAndHeight['h'])) {
if (!isset($details['MediaBox']) || !is_numeric($details['MediaBox'][2]) || !is_numeric($details['MediaBox'][3])) {
$this->logger->error('Impossible get metadata from this file: Error to get page width and height. If possible, open an issue at github.com/libresign/libresign with the file that you used.');
throw new LibresignException('Impossible get metadata from this file.');
}
$output['d'][] = $widthAndHeight;
$output['d'][] = [
'w' => $details['MediaBox'][2],
'h' => $details['MediaBox'][3],
];
}
$pending = $output['p'] - count($output['d']);
if ($pending) {
for ($i = 0; $i < $pending; $i++) {
$output['d'][] = $output['d'][0];
}
}
return $output;
}

private function getPageDimensionsWithPdfInfo(): array {
if (shell_exec('which pdfinfo') === null) {
return [];
}
$content = $this->getContent();
$filename = $this->tempManager->getTemporaryFile('.pdf');
file_put_contents($filename, $content);

// The output of this command go to STDERR and shell_exec get the STDOUT
// With 2>&1 the STRERR is redirected to STDOUT
$pdfinfo = shell_exec('pdfinfo ' . $filename . ' -l -1 2>&1');
if (!$pdfinfo) {
return [];
}
if (!preg_match_all('/Page +\d+ +size: +(\d+\.?\d*) x (\d+\.?\d*)/', $pdfinfo, $pages)) {
return [];
}
$output = [
'p' => count($pages[1]),
];
foreach ($pages[1] as $page => $width) {
$output['d'][] = [
'w' => (float)$width,
'h' => (float)$pages[2][$page],
];
}
return $output;
}
Expand Down
38 changes: 37 additions & 1 deletion tests/Unit/Service/PdfParseServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Libresign\Service;

/**
* Overwrite shell_exec in the OCA\Libresign\Service namespace.
*/
function shell_exec($command) {
if (\OCA\Libresign\Tests\Unit\Service\PdfParseServiceTest::$disablePdfInfo) {
return null;
}
return \shell_exec($command);
}

namespace OCA\Libresign\Tests\Unit\Service;

use OCA\Libresign\Exception\LibresignException;
Expand All @@ -21,6 +33,7 @@
final class PdfParseServiceTest extends \OCA\Libresign\Tests\Unit\TestCase {
private ITempManager $tempManager;
private LoggerInterface&MockObject $loggerInterface;
public static $disablePdfInfo = false;

public function setUp(): void {
parent::setUp();
Expand Down Expand Up @@ -62,7 +75,8 @@ public static function dataGetMetadataWithFail(): array {
/**
* @dataProvider providerGetMetadataWithSuccess
*/
public function testGetMetadataWithSuccess(string $path, array $expected): void {
public function testGetMetadataWithSuccess(bool $disablePdfInfo, string $path, array $expected): void {
self::$disablePdfInfo = $disablePdfInfo;
/** @var File|MockObject */
$file = $this->createMock(File::class);
$file->method('getContent')
Expand All @@ -76,6 +90,7 @@ public function testGetMetadataWithSuccess(string $path, array $expected): void
public static function providerGetMetadataWithSuccess(): array {
return [
[
'disablePdfInfo' => true,
'tests/fixtures/small_valid.pdf',
[
'p' => 1,
Expand All @@ -85,6 +100,7 @@ public static function providerGetMetadataWithSuccess(): array {
]
],
[
'disablePdfInfo' => true,
'tests/fixtures/small_valid-signed.pdf',
[
'p' => 1,
Expand All @@ -93,6 +109,26 @@ public static function providerGetMetadataWithSuccess(): array {
],
]
],
[
'disablePdfInfo' => false,
'tests/fixtures/small_valid.pdf',
[
'p' => 1,
'd' => [
['w' => 595.276, 'h' => 841.89],
],
]
],
[
'disablePdfInfo' => false,
'tests/fixtures/small_valid-signed.pdf',
[
'p' => 1,
'd' => [
['w' => 595.276, 'h' => 841.89],
],
]
],
];
}
}
Loading