Completed
Push — master ( f9cee4...42b255 )
by Esteban De La Fuente
01:43
created

Sii::getDireccionRegional()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 4
nc 4
nop 1
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;
25
26
/**
27
 * Clase para acciones genéricas asociadas al SII de Chile
28
 * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
29
 * @version 2018-01-17
30
 */
31
class Sii
32
{
33
34
    private static $config = [
35
        'wsdl' => [
36
            '*' => 'https://{servidor}.sii.cl/DTEWS/{servicio}.jws?WSDL',
37
            'QueryEstDteAv' => 'https://{servidor}.sii.cl/DTEWS/services/{servicio}?WSDL',
38
            'wsDTECorreo' => 'https://{servidor}.sii.cl/DTEWS/services/{servicio}?WSDL',
39
        ],
40
        'servidor' => ['palena', 'maullin'], ///< servidores 0: producción, 1: certificación
41
        'certs' => [300, 100], ///< certificados 0: producción, 1: certificación
42
    ];
43
44
    const PRODUCCION = 0; ///< Constante para indicar ambiente de producción
45
    const CERTIFICACION = 1; ///< Constante para indicar ambiente de desarrollo
46
47
    const IVA = 19; ///< Tasa de IVA
48
49
    private static $retry = 10; ///< Veces que se reintentará conectar a SII al usar el servicio web
50
    private static $verificar_ssl = true; ///< Indica si se deberá verificar o no el certificado SSL del SII
51
    private static $ambiente = self::PRODUCCION; ///< Ambiente que se utilizará
52
53
    private static $direcciones_regionales = [
54
        'ARICA' => 'ARICA',
55
        'CAMARONES' => 'ARICA',
56
        'PUTRE' => 'ARICA',
57
        'GENERAL LAGOS' => 'ARICA',
58
        'IQUIQUE' => 'IQUIQUE',
59
        'PICA' => 'IQUIQUE',
60
        'POZO ALMONTE' => 'IQUIQUE',
61
        'HUARA' => 'IQUIQUE',
62
        'CAMIÑA' => 'IQUIQUE',
63
        'COLCHANE' => 'IQUIQUE',
64
        'ALTO HOSPICIO' => 'IQUIQUE',
65
        'ANTOFAGASTA' => 'ANTOFAGASTA',
66
        'MEJILLONES' => 'ANTOFAGASTA',
67
        'SIERRA GORDA' => 'ANTOFAGASTA',
68
        'CALAMA' => 'CALAMA',
69
        'SAN PEDRO DE ATACAMA' => 'CALAMA',
70
        'OLLAGUE' => 'CALAMA',
71
        'TOCOPILLA' => 'TOCOPILLA',
72
        'MARÍA ELENA' => 'TOCOPILLA',
73
        'TALTAL' => 'TALTAL',
74
        'COPIAPÓ' => 'COPIAPÓ',
75
        'CALDERA' => 'COPIAPÓ',
76
        'TIERRA AMARILLA' => 'COPIAPÓ',
77
        'CHAÑARAL' => 'CHAÑARAL',
78
        'DIEGO DE ALMAGRO' => 'CHAÑARAL',
79
        'VALLENAR' => 'VALLENAR',
80
        'FREIRINA' => 'VALLENAR',
81
        'HUASCO' => 'VALLENAR',
82
        'ALTO DEL CARMEN' => 'VALLENAR',
83
        'LA SERENA' => 'LA SERENA',
84
        'LA HIGUERA' => 'LA SERENA',
85
        'PAIHUANO' => 'LA SERENA',
86
        'ANDACOLLO' => 'LA SERENA',
87
        'VICUÑA' => 'LA SERENA',
88
        'OVALLE' => 'OVALLE',
89
        'MONTE PATRIA' => 'OVALLE',
90
        'PUNITAQUI' => 'OVALLE',
91
        'COMBARBALÁ' => 'OVALLE',
92
        'RÍO HURTADO' => 'OVALLE',
93
        'ILLAPEL' => 'ILLAPEL',
94
        'SALAMANCA' => 'ILLAPEL',
95
        'LOS VILOS' => 'ILLAPEL',
96
        'CANELA' => 'ILLAPEL',
97
        'COMQUIMBO' => 'COQUIMBO',
98
        'VALPARAÍSO' => 'VALPARAÍSO',
99
        'CASABLANCA' => 'VALPARAÍSO',
100
        'JUAN FERNÁNDEZ' => 'VALPARAÍSO',
101
        'ISLA DE PASCUA' => 'VALPARAÍSO',
102
        'CONCÓN' => 'VIÑA DEL MAR',
103
        'QUINTERO' => 'VIÑA DEL MAR',
104
        'PUCHUNCAVÍ' => 'VIÑA DEL MAR',
105
        'VIÑA DEL MAR' => 'VIÑA DEL MAR',
106
        'LA LIGUA' => 'LA LIGUA',
107
        'PETORCA' => 'LA LIGUA',
108
        'CABILDO' => 'LA LIGUA',
109
        'ZAPALLAR' => 'LA LIGUA',
110
        'PAPUDO' => 'LA LIGUA',
111
        'SAN ANTONIO' => 'SAN ANTONIO',
112
        'SANTO DOMINGO' => 'SAN ANTONIO',
113
        'CARTAGENA' => 'SAN ANTONIO',
114
        'EL TABO' => 'SAN ANTONIO',
115
        'EL QUISCO' => 'SAN ANTONIO',
116
        'ALGARROBO' => 'SAN ANTONIO',
117
        'QUILLOTA' => 'QUILLOTA',
118
        'NOGALES' => 'QUILLOTA',
119
        'HIJUELAS' => 'QUILLOTA',
120
        'LA CALERA' => 'QUILLOTA',
121
        'LA CRUZ' => 'QUILLOTA',
122
        'LIMACHE' => 'QUILLOTA',
123
        'OLMUÉ' => 'QUILLOTA',
124
        'SAN FELIPE' => 'SAN FELIPE',
125
        'PANQUEHUE' => 'SAN FELIPE',
126
        'CATEMU' => 'SAN FELIPE',
127
        'PUTAENDO' => 'SAN FELIPE',
128
        'SANTA MARÍA' => 'SAN FELIPE',
129
        'LLAY LLAY' => 'SAN FELIPE',
130
        'LOS ANDES' => 'LOS ANDES',
131
        'CALLE LARGA' => 'LOS ANDES',
132
        'SAN ESTEBAN' => 'LOS ANDES',
133
        'RINCONADA' => 'LOS ANDES',
134
        'VILLA ALEMANA' => 'VILLA ALEMANA',
135
        'QUILPUÉ' => 'VILLA ALEMANA',
136
        'RANCAGUA' => 'RANCAGUA',
137
        'MACHALÍ' => 'RANCAGUA',
138
        'GRANEROS' => 'RANCAGUA',
139
        'SAN FRANCISCO DE MOSTAZAL' => 'RANCAGUA',
140
        'DOÑIHUE' => 'RANCAGUA',
141
        'CODEGUA' => 'RANCAGUA',
142
        'RENGO' => 'RANCAGUA',
143
        'COLTAUCO' => 'RANCAGUA',
144
        'REQUINOA' => 'RANCAGUA',
145
        'OLIVAR' => 'RANCAGUA',
146
        'MALLOA' => 'RANCAGUA',
147
        'COINCO' => 'RANCAGUA',
148
        'QUINTA DE TILCOCO' => 'RANCAGUA',
149
        'SAN FERNANDO' => 'SAN FERNANDO',
150
        'CHIMBARONGO' => 'SAN FERNANDO',
151
        'NANCAGUA' => 'SAN FERNANDO',
152
        'PLACILLA' => 'SAN FERNANDO',
153
        'SANTA CRUZ' => 'SANTA CRUZ',
154
        'LOLOL' => 'SANTA CRUZ',
155
        'PALMILLA' => 'SANTA CRUZ',
156
        'PERALILLO' => 'SANTA CRUZ',
157
        'CHÉPICA' => 'SANTA CRUZ',
158
        'PUMANQUE' => 'SANTA CRUZ',
159
        'SAN VICENTE' => 'SAN VICENTE TAGUA TAGUA',
160
        'LAS CABRAS' => 'SAN VICENTE TAGUA TAGUA',
161
        'PEUMO' => 'SAN VICENTE TAGUA TAGUA',
162
        'PICHIDEGUA' => 'SAN VICENTE TAGUA TAGUA',
163
        'PICHILEMU' => 'PICHILEMU',
164
        'PAREDONES' => 'PICHILEMU',
165
        'MARCHIGUE' => 'PICHILEMU',
166
        'LITUECHE' => 'PICHILEMU',
167
        'LA ESTRELLA' => 'PICHILEMU',
168
        'TALCA' => 'TALCA',
169
        'SAN CLEMENTE' => 'TALCA',
170
        'PELARCO' => 'TALCA',
171
        'RÍO CLARO' => 'TALCA',
172
        'PENCAHUE' => 'TALCA',
173
        'MAULE' => 'TALCA',
174
        'CUREPTO' => 'TALCA',
175
        'SAN JAVIER' => 'TALCA',
176
        'LINARES' => 'LINARES',
177
        'YERBAS BUENAS' => 'LINARES',
178
        'COLBÚN' => 'LINARES',
179
        'LONGAVÍ' => 'LINARES',
180
        'VILLA ALEGRE' => 'LINARES',
181
        'CONSTITUCIÓN' => 'CONSTITUCIÓN',
182
        'EMPEDRADO' => 'CONSTITUCIÓN',
183
        'CAUQUENES' => 'CAUQUENES',
184
        'PELLUHUE' => 'CAUQUENES',
185
        'CHANCO' => 'CAUQUENES',
186
        'PARRAL' => 'PARRAL',
187
        'RETIRO' => 'PARRAL',
188
        'CURICÓ' => 'CURICÓ',
189
        'TENO' => 'CURICÓ',
190
        'ROMERAL' => 'CURICÓ',
191
        'MOLINA' => 'CURICÓ',
192
        'HUALAÑE' => 'CURICÓ',
193
        'SAGRADA FAMILIA' => 'CURICÓ',
194
        'LICANTÉN' => 'CURICÓ',
195
        'VICHUQUÉN' => 'CURICÓ',
196
        'RAUCO' => 'CURICÓ',
197
        'CONCEPCIÓN' => 'CONCEPCIÓN',
198
        'CHIGUAYANTE' => 'CONCEPCIÓN',
199
        'SAN PEDRO DE LA PAZ' => 'CONCEPCIÓN',
200
        'PENCO' => 'CONCEPCIÓN',
201
        'HUALQUI' => 'CONCEPCIÓN',
202
        'FLORIDA' => 'CONCEPCIÓN',
203
        'TOMÉ' => 'CONCEPCIÓN',
204
        'CORONEL' => 'CONCEPCIÓN',
205
        'LOTA' => 'CONCEPCIÓN',
206
        'SANTA JUANA' => 'CONCEPCIÓN',
207
        'ARAUCO' => 'CONCEPCIÓN',
208
        'CHILLÁN' => 'CHILLÁN',
209
        'PINTO' => 'CHILLÁN',
210
        'EL CARMEN' => 'CHILLÁN',
211
        'SAN IGNACIO' => 'CHILLÁN',
212
        'PEMUCO' => 'CHILLÁN',
213
        'YUNGAY' => 'CHILLÁN',
214
        'BULNES' => 'CHILLÁN',
215
        'QUILLÓN' => 'CHILLÁN',
216
        'RANQUIL' => 'CHILLÁN',
217
        'PORTEZUELO' => 'CHILLÁN',
218
        'COELEMU' => 'CHILLÁN',
219
        'TREHUACO' => 'CHILLÁN',
220
        'QUIRIHUE' => 'CHILLÁN',
221
        'COBQUECURA' => 'CHILLÁN',
222
        'NINHUE' => 'CHILLÁN',
223
        'CHILLÁN VIEJO' => 'CHILLÁN',
224
        'LOS ÁNGELES' => 'LOS ÁNGELES',
225
        'SANTA BARBARA' => 'LOS ÁNGELES',
226
        'LAJA' => 'LOS ÁNGELES',
227
        'QUILLECO' => 'LOS ÁNGELES',
228
        'NACIMIENTO' => 'LOS ÁNGELES',
229
        'NEGRETE' => 'LOS ÁNGELES',
230
        'MULCHÉN' => 'LOS ÁNGELES',
231
        'QUILACO' => 'LOS ÁNGELES',
232
        'YUMBEL' => 'LOS ÁNGELES',
233
        'CABRERO' => 'LOS ÁNGELES',
234
        'SAN ROSENDO' => 'LOS ÁNGELES',
235
        'TUCAPEL' => 'LOS ÁNGELES',
236
        'ANTUCO' => 'LOS ÁNGELES',
237
        'ALTO BÍO-BÍO' => 'LOS ÁNGELES',
238
        'SAN CARLOS' => 'SAN CARLOS',
239
        'SAN GREGORIO DE ÑINQUEN' => 'SAN CARLOS',
240
        'SAN NICOLÁS' => 'SAN CARLOS',
241
        'SAN FABIÁN DE ALICO' => 'SAN CARLOS',
242
        'TALCAHUANO' => 'TALCAHUANO',
243
        'HUALPÉN' => 'TALCAHUANO',
244
        'LEBU' => 'LEBU',
245
        'CURANILAHUE' => 'LEBU',
246
        'LOS ALAMOS' => 'LEBU',
247
        'CAÑETE' => 'LEBU',
248
        'CONTULMO' => 'LEBU',
249
        'TIRÚA' => 'LEBU',
250
        'TEMUCO' => 'TEMUCO',
251
        'VILCÚN' => 'TEMUCO',
252
        'FREIRE' => 'TEMUCO',
253
        'CUNCO' => 'TEMUCO',
254
        'LAUTARO' => 'TEMUCO',
255
        'PERQUENCO' => 'TEMUCO',
256
        'GALVARINO' => 'TEMUCO',
257
        'NUEVA IMPERIAL' => 'TEMUCO',
258
        'CARAHUE' => 'TEMUCO',
259
        'PUERTO SAAVEDRA' => 'TEMUCO',
260
        'PITRUFQUÉN' => 'TEMUCO',
261
        'GORBEA' => 'TEMUCO',
262
        'TOLTÉN' => 'TEMUCO',
263
        'LONCOCHE' => 'TEMUCO',
264
        'MELIPEUCO' => 'TEMUCO',
265
        'TEODORO SCHMIDT' => 'TEMUCO',
266
        'PADRE LAS CASAS' => 'TEMUCO',
267
        'CHOLCHOL' => 'TEMUCO',
268
        'ANGOL' => 'ANGOL',
269
        'PURÉN' => 'ANGOL',
270
        'LOS SAUCES' => 'ANGOL',
271
        'REINACO' => 'ANGOL',
272
        'COLLIPULLI' => 'ANGOL',
273
        'ERCILLA' => 'ANGOL',
274
        'VICTORIA' => 'VICTORIA',
275
        'TRAIGUÉN' => 'VICTORIA',
276
        'LUMACO' => 'VICTORIA',
277
        'CURACAUTÍN' => 'VICTORIA',
278
        'LONQUIMAY' => 'VICTORIA',
279
        'VILLARRICA' => 'VILLARRICA',
280
        'PUCÓN' => 'VILLARRICA',
281
        'CURARREHUE' => 'VILLARRICA',
282
        'VALDIVIA' => 'VALDIVIA',
283
        'MARIQUINA' => 'VALDIVIA',
284
        'LANCO' => 'LANCO',
285
        'MÁFIL' => 'VALDIVIA',
286
        'CORRAL' => 'VALDIVIA',
287
        'LOS LAGOS' => 'VALDIVIA',
288
        'PAILLACO' => 'VALDIVIA',
289
        'PANGUIPULLI' => 'PANGUIPULLI',
290
        'LA UNIÓN' => 'LA UNIÓN',
291
        'FUTRONO' => 'VALDIVIA',
292
        'RÍO BUENO' => 'LA UNIÓN',
293
        'LAGO RANCO' => 'LA UNIÓN',
294
        'PUERTO MONTT' => 'PUERTO MONTT',
295
        'CALBUCO' => 'PUERTO MONTT',
296
        'MAULLÍN' => 'PUERTO MONTT',
297
        'LOS MUERMOS' => 'PUERTO MONTT',
298
        'HUALAIHUÉ' => 'PUERTO MONTT',
299
        'PUERTO VARAS' => 'PUERTO VARAS',
300
        'COCHAMÓ' => 'PUERTO VARAS',
301
        'FRESIA' => 'PUERTO VARAS',
302
        'LLANQUIHUE' => 'PUERTO VARAS',
303
        'FRUTILLAR' => 'PUERTO VARAS',
304
        'ANCUD' => 'ANCUD',
305
        'QUEMCHI' => 'ANCUD',
306
        'OSORNO' => 'OSORNO',
307
        'PUYEHUE' => 'OSORNO',
308
        'PURRANQUE' => 'OSORNO',
309
        'RÍO NEGRO' => 'OSORNO',
310
        'SAN PABLO' => 'OSORNO',
311
        'SAN JUAN DE LA COSTA' => 'OSORNO',
312
        'PUERTO OCTAY' => 'OSORNO',
313
        'CASTRO' => 'CASTRO',
314
        'CURACO DE VÉLEZ' => 'CASTRO',
315
        'CHOCHI' => 'CASTRO',
316
        'DALCAHUE' => 'CASTRO',
317
        'PUQUELDÓN' => 'CASTRO',
318
        'QUEILÉN' => 'CASTRO',
319
        'QUELLÓN' => 'CASTRO',
320
        'CHAITÉN' => 'CHAITÉN',
321
        'PALENA' => 'CHAITÉN',
322
        'FUTALEUFÚ' => 'CHAITÉN',
323
        'COYHAIQUE' => 'COYHAIQUE',
324
        'RÍO IBAÑEZ' => 'COYHAIQUE',
325
        'O`HIGGINS' => 'COCHRANE',
326
        'TORTEL' => 'COCHRANE',
327
        'AYSÉN' => 'AYSÉN',
328
        'CISNES' => 'AYSÉN',
329
        'LAGO VERDE' => 'AYSÉN',
330
        'GUAITECAS' => 'AYSÉN',
331
        'CHILE CHICO' => 'CHILE CHICO',
332
        'COCHRANE' => 'COCHRANE',
333
        'GUADAL' => 'COCHRANE',
334
        'PUERTO BELTRAND' => 'COCHRANE',
335
        'PUNTA ARENAS' => 'PUNTA ARENAS',
336
        'RÍO VERDE' => 'PUNTA ARENAS',
337
        'SAN GREGORIO' => 'PUNTA ARENAS',
338
        'LAGUNA BLANCA' => 'PUNTA ARENAS',
339
        'CABO DE HORNOS' => 'PUNTA ARENAS',
340
        'PUERTO NATALES' => 'PUERTO NATALES',
341
        'TORRES DEL PAINE' => 'PUERTO NATALES',
342
        'PORVENIR' => 'PORVENIR',
343
        'PRIMAVERA' => 'PORVENIR',
344
        'TIMAUKEL' => 'PORVENIR',
345
        'INDEPENDENCIA' => 'SANTIAGO NORTE',
346
        'RECOLETA' => 'SANTIAGO NORTE',
347
        'HUECHURABA' => 'SANTIAGO NORTE',
348
        'CONCHALÍ' => 'SANTIAGO NORTE',
349
        'QUILICURA' => 'SANTIAGO NORTE',
350
        'COLINA' => 'SANTIAGO NORTE',
351
        'LAMPA' => 'SANTIAGO NORTE',
352
        'TILTIL' => 'SANTIAGO NORTE',
353
        'SANTIAGO' => 'SANTIAGO CENTRO',
354
        'CERRO NAVIA' => 'SANTIAGO PONIENTE',
355
        'CURACAVÍ' => 'SANTIAGO PONIENTE',
356
        'ESTACIÓN CENTRAL' => 'SANTIAGO PONIENTE',
357
        'LO PRADO' => 'SANTIAGO PONIENTE',
358
        'PUDAHUEL' => 'SANTIAGO PONIENTE',
359
        'QUINTA NORMAL' => 'SANTIAGO PONIENTE',
360
        'RENCA' => 'SANTIAGO PONIENTE',
361
        'MELIPILLA' => 'MELIPILLA',
362
        'SAN PEDRO' => 'MELIPILLA',
363
        'ALHUÉ' => 'MELIPILLA',
364
        'MARÍA PINTO' => 'MELIPILLA',
365
        'MAIPÚ' => 'MAIPÚ',
366
        'CERRILLOS' => 'MAIPÚ',
367
        'PADRE HURTADO' => 'MAIPÚ',
368
        'PEÑAFLOR' => 'MAIPÚ',
369
        'TALAGANTE' => 'MAIPÚ',
370
        'EL MONTE' => 'MAIPÚ',
371
        'ISLA DE MAIPO' => 'MAIPÚ',
372
        'LAS CONDES' => 'SANTIAGO ORIENTE',
373
        'VITACURA' => 'SANTIAGO ORIENTE',
374
        'LO BARNECHEA' => 'SANTIAGO ORIENTE',
375
        'ÑUÑOA' => 'ÑUÑOA',
376
        'LA REINA' => 'ÑUÑOA',
377
        'MACUL' => 'ÑUÑOA',
378
        'PEÑALOLÉN' => 'ÑUÑOA',
379
        'PROVIDENCIA' => 'PROVIDENCIA',
380
        'SAN MIGUEL' => 'SANTIAGO SUR',
381
        'LA CISTERNA' => 'SANTIAGO SUR',
382
        'SAN JOAQUÍN' => 'SANTIAGO SUR',
383
        'PEDRO AGUIRRE CERDA' => 'SANTIAGO SUR',
384
        'LO ESPEJO' => 'SANTIAGO SUR',
385
        'LA GRANJA' => 'SANTIAGO SUR',
386
        'LA PINTANA' => 'SANTIAGO SUR',
387
        'SAN RAMÓN' => 'SANTIAGO SUR',
388
        'LA FLORIDA' => 'LA FLORIDA',
389
        'PUENTE ALTO' => 'LA FLORIDA',
390
        'PIRQUE' => 'LA FLORIDA',
391
        'SAN JOSÉ DE MAIPO' => 'LA FLORIDA',
392
        'SAN BERNARDO' => 'SAN BERNARDO',
393
        'CALERA DE TANGO' => 'SAN BERNARDO',
394
        'EL BOSQUE' => 'SAN BERNARDO',
395
        'BUIN' => 'BUIN',
396
        'PAINE' => 'BUIN',
397
    ]; /// Direcciones regionales del SII según la comuna
398
399
    /**
400
     * Método que permite asignar el nombre del servidor del SII que se
401
     * usará para las consultas al SII
402
     * @param servidor Servidor que se usará: maullin (certificación) o palena (producción)
403
     * @param certificacion Permite definir si se está cambiando el servidor de certificación o el de producción
404
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
405
     * @version 2015-09-14
406
     */
407
    public static function setServidor($servidor = 'maullin', $certificacion = Sii::CERTIFICACION)
408
    {
409
        self::$config['servidor'][$certificacion] = $servidor;
410
    }
411
412
    /**
413
     * Método que entrega el nombre del servidor a usar según el ambiente
414
     * @param ambiente Ambiente que se desea obtener el servidor, si es null se autodetectará
415
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
416
     * @version 2016-08-01
417
     */
418
    public static function getServidor($ambiente = null)
419
    {
420
        return self::$config['servidor'][self::getAmbiente($ambiente)];
421
    }
422
423
    /**
424
     * Método que entrega la URL de un recurso en el SII según el ambiente que se esté usando
425
     * @param recurso Recurso del sitio del SII que se desea obtener la URL
426
     * @param ambiente Ambiente que se desea obtener el servidor, si es null se autodetectará
427
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
428
     * @version 2018-05-18
429
     */
430
    public static function getURL($recurso, $ambiente = null)
431
    {
432
        $ambiente = self::getAmbiente($ambiente);
433
        // si es anulación masiva de folios
434
        if ($recurso=='/anulacionMsvDteInternet') {
435
            $servidor = $ambiente ? 'www4c' : 'www4';
436
        }
437
        // servidor estandar (maullin o palena)
438
        else {
439
            $servidor = self::getServidor($ambiente);
440
        }
441
        // entregar URL
442
        return 'https://'.$servidor.'.sii.cl'.$recurso;
443
    }
444
445
    /**
446
     * Método para obtener el WSDL
447
     *
448
     * \code{.php}
449
     *   $wsdl = \sasco\LibreDTE\Sii::wsdl('CrSeed'); // WSDL para pedir semilla
450
     * \endcode
451
     *
452
     * Para forzar el uso del WSDL de certificación hay dos maneras, una es
453
     * pasando un segundo parámetro al método get con valor Sii::CERTIFICACION:
454
     *
455
     * \code{.php}
456
     *   $wsdl = \sasco\LibreDTE\Sii::wsdl('CrSeed', \sasco\LibreDTE\Sii::CERTIFICACION);
457
     * \endcode
458
     *
459
     * La otra manera, para evitar este segundo parámetro, es asignar el valor a
460
     * través de la configuración:
461
     *
462
     * \code{.php}
463
     *   \sasco\LibreDTE\Sii::setAmbiente(\sasco\LibreDTE\Sii::CERTIFICACION);
464
     * \endcode
465
     *
466
     * @param servicio Servicio por el cual se está solicitando su WSDL
467
     * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION o null (para detección automática)
468
     * @return URL del WSDL del servicio según ambiente solicitado
469
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
470
     * @version 2016-06-11
471
     */
472
    public static function wsdl($servicio, $ambiente = null)
473
    {
474
        // determinar ambiente que se debe usar
475
        $ambiente = self::getAmbiente($ambiente);
476
        // entregar WSDL local (modificados para ambiente de certificación)
477
        if ($ambiente==self::CERTIFICACION) {
478
            $wsdl = dirname(dirname(__FILE__)).'/wsdl/'.self::$config['servidor'][$ambiente].'/'.$servicio.'.jws';
479
            if (is_readable($wsdl))
480
                return $wsdl;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $wsdl; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii::wsdl of type sasco\LibreDTE\URL.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
481
        }
482
        // entregar WSDL oficial desde SII
483
        $location = isset(self::$config['wsdl'][$servicio]) ? self::$config['wsdl'][$servicio] : self::$config['wsdl']['*'];
484
        $wsdl = str_replace(
485
            ['{servidor}', '{servicio}'],
486
            [self::$config['servidor'][$ambiente], $servicio],
487
            $location
488
        );
489
        // entregar wsdl
490
        return $wsdl;
491
    }
492
493
    /**
494
     * Método para realizar una solicitud al servicio web del SII
495
     * @param wsdl Nombre del WSDL que se usará
496
     * @param request Nombre de la función que se ejecutará en el servicio web
497
     * @param args Argumentos que se pasarán al servicio web
498
     * @param retry Intentos que se realizarán como máximo para obtener respuesta
499
     * @return Objeto SimpleXMLElement con la espuesta del servicio web consultado
500
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
501
     * @version 2018-11-12
502
     */
503
    public static function request($wsdl, $request, $args = null, $retry = null)
504
    {
505
        if (is_numeric($args)) {
506
            $retry = (int)$args;
507
            $args = null;
508
        }
509
        if (!$retry) {
510
            $retry = self::$retry;
511
        }
512
        if ($args and !is_array($args)) {
513
            $args = [$args];
514
        }
515
        $options = ['cache_wsdl' => WSDL_CACHE_DISK];
516
        if (!self::$verificar_ssl) {
517
            if (self::getAmbiente()==self::PRODUCCION) {
518
                $msg = Estado::get(Estado::ENVIO_SSL_SIN_VERIFICAR);
519
                \sasco\LibreDTE\Log::write(Estado::ENVIO_SSL_SIN_VERIFICAR, $msg, LOG_WARNING);
0 ignored issues
show
Documentation introduced by
$msg 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...
Documentation introduced by
LOG_WARNING is of type integer, but the function expects a object<sasco\LibreDTE\Gravedad>.

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...
520
            }
521
            $options['stream_context'] = stream_context_create([
522
                'ssl' => [
523
                    'verify_peer' => false,
524
                    'verify_peer_name' => false,
525
                    'allow_self_signed' => true
526
                ]
527
            ]);
528
        }
529
        try {
530
            $soap = new \SoapClient(self::wsdl($wsdl), $options);
531
        } catch (\Exception $e) {
532
            $msg = $e->getMessage();
533 View Code Duplication
            if (isset($e->getTrace()[0]['args'][1]) and is_string($e->getTrace()[0]['args'][1])) {
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...
534
                $msg .= ': '.$e->getTrace()[0]['args'][1];
535
            }
536
            \sasco\LibreDTE\Log::write(Estado::REQUEST_ERROR_SOAP, Estado::get(Estado::REQUEST_ERROR_SOAP, $msg));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...QUEST_ERROR_SOAP, $msg) 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...
537
            return false;
538
        }
539
        for ($i=0; $i<$retry; $i++) {
540
            try {
541
                if ($args) {
542
                    $body = call_user_func_array([$soap, $request], $args);
543
                } else {
544
                    $body = $soap->$request();
545
                }
546
                break;
547
            } catch (\Exception $e) {
548
                $msg = $e->getMessage();
549 View Code Duplication
                if (isset($e->getTrace()[0]['args'][1]) and is_string($e->getTrace()[0]['args'][1])) {
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...
550
                    $msg .= ': '.$e->getTrace()[0]['args'][1];
551
                }
552
                \sasco\LibreDTE\Log::write(Estado::REQUEST_ERROR_SOAP, Estado::get(Estado::REQUEST_ERROR_SOAP, $msg));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...QUEST_ERROR_SOAP, $msg) 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...
553
                $body = null;
554
                usleep(200000); // pausa de 0.2 segundos antes de volver a intentar el envío
555
            }
556
        }
