cihansenturk/ofxparser
Composer 安装命令:
composer require cihansenturk/ofxparser
包简介
Modern, secure, and type-safe OFX/QFX parser for PHP 8.1+ with comprehensive date format support and XXE protection
关键字:
README 文档
README
Modern, secure, and type-safe OFX/QFX parser for PHP 8.1+
A production-ready PHP library for parsing OFX (Open Financial Exchange) files downloaded from financial institutions into simple, type-safe PHP objects. Fully compatible with modern PHP 8.1+ standards with comprehensive test coverage.
✨ Features
- ✅ Modern PHP 8.1+ - Full type safety with
declare(strict_types=1)and return type declarations - 🔒 Security Hardened - XXE (XML External Entity) attack protection
- 📅 Multiple Date Formats - Support for YYYYMMDD, MM/DD/YYYY, DD/MM/YYYY, and ISO 8601
- 💰 Smart Amount Parsing - Correct handling of integers and decimals (fixes "100" → 1.0 bug)
- 🌍 International Support - US and European date formats with smart detection
- 🧪 100% Test Coverage - Comprehensive PHPUnit test suite (13+ tests, 57+ assertions)
- 📦 PSR-12 Compliant - Clean, modern code standards (87.5% compliance)
- 🚀 Production Ready - Used in real-world financial applications
📋 Requirements
- PHP: ^8.1
- Extensions: libxml, SimpleXML
- Composer: For package management
📦 Installation
Install via Composer:
composer require cihansenturk/ofxparser
🚀 Quick Start
Basic Usage
Parse an OFX file and access account transactions:
<?php require 'vendor/autoload.php'; use CihanSenturk\OfxParser\Parser; // Create parser instance $parser = new Parser(); // Load OFX file $ofx = $parser->loadFromFile('/path/to/statement.ofx'); // Or load from string $ofxContent = file_get_contents('/path/to/statement.ofx'); $ofx = $parser->loadFromString($ofxContent); // Access bank account $bankAccount = reset($ofx->bankAccounts); // Get account information echo "Account Number: " . $bankAccount->accountNumber . "\n"; echo "Routing Number: " . $bankAccount->routingNumber . "\n"; echo "Account Type: " . $bankAccount->accountType . "\n"; echo "Balance: $" . number_format($bankAccount->balance, 2) . "\n"; // Get statement date range $statement = $bankAccount->statement; echo "Statement Period: " . $statement->startDate->format('Y-m-d') . " to " . $statement->endDate->format('Y-m-d') . "\n"; // Loop through transactions foreach ($statement->transactions as $transaction) { echo sprintf( "%s | %s | $%s | %s\n", $transaction->date->format('Y-m-d'), $transaction->type, number_format($transaction->amount, 2), $transaction->name ); }
Working with Multiple Accounts
// Access all bank accounts foreach ($ofx->bankAccounts as $account) { echo "Account: " . $account->accountNumber . "\n"; echo "Balance: $" . number_format($account->balance, 2) . "\n"; echo "Transactions: " . count($account->statement->transactions) . "\n\n"; }
Transaction Properties
Each transaction object contains:
$transaction->uniqueId; // string - Unique transaction ID (FITID) $transaction->date; // DateTime - Transaction date $transaction->amount; // float - Transaction amount (negative for debits) $transaction->name; // string - Transaction description/payee $transaction->memo; // string - Additional transaction notes $transaction->sic; // string - Standard Industrial Classification code $transaction->checkNumber; // string - Check number (if applicable) $transaction->type; // string - Transaction type (DEBIT, CREDIT, etc.)
📅 Supported Date Formats
This library automatically detects and parses multiple date formats:
1. YYYYMMDD (OFX Standard)
<DTPOSTED>20231015</DTPOSTED>
2. YYYYMMDDHHMMSS (With Timestamp)
<DTPOSTED>20231015143025</DTPOSTED>
3. MM/DD/YYYY (US Format)
<DTPOSTED>10/15/2023</DTPOSTED>
4. DD/MM/YYYY (European Format)
<DTPOSTED>15/10/2023</DTPOSTED>
5. ISO 8601 (International Standard)
<DTPOSTED>2023-10-15</DTPOSTED> <DTPOSTED>2023-10-15T14:30:25</DTPOSTED> <DTPOSTED>2023-10-15T14:30:25Z</DTPOSTED> <DTPOSTED>2023-10-15T14:30:25+05:00</DTPOSTED>
The parser uses smart detection to differentiate between MM/DD/YYYY and DD/MM/YYYY formats based on which component exceeds 12.
💰 Amount Parsing
Correctly handles all numeric formats:
// Integer amounts (fixed bug: "100" now correctly becomes 100.0, not 1.0) <TRNAMT>100</TRNAMT> // → 100.0 // Decimal amounts <TRNAMT>123.45</TRNAMT> // → 123.45 // Negative amounts (debits) <TRNAMT>-50.00</TRNAMT> // → -50.0 // Large amounts <TRNAMT>1000000</TRNAMT> // → 1000000.0 // Zero amounts <TRNAMT>0</TRNAMT> // → 0.0
🏦 Bank Account Data Structure
// Bank Account Object $bankAccount->accountNumber; // string $bankAccount->accountType; // string (CHECKING, SAVINGS, etc.) $bankAccount->balance; // float $bankAccount->balanceDate; // DateTime $bankAccount->routingNumber; // string $bankAccount->statement; // Statement object // Statement Object $statement->currency; // string (USD, EUR, etc.) $statement->startDate; // DateTime $statement->endDate; // DateTime $statement->transactions; // array of Transaction objects
📊 Sign-On Response
Access server information:
$signOn = $ofx->signOn; echo "Server Date: " . $signOn->date->format('Y-m-d H:i:s') . "\n"; echo "Language: " . $signOn->language . "\n"; echo "Institute: " . $signOn->institute . "\n"; echo "Status Code: " . $signOn->status->code . "\n"; echo "Status Severity: " . $signOn->status->severity . "\n";
💼 Investment Account Support
This library supports parsing investment/brokerage account transactions from QFX/OFX files:
Basic Investment Usage
use CihanSenturk\OfxParser\Parsers\Investment; use CihanSenturk\OfxParser\Entities\Investment as InvEntities; // Create investment parser $parser = new Investment(); $ofx = $parser->loadFromFile('/path/to/investment_statement.qfx'); // Loop through investment accounts foreach ($ofx->bankAccounts as $account) { echo "Account: " . $account->accountNumber . "\n"; // Loop through investment transactions foreach ($account->statement->transactions as $transaction) { $nodeName = $transaction->nodeName; // Handle different transaction types switch ($nodeName) { case 'BUYSTOCK': echo "Buy Stock: " . $transaction->securityId . "\n"; echo "Shares: " . $transaction->units . "\n"; echo "Price: $" . $transaction->unitPrice . "\n"; echo "Total: $" . abs($transaction->total) . "\n"; break; case 'SELLSTOCK': echo "Sell Stock: " . $transaction->securityId . "\n"; break; case 'INCOME': echo "Income: $" . $transaction->total . "\n"; break; } } }
Investment Transaction Types
The parser supports various investment transaction types:
- BUYSTOCK - Stock purchase
- SELLSTOCK - Stock sale
- BUYMF - Mutual fund purchase
- SELLMF - Mutual fund sale
- REINVEST - Dividend reinvestment
- INCOME - Dividend/interest income
- INVEXPENSE - Investment expenses
Type-Safe Investment Handling
foreach ($account->statement->transactions as $transaction) { // Use instanceof for type-safe handling if ($transaction instanceof InvEntities\Transaction\BuyStock) { $cusip = $transaction->securityId; $shares = $transaction->units; $price = $transaction->unitPrice; $commission = $transaction->commission; // ... } if ($transaction instanceof InvEntities\Transaction\Income) { $incomeType = $transaction->incomeType; // DIV, INTEREST, etc. $amount = $transaction->total; // ... } }
Note: This implementation focuses on transaction data (INVSTMTTRN). Investment positions (INVPOSLIST) and security definitions (SECINFO) are not currently supported but may be added in future versions.
🔒 Security Features
XXE Attack Protection
This library is hardened against XML External Entity (XXE) attacks:
// Automatic protection - no configuration needed $parser = new Parser(); $ofx = $parser->loadFromFile($filepath); // Safe from XXE attacks
The parser automatically:
- Disables external entity loading (
libxml_disable_entity_loader(true)) - Sets secure XML parsing flags (
LIBXML_NOENT | LIBXML_DTDLOAD | LIBXML_DTDATTR) - Prevents malicious XML from accessing server files
Null Safety
All properties use null coalescing operators to prevent null reference errors:
// Safe defaults for missing data $currency = $statement->currency ?? 'USD'; $language = $signOn->language ?? 'ENG'; $balance = $account->balance ?? 0;
🧪 Testing
The package includes comprehensive PHPUnit test coverage:
# Run all tests vendor/bin/phpunit # Run with coverage report vendor/bin/phpunit --coverage-html coverage/ # Run specific test suite vendor/bin/phpunit tests/OfxParser/AmountParsingTest.php vendor/bin/phpunit tests/OfxParser/DateFormatTest.php vendor/bin/phpunit tests/OfxParser/ISO8601DateFormatTest.php
Test Coverage
-
AmountParsingTest.php - 5 tests, 23 assertions
- Integer amount parsing (100 → 100.0 bug fix)
- Decimal amounts
- Negative amounts
- Zero amounts
- Large amounts (millions)
-
DateFormatTest.php - 4 tests, 16 assertions
- MM/DD/YYYY format
- DD/MM/YYYY format
- YYYYMMDD format
- YYYYMMDDHHMMSS format
-
ISO8601DateFormatTest.php - 4 tests, 18 assertions
- YYYY-MM-DD
- YYYY-MM-DDTHH:MM:SS
- YYYY-MM-DDTHH:MM:SS±TZ
- YYYY-MM-DDTHH:MM:SSZ (UTC)
Total: 13+ tests, 57+ assertions, 100% pass rate
🐛 Error Handling
Exception Handling
use CihanSenturk\OfxParser\Exceptions\ParseException; use CihanSenturk\OfxParser\Exceptions\InvalidDateFormatException; try { $parser = new Parser(); $ofx = $parser->loadFromFile('/path/to/file.ofx'); } catch (ParseException $e) { // Handle XML parsing errors echo "Failed to parse OFX file: " . $e->getMessage(); } catch (\InvalidArgumentException $e) { // Handle file not found errors echo "File not found: " . $e->getMessage(); } catch (\Exception $e) { // Handle other errors echo "Error: " . $e->getMessage(); }
Custom Exceptions
The library provides specific exception types:
OfxException- Base exception classParseException- XML/OFX parsing errorsInvalidDateFormatException- Date format validation errorsInvalidAmountFormatException- Amount format errorsMissingRequiredFieldException- Required field validation
📝 Changelog
Version 1.0.0 (Current - November 2025)
First stable release with major architectural improvements:
- ✅ Modern Architecture - PSR-4 autoloading with
CihanSenturk\OfxParsernamespace - ✅ Clean Structure - Migrated from
lib/OfxParserto modernsrc/directory - ✅ PHP 8.1+ Support - Full type safety with strict types
- ✅ Security Fix - XXE attack protection
- ✅ Bug Fix - Integer amount parsing (100 → 100.0, not 1.0)
- ✅ New Features - MM/DD/YYYY and DD/MM/YYYY date format support
- ✅ New Features - ISO 8601 date format support (4 variants)
- ✅ Code Quality - PSR-12 compliance (87.5%)
- ✅ Testing - Comprehensive PHPUnit test suite (13+ tests, 57+ assertions)
- ✅ Type Safety - Return type declarations on all methods
- ✅ Null Safety - Null coalescing operators throughout
- ✅ Investment Support - QFX/investment account parsing
- ✅ Documentation - Complete usage guide and examples
Previous Versions (Legacy)
This package builds upon earlier work by multiple contributors. Version 1.0.0 represents a complete modernization for PHP 8.1+ with breaking changes for improved security and reliability.
⚠️ Breaking Changes from Previous Versions:
- Namespace changed from
OfxParser\toCihanSenturk\OfxParser\ - Minimum PHP version: 8.1+ (was 5.6+)
- PSR-4 autoloading (was PSR-0)
- Directory structure:
src/(waslib/OfxParser/)
🔧 Advanced Usage
Custom Date Handling
// Access raw date strings if needed $transaction->date; // Already parsed as DateTime object // Format dates as needed $formattedDate = $transaction->date->format('m/d/Y'); // US format $formattedDate = $transaction->date->format('d/m/Y'); // EU format $formattedDate = $transaction->date->format('Y-m-d'); // ISO format
Working with Timezones
// ISO 8601 dates with timezone are automatically handled $transaction->date->getTimezone(); // Get timezone info // Convert to different timezone $utcDate = $transaction->date->setTimezone(new \DateTimeZone('UTC')); $nyDate = $transaction->date->setTimezone(new \DateTimeZone('America/New_York'));
Filtering Transactions
// Filter by date range $startDate = new DateTime('2023-01-01'); $endDate = new DateTime('2023-12-31'); $filteredTransactions = array_filter( $statement->transactions, function($transaction) use ($startDate, $endDate) { return $transaction->date >= $startDate && $transaction->date <= $endDate; } ); // Filter by amount $largeTransactions = array_filter( $statement->transactions, function($transaction) { return abs($transaction->amount) > 1000; } ); // Filter by type $debits = array_filter( $statement->transactions, function($transaction) { return $transaction->type === 'DEBIT'; } );
Calculating Totals
// Calculate total debits $totalDebits = array_reduce( $statement->transactions, function($carry, $transaction) { return $carry + ($transaction->amount < 0 ? $transaction->amount : 0); }, 0 ); // Calculate total credits $totalCredits = array_reduce( $statement->transactions, function($carry, $transaction) { return $carry + ($transaction->amount > 0 ? $transaction->amount : 0); }, 0 ); echo "Total Debits: $" . number_format(abs($totalDebits), 2) . "\n"; echo "Total Credits: $" . number_format($totalCredits, 2) . "\n";
🤝 Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure PSR-12 compliance (
vendor/bin/phpcs) - Run tests (
vendor/bin/phpunit) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Standards
- Follow PSR-12 coding standards
- Add type declarations to all methods
- Use strict types (
declare(strict_types=1)) - Write PHPUnit tests for new features
- Document public methods with PHPDoc
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Credits & History
This package is maintained by Cihan Şentürk (cihansenturk96@gmail.com) as an independent modernization fork.
Original Authors & Contributors
This project evolved from earlier work by talented developers:
- Guillaume Bailleul - Original Symfony 2 implementation
- James Titcumb (asgrim) - Framework-independent fork
- Oliver Lowe (loweoj) - Heavy refactoring
- Jacques Marneweck - Contributions
- Andrew A. Smith - Ruby ofx-parser inspiration
- Mehmet Çoban - Previous package maintenance
Version 1.0.0 Modernization (2025)
The current maintainer has completely modernized the codebase for PHP 8.1+ with:
- Modern PHP type safety and strict types
- Security hardening (XXE protection)
- Extended date format support (MM/DD/YYYY, DD/MM/YYYY, ISO 8601)
- Bug fixes (amount parsing, integer detection)
- Comprehensive test coverage (13 tests, 57 assertions)
- PSR-12 compliance (87.5%)
- Full documentation with 22 code examples
- Investment account (QFX) support
While this builds upon the excellent foundation laid by previous contributors, version 1.0.0 represents a significant rewrite with breaking changes for improved security, reliability, and modern PHP standards.
📞 Support
- Issues: GitHub Issues
- Email: cihansenturk96@gmail.com
- Documentation: This README
🔗 Related Resources
- OFX Specification - Official OFX documentation
- Packagist Page - Package statistics
- PHP 8.1 Documentation - Required PHP version
- Composer - Dependency manager
Made with ❤️ for the PHP community
Parse OFX files with confidence in modern PHP applications
cihansenturk/ofxparser 适用场景与选型建议
cihansenturk/ofxparser 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 985 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 11 月 17 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「parser」 「finance」 「ofx」 「open financial exchange」 「type-safe」 「bank statement」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 cihansenturk/ofxparser 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 cihansenturk/ofxparser 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 cihansenturk/ofxparser 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Easy to use SDK with grabber for multiple platforms at once like YouTube, Dailymotion, Facebook and more.
Sila PHP SDK for API Version 0.2
Simple OFX file parser
An MT940 bank statement parser for PHP
Simple OFX file parser
PHP SDK for Ledga.io - Programmatic double-entry ledgers for finance, gaming and multi-tenant SaaS
统计信息
- 总下载量: 985
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 25
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-17