Issues (17)

src/Api.php (6 issues)

1
<?php
2
/**
3
 * Created by Marcin.
4
 * Date: 03.03.2019
5
 * Time: 14:22
6
 */
7
8
namespace Mrcnpdlk\Api\Unoconv;
9
10
set_time_limit(0);
11
12
use CURLFile;
13
use const CURLOPT_POST;
14
use const CURLOPT_POSTFIELDS;
15
use const CURLOPT_RETURNTRANSFER;
16
use const CURLOPT_URL;
17
use const JSON_ERROR_NONE;
18
use mikehaertl\shellcommand\Command;
19
use Mrcnpdlk\Api\Unoconv\Enum\FormatType;
20
use Mrcnpdlk\Api\Unoconv\Exception\DomainException;
21
use Mrcnpdlk\Api\Unoconv\Exception\InvalidFileArgumentException;
22
use Mrcnpdlk\Api\Unoconv\Exception\UnoconvException;
23
use SplFileObject;
24
25
/**
26
 * Class Api
27
 */
28
class Api
29
{
30
    /**
31
     * @var array
32
     */
33
    private $params = [];
34
    /** @noinspection PhpUndefinedClassInspection */
35
    /**
36
     * @var \Psr\Log\LoggerInterface
37
     */
38
    private $logger;
39
    /**
40
     * @var string
41
     */
42
    private $ws;
43
    /**
44
     * @var \Mrcnpdlk\Api\Unoconv\Config
45
     */
46
    private $oConfig;
47
48
    /**
49
     * Api constructor.
50
     *
51 6
     * @param \Mrcnpdlk\Api\Unoconv\Config $oConfig
52
     *
53 6
     * @throws \Mrcnpdlk\Lib\ConfigurationException
54 6
     */
55 6
    public function __construct(Config $oConfig = null)
56 6
    {
57 6
        $this->oConfig              = $oConfig ?? new Config();
58 6
        $this->logger               = $this->oConfig->getLogger();
59 6
        $this->ws                   = $this->oConfig->getWebservice();
60 6
        $this->params['connection'] = $this->oConfig->getConnectionString();
61
        $this->params['timeout']    = $this->oConfig->getTimeout();
62
        $this->params['docType']    = $this->oConfig->getDocType();
63
        $this->params['format']     = $this->oConfig->getFormat();
64
    }
65
66
    /**
67
     * @param string          $sourceFile  Path to input file
68
     * @param FormatType|null $format      Default PDF
69
     * @param string|null     $destination Path to output file or directory
70
     * @param array           $exportOpts  Export options
71
     *
72
     * @throws \Mrcnpdlk\Api\Unoconv\Exception\InvalidFileArgumentException
73
     * @throws \Mrcnpdlk\Api\Unoconv\Exception\UnoconvException
74 4
     * @throws \Mrcnpdlk\Api\Unoconv\Exception\DomainException
75
     *
76 4
     * @return SplFileObject
77
     */
78 4
    public function transcode(string $sourceFile, ?FormatType $format, ?string $destination, array $exportOpts = []): SplFileObject
79 1
    {
80
        $sourceFile = realpath($sourceFile);
81 3
82
        if (!is_file($sourceFile)) {
83
            throw new InvalidFileArgumentException(sprintf('Input file "%s" not exists', $sourceFile));
84
        }
85 3
        if (!is_readable($sourceFile)) {
86 3
            throw new InvalidFileArgumentException(sprintf('Input file "%s" is not readable', $sourceFile));
87
        }
88 3
89 1
        $format       = $format ?? $this->params['format'];
90 1
        $fromPathInfo = pathinfo($sourceFile);
91 1
92 1
        if (null === $destination) {
93 1
            $destination = sprintf('%s%s%s.%s',
94
                $fromPathInfo['dirname'],
95 2
                DIRECTORY_SEPARATOR,
96 2
                $fromPathInfo['filename'],
97 2
                $format->getExtension()
98 2
            );
99 2
        } elseif (is_dir($destination)) {
100 2
            $destination = sprintf('%s%s%s.%s',
101
                $destination,
102
                DIRECTORY_SEPARATOR,
103
                $fromPathInfo['filename'],
104 3
                $format->getExtension()
105
            );
106 3
        }
107
108 3
        $this->logger->debug(sprintf('Creating "%s" from "%s"', $destination, $sourceFile));
109 3
110 3
        $command = new Command($this->params['connection']);
111 3
        $command
112
            ->addArg('--doctype', $this->params['docType'], false)
113
            ->addArg('--format', $format, false)
114 3
            ->addArg('--timeout', $this->params['timeout'], false)
115 2
            ->addArg('--output', $destination, false)
116 1
        ;
117 2
118 1
        foreach ($exportOpts as $key => $value) {
119 1
            if (is_bool($value)) {
120 1
                $value = $value ? 'true' : 'false';
121 1
            } elseif (is_string($value)) {
122 1
                $value = sprintf('"%s"', $value);
123 1
            } elseif (!is_int($value)) {
124
                throw new DomainException(sprintf('Invalid type of export argument "%s", only %s are allowed.', gettype($value), implode(',', ['int', 'string', 'bool'])));
125
            }
126
127 1
            $command->addArg('--export', sprintf('%s=%s', $key, $value), false);
128
        }
129
130 2
        $command->addArg($sourceFile);
131
132 2
        $this->logger->debug(sprintf('Executing command: %s', $command->getExecCommand()));
0 ignored issues
show
It seems like $command->getExecCommand() can also be of type false; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
        $this->logger->debug(sprintf('Executing command: %s', /** @scrutinizer ignore-type */ $command->getExecCommand()));
Loading history...
133
134 2
        if ($command->execute()) {
135
            return new SplFileObject($destination);
136
        }
137 2
        throw new UnoconvException(sprintf('Unoconv error: %s', $command->getError()), $command->getExitCode());
138
    }
139
140
    /**
141
     * Generate PDF using external WebService
142
     *
143
     * @see https://github.com/zrrrzzt/docker-unoconv-webservice
144
     *
145
     * @param string      $sourceFile
146
     * @param string|null $destination
147
     *
148
     * @throws \Mrcnpdlk\Api\Unoconv\Exception\InvalidFileArgumentException
149
     * @throws \Mrcnpdlk\Api\Unoconv\Exception\UnoconvException
150
     * @throws \Mrcnpdlk\Api\Unoconv\Exception
151
     *
152
     * @return \SplFileObject
153 1
     */
154
    public function wsGetPdf(string $sourceFile, ?string $destination): SplFileObject
155 1
    {
156
        $sourceFile = realpath($sourceFile);
157 1
158
        if (!is_file($sourceFile)) {
159
            throw new InvalidFileArgumentException(sprintf('Input file "%s" not exists', $sourceFile));
160 1
        }
161
        if (!is_readable($sourceFile)) {
162
            throw new InvalidFileArgumentException(sprintf('Input file "%s" is not readable', $sourceFile));
163
        }
164 1
165
        $fromPathInfo = pathinfo($sourceFile);
166 1
167
        if (null === $destination) {
168
            $destination = sprintf('%s%s%s.pdf',
169
                $fromPathInfo['dirname'],
170
                DIRECTORY_SEPARATOR,
171
                $fromPathInfo['filename']
172 1
            );
173 1
        } elseif (is_dir($destination)) {
174 1
            $destination = sprintf('%s%s%s.pdf',
175 1
                $destination,
176 1
                DIRECTORY_SEPARATOR,
177
                $fromPathInfo['filename']
178
            );
179
        }
180 1
181
        $ch = curl_init();
182 1
        curl_setopt($ch, CURLOPT_URL, sprintf('%s/unoconv/pdf', $this->ws));
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_URL, sprintf('%s/unoconv/pdf', $this->ws));
Loading history...
183 1
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
184 1
        curl_setopt($ch, CURLOPT_POST, true);
185 1
        curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile($sourceFile)]);