557 View Code Duplication
        if ($body===null) {
0 ignored issues
show
Bug introduced by
The variable $body does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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...
558
            \sasco\LibreDTE\Log::write(Estado::REQUEST_ERROR_BODY, Estado::get(Estado::REQUEST_ERROR_BODY, $wsdl, $retry));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...OR_BODY, $wsdl, $retry) 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...
559
            return false;
560
        }
561
        return new \SimpleXMLElement($body, LIBXML_COMPACT);
562
    }
563
564
    /**
565
     * Método que permite indicar si se debe o no verificar el certificado SSL
566
     * del SII
567
     * @param verificar =true si se quiere verificar certificado, =false en caso que no (por defecto se verifica)
568
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
569
     * @version 2015-09-16
570
     */
571
    public static function setVerificarSSL($verificar = true)
572
    {
573
        self::$verificar_ssl = $verificar;
574
    }
575
576
    /**
577
     * Método que indica si se está o no verificando el SSL en las conexiones al SII
578
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
579
     * @version 2017-05-11
580
     */
581
    public static function getVerificarSSL()
582
    {
583
        return self::$verificar_ssl;
584
    }
585
586
    /**
587
     * Método que realiza el envío de un DTE al SII
588
     * Referencia: http://www.sii.cl/factura_electronica/factura_mercado/envio.pdf
589
     * @param usuario RUN del usuario que envía el DTE
590
     * @param empresa RUT de la empresa emisora del DTE
591
     * @param dte Documento XML con el DTE que se desea enviar a SII
592
     * @param token Token de autenticación automática ante el SII
593
     * @param gzip Permite enviar el archivo XML comprimido al servidor
594
     * @param retry Intentos que se realizarán como máximo para obtener respuesta
595
     * @return Respuesta XML desde SII o bien null si no se pudo obtener respuesta
596
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
597
     * @version 2017-10-23
598
     */
