Passed
Pull Request — master (#921)
by
unknown
08:01
created

ValidTXT   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 85%

Importance

Changes 0
Metric Value
wmc 23
eloc 86
dl 0
loc 132
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 16 4
D isValid() 0 93 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 3
    public static function loadStructure($version = 4.00, $baselayout = self::LOCAL)
32
    {
33 3
        $path = realpath(__DIR__ . "/../../storage");
34 3
        $comp = '';
35 3
        if (strtoupper($baselayout) === 'SEBRAE') {
36 1
            $comp = '_sebrae';
37 2
        } elseif (strtoupper($baselayout) === 'LOCAL_V12') {
38
            $comp = '_v1.2';
39
        }
40 3
        $file = $path . '/txtstructure' . ($version * 100) . $comp . '.json';
41 3
        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 3
        $json = file_get_contents($file);
46 3
        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 4
    public static function isValid($txt, $baselayout = self::LOCAL)
58
    {
59 4
        $errors = [];
60 4
        $txt = str_replace(["\r", "\t"], '', trim($txt));
61 4
        $rows = explode("\n", $txt);
62 4
        $num = 0;
63
64 4
        foreach ($rows as $row) {
65 4
            $fields = explode('|', $row);
66 4
            if (count($fields) == 0) {
67
                continue;
68
            }
69 4
            $ref = strtoupper($fields[0]);
70 4
            if (!$ref) {
71
                continue;
72
            }
73 4
            if ($ref === 'NOTAFISCAL') {
74 3
                continue;
75
            }
76 4
            if ($ref === 'A') {
77 4
                $num = 0;
78 4
                $entities = self::loadStructure($fields[1], $baselayout);
0 ignored issues
show
Bug introduced by
$fields[1] of type string is incompatible with the type double expected by parameter $version of NFePHP\NFe\Common\ValidTXT::loadStructure(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
                $entities = self::loadStructure(/** @scrutinizer ignore-type */ $fields[1], $baselayout);
Loading history...
79
            }
80 4
            if ($ref === 'I') {
81 4
                $num += 1;
82
            }
83 4
            $lastChar = substr($row, -1);
84 4
            $char = '';
85 4
            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 4
            if (empty($entities)) {
98
                $errors[] = "ERRO: O TXT não contêm um marcador A";
99
                return $errors;
100
            }
101 4
            if (!array_key_exists($ref, $entities)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $entities does not seem to be defined for all execution paths leading up to this point.
Loading history...
102 1
                $errors[] = "ERRO: ($num) Essa referência não está definida. [$row]";
103 1
                continue;
104
            }
105 4
            $count = count($fields) - 1;
106 4
            $default = count(explode('|', $entities[$ref])) - 1;
107 4
            if ($default !== $count) {
108 2
                $errors[] = "ERRO: ($num) O número de parâmetros na linha "
109 2
                    . "está errado (esperado #$default) -> (encontrado #$count). [ $row ] Esperado [ "
110 2
                    . $entities[$ref] . " ]";
111 2
                continue;
112
            }
113 4
            foreach ($fields as $field) {
114 4
                if (empty($field)) {
115 4
                    continue;
116
                }
117 4
                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 4
                $newfield = str_replace(['>', '<', '"', "'", "\t", "\r"], "", $field);
125 4
                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 4
                $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 4
                    '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
137 4
                    '?',
138 4
                    $field
139
                );
140 4
                 $newfield = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]' .
141 4
                    '|\xED[\xA0-\xBF][\x80-\xBF]/S', '?', $newfield);
142 4
                if ($field != $newfield) {
143
                    $errors[] = "ERRO: ($num) Existem caracteres não UTF-8, não permitidos, "
144
                        . "no campo [" . htmlentities($newfield) . "]";
145 4
                    continue;
146
                }
147
            }
148
        }
149 4
        return $errors;
150
    }
151
}
152