Passed
Pull Request — master (#95)
by
unknown
08:12
created
lib/Fhp/Parser/MT940.php 1 patch
Indentation   +233 added lines, -233 removed lines patch added patch discarded remove patch
@@ -13,238 +13,238 @@
 block discarded – undo
13 13
  */
14 14
 class MT940
15 15
 {
16
-	const TARGET_ARRAY = 0;
17
-
18
-	const CD_CREDIT = 'credit';
19
-	const CD_DEBIT = 'debit';
20
-	const CD_CREDIT_CANCELLATION = 'credit_cancellation';
21
-	const CD_DEBIT_CANCELLATION = 'debit_cancellation';
22
-
23
-	// The divider can be either \r\n or @@
24
-	const LINE_DIVIDER = "(@@|\r\n)";
25
-
26
-	/** @var string */
27
-	protected $rawData;
28
-	/** @var string */
29
-	protected $soaDate;
30
-
31
-	/**
32
-	 * MT940 constructor.
33
-	 *
34
-	 * @param string $rawData
35
-	 */
36
-	public function __construct($rawData)
37
-	{
38
-		$this->rawData = (string) $rawData;
39
-	}
40
-
41
-	/**
42
-	 * @param string $target
43
-	 * @return array
44
-	 * @throws MT940Exception
45
-	 */
46
-	public function parse($target)
47
-	{
48
-		switch ($target) {
49
-		case static::TARGET_ARRAY:
50
-			return $this->parseToArray();
51
-			break;
52
-		default:
53
-			throw new MT940Exception('Invalid parse type provided');
54
-		}
55
-	}
56
-
57
-	/**
58
-	 * @return array
59
-	 * @throws MT940Exception
60
-	 */
61
-	protected function parseToArray()
62
-	{
16
+    const TARGET_ARRAY = 0;
17
+
18
+    const CD_CREDIT = 'credit';
19
+    const CD_DEBIT = 'debit';
20
+    const CD_CREDIT_CANCELLATION = 'credit_cancellation';
21
+    const CD_DEBIT_CANCELLATION = 'debit_cancellation';
22
+
23
+    // The divider can be either \r\n or @@
24
+    const LINE_DIVIDER = "(@@|\r\n)";
25
+
26
+    /** @var string */
27
+    protected $rawData;
28
+    /** @var string */
29
+    protected $soaDate;
30
+
31
+    /**
32
+     * MT940 constructor.
33
+     *
34
+     * @param string $rawData
35
+     */
36
+    public function __construct($rawData)
37
+    {
38
+        $this->rawData = (string) $rawData;
39
+    }
40
+
41
+    /**
42
+     * @param string $target
43
+     * @return array
44
+     * @throws MT940Exception
45
+     */
46
+    public function parse($target)
47
+    {
48
+        switch ($target) {
49
+        case static::TARGET_ARRAY:
50
+            return $this->parseToArray();
51
+            break;
52
+        default:
53
+            throw new MT940Exception('Invalid parse type provided');
54
+        }
55
+    }
56
+
57
+    /**
58
+     * @return array
59
+     * @throws MT940Exception
60
+     */
61
+    protected function parseToArray()
62
+    {
63 63
 		
64
-		$result = array();
65
-
66
-		// split at every :20: ("Die Felder ":20:" bis ":28:" müssen vor jedem Zwischensaldo ausgegeben werden.")
67
-		$statementBlocks = preg_split('/' . self::LINE_DIVIDER . ':20:.*?' . self::LINE_DIVIDER . '/', $this->rawData);
68
-
69
-		foreach ($statementBlocks as $statementBlock) {
70
-			$parts = preg_split('/' . self::LINE_DIVIDER . ':/', $statementBlock);
71
-			$statement = array();
72
-			$transactions = array();
73
-			$cnt = 0;
74
-			for ($i = 0, $cnt = count($parts); $i < $cnt; $i++) {
75
-				// handle start balance
76
-				// 60F:C160401EUR1234,56
77
-				if (preg_match('/^60[FM]:/', $parts[$i])) {
78
-					$parts[$i] = substr($parts[$i], 4);
79
-					$this->soaDate = $this->getDate(substr($parts[$i], 1, 6));
80
-
81
-					$amount = str_replace(',', '.', substr($parts[$i], 10));
82
-					$statement['start_balance'] = array(
83
-									'amount' => $amount,
84
-									'credit_debit' => (substr($parts[$i], 0, 1) == 'C') ? static::CD_CREDIT : static::CD_DEBIT
85
-							);
86
-					$statement['date'] = $this->soaDate;
87
-				} elseif (
88
-							// found transaction
89
-							// trx:61:1603310331DR637,39N033NONREF
90
-							0 === strpos($parts[$i], '61:')
91
-							&& isset($parts[$i + 1])
92
-							&& 0 === strpos($parts[$i + 1], '86:')
93
-					) {
94
-					$transaction = substr($parts[$i], 3);
95
-					$description = substr($parts[$i + 1], 3);
96
-
97
-					$currentTrx = array();
98
-
99
-					preg_match('/^\d{6}(\d{4})?(C|D|RC|RD)[A-Z]?([^N]+)N/', $transaction, $matches);
100
-
101
-					switch ($matches[2]) {
102
-							case 'C':
103
-									$currentTrx['credit_debit'] = static::CD_CREDIT;
104
-									break;
105
-							case 'D':
106
-									$currentTrx['credit_debit'] = static::CD_DEBIT;
107
-									break;
108
-							case 'RC':
109
-									$currentTrx['credit_debit'] = static::CD_CREDIT_CANCELLATION;
110
-									break;
111
-							case 'RD':
112
-									$currentTrx['credit_debit'] = static::CD_DEBIT_CANCELLATION;
113
-									break;
114
-							default:
115
-									throw new MT940Exception('c/d/rc/rd mark not found in: ' . $transaction);
116
-							}
117
-
118
-					$amount = $matches[3];
119
-					$amount = str_replace(',', '.', $amount);
120
-					$currentTrx['amount'] = floatval($amount);
121
-
122
-					$currentTrx['transaction_code'] = substr($description, 0, 3);
123
-
124
-					$description = $this->parseDescription($description);
125
-					$currentTrx['description'] = $description;
126
-
127
-					// :61:1605110509D198,02NMSCNONREF
128
-					// 16 = year
129
-					// 0511 = valuta date
130
-					// 0509 = booking date
131
-					$year = substr($transaction, 0, 2);
132
-					$valutaDate = $this->getDate($year . substr($transaction, 2, 4));
133
-
134
-					$bookingDate = substr($transaction, 6, 4);
135
-					if (preg_match('/^\d{4}$/', $bookingDate)) {
136
-						// if valuta date is earlier than booking date, then it must be in the new year.
137
-						if (substr($transaction, 2, 2) == '12' && substr($transaction, 6, 2) == '01') {
138
-							$year++;
139
-						} elseif (substr($transaction, 2, 2) == '01' && substr($transaction, 6, 2) == '12') {
140
-							$year--;
141
-						}
142
-						$bookingDate = $this->getDate($year . $bookingDate);
143
-					} else {
144
-						// if booking date not set in :61, then we have to take it from :60F
145
-						$bookingDate = $this->soaDate;
146
-					}
147
-
148
-					$currentTrx['booking_date'] = $bookingDate;
149
-					$currentTrx['valuta_date'] = $valutaDate;
150
-
151
-					$transactions[] = $currentTrx;
152
-				}
153
-			}
154
-			$statement['transactions'] = $transactions;
155
-			if (count($transactions) > 0) {
156
-				$result[] = $statement;
157
-			}
158
-		}
159
-
160
-		return $result;
161
-	}
162
-
163
-	/**
164
-	 * @param string $descr
165
-	 * @return array
166
-	 */
167
-	protected function parseDescription($descr)
168
-	{
169
-		$prepared = array();
170
-		$result = array();
171
-
172
-		// prefill with empty values
173
-		for ($i = 0; $i <= 63; $i++) {
174
-			$prepared[$i] = null;
175
-		}
176
-
177
-		$descr = preg_replace('/' . self::LINE_DIVIDER . '/', '', $descr);
178
-		$descr = preg_replace('/  +/', ' ', $descr);
179
-		$descr = str_replace('? ', '?', $descr);
180
-		preg_match_all('/\?[ \r\n]*(\d{2})([^\?]+)/', $descr, $matches, PREG_SET_ORDER);
181
-
182
-		$descriptionLines = array();
183
-		$description1 = ''; // Legacy, could be removed.
184
-		$description2 = ''; // Legacy, could be removed.
185
-		foreach ($matches as $m) {
186
-			$index = (int) $m[1];
187
-			if ((20 <= $index && $index <= 29) || (60 <= $index && $index <= 63)) {
188
-				if (20 <= $index && $index <= 29) {
189
-					$description1 .= $m[2];
190
-				} else {
191
-					$description2 .= $m[2];
192
-				}
193
-				$m[2] = trim($m[2]);
194
-				if (!empty($m[2])) {
195
-					$descriptionLines[] = $m[2];
196
-				}
197
-			} else {
198
-				$prepared[$index] = $m[2];
199
-			}
200
-		}
201
-
202
-		$description = array();
203
-		if (empty($descriptionLines) || strlen($descriptionLines[0]) < 5 || $descriptionLines[0][4] !== '+') {
204
-			$description['SVWZ'] = implode('', $descriptionLines);
205
-		} else {
206
-			$lastType = null;
207
-			foreach ($descriptionLines as $line) {
208
-				if (strlen($line) > 5 && $line[4] === '+') {
209
-					if ($lastType != null) {
210
-						$description[$lastType] = trim($description[$lastType]);
211
-					}
212
-					$lastType = substr($line, 0, 4);
213
-					$description[$lastType] = substr($line, 5);
214
-				} else {
215
-					$description[$lastType] .= $line;
216
-				}
217
-				if (strlen($line) < 27) {
218
-					// Usually, lines are 27 characters long. In case characters are missing, then it's either the end
219
-					// of the current type or spaces have been trimmed from the end. We want to collapse multiple spaces
220
-					// into one and we don't want to leave trailing spaces behind. So add a single space here to make up
221
-					// for possibly missing spaces, and if it's the end of the type, it will be trimmed off later.
222
-					$description[$lastType] .= ' ';
223
-				}
224
-			}
225
-			$description[$lastType] = trim($description[$lastType]);
226
-		}
227
-
228
-		$result['description']       = $description;
229
-		$result['booking_text']      = trim($prepared[0]);
230
-		$result['primanoten_nr']     = trim($prepared[10]);
231
-		$result['description_1']     = trim($description1);
232
-		$result['bank_code']         = trim($prepared[30]);
233
-		$result['account_number']    = trim($prepared[31]);
234
-		$result['name']              = trim($prepared[32] . $prepared[33]);
235
-		$result['text_key_addition'] = trim($prepared[34]);
236
-		$result['description_2']     = trim($description2);
237
-		return $result;
238
-	}
239
-
240
-	/**
241
-	 * @param string $val
242
-	 * @return string
243
-	 */
244
-	protected function getDate($val)
245
-	{
246
-		$val = '20' . $val;
247
-		preg_match('/(\d{4})(\d{2})(\d{2})/', $val, $m);
248
-		return $m[1] . '-' . $m[2] . '-' . $m[3];
249
-	}
64
+        $result = array();
65
+
66
+        // split at every :20: ("Die Felder ":20:" bis ":28:" müssen vor jedem Zwischensaldo ausgegeben werden.")
67
+        $statementBlocks = preg_split('/' . self::LINE_DIVIDER . ':20:.*?' . self::LINE_DIVIDER . '/', $this->rawData);
68
+
69
+        foreach ($statementBlocks as $statementBlock) {
70
+            $parts = preg_split('/' . self::LINE_DIVIDER . ':/', $statementBlock);
71
+            $statement = array();
72
+            $transactions = array();
73
+            $cnt = 0;
74
+            for ($i = 0, $cnt = count($parts); $i < $cnt; $i++) {
75
+                // handle start balance
76
+                // 60F:C160401EUR1234,56
77
+                if (preg_match('/^60[FM]:/', $parts[$i])) {
78
+                    $parts[$i] = substr($parts[$i], 4);
79
+                    $this->soaDate = $this->getDate(substr($parts[$i], 1, 6));
80
+
81
+                    $amount = str_replace(',', '.', substr($parts[$i], 10));
82
+                    $statement['start_balance'] = array(
83
+                                    'amount' => $amount,
84
+                                    'credit_debit' => (substr($parts[$i], 0, 1) == 'C') ? static::CD_CREDIT : static::CD_DEBIT
85
+                            );
86
+                    $statement['date'] = $this->soaDate;
87
+                } elseif (
88
+                            // found transaction
89
+                            // trx:61:1603310331DR637,39N033NONREF
90
+                            0 === strpos($parts[$i], '61:')
91
+                            && isset($parts[$i + 1])
92
+                            && 0 === strpos($parts[$i + 1], '86:')
93
+                    ) {
94
+                    $transaction = substr($parts[$i], 3);
95
+                    $description = substr($parts[$i + 1], 3);
96
+
97
+                    $currentTrx = array();
98
+
99
+                    preg_match('/^\d{6}(\d{4})?(C|D|RC|RD)[A-Z]?([^N]+)N/', $transaction, $matches);
100
+
101
+                    switch ($matches[2]) {
102
+                            case 'C':
103
+                                    $currentTrx['credit_debit'] = static::CD_CREDIT;
104
+                                    break;
105
+                            case 'D':
106
+                                    $currentTrx['credit_debit'] = static::CD_DEBIT;
107
+                                    break;
108
+                            case 'RC':
109
+                                    $currentTrx['credit_debit'] = static::CD_CREDIT_CANCELLATION;
110
+                                    break;
111
+                            case 'RD':
112
+                                    $currentTrx['credit_debit'] = static::CD_DEBIT_CANCELLATION;
113
+                                    break;
114
+                            default:
115
+                                    throw new MT940Exception('c/d/rc/rd mark not found in: ' . $transaction);
116
+                            }
117
+
118
+                    $amount = $matches[3];
119
+                    $amount = str_replace(',', '.', $amount);
120
+                    $currentTrx['amount'] = floatval($amount);
121
+
122
+                    $currentTrx['transaction_code'] = substr($description, 0, 3);
123
+
124
+                    $description = $this->parseDescription($description);
125
+                    $currentTrx['description'] = $description;
126
+
127
+                    // :61:1605110509D198,02NMSCNONREF
128
+                    // 16 = year
129
+                    // 0511 = valuta date
130
+                    // 0509 = booking date
131
+                    $year = substr($transaction, 0, 2);
132
+                    $valutaDate = $this->getDate($year . substr($transaction, 2, 4));
133
+
134
+                    $bookingDate = substr($transaction, 6, 4);
135
+                    if (preg_match('/^\d{4}$/', $bookingDate)) {
136
+                        // if valuta date is earlier than booking date, then it must be in the new year.
137
+                        if (substr($transaction, 2, 2) == '12' && substr($transaction, 6, 2) == '01') {
138
+                            $year++;
139
+                        } elseif (substr($transaction, 2, 2) == '01' && substr($transaction, 6, 2) == '12') {
140
+                            $year--;
141
+                        }
142
+                        $bookingDate = $this->getDate($year . $bookingDate);
143
+                    } else {
144
+                        // if booking date not set in :61, then we have to take it from :60F
145
+                        $bookingDate = $this->soaDate;
146
+                    }
147
+
148
+                    $currentTrx['booking_date'] = $bookingDate;
149
+                    $currentTrx['valuta_date'] = $valutaDate;
150
+
151
+                    $transactions[] = $currentTrx;
152
+                }
153
+            }
154
+            $statement['transactions'] = $transactions;
155
+            if (count($transactions) > 0) {
156
+                $result[] = $statement;
157
+            }
158
+        }
159
+
160
+        return $result;
161
+    }
162
+
163
+    /**
164
+     * @param string $descr
165
+     * @return array
166
+     */
167
+    protected function parseDescription($descr)
168
+    {
169
+        $prepared = array();
170
+        $result = array();
171
+
172
+        // prefill with empty values
173
+        for ($i = 0; $i <= 63; $i++) {
174
+            $prepared[$i] = null;
175
+        }
176
+
177
+        $descr = preg_replace('/' . self::LINE_DIVIDER . '/', '', $descr);
178
+        $descr = preg_replace('/  +/', ' ', $descr);
179
+        $descr = str_replace('? ', '?', $descr);
180
+        preg_match_all('/\?[ \r\n]*(\d{2})([^\?]+)/', $descr, $matches, PREG_SET_ORDER);
181
+
182
+        $descriptionLines = array();
183
+        $description1 = ''; // Legacy, could be removed.
184
+        $description2 = ''; // Legacy, could be removed.
185
+        foreach ($matches as $m) {
186
+            $index = (int) $m[1];
187
+            if ((20 <= $index && $index <= 29) || (60 <= $index && $index <= 63)) {
188
+                if (20 <= $index && $index <= 29) {
189
+                    $description1 .= $m[2];
190
+                } else {
191
+                    $description2 .= $m[2];
192
+                }
193
+                $m[2] = trim($m[2]);
194
+                if (!empty($m[2])) {
195
+                    $descriptionLines[] = $m[2];
196
+                }
197
+            } else {
198
+                $prepared[$index] = $m[2];
199
+            }
200
+        }
201
+
202
+        $description = array();
203
+        if (empty($descriptionLines) || strlen($descriptionLines[0]) < 5 || $descriptionLines[0][4] !== '+') {
204
+            $description['SVWZ'] = implode('', $descriptionLines);
205
+        } else {
206
+            $lastType = null;
207
+            foreach ($descriptionLines as $line) {
208
+                if (strlen($line) > 5 && $line[4] === '+') {
209
+                    if ($lastType != null) {
210
+                        $description[$lastType] = trim($description[$lastType]);
211
+                    }
212
+                    $lastType = substr($line, 0, 4);
213
+                    $description[$lastType] = substr($line, 5);
214
+                } else {
215
+                    $description[$lastType] .= $line;
216
+                }
217
+                if (strlen($line) < 27) {
218
+                    // Usually, lines are 27 characters long. In case characters are missing, then it's either the end
219
+                    // of the current type or spaces have been trimmed from the end. We want to collapse multiple spaces
220
+                    // into one and we don't want to leave trailing spaces behind. So add a single space here to make up
221
+                    // for possibly missing spaces, and if it's the end of the type, it will be trimmed off later.
222
+                    $description[$lastType] .= ' ';
223
+                }
224
+            }
225
+            $description[$lastType] = trim($description[$lastType]);
226
+        }
227
+
228
+        $result['description']       = $description;
229
+        $result['booking_text']      = trim($prepared[0]);
230
+        $result['primanoten_nr']     = trim($prepared[10]);
231
+        $result['description_1']     = trim($description1);
232
+        $result['bank_code']         = trim($prepared[30]);
233
+        $result['account_number']    = trim($prepared[31]);
234
+        $result['name']              = trim($prepared[32] . $prepared[33]);
235
+        $result['text_key_addition'] = trim($prepared[34]);
236
+        $result['description_2']     = trim($description2);
237
+        return $result;
238
+    }
239
+
240
+    /**
241
+     * @param string $val
242
+     * @return string
243
+     */
244
+    protected function getDate($val)
245
+    {
246
+        $val = '20' . $val;
247
+        preg_match('/(\d{4})(\d{2})(\d{2})/', $val, $m);
248
+        return $m[1] . '-' . $m[2] . '-' . $m[3];
249
+    }
250 250
 }
Please login to merge, or discard this patch.