599
    public static function enviar($usuario, $empresa, $dte, $token, $gzip = false, $retry = null)
600
    {
601
        // definir datos que se usarán en el envío
602
        list($rutSender, $dvSender) = explode('-', str_replace('.', '', $usuario));
603
        list($rutCompany, $dvCompany) = explode('-', str_replace('.', '', $empresa));
604
        if (strpos($dte, '<?xml')===false) {
605
            $dte = '<?xml version="1.0" encoding="ISO-8859-1"?>'."\n".$dte;
606
        }
607 View Code Duplication
        do {
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...
608
            $file = sys_get_temp_dir().'/dte_'.md5(microtime().$token.$dte).'.'.($gzip?'gz':'xml');
609
        } while (file_exists($file));
610
        if ($gzip) {
611
            $dte = gzencode($dte);
612 View Code Duplication
            if ($dte===false) {
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...
613
                \sasco\LibreDTE\Log::write(Estado::ENVIO_ERROR_GZIP, Estado::get(Estado::ENVIO_ERROR_GZIP));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...tado::ENVIO_ERROR_GZIP) 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...
614
                return false;
615
            }
616
        }
617
        file_put_contents($file, $dte);
618
        $data = [
619
            'rutSender' => $rutSender,
620
            'dvSender' => $dvSender,
621
            'rutCompany' => $rutCompany,
622
            'dvCompany' => $dvCompany,
623
            'archivo' => curl_file_create(
624
                $file,
625
                $gzip ? 'application/gzip' : 'application/xml',
626
                basename($file)
627
            ),
628
        ];