186 1
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->params['timeout']);
187 1
188 1
        $output   = null;
189 1
        $maxLoops = $this->oConfig->getMaxLoop();
190 1
        for ($iLoop = 0; true; ++$iLoop) {
191
            $this->logger->debug(sprintf('Creating "%s" from "%s" [loop #%d]', $destination, $sourceFile, $iLoop + 1));
192
193
            $output = curl_exec($ch);
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

193
            $output = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
194
            if (false === $output) {
195
                throw new UnoconvException('Curl error: ' . curl_error($ch));
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_error() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
                throw new UnoconvException('Curl error: ' . curl_error(/** @scrutinizer ignore-type */ $ch));
Loading history...
196
            }
197
198
            $ret = json_decode($output, false);
0 ignored issues
show
It seems like $output can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

198
            $ret = json_decode(/** @scrutinizer ignore-type */ $output, false);
Loading history...
199
            if (JSON_ERROR_NONE !== json_last_error()) {
200
                break;
201
            }
202
            /*
203
             * Fix: sometime the first request is with error
204
             */
205
            if ($iLoop >= $maxLoops) {
206
                throw new UnoconvException('WebService Error: ' . $ret->message);
207
            }
208
            $this->logger->debug(sprintf('Creating "%s" from "%s" [loop #%d] - restarting request', $destination, $sourceFile, $iLoop + 1));
209
        }
210
211
        curl_close($ch);
0 ignored issues
show
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
212
        if (null === $output) {
213
            throw new Exception('WTF. Output is NULL');
214
        }
215
        file_put_contents($destination, $output);
216
217
        return new SplFileObject($destination);
218
    }
219
}
220