This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Fhp\Parser; |
||
4 | |||
5 | use Fhp\Parser\Exception\MT940Exception; |
||
6 | |||
7 | /** |
||
8 | * Class MT940 |
||
9 | * @package Fhp\Parser |
||
10 | */ |
||
11 | class MT940 |
||
12 | { |
||
13 | const TARGET_ARRAY = 0; |
||
14 | |||
15 | const CD_CREDIT = 'credit'; |
||
16 | const CD_DEBIT = 'debit'; |
||
17 | |||
18 | /** @var string */ |
||
19 | protected $rawData; |
||
20 | /** @var string */ |
||
21 | protected $soaDate; |
||
22 | |||
23 | /** |
||
24 | * MT940 constructor. |
||
25 | * |
||
26 | * @param string $rawData |
||
27 | */ |
||
28 | 1 | public function __construct($rawData) |
|
29 | { |
||
30 | 1 | $this->rawData = (string) $rawData; |
|
31 | 1 | } |
|
32 | |||
33 | /** |
||
34 | * @param string $target |
||
35 | * @return array |
||
36 | * @throws MT940Exception |
||
37 | */ |
||
38 | 1 | public function parse($target) |
|
39 | { |
||
40 | switch ($target) { |
||
41 | 1 | case static::TARGET_ARRAY: |
|
42 | 1 | return $this->parseToArray(); |
|
43 | break; |
||
0 ignored issues
–
show
|
|||
44 | default: |
||
45 | throw new MT940Exception('Invalid parse type provided'); |
||
46 | } |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * @return array |
||
51 | * @throws MT940Exception |
||
52 | */ |
||
53 | 1 | protected function parseToArray() |
|
54 | { |
||
55 | // The divider can be either \r\n or @@ |
||
56 | 1 | $divider = substr_count($this->rawData, "\r\n-") > substr_count($this->rawData, '@@-') ? "\r\n" : '@@'; |
|
57 | |||
58 | 1 | $result = array(); |
|
59 | 1 | $days = preg_split('%' . $divider . '-$%', $this->rawData); |
|
60 | 1 | foreach ($days as &$day) { |
|
61 | 1 | $day = explode($divider . ':', $day); |
|
62 | 1 | for ($i = 0, $cnt = count($day); $i < $cnt; $i++) { |
|
63 | // handle start balance |
||
64 | // 60F:C160401EUR1234,56 |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
65 | 1 | if (preg_match('/^60(F|M):/', $day[$i])) { |
|
66 | // remove 60(F|M): for better parsing |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
67 | 1 | $day[$i] = substr($day[$i], 4); |
|
68 | 1 | $this->soaDate = $this->getDate(substr($day[$i], 1, 6)); |
|
69 | |||
70 | 1 | if (!isset($result[$this->soaDate])) { |
|
71 | 1 | $result[$this->soaDate] = array('start_balance' => array()); |
|
72 | 1 | } |
|
73 | |||
74 | 1 | $cdMark = substr($day[$i], 0, 1); |
|
75 | 1 | if ($cdMark == 'C') { |
|
76 | 1 | $result[$this->soaDate]['start_balance']['credit_debit'] = static::CD_CREDIT; |
|
77 | 1 | } elseif ($cdMark == 'D') { |
|
78 | $result[$this->soaDate]['start_balance']['credit_debit'] = static::CD_DEBIT; |
||
79 | } |
||
80 | |||
81 | 1 | $amount = str_replace(',', '.', substr($day[$i], 10)); |
|
82 | 1 | $result[$this->soaDate]['start_balance']['amount'] = $amount; |
|
83 | 1 | } elseif ( |
|
84 | // found transaction |
||
85 | // trx:61:1603310331DR637,39N033NONREF |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
56% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
86 | 1 | 0 === strpos($day[$i], '61:') |
|
87 | 1 | && isset($day[$i + 1]) |
|
88 | 1 | && 0 === strpos($day[$i + 1], '86:') |
|
89 | 1 | ) { |
|
90 | 1 | $transaction = substr($day[$i], 3); |
|
91 | 1 | $description = substr($day[$i + 1], 3); |
|
92 | |||
93 | 1 | if (!isset($result[$this->soaDate]['transactions'])) { |
|
94 | 1 | $result[$this->soaDate]['transactions'] = array(); |
|
95 | 1 | } |
|
96 | |||
97 | // short form for better handling |
||
98 | 1 | $trx = &$result[$this->soaDate]['transactions']; |
|
99 | |||
100 | 1 | preg_match('/^\d{6}(\d{4})?(C|D|RC|RD)([A-Z]{1})?([^N]+)N/', $transaction, $trxMatch); |
|
101 | 1 | if ($trxMatch[2] == 'C') { |
|
102 | 1 | $trx[count($trx)]['credit_debit'] = static::CD_CREDIT; |
|
103 | 1 | } elseif ($trxMatch[2] == 'D') { |
|
104 | $trx[count($trx)]['credit_debit'] = static::CD_DEBIT; |
||
105 | } else { |
||
106 | throw new MT940Exception('cd mark not found in: ' . $transaction); |
||
107 | } |
||
108 | |||
109 | 1 | $amount = $trxMatch[4]; |
|
110 | 1 | $amount = str_replace(',', '.', $amount); |
|
111 | 1 | $trx[count($trx) - 1]['amount'] = floatval($amount); |
|
112 | |||
113 | 1 | $description = $this->parseDescription($description); |
|
114 | 1 | $trx[count($trx) - 1]['description'] = $description; |
|
115 | |||
116 | // :61:1605110509D198,02NMSCNONREF |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
67% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
117 | // 16 = year |
||
118 | // 0511 = valuta date |
||
119 | // 0509 = booking date |
||
120 | 1 | $year = substr($transaction, 0, 2); |
|
121 | 1 | $valutaDate = $this->getDate($year . substr($transaction, 2, 4)); |
|
122 | |||
123 | 1 | $bookingDate = substr($transaction, 6, 4); |
|
124 | 1 | if (preg_match('/^\d{4}$/', $bookingDate)) { |
|
125 | // if valuta date is earlier than booking date, then it must be in the new year. |
||
126 | 1 | if (substr($transaction, 2, 2) == '12' && substr($transaction, 6, 2) == '01') { |
|
127 | $year++; |
||
128 | 1 | } elseif (substr($transaction, 2, 2) == '01' && substr($transaction, 6, 2) == '12') { |
|
129 | $year--; |
||
130 | } |
||
131 | 1 | $bookingDate = $this->getDate($year . $bookingDate); |
|
132 | 1 | } else { |
|
133 | // if booking date not set in :61, then we have to take it from :60F |
||
134 | $bookingDate = $this->soaDate; |
||
135 | } |
||
136 | |||
137 | 1 | $trx[count($trx) - 1]['booking_date'] = $bookingDate; |
|
138 | 1 | $trx[count($trx) - 1]['valuta_date'] = $valutaDate; |
|
139 | 1 | } |
|
140 | 1 | } |
|
141 | 1 | } |
|
142 | |||
143 | 1 | return $result; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * @param string $descr |
||
148 | * @return array |
||
149 | */ |
||
150 | 1 | protected function parseDescription($descr) |
|
151 | { |
||
152 | 1 | $prepared = array(); |
|
153 | 1 | $result = array(); |
|
154 | |||
155 | // prefill with empty values |
||
156 | 1 | for ($i = 0; $i <= 63; $i++) { |
|
157 | 1 | $prepared[$i] = null; |
|
158 | 1 | } |
|
159 | |||
160 | 1 | $descr = str_replace("\r\n", '', $descr); |
|
161 | 1 | $descr = str_replace('? ', '?', $descr); |
|
162 | 1 | preg_match_all('/\?[\r\n]*(\d{2})([^\?]+)/', $descr, $matches, PREG_SET_ORDER); |
|
163 | |||
164 | 1 | $descriptionLines = array(); |
|
165 | 1 | $description1 = ''; // Legacy, could be removed. |
|
166 | 1 | $description2 = ''; // Legacy, could be removed. |
|
167 | 1 | foreach ($matches as $m) { |
|
168 | 1 | $index = (int) $m[1]; |
|
169 | 1 | if ((20 <= $index && $index <= 29) || (60 <= $index && $index <= 63)) { |
|
170 | 1 | if (20 <= $index && $index <= 29) { |
|
171 | 1 | $description1 .= $m[2]; |
|
172 | 1 | } else { |
|
173 | $description2 .= $m[2]; |
||
174 | } |
||
175 | 1 | $m[2] = trim($m[2]); |
|
176 | 1 | if (!empty($m[2])) { |
|
177 | 1 | $descriptionLines[] = $m[2]; |
|
178 | 1 | } |
|
179 | 1 | } else { |
|
180 | 1 | $prepared[$index] = $m[2]; |
|
181 | } |
||
182 | 1 | } |
|
183 | |||
184 | 1 | $description = array(); |
|
185 | 1 | if (empty($descriptionLines) || strlen($descriptionLines[0]) < 5 || $descriptionLines[0][4] !== '+') { |
|
186 | $description['SVWZ'] = implode('', $descriptionLines); |
||
187 | } else { |
||
188 | 1 | $lastType = null; |
|
189 | 1 | foreach ($descriptionLines as $line) { |
|
190 | 1 | if (strlen($line) >= 5 && $line[4] === '+') { |
|
191 | 1 | if ($lastType != null) { |
|
0 ignored issues
–
show
|
|||
192 | 1 | $description[$lastType] = trim($description[$lastType]); |
|
193 | 1 | } |
|
194 | 1 | $lastType = substr($line, 0, 4); |
|
195 | 1 | $description[$lastType] = substr($line, 5); |
|
196 | 1 | } else { |
|
197 | 1 | $description[$lastType] .= $line; |
|
198 | } |
||
199 | 1 | if (strlen($line) < 27) { |
|
200 | // Usually, lines are 27 characters long. In case characters are missing, then it's either the end |
||
201 | // of the current type or spaces have been trimmed from the end. We want to collapse multiple spaces |
||
202 | // into one and we don't want to leave trailing spaces behind. So add a single space here to make up |
||
203 | // for possibly missing spaces, and if it's the end of the type, it will be trimmed off later. |
||
204 | 1 | $description[$lastType] .= ' '; |
|
205 | 1 | } |
|
206 | 1 | } |
|
207 | 1 | $description[$lastType] = trim($description[$lastType]); |
|
208 | } |
||
209 | |||
210 | 1 | $result['description'] = $description; |
|
211 | 1 | $result['booking_text'] = trim($prepared[0]); |
|
212 | 1 | $result['primanoten_nr'] = trim($prepared[10]); |
|
213 | 1 | $result['description_1'] = trim($description1); |
|
214 | 1 | $result['bank_code'] = trim($prepared[30]); |
|
215 | 1 | $result['account_number'] = trim($prepared[31]); |
|
216 | 1 | $result['name'] = trim($prepared[32] . $prepared[33]); |
|
217 | 1 | $result['text_key_addition'] = trim($prepared[34]); |
|
218 | 1 | $result['description_2'] = trim($description2); |
|
219 | |||
220 | 1 | return $result; |
|
221 | } |
||
222 | |||
223 | /** |
||
224 | * @param string $val |
||
225 | * @return string |
||
226 | */ |
||
227 | 1 | protected function getDate($val) |
|
228 | { |
||
229 | 1 | $val = '20' . $val; |
|
230 | 1 | preg_match('/(\d{4})(\d{2})(\d{2})/', $val, $m); |
|
231 | 1 | return $m[1] . '-' . $m[2] . '-' . $m[3]; |
|
232 | } |
||
233 | } |
||
234 |
The break statement is not necessary if it is preceded for example by a return statement:
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.