629
        // definir reintentos si no se pasaron
630
        if (!$retry) {
631
            $retry = self::$retry;
632
        }
633
        // crear sesión curl con sus opciones
634
        $curl = curl_init();
635
        $header = [
636
            'User-Agent: Mozilla/4.0 (compatible; PROG 1.0; LibreDTE)',
637
            'Referer: https://libredte.cl',
638
            'Cookie: TOKEN='.$token,
639
        ];
640
        $url = 'https://'.self::$config['servidor'][self::getAmbiente()].'.sii.cl/cgi_dte/UPL/DTEUpload';
641
        curl_setopt($curl, CURLOPT_POST, true);
642
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
643
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
644
        curl_setopt($curl, CURLOPT_URL, $url);
645
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
646
        // si no se debe verificar el SSL se asigna opción a curl, además si
647
        // se está en el ambiente de producción y no se verifica SSL se
648
        // generará una entrada en el log
649 View Code Duplication
        if (!self::$verificar_ssl) {
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...
650
            if (self::getAmbiente()==self::PRODUCCION) {
651
                $msg = Estado::get(Estado::ENVIO_SSL_SIN_VERIFICAR);
652
                \sasco\LibreDTE\Log::write(Estado::ENVIO_SSL_SIN_VERIFICAR, $msg, LOG_WARNING);
0 ignored issues
show
Documentation introduced by
$msg 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...
Documentation introduced by
LOG_WARNING is of type integer, but the function expects a object<sasco\LibreDTE\Gravedad>.

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...
653
            }
654
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
655
        }
