Passed
Push — master ( 1b6929...f2763b )
by Stefan
02:06
created

Sepa::getPainVersion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 23
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
namespace SKien\Sepa;
3
4
/**
5
 * Package to create sepa-xml File.
6
 *
7
 * #### Providing
8
 * <ul>
9
 * <li> Credit Transfer Initiation (CCT; pain.001.002.03.xsd) </li>
10
 * <li> Direct Debit Initiation (CDD; pain.008.002.02.xsd) </li>
11
 * </ul>
12
 *
13
 * #### Main class of the package
14
 * This class containins some global constants, support for country specific
15
 * validation of IBAN / BIC / CI and language support for the generated
16
 * error messages.
17
 *
18
 * @package Sepa
19
 * @author Stefanius <[email protected]>
20
 * @copyright MIT License - see the LICENSE file for details
21
 */
22
class Sepa
23
{
24
    use SepaHelper;
25
26
    /** Version 2.6 (2012: pain.001.002.03 / pain.008.002.02)*/
27
    const V26 = "2.6";
28
    /** Version 2.9 (2015: pain.001.003.03 / pain.008.003.02)*/
29
    const V29 = "2.9";
30
    /** Version 3.0 (2016: pain.001.001.03 / pain.008.001.02)*/
31
    const V30 = "3.0";
32
33
    /** Credit Transfer Transaction  */
34
    const CCT = "TRF";
35
    /** Direct Debit Transaction     */
36
    const CDD = "DD";
37
38
    /** ID1 validation
39
     * @see SepaHelper::validString()   */
40
    const ID1     = 1;
41
    /** ID2 validation
42
     * @see SepaHelper::validString()   */
43
    const ID2     = 2;
44
    /** MAX35 validation
45
     * @see SepaHelper::validString()   */
46
    const MAX35   = 3;
47
    /** MAX70 validation
48
     * @see SepaHelper::validString()   */
49
    const MAX70   = 4;
50
    /** MAX140 validation
51
     * @see SepaHelper::validString()   */
52
    const MAX140  = 5;
53
    /** MAX1025 validation
54
     * @see SepaHelper::validString()   */
55
    const MAX1025 = 6;
56
57
    /** sequence type first dd sequence     */
58
    const SEQ_FIRST     = "FRST";
59
    /** sequence type recurrent dd sequence */
60
    const SEQ_RECURRENT = "RCUR";
61
    /** sequence type one-off dd sequence   */
62
    const SEQ_ONE_OFF   = "OOFF";
63
    /** sequence type final dd sequence */
64
    const SEQ_FINAL     = "FNAL";
65
66
    /** full validation  */
67
    const V_FULL_VALIDATION         = 0;
68
    /** no validation at all   */
69
    const V_NO_VALIDATION           = 0x001F;
70
    /** no validation of IBAN   */
71
    const V_NO_IBAN_VALIDATION      = 0x0001;
72
    /** no validation of the BIC   */
73
    const V_NO_BIC_VALIDATION       = 0x0002;
74
    /** no validation of the CI   */
75
    const V_NO_CI_VALIDATION        = 0x0004;
76
    /** no validation if no class set for country  */
77
    const V_IGNORE_MISSING_CNTRY    = 0x0008;
78
    /** ignore missing mandatory value   */
79
    const V_IGNORE_MISSING_VALUE    = 0x0010;
80
81
    /** validation succeeded    */
82
    const OK                        = 0;
83
    // error codes for IBAN validation
84
    /** invalid country code   */
85
    const ERR_IBAN_INVALID_CNTRY    = 1;
86
    /** invalid length  */
87
    const ERR_IBAN_INVALID_LENGTH   = 2;
88
    /** iban contains invalid sign(s)   */
89
    const ERR_IBAN_INVALID_SIGN     = 3;
90
    /** wrong checksum  */
91
    const ERR_IBAN_CHECKSUM         = 4;
92
93
    // error codes for BIC validation
94
    /** invalid BIC */
95
    const ERR_BIC_INVALID           = 10;
96
    /** invalid country code   */
97
    const ERR_BIC_INVALID_CNTRY     = 11;
98
99
    // error codes for CI validation
100
    /** invalid country code  */
101
    const ERR_CI_INVALID_CNTRY      = 20;
102
    /** invalid length  */
103
    const ERR_CI_INVALID_LENGTH     = 21;
104
    /** iban contains invalid sign(s)   */
105
    const ERR_CI_INVALID_SIGN       = 22;
106
    /** wrong checksum  */
107
    const ERR_CI_CHECKSUM           = 23;
108
109
    // error codes for payment info validation
110
    const ERR_PMT_NAME_MISSING      = 0x0001;
111
    const ERR_PMT_IBAN_MISSING      = 0x0002;
112
    const ERR_PMT_BIC_MISSING       = 0x0004;
113
    const ERR_PMT_CI_MISSING        = 0x0008;
114
    const ERR_PMT_INVALID_IBAN      = 0x0010;
115
    const ERR_PMT_INVALID_BIC       = 0x0020;
116
    const ERR_PMT_INVALID_CI        = 0x0040;
117
    const ERR_PMT_SEQ_TYPE_MISSING  = 0x0080;
118
    const ERR_PMT_INVALID_SEQ_TYPE  = 0x0100;
119
    const ERR_PMT_MAX               = 0x0100;
120
121
    // error codes for transaction validation
122
    const ERR_TX_NAME_MISSING       = 0x0001;
123
    const ERR_TX_IBAN_MISSING       = 0x0002;
124
    const ERR_TX_BIC_MISSING        = 0x0004;
125
    const ERR_TX_INVALID_IBAN       = 0x0010;
126
    const ERR_TX_INVALID_BIC        = 0x0020;
127
    const ERR_TX_MAND_ID_MISSING    = 0x0200;
128
    const ERR_TX_MAND_DOS_MISSING   = 0x0400;
129
    const ERR_TX_DESCR_MISSING      = 0x0800;
130
    const ERR_TX_ZERO_VALUE         = 0x1000;
131
    const ERR_TX_INVALID_TYPE       = 0x2000;
132
    const ERR_TX_INVALID_MAND_DOS   = 0x4000;
133
    const ERR_TX_MAX                = 0x4000;
134
135
    /** @var array<string>  validation classes for different countries     */
136
    static protected array $aValidation = array();
137
    /** @var int set the validation level. Any combination of the self::V_... flags (default: V_FULL)    */
138
    static protected int $wValidation = 0;
139
140
    /** @var array<string> error messages for IBAN validation   */
141
    static protected array $aIBANError = array();
142
    /** @var array<string> error messages for BIC validation   */
143
    static protected array $aBICError = array();
144
    /** @var array<string> error messages for CI validation   */
145
    static protected array $aCIError = array();
146
    /** @var array<string> error messages for payment info validation   */
147
    static protected array $aPmtInfError = array();
148
    /** @var array<string> error messages for transaction info validation   */
149
    static protected array $aTxInfError = array();
150
151
    /**
152
     * Get the pain version for requested SEPA version and -type.
153
     * The pain version is needed to bind the SEPA XML document to the correct namespace and XSD schema.
154
     * @param string $strType
155
     * @param string $strSepaVersion
156
     * @return string
157
     */
158
    public static function getPainVersion(string $strType, string $strSepaVersion = Sepa::V30) : string
159
    {
160
        $aPainVersion = [
161
            self::V26 => [
162
                self::CCT => 'pain.001.002.03',
163
                self::CDD => 'pain.008.002.02',
164
                'year' => 2012,
165
            ],
166
            self::V29 => [
167
                self::CCT => 'pain.001.003.03',
168
                self::CDD => 'pain.008.003.02',
169
                'year' => 2015,
170
            ],
171
            self::V30 => [
172
                self::CCT => 'pain.001.001.03',
173
                self::CDD => 'pain.008.001.02',
174
                'year' => 2016,
175
            ],
176
        ];
177
        if (!isset($aPainVersion[$strSepaVersion])) {
178
            trigger_error('Not supported SEPA Version: ' . $strSepaVersion . ' (Supported versions: ' . implode(', ', array_keys($aPainVersion)) . ')!', E_USER_ERROR);
179
        }
180
        return $aPainVersion[$strSepaVersion][$strType];
181
    }
182
183
    /**
184
     * Initializition of the package.
185
     * This static method must be called before using the package. <br/>
186
     * All available country validations are added and the errormessages are
187
     * initialized in english language.
188
     */
189
    public static function init() : void
190
    {
191
        if (count(self::$aValidation) > 0) {
192
            return;
193
        }
194
        self::addValidation('DE', 'SKien\Sepa\CntryValidation\SepaCntryValidationDE');
195
        self::addValidation('CH', 'SKien\Sepa\CntryValidation\SepaCntryValidationCH');
196
        self::addValidation('FR', 'SKien\Sepa\CntryValidation\SepaCntryValidationFR');
197
        self::addValidation('AT', 'SKien\Sepa\CntryValidation\SepaCntryValidationAT');
198
        self::addValidation('LU', 'SKien\Sepa\CntryValidation\SepaCntryValidationLU');
199
        self::addValidation('BE', 'SKien\Sepa\CntryValidation\SepaCntryValidationBE');
200
        self::addValidation('GB', 'SKien\Sepa\CntryValidation\SepaCntryValidationGB');
201
        self::addValidation('EE', 'SKien\Sepa\CntryValidation\SepaCntryValidationEE');
202
        self::addValidation('IT', 'SKien\Sepa\CntryValidation\SepaCntryValidationIT');
203
204
        self::$aIBANError = array(
205
            Sepa::ERR_IBAN_INVALID_CNTRY   => 'The country code of the IBAN is not supported!',
206
            Sepa::ERR_IBAN_INVALID_LENGTH  => 'Invalid length of the IBAN!',
207
            Sepa::ERR_IBAN_INVALID_SIGN    => 'The IBAN contains invalid characters!',
208
            Sepa::ERR_IBAN_CHECKSUM        => 'Invalid IBAN checksum!',
209
        );
210
211
        self::$aBICError = array(
212
            Sepa::ERR_BIC_INVALID          => 'Invalid BIC!',
213
            Sepa::ERR_BIC_INVALID_CNTRY    => 'The country code of the BIC is not supported!',
214
        );
215
216
        self::$aCIError = array(
217
            Sepa::ERR_CI_INVALID_CNTRY     => 'The country code of the CI is not supported!',
218
            Sepa::ERR_CI_INVALID_LENGTH    => 'Invalid length of the CI!',
219
            Sepa::ERR_CI_INVALID_SIGN      => 'The CI contains invalid characters!',
220
            Sepa::ERR_CI_CHECKSUM          => 'Invalid CI checksum!',
221
        );
222
223
        self::$aPmtInfError = array(
224
            Sepa::ERR_PMT_NAME_MISSING      => 'Name missing',
225
            Sepa::ERR_PMT_IBAN_MISSING      => 'IBAN missing',
226
            Sepa::ERR_PMT_BIC_MISSING       => 'BIC missing',
227
            Sepa::ERR_PMT_CI_MISSING        => 'CI missing',
228
            Sepa::ERR_PMT_INVALID_IBAN      => 'Invalid IBAN',
229
            Sepa::ERR_PMT_INVALID_BIC       => 'Invalid BIC',
230
            Sepa::ERR_PMT_INVALID_CI        => 'Invalid CI',
231
            Sepa::ERR_PMT_SEQ_TYPE_MISSING  => 'Sequence type missing',
232
            Sepa::ERR_PMT_INVALID_SEQ_TYPE  => 'Invalid sequence type',
233
        );
234
235
        self::$aTxInfError = array(
236
            Sepa::ERR_TX_NAME_MISSING       => 'Name missing',
237
            Sepa::ERR_TX_IBAN_MISSING       => 'IBAN missing',
238
            Sepa::ERR_TX_BIC_MISSING        => 'BIC missing',
239
            Sepa::ERR_TX_INVALID_IBAN       => 'Invalid IBAN',
240
            Sepa::ERR_TX_INVALID_BIC        => 'Invalid BIC',
241
            Sepa::ERR_TX_MAND_ID_MISSING    => 'SEPA mandate missing',
242
            Sepa::ERR_TX_MAND_DOS_MISSING   => 'Invalid date of the SEPA mandate',
243
            Sepa::ERR_TX_DESCR_MISSING      => 'Usage text missing',
244
            Sepa::ERR_TX_ZERO_VALUE         => 'The value is 0.0 EUR',
245
            Sepa::ERR_TX_INVALID_TYPE       => 'Invalid transaction type',
246
            Sepa::ERR_TX_INVALID_MAND_DOS   => 'Invalid date value',
247
        );
248
    }
249
250
    /**
251
     * Destroing the static arrays.
252
     * This method mainly is provided for use in the PHPUnit TestCases to reset the static object!
253
     * @internal
254
     */
255
    public static function reset() : void
256
    {
257
        self::$aValidation = array();
258
        self::$wValidation = 0;
259
        self::$aIBANError = array();
260
        self::$aBICError = array();
261
        self::$aCIError = array();
262
        self::$aPmtInfError = array();
263
        self::$aTxInfError = array();
264
    }
265
266
    /**
267
     * Add validation to the package.
268
     * The PHP class `$strValidationClass` must implement the `SepaCntryValidation` interface.
269
     * @param string $strCntry  the 2 digit country code
270
     * @param string $strValidationClass    name of the PHP class for validation
271
     */
272
    public static function addValidation(string $strCntry, string $strValidationClass) : void
273
    {
274
        if (isset(self::$aValidation[$strCntry])) {
275
            trigger_error('validation for cntry ' . $strCntry . ' already defined!', E_USER_ERROR);
276
        }
277
        if (!is_subclass_of($strValidationClass, 'SKien\Sepa\CntryValidation\SepaCntryValidation', true)) {
278
            trigger_error('class ' . $strValidationClass . ' must implement SepaCntryValidation interface!', E_USER_ERROR);
279
        }
280
        self::$aValidation[$strCntry] = $strValidationClass;
281
    }
282
283
    /**
284
     * Set the validation level.
285
     * This method can be used to disable some or complete validation. <br/>
286
     * > It is recommended to deactivate the validations only for test purposes or if you can
287
     * guarantee the validity of all values based on previous checks. <br/>
288
     * A partial deactivation with `Sepa::V_IGNORE_MISSING_CNTRY` may be useful if you sometimes
289
     * have to process data from a country for which there is (still) no validation in the package.
290
     *
291
     * Supported is any combination of:
292
     *
293
     * | Flag                           | Description                               |
294
     * |--------------------------------|-------------------------------------------|
295
     * | `Sepa::V_NO_VALIDATION`        | no validation at all (not recommended!)   |
296
     * | `Sepa::V_NO_IBAN_VALIDATION`   | no validation of IBAN                     |
297
     * | `Sepa::V_NO_BIC_VALIDATION`    | no validation of the BIC                  |
298
     * | `Sepa::V_NO_CI_VALIDATION`     | no validation of the CI                   |
299
     * | `Sepa::V_IGNORE_MISSING_CNTRY` | no validation if no class set for country |
300
     * | `Sepa::V_IGNORE_MISSING_VALUE` | no error on missing mandatory value       |
301
     *
302
     * Default value is full validation:  `Sepa::V_FULL_VALIDATION`
303
     * @param int $wValidation  see the description
304
     */
305
    public static function setValidationLevel(int $wValidation) : void
306
    {
307
        self::$wValidation = $wValidation;
308
    }
309
310
    /**
311
     * Check, if validation level is set.
312
     * @param int $wValidation
313
     * @return bool
314
     * @internal
315
     */
316
    public static function checkValidation(int $wValidation) : bool
317
    {
318
        return (self::$wValidation & $wValidation) != 0;
319
    }
320
321
    /**
322
     * Load error messages from JSON file.
323
     * For different language support, all messages can be loaded from a JSON file.
324
     * > Use the `sepa_errormsg_en.json` or `sepa_errormsg_de.json` contained in the
325
     * package as a starting point for your own translation .
326
     * @param string $strFilename   relative or absolute JSON file
327
     */
328
    public static function loadErrorMsg(string $strFilename = 'sepa_error.json') : void
329
    {
330
        /*
331
        // ... testcode to create sample json file
332
        $aError = array( 'aIBAN' => self::$aIBANError, 'aCI' => self::$aCIError, 'aPmtInf' => self::$aPmtInfError, 'aTxInf' => self::$aTxInfError );
333
        $strJSON = json_encode($aError, JSON_PRETTY_PRINT);
334
        file_put_contents($strFilename, $strJSON);
335
        chmod($strFilename, 0666);
336
        */
337
        if (file_exists($strFilename)) {
338
            $strJson = file_get_contents($strFilename);
339
            $jsonData = json_decode((string)$strJson, true);
340
            if ($jsonData) {
341
                if (isset($jsonData['aIBAN'])) {
342
                    self::$aIBANError = $jsonData['aIBAN'];
343
                }
344
                if (isset($jsonData['aCI'])) {
345
                    self::$aCIError = $jsonData['aCI'];
346
                }
347
                if (isset($jsonData['aPmtInf'])) {
348
                    self::$aPmtInfError = $jsonData['aPmtInf'];
349
                }
350
                if (isset($jsonData['aTxInf'])) {
351
                    self::$aTxInfError = $jsonData['aTxInf'];
352
                }
353
            } else {
354
                trigger_error('invalid error message file: ' . $strFilename, E_USER_ERROR);
355
            }
356
        } else {
357
            trigger_error('error message file ' . $strFilename . ' not exist!', E_USER_ERROR);
358
        }
359
    }
360
361
    /**
362
     * Validates given IBAN.
363
     * If the passed value contains any leading/trailing or formating spaces, they all
364
     * will be removed.
365
     * @param string $strIBAN   IBAN to validate
366
     * @return int Sepa::OK or errorcode
367
     */
368
    public static function validateIBAN(string &$strIBAN) : int
369
    {
370
        $strIBAN = str_replace(' ', '', trim(strtoupper($strIBAN)));
371
        if ((self::$wValidation & self::V_NO_IBAN_VALIDATION) != 0) {
372
            return self::OK;
373
        }
374
375
        if (count(self::$aValidation) == 0) {
376
            trigger_error('no country validation specified! (possibly forgotten to call Sepa::init()?)', E_USER_ERROR);
377
        }
378
        $strCntry = substr($strIBAN, 0, 2);
379
        if (!isset(self::$aValidation[$strCntry])) {
380
            if ((self::$wValidation & self::V_IGNORE_MISSING_CNTRY) != 0) {
381
                return Sepa::OK;
382
            } else {
383
                return Sepa::ERR_IBAN_INVALID_CNTRY;
384
            }
385
        }
386
        $strClass = self::$aValidation[$strCntry];
387
        $oValidate = new $strClass($strCntry);
388
389
        return $oValidate->validateIBAN($strIBAN);
390
    }
391
392
    /**
393
     * validates given BIC.
394
     * If the passed value contains any leading/trailing or formating spaces, they all
395
     * will be removed.
396
     * @param string $strBIC    BIC to validate
397
     * @return int Sepa::OK or errorcode
398
     */
399
    public static function validateBIC(string &$strBIC) : int
400
    {
401
        $strBIC = str_replace(' ', '', trim(strtoupper($strBIC)));
402
        if ((self::$wValidation & self::V_NO_BIC_VALIDATION) != 0) {
403
            return self::OK;
404
        }
405
406
        if (count(self::$aValidation) == 0) {
407
            trigger_error('no country validation specified! (possibly forgotten to call Sepa::init()?)', E_USER_ERROR);
408
        }
409
        $strCntry = substr($strBIC, 4, 2);
410
        if (!isset(self::$aValidation[$strCntry])) {
411
            if ((self::$wValidation & self::V_IGNORE_MISSING_CNTRY) != 0) {
412
                return Sepa::OK;
413
            } else {
414
                return Sepa::ERR_BIC_INVALID_CNTRY;
415
            }
416
        }
417
        $strClass = self::$aValidation[$strCntry];
418
        $oValidate = new $strClass($strCntry);
419
420
        return $oValidate->validateBIC($strBIC);
421
    }
422
423
    /**
424
     * validates given CI (Creditor Scheme Identification).
425
     * If the passed value contains any leading/trailing or formating spaces, they all
426
     * will be removed.
427
     * @param string $strCI     CI to validate
428
     * @return int Sepa::OK or errorcode
429
     */
430
    public static function validateCI(string &$strCI) : int
431
    {
432
        $strCI = str_replace(' ', '', trim(strtoupper($strCI)));
433
        if ((self::$wValidation & self::V_NO_CI_VALIDATION) != 0) {
434
            return self::OK;
435
        }
436
437
        if (count(self::$aValidation) == 0) {
438
            trigger_error('no country validation specified! (possibly forgotten to call Sepa::init()?)', E_USER_ERROR);
439
        }
440
        $strCntry = substr($strCI, 0, 2);
441
        if (!isset(self::$aValidation[$strCntry])) {
442
            if ((self::$wValidation & self::V_IGNORE_MISSING_CNTRY) != 0) {
443
                return Sepa::OK;
444
            } else {
445
                return Sepa::ERR_CI_INVALID_CNTRY;
446
            }
447
        }
448
        $strClass = self::$aValidation[$strCntry];
449
        $oValidate = new $strClass($strCntry);
450
451
        return $oValidate->validateCI($strCI);
452
    }
453
454
    /**
455
     * Message to the given errorcode for IBAN / BIC / CI validation errors.
456
     * @param int $iError   the errorcode
457
     * @return string
458
     */
459
    public static function errorMsg(int $iError) : string
460
    {
461
        $aError = array_merge(self::$aIBANError, self::$aBICError, self::$aCIError);
462
        $strMsg = 'unknown Error (' . $iError . ')!';
463
        if (isset($aError[$iError])) {
464
            $strMsg = $aError[$iError];
465
        }
466
        return $strMsg;
467
    }
468
469
    /**
470
     * Message to the given IBAN errorcode.
471
     * @param int $iError   the errorcode
472
     * @return string
473
     * @internal
474
     */
475
    public static function errorMsgIBAN(int $iError) : string
476
    {
477
        $strMsg = 'unknown Error (' . $iError . ')!';
478
        if (isset(self::$aIBANError[$iError])) {
479
            $strMsg = self::$aIBANError[$iError];
480
        }
481
        return $strMsg;
482
    }
483
484
    /**
485
     * Message to the given BIC errorcode.
486
     * @param int $iError   the errorcode
487
     * @return string
488
     * @internal
489
     */
490
    public static function errorMsgBIC(int $iError) : string
491
    {
492
        $strMsg = 'unknown Error (' . $iError . ')!';
493
        if (isset(self::$aBICError[$iError])) {
494
            $strMsg = self::$aBICError[$iError];
495
        }
496
        return $strMsg;
497
    }
498
499
    /**
500
     * Message to the given CI errorcode.
501
     * @param int $iError   the errorcode
502
     * @return string
503
     * @internal
504
     */
505
    public static function errorMsgCI(int $iError) : string
506
    {
507
        $strMsg = 'unknown Error (' . $iError . ')!';
508
        if (isset(self::$aCIError[$iError])) {
509
            $strMsg = self::$aCIError[$iError];
510
        }
511
        return $strMsg;
512
    }
513
514
    /**
515
     * Message to the given payment info errorcode.
516
     * Used by `SepaPmtInf::getError()` to get localized message.
517
     * @param int $iError
518
     * @param string $strLF
519
     * @return string
520
     * @internal
521
     */
522
    public static function errorMsgPmtInf(int $iError, string $strLF = PHP_EOL) : string
523
    {
524
        $strSep = '';
525
        $strMsg = '';
526
        for ($iCheck = 0x0001; $iCheck <= Sepa::ERR_PMT_MAX; $iCheck <<= 1) {
527
            if (($iError & $iCheck) != 0 && isset(self::$aPmtInfError[$iCheck])) {
528
                $strMsg .= $strSep . self::$aPmtInfError[$iCheck];
529
                $strSep = $strLF;
530
            }
531
        }
532
        return $strMsg;
533
    }
534
535
    /**
536
     * Message to the given transaction info errorcode.
537
     * Used by `SepaTxInf::getError()` to get localized message.
538
     * @param int $iError
539
     * @param string $strLF
540
     * @return string
541
     * @internal
542
     */
543
    public static function errorMsgTxInf(int $iError, string $strLF = PHP_EOL) : string
544
    {
545
        $strSep = '';
546
        $strMsg = '';
547
        for ($iCheck = 0x0001; $iCheck <= Sepa::ERR_TX_MAX; $iCheck <<= 1) {
548
            if (($iError & $iCheck) != 0 && isset(self::$aTxInfError[$iCheck])) {
549
                $strMsg .= $strSep . self::$aTxInfError[$iCheck];
550
                $strSep = $strLF;
551
            }
552
        }
553
        return $strMsg;
554
    }
555
}
556
557