From 4db932dac0e9f53ccfed1fa56dca7774fe1eb315 Mon Sep 17 00:00:00 2001 From: Jacques Marneweck Date: Fri, 6 Jan 2017 22:33:23 +0200 Subject: [PATCH 01/11] Handle the issue with FNB's multiple elements on a single line which throws 'RuntimeException: Failed to initialize DateTime for string:' --- lib/OfxParser/Parser.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/OfxParser/Parser.php b/lib/OfxParser/Parser.php index 081c82a..cedbc41 100644 --- a/lib/OfxParser/Parser.php +++ b/lib/OfxParser/Parser.php @@ -63,6 +63,10 @@ private function conditionallyAddNewlines($ofxContent) return str_replace('<', "\n<", $ofxContent); // add line breaks to allow XML to parse } + if (preg_match('/<.+>.*<.+>/', $ofxContent) === 1) { + return str_replace('<', "\n<", $ofxContent); // add line breaks to allow XML to parse + } + return $ofxContent; } From ca3ccee699564db2dfbee17e471d428076eeafdb Mon Sep 17 00:00:00 2001 From: Jacques Marneweck Date: Wed, 21 Jun 2017 23:29:40 +0000 Subject: [PATCH 02/11] Parse the 2.00 format of the OFX file --- lib/OfxParser/Parserv2.php | 126 +++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 lib/OfxParser/Parserv2.php diff --git a/lib/OfxParser/Parserv2.php b/lib/OfxParser/Parserv2.php new file mode 100644 index 0000000..508fb41 --- /dev/null +++ b/lib/OfxParser/Parserv2.php @@ -0,0 +1,126 @@ + + * @author James Titcumb + * @author Oliver Lowe + */ +class Parserv2 +{ + /** + * Load an OFX file into this parser by way of a filename + * + * @param string $ofxFile A path that can be loaded with file_get_contents + * @return Ofx + * @throws \Exception + */ + public function loadFromFile($ofxFile) + { + if (!file_exists($ofxFile)) { + throw new \InvalidArgumentException("File '{$ofxFile}' could not be found"); + } + + return $this->loadFromString(file_get_contents($ofxFile)); + } + + /** + * Load an OFX by directly using the text content + * + * @param string $ofxContent + * @return Ofx + * @throws \Exception + */ + public function loadFromString($ofxContent) + { + $ofxContent = utf8_encode($ofxContent); + $xml = $this->xmlLoadString($ofxContent); + + return new Ofx($xml); + } + + /** + * Detect if the OFX file is on one line. If it is, add newlines automatically. + * + * @param string $ofxContent + * @return string + */ + private function conditionallyAddNewlines($ofxContent) + { + if (preg_match('/.*<\/OFX>/', $ofxContent) === 1) { + return str_replace('<', "\n<", $ofxContent); // add line breaks to allow XML to parse + } + + if (preg_match('/<.+>.*<.+>/', $ofxContent) === 1) { + return str_replace('<', "\n<", $ofxContent); // add line breaks to allow XML to parse + } + + return $ofxContent; + } + + /** + * Load an XML string without PHP errors - throws exception instead + * + * @param string $xmlString + * @throws \Exception + * @return \SimpleXMLElement + */ + private function xmlLoadString($xmlString) + { + libxml_clear_errors(); + libxml_use_internal_errors(true); + $xml = simplexml_load_string($xmlString); + + if ($errors = libxml_get_errors()) { + throw new \RuntimeException('Failed to parse OFX: ' . var_export($errors, true)); + } + + return $xml; + } + + /** + * Detect any unclosed XML tags - if they exist, close them + * + * @param string $line + * @return string + */ + private function closeUnclosedXmlTags($line) + { + // Matches: blah + // Does not match: + // Does not match: blah + if (preg_match( + "/<([A-Za-z0-9.]+)>([\wà-úÀ-Ú0-9\.\-\_\+\, ;:\[\]\'\&\/\\\*\(\)\+\{\|\}\!\£\$\?=@€£#%±§~`]+)$/", + trim($line), + $matches + )) { + return "<{$matches[1]}>{$matches[2]}"; + } + return $line; + } + + /** + * Convert an SGML to an XML string + * + * @param string $sgml + * @return string + */ + private function convertSgmlToXml($sgml) + { + $sgml = str_replace(["\r\n", "\r"], "\n", $sgml); + + $lines = explode("\n", $sgml); + + $xml = ''; + foreach ($lines as $line) { + $xml .= trim($this->closeUnclosedXmlTags($line)) . "\n"; + } + + return trim($xml); + } +} From 7bf1e093548bc35a53a001d38b20518a1133d7a6 Mon Sep 17 00:00:00 2001 From: Marcelo Cerqueira Date: Wed, 29 Mar 2017 16:07:05 -0300 Subject: [PATCH 03/11] fix buildBankAccounts when have two or more STMTRS inside --- lib/OfxParser/Ofx.php | 43 ++- tests/OfxParser/ParserTest.php | 1 + tests/fixtures/ofxdata-bb-two-stmtrs.ofx | 357 +++++++++++++++++++++++ 3 files changed, 387 insertions(+), 14 deletions(-) create mode 100644 tests/fixtures/ofxdata-bb-two-stmtrs.ofx diff --git a/lib/OfxParser/Ofx.php b/lib/OfxParser/Ofx.php index c3d0b6e..ad494ed 100644 --- a/lib/OfxParser/Ofx.php +++ b/lib/OfxParser/Ofx.php @@ -147,32 +147,47 @@ private function buildBankAccounts(SimpleXMLElement $xml) // Loop through the bank accounts $bankAccounts = []; foreach ($xml->BANKMSGSRSV1->STMTTRNRS as $accountStatement) { - $bankAccounts[] = $this->buildBankAccount($accountStatement); + foreach ($accountStatement->STMTRS as $statementResponse) { + $bankAccounts[] = $this->buildBankAccount($accountStatement->TRNUID, $statementResponse); + } } return $bankAccounts; } /** - * @param SimpleXMLElement $xml + * @param string $transactionUid + * @param SimpleXMLElement $statementResponse * @return BankAccount * @throws \Exception */ - private function buildBankAccount(SimpleXMLElement $xml) + private function buildBankAccount($transactionUid, SimpleXMLElement $statementResponse) { $bankAccount = new BankAccount(); - $bankAccount->transactionUid = $xml->TRNUID; - $bankAccount->agencyNumber = $xml->STMTRS->BANKACCTFROM->BRANCHID; - $bankAccount->accountNumber = $xml->STMTRS->BANKACCTFROM->ACCTID; - $bankAccount->routingNumber = $xml->STMTRS->BANKACCTFROM->BANKID; - $bankAccount->accountType = $xml->STMTRS->BANKACCTFROM->ACCTTYPE; - $bankAccount->balance = $xml->STMTRS->LEDGERBAL->BALAMT; - $bankAccount->balanceDate = $this->createDateTimeFromStr($xml->STMTRS->LEDGERBAL->DTASOF, true); + $bankAccount->transactionUid = $transactionUid; + $bankAccount->agencyNumber = $statementResponse->BANKACCTFROM->BRANCHID; + $bankAccount->accountNumber = $statementResponse->BANKACCTFROM->ACCTID; + $bankAccount->routingNumber = $statementResponse->BANKACCTFROM->BANKID; + $bankAccount->accountType = $statementResponse->BANKACCTFROM->ACCTTYPE; + $bankAccount->balance = $statementResponse->LEDGERBAL->BALAMT; + $bankAccount->balanceDate = $this->createDateTimeFromStr( + $statementResponse->LEDGERBAL->DTASOF, + true + ); $bankAccount->statement = new Statement(); - $bankAccount->statement->currency = $xml->STMTRS->CURDEF; - $bankAccount->statement->startDate = $this->createDateTimeFromStr($xml->STMTRS->BANKTRANLIST->DTSTART); - $bankAccount->statement->endDate = $this->createDateTimeFromStr($xml->STMTRS->BANKTRANLIST->DTEND); - $bankAccount->statement->transactions = $this->buildTransactions($xml->STMTRS->BANKTRANLIST->STMTTRN); + $bankAccount->statement->currency = $statementResponse->CURDEF; + + $bankAccount->statement->startDate = $this->createDateTimeFromStr( + $statementResponse->BANKTRANLIST->DTSTART + ); + + $bankAccount->statement->endDate = $this->createDateTimeFromStr( + $statementResponse->BANKTRANLIST->DTEND + ); + + $bankAccount->statement->transactions = $this->buildTransactions( + $statementResponse->BANKTRANLIST->STMTTRN + ); return $bankAccount; } diff --git a/tests/OfxParser/ParserTest.php b/tests/OfxParser/ParserTest.php index 77d2f1e..6e5c773 100644 --- a/tests/OfxParser/ParserTest.php +++ b/tests/OfxParser/ParserTest.php @@ -163,6 +163,7 @@ public function loadFromStringProvider() 'ofxdata-oneline.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-oneline.ofx'], 'ofxdata-cmfr.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-cmfr.ofx'], 'ofxdata-bb.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bb.ofx'], + 'ofxdata-bb-two-stmtrs.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bb-two-stmtrs.ofx'], 'ofxdata-credit-card.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-credit-card.ofx'], 'ofxdata-bpbfc.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bpbfc.ofx'], ]; diff --git a/tests/fixtures/ofxdata-bb-two-stmtrs.ofx b/tests/fixtures/ofxdata-bb-two-stmtrs.ofx new file mode 100644 index 0000000..8775285 --- /dev/null +++ b/tests/fixtures/ofxdata-bb-two-stmtrs.ofx @@ -0,0 +1,357 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + + + + + 0 + INFO + + 20170329 + POR + 20170329 + + Banco do Brasil S/A + 001 + + + + + + 0 + + 0 + INFO + + + BRL + + 001 + 455000-5 + CHECKING + + + 20170220 + 20170220 + + + 0.00 + 20170329 + + Banco do Brasil, esse parceiro é todo seu. + + + BRL + + 001 + 655000-2 + CHECKING + + + 20170224 + 20170329 + + DEP + 20170301 + 13318.36 + 2017030101331836 + 5322222 + TED-CRÉDITO EM CONTA + + + DEP + 20170301 + 413.29 + 20170301041329 + 5398076 + TED-CRÉDITO EM CONTA + + + DEP + 20170301 + 1.00 + 201703010100 + 6728440 + TED-CRÉDITO EM CONTA + + + DEP + 20170302 + 1657.34 + 201703020165734 + 7472895 + TED-CRÉDITO EM CONTA + + + DEP + 20170302 + 2299.00 + 201703020229900 + 74283522 + CRÉDITO SISTEMA CDA + + + DEP + 20170302 + 4000.00 + 201703020400000 + 74283531 + CRÉDITO SISTEMA CDA + + + DEP + 20170303 + 1580.04 + 201703030158004 + 74643016 + CRÉDITO SISTEMA CDA + + + DEP + 20170306 + 408.31 + 20170306040831 + 200005 + RECEBIMENTO FORNECEDOR + + + DEP + 20170306 + 106.43 + 20170306010643 + 7177022 + TED-CRÉDITO EM CONTA + + + DEBIT + 20170306 + -92.16 + 2017030619216 + 27238 + SEGURO VIDA EMPRESA FLEX + + + DEP + 20170308 + 138.79 + 20170308013879 + 443977 + DOC-FORNECEDOR/HONORÁRIOS + + + DEP + 20170308 + 408.72 + 20170308040872 + 9681298 + TED-PAG FORNECEDORES + + + DEP + 20170308 + 699.58 + 20170308069958 + 74699168 + CRÉDITO SISTEMA CDA + + + DEP + 20170309 + 5973.24 + 201703090597324 + 5741509 + TED-CRÉDITO EM CONTA + + + DEP + 20170313 + 75.62 + 2017031307562 + 9731 + DOC CRÉDITO EM CONTA + + + DEP + 20170313 + 100.94 + 20170313010094 + 9732 + DOC CRÉDITO EM CONTA + + + DEP + 20170313 + 395.64 + 20170313039564 + 9824 + DOC CRÉDITO EM CONTA + + + DEP + 20170313 + 39.30 + 2017031303930 + 318100 + DOC-FORNECEDOR/HONORÁRIOS + + + DEP + 20170313 + 1312.38 + 201703130131238 + 74744818 + CRÉDITO SISTEMA CDA + + + DEP + 20170313 + 1203.26 + 201703130120326 + 74744904 + CRÉDITO SISTEMA CDA + + + DEP + 20170313 + 1005.39 + 201703130100539 + 74744955 + CRÉDITO SISTEMA CDA + + + DEP + 20170313 + 16660.00 + 2017031301666000 + 00033703 + ORDEM BANCÁRIA + + + DEP + 20170316 + 2299.00 + 201703160229900 + 74554810 + CRÉDITO SISTEMA CDA + + + DEBIT + 20170317 + -41272.37 + 2017031714127237 + 31701 + IMPOSTOS + + + DEP + 20170320 + 337.05 + 20170320033705 + 200005 + RECEBIMENTO FORNECEDOR + + + DEP + 20170321 + 3568.96 + 201703210356896 + 58509 + TED-CRÉDITO EM CONTA + + + DEP + 20170322 + 473.68 + 20170322047368 + 571721 + DOC CRÉDITO EM CONTA + + + DEP + 20170322 + 3153.76 + 201703220315376 + 6995389 + TED-CRÉDITO EM CONTA + + + DEP + 20170322 + 4000.00 + 201703220400000 + 74554819 + CRÉDITO SISTEMA CDA + + + DEP + 20170323 + 2676.10 + 201703230267610 + 9397855 + TED-CRÉDITO EM CONTA + + + XFER + 20170323 + 4992.92 + 201703230499292 + 00044345 + TRANSFERÊNCIA AGENDADA + + + DEBIT + 20170324 + -37000.00 + 2017032413700000 + 32401 + TED TRANSF.ELETR.DISPONIV + + + DEP + 20170327 + 917.96 + 20170327091796 + 4329891 + TED-CRÉDITO EM CONTA + + + DEP + 20170327 + 413.29 + 20170327041329 + 4452039 + TED-CRÉDITO EM CONTA + + + DEP + 20170327 + 154.52 + 20170327015452 + 5171371 + TED-PAG FORNECEDORES + + + DEBIT + 20170327 + -68.00 + 2017032716800 + 01096659 + TARIFA PACOTE DE SERVIÇOS + + + + 4555.28 + 20170329 + + Banco do Brasil, esse parceiro é todo seu. + + + + \ No newline at end of file From bddecdf702a3967ed30e9273392a0d158067b31b Mon Sep 17 00:00:00 2001 From: Jean Gwennael Date: Fri, 19 Jan 2018 15:46:08 +0100 Subject: [PATCH 04/11] fix: check + symbole for positive amount --- lib/OfxParser/Ofx.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/OfxParser/Ofx.php b/lib/OfxParser/Ofx.php index ad494ed..b93c075 100644 --- a/lib/OfxParser/Ofx.php +++ b/lib/OfxParser/Ofx.php @@ -325,7 +325,7 @@ private function createDateTimeFromStr($dateString, $ignoreErrors = false) private function createAmountFromStr($amountString) { // Decimal mark style (UK/US): 000.00 or 0,000.00 - if (preg_match('/^-?([\d,]+)(\.?)([\d]{2})$/', $amountString) === 1) { + if (preg_match('/^(-|\+)?([\d,]+)(\.?)([\d]{2})$/', $amountString) === 1) { return (float)preg_replace( ['/([,]+)/', '/\.?([\d]{2})$/'], ['', '.$1'], @@ -334,7 +334,7 @@ private function createAmountFromStr($amountString) } // European style: 000,00 or 0.000,00 - if (preg_match('/^-?([\d\.]+,?[\d]{2})$/', $amountString) === 1) { + if (preg_match('/^(-|\+)?([\d\.]+,?[\d]{2})$/', $amountString) === 1) { return (float)preg_replace( ['/([\.]+)/', '/,?([\d]{2})$/'], ['', '.$1'], From 0fe90759abdda292288619dad1686526168b42a8 Mon Sep 17 00:00:00 2001 From: Jean Gwennael Date: Fri, 19 Jan 2018 15:57:53 +0100 Subject: [PATCH 05/11] test: add test for positive value --- tests/OfxParser/OfxTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/OfxParser/OfxTest.php b/tests/OfxParser/OfxTest.php index 486f287..61f7546 100644 --- a/tests/OfxParser/OfxTest.php +++ b/tests/OfxParser/OfxTest.php @@ -38,6 +38,12 @@ public function amountConversionProvider() '1' => ['1', 1.0], '10' => ['10', 10.0], '100' => ['100', 1.0], // @todo this is weird behaviour, should not really expect this + '+1' => ['+1', 1.0], + '+10' => ['+10', 10.0], + '+1000.00' => ['+1000.00', 1000.0], + '+1000,00' => ['+1000,00', 1000.0], + '+1,000.00' => ['+1,000.00', 1000.0], + '+1.000,00' => ['+1.000,00', 1000.0], ]; } From f3a795821711c80e4c43c5eab6dafc1042caa3f4 Mon Sep 17 00:00:00 2001 From: Renato Monteiro Batisa Date: Fri, 26 Oct 2018 17:06:42 -0300 Subject: [PATCH 06/11] Fix malfunction on closeUnclosedXmlTags when an open has " inside, reported issue #49 --- lib/OfxParser/Parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OfxParser/Parser.php b/lib/OfxParser/Parser.php index cedbc41..1315003 100644 --- a/lib/OfxParser/Parser.php +++ b/lib/OfxParser/Parser.php @@ -102,7 +102,7 @@ private function closeUnclosedXmlTags($line) // Does not match: // Does not match: blah if (preg_match( - "/<([A-Za-z0-9.]+)>([\wà-úÀ-Ú0-9\.\-\_\+\, ;:\[\]\'\&\/\\\*\(\)\+\{\|\}\!\£\$\?=@€£#%±§~`]+)$/", + "/<([A-Za-z0-9.]+)>([\wà-úÀ-Ú0-9\.\-\_\+\, ;:\[\]\'\&\/\\\*\(\)\+\{\|\}\!\£\$\?=@€£#%±§~`\"]+)$/", trim($line), $matches )) { From 60d6b361833697bf31943b51693ebc5d15c82e10 Mon Sep 17 00:00:00 2001 From: Renato Monteiro Batisa Date: Mon, 29 Oct 2018 06:14:10 -0300 Subject: [PATCH 07/11] Test case for issue with closeUnclosedXmlTags when an open has quotation marks --- tests/OfxParser/ParserTest.php | 1 + tests/fixtures/ofxdata-memoWithQuotes.ofx | 176 ++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 tests/fixtures/ofxdata-memoWithQuotes.ofx diff --git a/tests/OfxParser/ParserTest.php b/tests/OfxParser/ParserTest.php index 6e5c773..7c3e478 100644 --- a/tests/OfxParser/ParserTest.php +++ b/tests/OfxParser/ParserTest.php @@ -166,6 +166,7 @@ public function loadFromStringProvider() 'ofxdata-bb-two-stmtrs.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bb-two-stmtrs.ofx'], 'ofxdata-credit-card.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-credit-card.ofx'], 'ofxdata-bpbfc.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bpbfc.ofx'], + 'ofxdata-memoWithQuotes.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-memoWithQuotes.ofx'], ]; } diff --git a/tests/fixtures/ofxdata-memoWithQuotes.ofx b/tests/fixtures/ofxdata-memoWithQuotes.ofx new file mode 100644 index 0000000..0b16682 --- /dev/null +++ b/tests/fixtures/ofxdata-memoWithQuotes.ofx @@ -0,0 +1,176 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + + + + +0 +INFO + + +20181026000000[-3:GMT] +POR + + + + + +1001 + +0 +INFO + + + +BRL + +99999999-9999-9999-9999-999999999999 + + + +20180913000000[-3:GMT] +20181013000000[-3:GMT] + +DEBIT +20180913000000[-3:GMT] +-33.3 +5b4f6eea-9999-9999-9999-794a31c8f61b +Amazon.Com.Br Amazon S 3/3 + + + +DEBIT +20180913000000[-3:GMT] +-9.9 +5b62619e-9999-9999-9999-e26b2df210fc +Empiricus 3/12 + + + +DEBIT +20180913000000[-3:GMT] +-140 +5b4f3b92-9999-9999-9999-902a256f3470 +Funcern 3/4 + + + +DEBIT +20180913000000[-3:GMT] +-40 +5b2b9e42-9999-9999-9999-1742bdf860ad +Azul Linhas Aereas*Fef 4/4 + + + +DEBIT +20180917000000[-3:GMT] +-5.27 +5ba09990-9999-9999-9999-ebd979a2a758 +IOF de "Leupay.Eu" + + + +DEBIT +20180917000000[-3:GMT] +-82.54 +5ba09c73-9999-9999-9999-191cf5c75cb1 +Leupay.Eu + + + +DEBIT +20180918000000[-3:GMT] +-225 +5b9fe897-9999-9999-9999-8ef65fb1ec8f +Mercpago + + + +CREDIT +20180920000000[-3:GMT] +600 +5ba47b96-9999-9999-9999-d57a38a6507d +Pagamento recebido + + + +DEBIT +20180920000000[-3:GMT] +-12.2 +5ba2937e-9999-9999-9999-7f21ffede0af +Mundo Verde + + + +CREDIT +20180920000000[-3:GMT] +127.87 +5ba47b64-9999-9999-9999-4e784e26540d +Pagamento recebido + + + +CREDIT +20180920000000[-3:GMT] +400 +5ba47b9d-9999-9999-9999-3635c88dfb3f +Pagamento recebido + + + +DEBIT +20180921000000[-3:GMT] +-80.68 +5ba38bad-9999-9999-9999-354f59379d1d +Assai Ata + + + +DEBIT +20180922000000[-3:GMT] +-14.5 +5ba5599b-9999-9999-9999-986103e3cd9e +Pag*Marianadiasdebrit + + + +DEBIT +20180924000000[-3:GMT] +-9.88 +5ba66b2a-9999-9999-9999-2da061b5ad4d +Superfacil Atacado + + + +DEBIT +20181005000000[-3:GMT] +-4.84 +5bb8d7fa-9999-9999-9999-d9632e284d02 +IOF de "Leupay.Eu" + + + +DEBIT +20181005000000[-3:GMT] +-75.94 +5bb8d808-9999-9999-9999-dfa3886b11ab +Leupay.Eu + + + + +-734.05 +20181013000000[-3:GMT] + + + + + From 2a628f5f2de54fbce5ddd206cd13f3f0ce949562 Mon Sep 17 00:00:00 2001 From: Nicolas Rabier Date: Tue, 18 Dec 2018 16:46:26 +1100 Subject: [PATCH 08/11] First test if dateString is set and not empty in createDateTimeFromStr Some OFX files don't have all the date tags. So when the value of the date tag that doesn't exist and it is passed as a parameter to $dateString into the function "createDateTimeFromStr", this function returns "=> Failed to initialize DateTime for string: ". To bring more flexibility, I suggest testing first if dateString is set and is not empty before converting it into a string. --- lib/OfxParser/Ofx.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/OfxParser/Ofx.php b/lib/OfxParser/Ofx.php index b93c075..b6bfb54 100644 --- a/lib/OfxParser/Ofx.php +++ b/lib/OfxParser/Ofx.php @@ -279,6 +279,8 @@ private function buildStatus(SimpleXMLElement $xml) */ private function createDateTimeFromStr($dateString, $ignoreErrors = false) { + if((!isset($dateString) || trim($dateString) === '')) return null; + $regex = '/' . "(\d{4})(\d{2})(\d{2})?" // YYYYMMDD 1,2,3 . "(?:(\d{2})(\d{2})(\d{2}))?" // HHMMSS - optional 4,5,6 From 19e39c505db181eb90610039ac2b6068c021e401 Mon Sep 17 00:00:00 2001 From: Nicolas Rabier Date: Tue, 18 Dec 2018 16:59:50 +1100 Subject: [PATCH 09/11] Replace "&" sign in XML tag value by its html code In OFX files, some tag values like in MEMO tag contains special characters such as the 'at' sign (@) which generate an issue with simplexml_load_string function. `LibXMLError::__set_state(array( 'level' => 3, 'code' => 68, 'column' => 30, 'message' => 'xmlParseEntityRef: no name ', 'file' => '', 'line' => 27, )),` This code simply converts the '&' sign to its html code (&) which is tolerated by simplexml_load_string. --- lib/OfxParser/Parser.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/OfxParser/Parser.php b/lib/OfxParser/Parser.php index 1315003..4fec0a7 100644 --- a/lib/OfxParser/Parser.php +++ b/lib/OfxParser/Parser.php @@ -121,6 +121,8 @@ private function convertSgmlToXml($sgml) { $sgml = str_replace(["\r\n", "\r"], "\n", $sgml); + $sgml = preg_replace('/&(?!#?[a-z0-9]+;)/', '&', $sgml); + $lines = explode("\n", $sgml); $xml = ''; From 75ce43ce3cbaaf1a371ee377d8db1a2841298df1 Mon Sep 17 00:00:00 2001 From: "nicolas.rabier" Date: Sun, 20 Jan 2019 22:13:53 +1100 Subject: [PATCH 10/11] tests for fix #52 --- tests/OfxParser/OfxTest.php | 5 +++ tests/OfxParser/ParserTest.php | 1 + tests/fixtures/ofxdata-emptyDateTime.ofx | 49 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/fixtures/ofxdata-emptyDateTime.ofx diff --git a/tests/OfxParser/OfxTest.php b/tests/OfxParser/OfxTest.php index 61f7546..8691d97 100644 --- a/tests/OfxParser/OfxTest.php +++ b/tests/OfxParser/OfxTest.php @@ -87,6 +87,11 @@ public function testCreateDateTimeFromOFXDateFormats() // Test YYYYMMDDHHMMSS.XXX $DateTimeFour = $method->invoke($Ofx, '20081005132200.124'); self::assertEquals($expectedDateTime->getTimestamp(), $DateTimeFour->getTimestamp()); + + // Test empty datetime + $DateTimeFour = $method->invoke($Ofx, ''); + self::assertEquals(null, $DateTimeFour); + } public function testBuildsSignOn() diff --git a/tests/OfxParser/ParserTest.php b/tests/OfxParser/ParserTest.php index 7c3e478..e94c5e1 100644 --- a/tests/OfxParser/ParserTest.php +++ b/tests/OfxParser/ParserTest.php @@ -167,6 +167,7 @@ public function loadFromStringProvider() 'ofxdata-credit-card.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-credit-card.ofx'], 'ofxdata-bpbfc.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bpbfc.ofx'], 'ofxdata-memoWithQuotes.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-memoWithQuotes.ofx'], + 'ofxdata-emptyDateTime.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-emptyDateTime.ofx'], ]; } diff --git a/tests/fixtures/ofxdata-emptyDateTime.ofx b/tests/fixtures/ofxdata-emptyDateTime.ofx new file mode 100644 index 0000000..fe7e7a2 --- /dev/null +++ b/tests/fixtures/ofxdata-emptyDateTime.ofx @@ -0,0 +1,49 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + + + + +0 +INFO + +20181217111357 +ENG + + + + +1 + +0 +INFO + + +AUD + + +CREDIT +20181214000000 +337.50 +140217 +TEST TEST TEST AAAA + + +CREDIT +20181213000000 +150.00 +126659 +TEST TEST TEST BBBB + + + + + + \ No newline at end of file From 0b5ddaa01c01125d64460b631254d4870f16df04 Mon Sep 17 00:00:00 2001 From: "nicolas.rabier" Date: Sun, 20 Jan 2019 23:02:07 +1100 Subject: [PATCH 11/11] tests for fix #51 --- tests/OfxParser/ParserTest.php | 13 ++ tests/fixtures/ofxdata-memoWithAmpersand.ofx | 176 +++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 tests/fixtures/ofxdata-memoWithAmpersand.ofx diff --git a/tests/OfxParser/ParserTest.php b/tests/OfxParser/ParserTest.php index e94c5e1..20bcf5f 100644 --- a/tests/OfxParser/ParserTest.php +++ b/tests/OfxParser/ParserTest.php @@ -112,6 +112,18 @@ public function convertSgmlToXmlProvider() XXXXXXXXXXX CHECKING +HERE + ],[<< + bar & restaurant + bat + +HERE + , << +bar & restaurant +bat + HERE ], ]; @@ -168,6 +180,7 @@ public function loadFromStringProvider() 'ofxdata-bpbfc.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-bpbfc.ofx'], 'ofxdata-memoWithQuotes.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-memoWithQuotes.ofx'], 'ofxdata-emptyDateTime.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-emptyDateTime.ofx'], + 'ofxdata-memoWithAmpersand.ofx' => [dirname(__DIR__).'/fixtures/ofxdata-memoWithAmpersand.ofx'], ]; } diff --git a/tests/fixtures/ofxdata-memoWithAmpersand.ofx b/tests/fixtures/ofxdata-memoWithAmpersand.ofx new file mode 100644 index 0000000..09320e6 --- /dev/null +++ b/tests/fixtures/ofxdata-memoWithAmpersand.ofx @@ -0,0 +1,176 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + + + + +0 +INFO + + +20181026000000[-3:GMT] +POR + + + + + +1001 + +0 +INFO + + + +BRL + +99999999-9999-9999-9999-999999999999 + + + +20180913000000[-3:GMT] +20181013000000[-3:GMT] + +DEBIT +20180913000000[-3:GMT] +-33.3 +5b4f6eea-9999-9999-9999-794a31c8f61b +Amazon.Com.Br Amazon & Cloud 3/3 + + + +DEBIT +20180913000000[-3:GMT] +-9.9 +5b62619e-9999-9999-9999-e26b2df210fc +Empiricus 3/12 + + + +DEBIT +20180913000000[-3:GMT] +-140 +5b4f3b92-9999-9999-9999-902a256f3470 +Funcern 3/4 + + + +DEBIT +20180913000000[-3:GMT] +-40 +5b2b9e42-9999-9999-9999-1742bdf860ad +Azul Linhas Aereas*Fef 4/4 + + + +DEBIT +20180917000000[-3:GMT] +-5.27 +5ba09990-9999-9999-9999-ebd979a2a758 +IOF de "Leupay.Eu" & Whoelse + + + +DEBIT +20180917000000[-3:GMT] +-82.54 +5ba09c73-9999-9999-9999-191cf5c75cb1 +Leupay.Eu + + + +DEBIT +20180918000000[-3:GMT] +-225 +5b9fe897-9999-9999-9999-8ef65fb1ec8f +Mercpago + + + +CREDIT +20180920000000[-3:GMT] +600 +5ba47b96-9999-9999-9999-d57a38a6507d +Pagamento recebido + + + +DEBIT +20180920000000[-3:GMT] +-12.2 +5ba2937e-9999-9999-9999-7f21ffede0af +Mundo Verde + + + +CREDIT +20180920000000[-3:GMT] +127.87 +5ba47b64-9999-9999-9999-4e784e26540d +Pagamento recebido + + + +CREDIT +20180920000000[-3:GMT] +400 +5ba47b9d-9999-9999-9999-3635c88dfb3f +Pagamento recebido + + + +DEBIT +20180921000000[-3:GMT] +-80.68 +5ba38bad-9999-9999-9999-354f59379d1d +Assai Ata + + + +DEBIT +20180922000000[-3:GMT] +-14.5 +5ba5599b-9999-9999-9999-986103e3cd9e +Pag*Marianadiasdebrit + + + +DEBIT +20180924000000[-3:GMT] +-9.88 +5ba66b2a-9999-9999-9999-2da061b5ad4d +Superfacil Atacado + + + +DEBIT +20181005000000[-3:GMT] +-4.84 +5bb8d7fa-9999-9999-9999-d9632e284d02 +IOF de "Leupay.Eu" + + + +DEBIT +20181005000000[-3:GMT] +-75.94 +5bb8d808-9999-9999-9999-dfa3886b11ab +Leupay.Eu + + + + +-734.05 +20181013000000[-3:GMT] + + + + +