656
        // enviar XML al SII
657 View Code Duplication
        for ($i=0; $i<$retry; $i++) {
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...
658
            $response = curl_exec($curl);
659
            if ($response and $response!='Error 500') {
660
                break;
661
            }
662
        }
663
        unlink($file);
664
        // verificar respuesta del envío y entregar error en caso que haya uno
665 View Code Duplication
        if (!$response or $response=='Error 500') {
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...
666
            if (!$response) {
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
667
                \sasco\LibreDTE\Log::write(Estado::ENVIO_ERROR_CURL, Estado::get(Estado::ENVIO_ERROR_CURL, curl_error($curl)));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...URL, curl_error($curl)) 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...
668
            }
669
            if ($response=='Error 500') {
670
                \sasco\LibreDTE\Log::write(Estado::ENVIO_ERROR_500, Estado::get(Estado::ENVIO_ERROR_500));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...stado::ENVIO_ERROR_500) 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...
671
            }
672
            return false;
673
        }
674
        // cerrar sesión curl
675
        curl_close($curl);
676
        // crear XML con la respuesta y retornar
677
        try {
678
            $xml = new \SimpleXMLElement($response, LIBXML_COMPACT);
679
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class sasco\LibreDTE\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...
680
            \sasco\LibreDTE\Log::write(Estado::ENVIO_ERROR_XML, Estado::get(Estado::ENVIO_ERROR_XML, $e->getMessage()));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::..._XML, $e->getMessage()) 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...
