Completed
Push — master ( 8037fb...a56aaf )
by Esteban De La Fuente
03:02
created

Folios::check()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 42
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 42
rs 4.909
cc 9
eloc 29
nc 7
nop 0
1
<?php
2
3
/**
4
 * LibreDTE
5
 * Copyright (C) SASCO SpA (https://sasco.cl)
6
 *
7
 * Este programa es software libre: usted puede redistribuirlo y/o
8
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
9
 * publicada por la Fundación para el Software Libre, ya sea la versión
10
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
11
 * misma.
12
 *
13
 * Este programa se distribuye con la esperanza de que sea útil, pero
14
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
15
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
16
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
17
 * obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
22
 */
23
24
namespace sasco\LibreDTE\Sii;
25
26
/**
27
 * Clase para realizar operaciones con lo Folios autorizados por el SII
28
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
29
 * @version 2018-03-20
30
 */
31
class Folios
32
{
33
34
    private $xml; ///< Objeto XML que representa el CAF
35
36
    /**
37
     * Constructor de la clase
38
     * @param xml Datos XML del código de autorización de folios (CAF)
39
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
40
     * @version 2016-11-21
41
     */
42
    public function __construct($xml)
43
    {
44
        $this->xml = new \sasco\LibreDTE\XML();
45
        $this->xml->loadXML(utf8_encode($xml));
46 View Code Duplication
        if (!$this->check()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
47
            \sasco\LibreDTE\Log::write(
48
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_CHECK,
49
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::FOLIOS_ERROR_CHECK)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::FOLIOS_ERROR_CHECK) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
50
            );
51
            $this->xml = null;
52
        }
53
    }
54
55
    /**
56
     * Método que verifica el código de autorización de folios
57
     * @return =true si está ok el XML cargado
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
58
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
59
     * @version 2015-10-30
60
     */
61
    public function check()
62
    {
63
        // validar firma del SII sobre los folios
64
        $firma = $this->getFirma();
65
        $idk = $this->getIDK();
66
        if (!$firma || !$idk) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $firma of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Bug Best Practice introduced by
The expression $idk of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
67
            return false;
68
        }
69
        $pub_key = \sasco\LibreDTE\Sii::cert($idk);
0 ignored issues
show
Documentation introduced by
$idk is of type integer, but the function expects a object<sasco\LibreDTE\IDK>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
70
        if (!$pub_key || openssl_verify($this->xml->getFlattened('/AUTORIZACION/CAF/DA'), base64_decode($firma), $pub_key)!==1) {
0 ignored issues
show
Documentation introduced by
'/AUTORIZACION/CAF/DA' is of type string, but the function expects a object<sasco\LibreDTE\XPath>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Best Practice introduced by
The expression $pub_key of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
71
            \sasco\LibreDTE\Log::write(
72
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_FIRMA,
73
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::FOLIOS_ERROR_FIRMA)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...do::FOLIOS_ERROR_FIRMA) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
74
            );
75
            return false;
76
        }
77
        // validar clave privada y pública proporcionada por el SII
78
        $private_key = $this->getPrivateKey();
79
        if (!$private_key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $private_key of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
80
            return false;
81
        }
82
        $plain = md5(date('U'));
83
        if (!openssl_private_encrypt($plain, $crypt, $private_key)) {
84
            \sasco\LibreDTE\Log::write(
85
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_ENCRIPTAR,
86
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::FOLIOS_ERROR_ENCRIPTAR)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...FOLIOS_ERROR_ENCRIPTAR) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
87
            );
88
            return false;
89
        }
90
        $public_key = $this->getPublicKey();
91
        if (!$public_key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $public_key of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
92
            return false;
93
        }
94
        if (!openssl_public_decrypt($crypt, $plain_firmado, $public_key)) {
95
            \sasco\LibreDTE\Log::write(
96
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_DESENCRIPTAR,
97
                \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::FOLIOS_ERROR_DESENCRIPTAR)
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...IOS_ERROR_DESENCRIPTAR) is of type integer|string, but the function expects a object<sasco\LibreDTE\Mensaje>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
98
            );
99
            return false;
100
        }
101
        return $plain === $plain_firmado;
102
    }
103
104
    /**
105
     * Método que entrega el nodo CAF
106
     * @return DomElement
107
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
108
     * @version 2015-10-30
109
     */
110
    public function getCaf()
111
    {
112
        if (!$this->xml) {
113
            return false;
114
        }
115
        $CAF = $this->xml->getElementsByTagName('CAF')->item(0);
116
        return $CAF ? $CAF : false;
117
    }
118
119
    /**
120
     * Método que entrega el RUT de a quién se está autorizando el CAF
121
     * @return Rut del emisor del CAF
122
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
123
     * @version 2015-10-30
124
     */
125
    public function getEmisor()
126
    {
127
        if (!$this->xml) {
128
            return false;
129
        }
130
        $RE = $this->xml->getElementsByTagName('RE')->item(0);
131
        return $RE ? $RE->nodeValue : false;
132
    }
