Passed
Push — master ( 92c377...02ff21 )
by Roberto
02:33 queued 10s
created

ValidTXT   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 0

Test Coverage

Coverage 85%

Importance

Changes 0
Metric Value
wmc 23
lcom 0
cbo 0
dl 0
loc 134
ccs 68
cts 80
cp 0.85
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A loadStructure() 0 17 4
D isValid() 0 94 19
1
<?php
2
3
namespace NFePHP\NFe\Common;
4
5
/**
6
 * Validation for TXT representation of NFe
7
 *
8
 * @category  NFePHP
9
 * @package   NFePHP\NFe\Common\ValidTXT
10
 * @copyright NFePHP Copyright (c) 2008-2019
11
 * @license   http://www.gnu.org/licenses/lgpl.txt LGPLv3+
12
 * @license   https://opensource.org/licenses/MIT MIT
13
 * @license   http://www.gnu.org/licenses/gpl.txt GPLv3+
14
 * @author    Roberto L. Machado <linux.rlm at gmail dot com>
15
 * @link      http://github.com/nfephp-org/sped-nfe for the canonical source repository
16
 */
17
18
class ValidTXT
19
{
20
    const LOCAL="LOCAL";
21
    const LOCAL_V12 = "LOCAL_V12";
22
    const SEBRAE="SEBRAE";
23
24
    /**
25
     * Loads structure of txt from json file in storage folder
26
     * @param float $version
27
     * @param string $baselayout
28
     * @throws \InvalidArgumentException
29
     * @return mixed
30
     */
31 2
    public static function loadStructure($version = 4.00, $baselayout = self::LOCAL)
32
    {
33 2
        $path = realpath(__DIR__ . "/../../storage");
34 2
        $comp = '';
35 2
        if (strtoupper($baselayout) === 'SEBRAE') {
36 1
            $comp = '_sebrae';
37 1
        } elseif (strtoupper($baselayout) === 'LOCAL_V12') {
38
            $comp = '_v1.2';
39
        }
40 2
        $file = $path . '/txtstructure' . ($version*100) . $comp . '.json';
41 2
        if (!is_file($file)) {
42
            throw new \InvalidArgumentException("O arquivo de estrutura para a "
43
                . "versão de layout indicada no TXT, não foi encontrado [$file].");
44
        }
45 2
        $json = file_get_contents($file);
46 2
        return json_decode($json, true);
47
    }
48
49
    /**
50
     * Verifies the validity of txt according to the rules of the code
51
     * If is valid returns empty array
52
     * Else return array with errors
53
     * @param string $txt
54
     * @param string $baselayout
55
     * @return array
56
     */
57 3
    public static function isValid($txt, $baselayout = self::LOCAL)
58
    {
59 3
        $errors = [];
60 3
        $txt = str_replace(["\r", "\t"], '', trim($txt));
61 3
        $rows = explode("\n", $txt);
62 3
        $num = 0;
63
64 3
        foreach ($rows as $row) {
65 3
            $fields = explode('|', $row);
66 3
            if (empty($fields)) {
67
                continue;
68
            }
69 3
            $ref = strtoupper($fields[0]);
70 3
            if (empty($ref)) {
71
                continue;
72
            }
73 3
            if ($ref === 'NOTAFISCAL') {
74 3
                continue;
75
            }
76 3
            if ($ref === 'A') {
77 3
                $num = 0;
78 3
                $entities = self::loadStructure($fields[1], $baselayout);
79
            }
80 3
            if ($ref === 'I') {
81 3
                $num += 1;
82
            }
83 3
            $lastChar = substr($row, -1);
84 3
            $char = '';
85 3
            if ($lastChar != '|') {
86 1
                if ($lastChar == ' ') {
87
                    $char = '[ESP]';
88 1
                } elseif ($lastChar == "\r") {
89
                    $char = '[CR]';
90 1
                } elseif ($lastChar == "\t") {
91
                    $char = '[TAB]';
92
                }
93 1
                $nrow = str_replace(["\r", "\t"], '', trim($row));
94 1
                $errors[] = "ERRO: ($num) Todas as linhas devem terminar com 'pipe' e não $char. [$nrow]";
95 1
                continue;
96
            }
97 3
            if (empty($entities)) {
98
                $errors[] = "ERRO: O TXT não contêm um marcador A";
99
                return $errors;
100
            }
101 3
            if (!array_key_exists($ref, $entities)) {
102 1
                $errors[] = "ERRO: ($num) Essa referência não está definida. [$row]";
103 1
                continue;
104
            }
105 3
            $count = count($fields)-1;
106 3
            $default = count(explode('|', $entities[$ref]))-1;
107 3
            if ($default !== $count) {
108 3
                $errors[] = "ERRO: ($num) O número de parâmetros na linha "
109 3
                    . "está errado (esperado #$default) -> (encontrado #$count). [ $row ] Esperado [ "
110 3
                    . $entities[$ref]." ]";
111 3
                continue;
112
            }
113 3
            foreach ($fields as $field) {
114 3
                if (empty($field)) {
115 3
                    continue;
116
                }
117 3
                if (empty(trim($field))) {
118 1
                    $errors[] = "ERRO: ($num) Existem apenas espaços no campo dos dados. [$row]";
119 1
                    continue;
120
                }
121
                //permitindo acentuação, isso pode permitir algumas falhas de validação
122
                //mas em principio a SEFAZ autoriza o uso de alguns caracteres acentuados
123
                //apesar de recomendar que não sejam usados
124 3
                $newfield = str_replace(['>', '<', '"', "'", "\t", "\r"], "", $field);
125 3
                if ($field != $newfield) {
126 1
                    $errors[] = "ERRO: ($num) Existem caracteres especiais não permitidos, "
127 1
                        . "como por ex. caracteres de controle, sinais de maior ou menor, aspas ou apostrofes, "
128 1
                        . "na entidade [" . htmlentities($row) . "]";
129 1
                    continue;
130
                }
131 3
                $newfield = preg_replace(
132
                    '/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'.
133
                    '|[\x00-\x7F][\x80-\xBF]+'.
134
                    '|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
135
                    '|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
136 3
                    '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
137 3
                    '?',
138 3
                    $field
139
                );
140 3
                 $newfield = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]'.
141 3
                    '|\xED[\xA0-\xBF][\x80-\xBF]/S', '?', $newfield);
142 3
                if ($field != $newfield) {
143
                    $errors[] = "ERRO: ($num) Existem caracteres não UTF-8, não permitidos, "
144
                        . "no campo [" . htmlentities($newfield) . "]";
145 3
                    continue;
146
                }
147
            }
148
        }
149 3
        return $errors;
150
    }
151
}
152