681
            return false;
682
        }
683
        if ($xml->STATUS!=0) {
684
            \sasco\LibreDTE\Log::write(
685
                $xml->STATUS,
686
                Estado::get($xml->STATUS).(isset($xml->DETAIL)?'. '.implode("\n", (array)$xml->DETAIL->ERROR):'')
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...l->DETAIL->ERROR) : '') is of type 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...
687
            );
688
        }
689
        return $xml;
690
    }
691
692
    /**
693
     * Método para obtener la clave pública (certificado X.509) del SII
694
     *
695
     * \code{.php}
696
     *   $pub_key = \sasco\LibreDTE\Sii::cert(100); // Certificado IDK 100 (certificación)
697
     * \endcode
698
     *
699
     * @param idk IDK de la clave pública del SII. Si no se indica se tratará de determinar con el ambiente que se esté usando
700
     * @return Contenido del certificado
701
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
702
     * @version 2015-09-16
703
     */
704
    public static function cert($idk = null)
705
    {
706
        // si se pasó un idk y existe el archivo asociado se entrega
707
        if ($idk) {
708
            $cert = dirname(dirname(__FILE__)).'/certs/'.$idk.'.cer';
709
            if (is_readable($cert)) {
710
                return file_get_contents($cert);
711
            }
712
        }
713
        // buscar certificado y entregar si existe o =false si no
714
        $ambiente = self::getAmbiente();
715
        $cert = dirname(dirname(__FILE__)).'/certs/'.self::$config['certs'][$ambiente].'.cer';
716
        if (!is_readable($cert)) {
717
            \sasco\LibreDTE\Log::write(Estado::SII_ERROR_CERTIFICADO, Estado::get(Estado::SII_ERROR_CERTIFICADO, self::$config['certs'][$ambiente]));
0 ignored issues
show
Documentation introduced by
\sasco\LibreDTE\Estado::...ig['certs'][$ambiente]) 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...
718
            return false;
719
        }
