Passed
Push — master ( 8cb679...56af05 )
by Roberto
03:45
created

SoapBase::saveDebugFiles()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 0
cts 14
cp 0
rs 9.0856
c 0
b 0
f 0
cc 3
eloc 16
nc 4
nop 3
crap 12
1
<?php
2
3
namespace NFePHP\Common\Soap;
4
5
/**
6
 * Soap base class
7
 *
8
 * @category  NFePHP
9
 * @package   NFePHP\Common\Soap\SoapBase
10
 * @copyright NFePHP Copyright (c) 2017
11
 * @license   http://www.gnu.org/licenses/lgpl.txt LGPLv3+
12
 * @license   https://opensource.org/licenses/MIT MIT
13
 * @license   http://www.gnu.org/licenses/gpl.txt GPLv3+
14
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
15
 * @link      http://github.com/nfephp-org/sped-nfse for the canonical source repository
16
 */
17
18
use NFePHP\Common\Certificate;
19
use NFePHP\Common\Soap\SoapInterface;
20
use NFePHP\Common\Exception\SoapException;
21
use NFePHP\Common\Exception\RuntimeException;
22
use NFePHP\Common\Strings;
23
use League\Flysystem\Filesystem;
24
use League\Flysystem\Adapter\Local;
25
use Psr\Log\LoggerInterface;
26
27
abstract class SoapBase implements SoapInterface
28
{
29
    //soap parameters
30
    protected $connection;
31
    protected $soapprotocol = self::SSL_DEFAULT;
32
    /**
33
     * @var int
34
     */
35
    protected $soaptimeout = 20;
36
    /**
37
     * @var string
38
     */
39
    protected $proxyIP;
40
    /**
41
     * @var string
42
     */
43
    protected $proxyPort;
44
    /**
45
     * @var string
46
     */
47
    protected $proxyUser;
48
    /**
49
     * @var string
50
     */
51
    protected $proxyPass;
52
    /**
53
     * @var array
54
     */
55
    protected $prefixes = [1 => 'soapenv', 2 => 'soap'];
56
    //certificate parameters
57
    /**
58
     * @var Certificate
59
     */
60
    protected $certificate;
61
    /**
62
     * @var string
63
     */
64
    protected $tempdir;
65
    /**
66
     * @var string
67
     */
68
    protected $certsdir;
69
    /**
70
     * @var string
71
     */
72
    protected $debugdir;
73
    protected $prifile;
74
    protected $pubfile;
75
    protected $certfile;
76
    protected $casefaz; //certificates from webservices
77
    /**
78
     * @var bool
79
     */
80
    protected $disablesec = false;
81
    protected $disableCertValidation = false;
82
    //log info
83
    public $responseHead;
84
    public $responseBody;
85
    public $requestHead;
86
    public $requestBody;
87
    public $soaperror;
88
    /**
89
     * @var array
90
     */
91
    public $soapinfo = [];
92
    /**
93
     * @var bool
94
     */
95
    public $debugmode = false;
96
    //flysystem
97
    protected $adapter;
98
    protected $filesystem;
99
100
    /**
101
     * Constructor
102
     * @param Certificate $certificate
103
     * @param LoggerInterface $logger
104
     */
105 4
    public function __construct(
106
        Certificate $certificate = null,
107
        LoggerInterface $logger = null
108
    ) {
109 4
        $this->logger = $logger;
0 ignored issues
show
Bug introduced by
The property logger does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
110 4
        $this->certificate = $this->checkCertValidity($certificate);
111 3
        $this->setTemporaryFolder(sys_get_temp_dir() . '/sped/');
112 3
    }
113
    
114
    /**
115
     * Check if certificate is valid
116
     * @param Certificate $certificate
117
     * @return Certificate
118
     * @throws RuntimeException
119
     */
120 4
    private function checkCertValidity(Certificate $certificate = null)
121
    {
122 4
        if ($this->disableCertValidation) {
123 1
            return $certificate;
124
        }
125 4
        if (!empty($certificate)) {
126 1
            if ($certificate->isExpired()) {
127 1
                throw new RuntimeException(
128 1
                    'The validity of the certificate has expired.'
129
                );
130
            }
131
        }
132 3
        return $certificate;
133
    }
134
    
135
    /**
136
     * Destructor
137
     * Clean temporary files
138
     */
139 3
    public function __destruct()
140
    {
141 3
        $this->removeTemporarilyFiles($this->certsdir);
142 3
    }
143
    
144
    /**
145
     * Disables the security checking of host and peer certificates
146
     * @param bool $flag
147
     */
148 1
    public function disableSecurity($flag = false)
149
    {
150 1
        $this->disablesec = $flag;
151 1
        return $this->disablesec;
152
    }
153
    
154
    /**
155
     * ONlY for tests
156
     * @param bool $flag
157
     * @return bool
158
     */
159 1
    public function disableCertValidation($flag = true)
160
    {
161 1
        $this->disableCertValidation = $flag;
162 1
        return $this->disableCertValidation;
163
    }
164
165
    /**
166
     * Load path to CA and enable to use on SOAP
167
     * @param string $capath
168
     */
169
    public function loadCA($capath)
170
    {
171
        if (is_file($capath)) {
172
            $this->casefaz = $capath;
173
        }
174
    }
175
    
176
    /**
177
     * Set another temporayfolder for saving certificates for SOAP utilization
178
     * @param string $folderRealPath
179
     */
180 3
    public function setTemporaryFolder($folderRealPath)
181
    {
182 3
        $this->tempdir = $folderRealPath;
183 3
        $this->setLocalFolder($folderRealPath);
184 3
    }
185
    
186
    /**
187
     * Set Local folder for flysystem
188
     * @param string $folder
189
     */
190 3
    protected function setLocalFolder($folder = '')
191
    {
192 3
        $this->adapter = new Local($folder);
193 3
        $this->filesystem = new Filesystem($this->adapter);
194 3
    }
195
196
    /**
197
     * Set debug mode, this mode will save soap envelopes in temporary directory
198
     * @param bool $value
199
     */
200
    public function setDebugMode($value = false)
201
    {
202
        $this->debugmode = $value;
203
    }
204
    
205
    /**
206
     * Set certificate class for SSL comunications
207
     * @param Certificate $certificate
208
     */
209 1
    public function loadCertificate(Certificate $certificate)
210
    {
211 1
        $this->certificate = $this->checkCertValidity($certificate);
212 1
    }
213
    
214
    /**
215
     * Set logger class
216
     * @param LoggerInterface $logger
217
     */
218
    public function loadLogger(LoggerInterface $logger)
219
    {
220
        return $this->logger = $logger;
221
    }
222
    
223
    /**
224
     * Set timeout for communication
225
     * @param int $timesecs
226
     */
227
    public function timeout($timesecs)
228
    {
229
        return $this->soaptimeout = $timesecs;
230
    }
231
    
232
    /**
233
     * Set security protocol
234
     * @param int $protocol
235
     * @return type Description
236
     */
237
    public function protocol($protocol = self::SSL_DEFAULT)
238
    {
239
        return $this->soapprotocol = $protocol;
240
    }
241
    
242
    /**
243
     * Set prefixes
244
     * @param string $prefixes
245
     */
246
    public function setSoapPrefix($prefixes)
247
    {
248
        $this->prefixes = $prefixes;
0 ignored issues
show
Documentation Bug introduced by
It seems like $prefixes of type string is incompatible with the declared type array of property $prefixes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
249
    }
250
    
251
    /**
252
     * Set proxy parameters
253
     * @param string $ip
254
     * @param int $port
255
     * @param string $user
256
     * @param string $password
257
     */
258
    public function proxy($ip, $port, $user, $password)
259
    {
260
        $this->proxyIP = $ip;
261
        $this->proxyPort = $port;
0 ignored issues
show
Documentation Bug introduced by
The property $proxyPort was declared of type string, but $port is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
262
        $this->proxyUser = $user;
263
        $this->proxyPass = $password;
264
    }
265
    
266
    /**
267
     * Send message to webservice
268
     */
269
    abstract public function send(
270
        $url,
271
        $operation = '',
272
        $action = '',
273
        $soapver = SOAP_1_2,
274
        $parameters = [],
275
        $namespaces = [],
276
        $request = '',
277
        $soapheader = null
278
    );
279
    
280
    /**
281
     * Mount soap envelope
282
     * @param string $request
283
     * @param string $operation
284
     * @param array $namespaces
285
     * @param \SOAPHeader $header
286
     * @return string
287
     */
288
    protected function makeEnvelopeSoap(
289
        $request,
290
        $operation,
0 ignored issues
show
Unused Code introduced by
The parameter $operation is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
291
        $namespaces,
292
        $soapver = SOAP_1_2,
293
        $header = null
294
    ) {
295
        $prefix = $this->prefixes[$soapver];
296
        $envelope = "<$prefix:Envelope";
297
        foreach ($namespaces as $key => $value) {
298
            $envelope .= " $key=\"$value\"";
299
        }
300
        $envelope .= ">";
301
        $soapheader = "<$prefix:Header/>";
302
        if (!empty($header)) {
303
            $ns = !empty($header->namespace) ? $header->namespace : '';
0 ignored issues
show
Bug introduced by
The property namespace does not seem to exist in SoapHeader.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
304
            $name = $header->name;
0 ignored issues
show
Bug introduced by
The property name does not seem to exist in SoapHeader.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
305
            $soapheader = "<$prefix:Header>";
306
            $soapheader .= "<$name xmlns=\"$ns\">";
307
            foreach ($header->data as $key => $value) {
0 ignored issues
show
Bug introduced by
The property data does not seem to exist in SoapHeader.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
308
                $soapheader .= "<$key>$value</$key>";
309
            }
310
            $soapheader .= "</$name></$prefix:Header>";
311
        }
312
        $envelope .= $soapheader;
313
        $envelope .= "<$prefix:Body>$request</$prefix:Body>"
314
            . "</$prefix:Envelope>";
315
        return $envelope;
316
    }
317
    
318
    /**
319
     * Temporarily saves the certificate keys for use cURL or SoapClient
320
     */
321
    public function saveTemporarilyKeyFiles()
322
    {
323
        if (!is_object($this->certificate)) {
324
            throw new RuntimeException(
325
                'Certificate not found.'
326
            );
327
        }
328
        $this->certsdir = $this->certificate->getCnpj() . '/certs/';
329
        $this->prifile = $this->certsdir. Strings::randomString(10).'.pem';
330
        $this->pubfile = $this->certsdir . Strings::randomString(10).'.pem';
331
        $this->certfile = $this->certsdir . Strings::randomString(10).'.pem';
332
        $ret = true;
333
        $ret &= $this->filesystem->put(
334
            $this->prifile,
335
            $this->certificate->privateKey
336
        );
337
        $ret &= $this->filesystem->put(
338
            $this->pubfile,
339
            $this->certificate->publicKey
340
        );
341
        $ret &= $this->filesystem->put(
342
            $this->certfile,
343
            "{$this->certificate}"
344
        );
345
        if (!$ret) {
346
            throw new RuntimeException(
347
                'Unable to save temporary key files in folder.'
348
            );
349
        }
350
    }
351
    
352
    /**
353
     * Delete all files in folder
354
     */
355 3
    public function removeTemporarilyFiles($folder)
356
    {
357 3
        $contents = $this->filesystem->listContents($folder, true);
358 3
        foreach ($contents as $item) {
359
            if ($item['type'] == 'file') {
360
                $this->filesystem->delete($item['path']);
361
            }
362
        }
363 3
    }
364
    
365
    /**
366
     * Save request envelope and response for debug reasons
367
     * @param string $operation
368
     * @param string $request
369
     * @param string $response
370
     * @return void
371
     */
372
    public function saveDebugFiles($operation, $request, $response)
373
    {
374
        if (!$this->debugmode) {
375
            return;
376
        }
377
        $this->debugdir = $this->certificate->getCnpj() . '/debug/';
378
        $now = \DateTime::createFromFormat('U.u', microtime(true));
379
        $time = substr($now->format("ymdHisu"), 0, 16);
380
        try {
381
            $this->filesystem->put(
382
                $this->debugdir . $time . "_" . $operation . "_sol.txt",
383
                $request
384
            );
385
            $this->filesystem->put(
386
                $this->debugdir . $time . "_" . $operation . "_res.txt",
387
                $response
388
            );
389
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class NFePHP\Common\Soap\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
390
            throw new RuntimeException(
391
                'Unable to create debug files.'
392
            );
393
        }
394
    }
395
}
396