Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,74 @@
<?php
namespace Xentral\Components\Pdf\Merger;
use Xentral\Components\Pdf\Exception\FileExistsException;
use Xentral\Components\Pdf\Exception\FileNotFoundException;
use Xentral\Components\Pdf\Exception\FileNotWritableException;
use Xentral\Components\Pdf\Exception\InvalidArgumentException;
use Xentral\Components\Pdf\Exception\PdfComponentExceptionInterface;
abstract class AbstractPdfMerger
{
/**
* @param array|string[] $sourceFiles
* @param string $targetFile
*
* @throws PdfComponentExceptionInterface
*
* @return void
*/
abstract public function mergeFiles(array $sourceFiles, $targetFile);
/**
* @param array|string[] $sourceFiles
* @param string $targetFile
*
* @throws InvalidArgumentException
* @throws FileExistsException
* @throws FileNotWritableException
* @throws FileNotFoundException
*
* @return void
*/
protected function preCheckMergeFiles(array $sourceFiles, $targetFile)
{
if (empty($sourceFiles)) {
throw new InvalidArgumentException('Can not merge PDFs. Required parameter "sourceFiles" is empty.');
}
if (empty($targetFile)) {
throw new InvalidArgumentException('Can not merge PDFs. Required parameter "$targetFile" is empty.');
}
if (is_file($targetFile)) {
throw new FileExistsException(sprintf(
'Can not merge PDFs. Target file "%s" already exists.', $targetFile
));
}
if (!$this->isFilePathWriteable($targetFile)) {
throw new FileNotWritableException(sprintf(
'Can not merge PDFs. Unable to create target file "%s" .', $targetFile
));
}
foreach ($sourceFiles as $sourceFile) {
if (!is_file($sourceFile)) {
throw new FileNotFoundException(sprintf(
'Can not merge PDFs. Source file "%s" does not exist.', $sourceFile
));
}
}
}
/**
* @param string $filePath
*
* @return bool
*/
protected function isFilePathWriteable($filePath)
{
$result = @fopen($filePath, 'wb');
@unlink($filePath);
return $result !== false;
}
}
@@ -0,0 +1,90 @@
<?php
namespace Xentral\Components\Pdf\Merger;
use fpdi;
use Xentral\Components\Pdf\Exception\FileExistsException;
use Xentral\Components\Pdf\Exception\FileNotFoundException;
use Xentral\Components\Pdf\Exception\FileNotWritableException;
use Xentral\Components\Pdf\Exception\InvalidArgumentException;
use Xentral\Components\Pdf\Exception\PdfIncompatibleException;
/**
* Anti-Corruption-Layer für alte FPDI-Klasse
*/
final class FpdiPdfMerger extends AbstractPdfMerger
{
/**
* @param string[] $sourceFiles Array with files pathes
* @param string $targetFile Path to merged file
*
* @throws InvalidArgumentException If required parameter is invalid/empty
* @throws FileNotWritableException If target file is not writable
* @throws FileExistsException If target file already exists
* @throws FileNotFoundException If one of the source files does not exist
* @throws PdfIncompatibleException If XRef-Pointer is missing
*
* @return void
*/
public function mergeFiles(array $sourceFiles, $targetFile)
{
$this->preCheckMergeFiles($sourceFiles, $targetFile);
$fpdi = new fpdi('P', 'mm', 'A4');
foreach ($sourceFiles as $file) {
if (!$this->hasPdfXrefError($file)) {
throw new PdfIncompatibleException(sprintf(
'Can not merge PDFs. Unable to find pointer to xref table in file "%s".', $file
));
}
$pageCount = $fpdi->setSourceFile($file);
for ($pageNumber = 1; $pageNumber <= $pageCount; $pageNumber++) {
$templateId = $fpdi->importPage($pageNumber);
$size = $fpdi->getTemplateSize($templateId);
// Create empty page
if ($size['w'] > $size['h']) {
// Landscape orientation
$fpdi->addPage('L', [$size['h'], $size['w']]);
} else {
// Portrait orientation
$fpdi->addPage('P', [$size['w'], $size['h']]);
}
// Import page
$fpdi->useTemplate($templateId);
}
}
$fpdi->Output($targetFile, 'F');
}
/**
* Helper method to detect xref-Error
*
* @see \fpdi_pdf_parser::pdf_find_xref
*
* @param string $pdfFile Path to pdf file
*
* @return bool
*/
public function hasPdfXrefError($pdfFile)
{
$resource = @fopen($pdfFile, 'rb');
fseek($resource, -50, SEEK_END);
$data = fread($resource, 50);
$foundXrefOffset = preg_match('/startxref\s*(\d+)\s*%%EOF\s*$/', $data, $matches);
if (!$foundXrefOffset) {
return false;
}
$xrefOffset = (int)$matches[1];
fseek($resource, $xrefOffset);
$data = trim(fgets($resource));
return $data === 'xref';
}
}
@@ -0,0 +1,103 @@
<?php
namespace Xentral\Components\Pdf\Merger;
use Xentral\Components\Pdf\Exception\PdfComponentExceptionInterface;
use Xentral\Components\Pdf\Exception\ShellCommandFailedException;
final class GhostScriptPdfMerger extends AbstractPdfMerger
{
/**
* @param array $sourceFiles
* @param string $targetFile
*
* @throws PdfComponentExceptionInterface
*
* @return void
*/
public function mergeFiles(array $sourceFiles, $targetFile)
{
$this->preCheckMergeFiles($sourceFiles, $targetFile);
if (!$this->isGhostscriptAvailable()) {
throw new ShellCommandFailedException('Ghostscript command "gs" is missing or not callable.');
}
$sourceFilesParam = '';
foreach ($sourceFiles as $sourceFile) {
$sourceFilesParam .= escapeshellarg($sourceFile) . ' ';
}
$cmdTemplate = 'gs -dQUIET -dNOPAUSE -dBATCH ';
$cmdTemplate .= '-dPDFSETTINGS=/prepress '; // High quality, color preserving, 300 dpi images
$cmdTemplate .= '-dAutoRotatePages=/None -sDEVICE=pdfwrite -sOUTPUTFILE=%s %s';
$cmd = sprintf($cmdTemplate, escapeshellarg($targetFile), $sourceFilesParam);
$this->executeShellCommand($cmd);
}
/**
* @param string $command
*
* @throws ShellCommandFailedException
*
* @return array|string[] Zeilenweise Ausgabe des Commands
*/
private function executeShellCommand($command)
{
if ($this->isFunctionDisabled('exec')) {
throw new ShellCommandFailedException('PHP function "exec" is disabled by php.ini settings.');
}
$output = [];
@exec($command, $output, $returnVar);
switch ($returnVar) {
case 0:
// Kein Fehler
break;
case 1:
throw new ShellCommandFailedException('General error: ' . implode(' ', $output));
break;
case 126:
throw new ShellCommandFailedException('Can not execute "gs" command.');
break;
case 127:
throw new ShellCommandFailedException('Command "gs" not found.');
break;
}
return $output;
}
/**
* @return bool
*/
private function isGhostscriptAvailable()
{
if ($this->isFunctionDisabled('shell_exec')) {
throw new ShellCommandFailedException('PHP function "shell_exec" is disabled by php.ini settings.');
}
$result = @shell_exec('gs');
return !empty($result);
}
/**
* @param string $functionName PHP function name
*
* @return bool
*/
public function isFunctionDisabled($functionName)
{
$functionName = trim($functionName);
$disabledFunctions = explode(',', ini_get('disable_functions'));
foreach ($disabledFunctions as $disabledFunction) {
if (trim($disabledFunction) === $functionName) {
return true;
}
}
return false;
}
}