720
        return file_get_contents($cert);
721
    }
722
723
    /**
724
     * Método que asigna el ambiente que se usará por defecto (si no está
725
     * asignado con la constante _LibreDTE_CERTIFICACION_)
726
     * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION
727
     * @warning No se está verificando SSL en ambiente de certificación
728
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
729
     * @version 2016-08-28
730
     */
731
    public static function setAmbiente($ambiente = self::PRODUCCION)
732
    {
733
        $ambiente = $ambiente ? self::CERTIFICACION : self::PRODUCCION;
734
        if ($ambiente==self::CERTIFICACION) {
735
            self::setVerificarSSL(false);
736
        }
737
        self::$ambiente = $ambiente;
738
    }
739
740
    /**
741
     * Método que determina el ambiente que se debe utilizar: producción o
742
     * certificación
743
     * @param ambiente Ambiente a usar: Sii::PRODUCCION o Sii::CERTIFICACION o null (para detección automática)
744
     * @return Ambiente que se debe utilizar
745
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
746
     * @version 2015-09-07
747
     */
748
    public static function getAmbiente($ambiente = null)
749
    {
750
        if ($ambiente===null) {
751
            if (defined('_LibreDTE_CERTIFICACION_'))
752
                $ambiente = (int)_LibreDTE_CERTIFICACION_;
0 ignored issues
show
Bug Compatibility introduced by
The expression (int) _LibreDTE_CERTIFICACION_; of type integer adds the type integer to the return on line 756 which is incompatible with the return type documented by sasco\LibreDTE\Sii::getAmbiente of type sasco\LibreDTE\Ambiente.
Loading history...
753
            else
754
                $ambiente = self::$ambiente;
0 ignored issues
show
Bug Compatibility introduced by
The expression self::$ambiente; of type integer adds the type integer to the return on line 756 which is incompatible with the return type documented by sasco\LibreDTE\Sii::getAmbiente of type sasco\LibreDTE\Ambiente.
Loading history...
755
        }
756
        return $ambiente;
757
    }
