Completed
Push — master ( 5996f2...c00d3b )
by Esteban De La Fuente
02:07
created

Folios::getCertificacion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
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 2017-07-19
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 or !$idk)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
67
            return false;
68
        $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...
69
        if (!$pub_key or 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...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
70
            \sasco\LibreDTE\Log::write(
71
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_FIRMA,
72
                \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...
73
            );
74
            return false;
75
        }
76
        // validar clave privada y pública proporcionada por el SII
77
        $private_key = $this->getPrivateKey();
78
        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...
79
            return false;
80
        $plain = md5(date('U'));
81
        if (!openssl_private_encrypt($plain, $crypt, $private_key)) {
82
            \sasco\LibreDTE\Log::write(
83
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_ENCRIPTAR,
84
                \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...
85
            );
86
            return false;
87
        }
88
        $public_key = $this->getPublicKey();
89
        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...
90
            return false;
91
        if (!openssl_public_decrypt($crypt, $plain_firmado, $public_key)) {
92
            \sasco\LibreDTE\Log::write(
93
                \sasco\LibreDTE\Estado::FOLIOS_ERROR_DESENCRIPTAR,
94
                \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...
95
            );
96
            return false;
97
        }
98
        return $plain === $plain_firmado;
99
    }
100
101
    /**
102
     * Método que entrega el nodo CAF
103
     * @return DomElement
104
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
105
     * @version 2015-10-30
106
     */
107
    public function getCaf()
108
    {
109
        if (!$this->xml)
110
            return false;
111
        $CAF = $this->xml->getElementsByTagName('CAF')->item(0);
112
        return $CAF ? $CAF : false;
113
    }
114
115
    /**
116
     * Método que entrega el RUT de a quién se está autorizando el CAF
117
     * @return Rut del emisor del CAF
118
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
119
     * @version 2015-10-30
120
     */
121
    public function getEmisor()
122
    {
123
        if (!$this->xml)
124
            return false;
125
        $RE = $this->xml->getElementsByTagName('RE')->item(0);
126
        return $RE ? $RE->nodeValue : false;
127
    }
128
129
    /**
130
     * Método que entrega el primer folio autorizado en el CAF
131
     * @return Número del primer folio
132
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
133
     * @version 2015-10-30
134
     */
135
    public function getDesde()
136
    {
137
        if (!$this->xml)
138
            return false;
139
        $D = $this->xml->getElementsByTagName('D')->item(0);
140
        return $D ? (int)$D->nodeValue : false;
141
    }
142
143
    /**
144
     * Método que entrega el últimmo folio autorizado en el CAF
145
     * @return Número del último folio
146
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
147
     * @version 2015-10-30
148
     */
149
    public function getHasta()
150
    {
151
        if (!$this->xml)
152
            return false;
153
        $H = $this->xml->getElementsByTagName('H')->item(0);
154
        return $H ? (int)$H->nodeValue : false;
155
    }
156
157
    /**
158
     * Método que entrega la firma del SII sobre el nodo DA
159
     * @return Firma en base64
160
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
161
     * @version 2015-10-30
162
     */
163 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...
164
    {
165
        if (!$this->xml)
166
            return false;
167
        $FRMA = $this->xml->getElementsByTagName('FRMA')->item(0);
168
        return $FRMA ? $FRMA->nodeValue : false;
169
    }
170
171
    /**
172
     * Método que entrega el IDK (serial number) de la clave pública del SII
173
     * utilizada para firmar el CAF
174
     * @return Serial number
175
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
176
     * @version 2015-10-30
177
     */
178 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...
179
    {
180
        if (!$this->xml)
181
            return false;
182
        $IDK = $this->xml->getElementsByTagName('IDK')->item(0);
183
        return $IDK ? (int)$IDK->nodeValue : false;
184
    }
185
186
    /**
187
     * Método que entrega la clave privada proporcionada por el SII para el CAF
188
     * @return Clave privada en base64
189
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
190
     * @version 2015-10-30
191
     */
192
    public function getPrivateKey()
193
    {
194
        if (!$this->xml)
195
            return false;
196
        $RSASK = $this->xml->getElementsByTagName('RSASK')->item(0);
197
        return $RSASK ? $RSASK->nodeValue : false;
198
    }
199
200
    /**
201
     * Método que entrega la clave pública proporcionada por el SII para el CAF
202
     * @return Clave pública en base64
203
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
204
     * @version 2015-10-30
205
     */
206
    public function getPublicKey()
207
    {
208
        if (!$this->xml)
209
            return false;
210
        $RSAPUBK = $this->xml->getElementsByTagName('RSAPUBK')->item(0);
211
        return $RSAPUBK ? $RSAPUBK->nodeValue : false;
212
    }
213
214
    /**
215
     * Método que entrega el tipo de DTE para el cual se emitió el CAF
216
     * @return Código de tipo de DTE
217
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
218
     * @version 2015-10-30
219
     */
220
    public function getTipo()
221
    {
222
        if (!$this->xml)
223
            return false;
224
        $TD = $this->xml->getElementsByTagName('TD')->item(0);
225
        return $TD ? (int)$TD->nodeValue : false;
226
    }
227
228
    /**
229
     * Método que entrega la fecha de autorización con la que se emitió el CAF
230
     * @return Fecha de autorización del CAF
231
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
232
     * @version 2017-07-19
233
     */
234
    public function getFechaAutorizacion()
235
    {
236
        if (!$this->xml)
237
            return false;
238
        $FA = $this->xml->getElementsByTagName('FA')->item(0);
239
        return $FA ? $FA->nodeValue : false;
240
    }
241
242
    /**
243
     * Método que indica si el CAF es de certificación o no
244
     * @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...
245
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
246
     * @version 2015-10-30
247
     */
248
    public function getCertificacion()
249
    {
250
        $idk = $this->getIDK();
251
        return $idk ?  $idk === 100 : null;
252
    }
253
254
    /**
255
     * Método que entrega el XML completo del archivo CAF
256
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
257
     * @version 2016-08-24
258
     */
259
    public function saveXML()
260
    {
261
        return $this->xml->saveXML();
262
    }
263
264
}
265