133
134
    /**
135
     * Método que entrega el primer folio autorizado en el CAF
136
     * @return Número del primer folio
137
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
138
     * @version 2015-10-30
139
     */
140
    public function getDesde()
141
    {
142
        if (!$this->xml) {
143
            return false;
144
        }
145
        $D = $this->xml->getElementsByTagName('D')->item(0);
146
        return $D ? (int)$D->nodeValue : false;
147
    }
148
149
    /**
150
     * Método que entrega el últimmo folio autorizado en el CAF
151
     * @return Número del último folio
152
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
153
     * @version 2015-10-30
154
     */
155
    public function getHasta()
156
    {
157
        if (!$this->xml) {
158
            return false;
159
        }
160
        $H = $this->xml->getElementsByTagName('H')->item(0);
161
        return $H ? (int)$H->nodeValue : false;
162
    }
163
164
    /**
165
     * Método que entrega la firma del SII sobre el nodo DA
166
     * @return Firma en base64
167
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
168
     * @version 2015-10-30
169
     */
170 View Code Duplication
    private function getFirma()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        if (!$this->xml) {
173
            return false;
174
        }
175
        $FRMA = $this->xml->getElementsByTagName('FRMA')->item(0);
176
        return $FRMA ? $FRMA->nodeValue : false;
177
    }
178
179
    /**
180
     * Método que entrega el IDK (serial number) de la clave pública del SII
181
     * utilizada para firmar el CAF
182
     * @return Serial number
183
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
184
     * @version 2015-10-30
185
     */
186 View Code Duplication
    private function getIDK()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
    {
188
        if (!$this->xml) {
189
            return false;
190
        }
191
        $IDK = $this->xml->getElementsByTagName('IDK')->item(0);
192
        return $IDK ? (int)$IDK->nodeValue : false;
193
    }
194
195
    /**
196
     * Método que entrega la clave privada proporcionada por el SII para el CAF
197
     * @return Clave privada en base64
198
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
199
     * @version 2015-10-30
200
     */
201
    public function getPrivateKey()
202
    {
203
        if (!$this->xml) {
204
            return false;
205
        }
206
        $RSASK = $this->xml->getElementsByTagName('RSASK')->item(0);
207
        return $RSASK ? $RSASK->nodeValue : false;
208
    }
209
210
    /**
211
     * Método que entrega la clave pública proporcionada por el SII para el CAF
212
     * @return Clave pública en base64
213
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
214
     * @version 2015-10-30
215
     */
216
    public function getPublicKey()
217
    {
218
        if (!$this->xml) {
219
            return false;
220
        }
221
        $RSAPUBK = $this->xml->getElementsByTagName('RSAPUBK')->item(0);
222
        return $RSAPUBK ? $RSAPUBK->nodeValue : false;
223
    }
224
225
    /**
226
     * Método que entrega el tipo de DTE para el cual se emitió el CAF
227
     * @return Código de tipo de DTE
228
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
229
     * @version 2015-10-30
230
     */
231
    public function getTipo()
232
    {
233
        if (!$this->xml) {
234
            return false;
235
        }
236
        $TD = $this->xml->getElementsByTagName('TD')->item(0);
237
        return $TD ? (int)$TD->nodeValue : false;
238
    }
239
240
    /**
241
     * Método que entrega la fecha de autorización con la que se emitió el CAF
242
     * @return Fecha de autorización del CAF
243
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
244
     * @version 2017-07-19
245
     */
246
    public function getFechaAutorizacion()
247
    {
248
        if (!$this->xml) {
249
            return false;
250
        }
251
        $FA = $this->xml->getElementsByTagName('FA')->item(0);
252
        return $FA ? $FA->nodeValue : false;
253
    }
254
255
    /**
256
     * Método que indica si el CAF es de certificación o no
257
     * @return =true si los folios son del ambiente de certificación, =null si no se pudo determinar
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
258
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
259
     * @version 2015-10-30
260
     */
261
    public function getCertificacion()
262
    {
263
        $idk = $this->getIDK();
264
        return $idk ?  $idk === 100 : null;
265
    }
266
267
    /**
268
     * Método que indica si el CAF está o no vigente
269
     * @return =true si el CAF está vigente, =false si no está vigente
0 ignored issues
show
Documentation introduced by
The doc-type =true could not be parsed: Unknown type name "=true" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
270
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
271
     * @version 2018-03-20
272
     */
273
    public function vigente()
274
    {
275
        if (!in_array($this->getTipo(), [33, 46, 61])) {
276
            return true;
277
        }
278
        $d1 = new \DateTime($this->getFechaAutorizacion());
279
        $d2 = new \DateTime(date('Y-m-d'));
280
        $meses = $d1->diff($d2)->m + ($d1->diff($d2)->y*12);
281
        return $meses <= 18;
282
    }
283
284
    /**
285
     * Método que entrega el XML completo del archivo CAF
286
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
287
     * @version 2016-08-24
288
     */
289
    public function saveXML()
290
    {
291
        return $this->xml->saveXML();
292
    }
293
294
}
295