758
759
    /**
760
     * Método que entrega la tasa de IVA vigente
761
     * @return Tasa de IVA vigente
762
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
763
     * @version 2015-09-03
764
     */
765
    public static function getIVA()
766
    {
767
        return self::IVA;
768
    }
769
770
    /**
771
     * Método que entrega la dirección regional según la comuna que se esté
772
     * consultando
773
     * @param comuna de la sucursal del emior o bien código de la sucursal del SII
774
     * @return Dirección regional del SII
775
     * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl)
776
     * @version 2017-11-07
777
     */
778
    public static function getDireccionRegional($comuna)
779
    {
780
        if (!$comuna) {
781
            return 'N.N.';
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 'N.N.'; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii::getDireccionRegional of type sasco\LibreDTE\Dirección.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
782
        }
783
        if (!is_numeric($comuna)) {
784
            $direccion = mb_strtoupper($comuna, 'UTF-8');
785
            return isset(self::$direcciones_regionales[$direccion]) ? self::$direcciones_regionales[$direccion] : $direccion;
786
        }
787
        return 'SUC '.$comuna;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return 'SUC ' . $comuna; (string) is incompatible with the return type documented by sasco\LibreDTE\Sii::getDireccionRegional of type sasco\LibreDTE\Dirección.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
788
    }
789
790
}
791