phpfints

repository·master·Indexed 41 days ago

https://github.com/nemiah/phpfints

A PHP library for implementing the FinTS/HBCI protocol (FinTS V3.0 specification), enabling interaction with German bank accounts to retrieve balances, transactions, and execute transfers. It provides a user-facing API in the Fhp\Model and Fhp\Action namespaces, handles PSD2 PIN/TAN authentication, and includes specific configurations for banks like Hypovereinsbank and ING Diba.

Tokens
10.5K
Snippets
38
Records
50
Agent score
50%

What's inside phpfints

  1. Understand Segment and DEG class naming conventions

    master

    The library maps FinTS specification segments and DEGs to PHP classes:

    Segment Classes

    Segments inherit from BaseSegment. The naming follows the pattern HXyyyvN:

    • H: Constant for "HBCI".
    • X: Indicates the direction: K (Kunde/Customer request), I (Institut/Bank response), or N (Nachricht/Message containing both).
    • yyy: Abbreviation of the functionality.
    • vN: The version number (e.g., v6).

    Segments are grouped in namespaces like Fhp\Segment\HXyyy (for versioned groups) or Fhp\Segment\yyy (to group request and response segments together).

    DEG Classes

    Data Element Groups inherit from BaseDeg. Their names correspond to the sub-section titles in the specification. Version suffixes (VN) are optional.

  2. Understand PSD2 PIN/TAN authentication

    master

    Under PSD2, PIN/TAN authentication piggy-backs on the existing HBCI encryption/signature specification. While TLS provides transport-layer security, FinTS messages must still be wrapped in an envelope to carry PIN and TAN data. This envelope is implemented via Fhp\Protocol\Message.

    To manage the TAN lifecycle (requesting a TAN, defining its format, sending it, and verifying acceptance), the library uses the HKTAN family of segments. Note that HKTAN version 6 is the version equivalent to PSD2.

    Important Note: Some banks require a TAN during the initial login phase. Because HKTAN was originally designed for authenticating transactions within an active dialog rather than initializing one, implementation variations between banks may occur.

  3. How the FinTS protocol and dialogs work

    master

    The protocol follows a request-response pattern: for every request sent by the client, the client must wait for exactly one response from the server before sending the next request.

    Dialog Initialization: Before performing any business transactions, a client must initialize a dialog (implemented in Fhp\Protocol\DialogInitialization and FinTs). This process is similar to a TCP/TLS handshake and often involves authentication (login). While FinTS is transport-agnostic, in practice, banks use TLS 3.0 via https:// URIs.

  4. Understand the FinTS message structure

    master

    The library implements the FinTS V3.0 specification. The core hierarchy of data is as follows:

    1. Message (Fhp\Protocol\Message): A collection of segments.
    2. Segment (Fhp\Segment\...): A top-level unit identified by a header (e.g., HNHBK). Segments are delimited by the ' character.
    3. Data Element Group (DEG) (Fhp\Segment\... inheriting from BaseDeg): A compound value consisting of multiple data elements or nested DEGs.
    4. Data Element (DE): The leaf nodes containing actual values (e.g., strings, integers, booleans).

    Wire Format Example: An example of a message containing three segments in its raw wire format:

    HNHBK:1:3+000000000079+300+dialogID+2'HKEND:2:1+dialogID'HNHBS:3:1+2'
    • The first segment is HNHBK.
    • The second segment is HKEND (version 1) containing the dialogId.
    • The third segment is HNHBS.
  5. Install the phpfints library via Composer

    master

    Install the library using Composer. Ensure you have the php-mbstring extension and either unzip or 7z installed on your system to avoid errors during installation and unpacking.

    Prerequisites

    • Install php-mbstring.
    • Install unzip or 7z (to avoid using the PHP zip extension for unpacking).
    • Register your application with Die Deutsche Kreditwirtschaft to obtain a registration number. Note that it can take several weeks for this registration to reach your bank's server.
    composer require nemiah/php-fints
  6. Debug serialized messages with prettifier scripts

    master

    If you need to debug raw wire format messages, you can use the provided prettifier scripts to render them in a human-readable format with field names inlined. These scripts accept the wire format via stdin.

    # Example usage (assuming scripts are in your path or local directory)
    echo "HNHBK:1:3+000000000079+300+dialogID+2'" | php prettify_message.php
    echo "HNHBK:1:3+000000000079+300+dialogID+2'" | php prettify_message.php
  7. Record and use bank dialogs for integration testing

    master

    Since sandbox environments are rare, developers often test against real bank accounts. To facilitate automated integration testing without risking account locks or undesired transactions, you can record real bank dialogs and replay them in PhpUnit tests using fake backends.

    1. Record the dialog: Use the CLILogger class to capture requests and responses during a manual bank interaction.
    2. Sanitize data: When using FinTs::setLogger(), sensitive values like usernames and PINs are automatically replaced with placeholders. However, personal information like IBANs, names, and transaction descriptions will still be present in the recorded segments.
    3. Anonymize without breaking the wire format: When editing recorded segments to remove personal data, do not change the overall length of the string. The FinTS wire format hard-codes lengths in multiple places; deleting characters will cause parsing failures. Instead, use an 'Insert' mode in your editor to overwrite existing data with dummy values of the exact same length.

    For implementation patterns, refer to the Tests\Fhp\Integration\... directory in the repository.

  8. Use the user-facing API for business transactions

    master

    While the library provides low-level protocol implementations, developers should use the user-facing API located in the Fhp\Model namespace. This provides a more stable and simplified interface compared to the raw protocol segments.

    Business transactions (like account statements or wire transfers) are implemented in the Fhp\Action\ namespace.

  9. Get started with phpfints examples

    master

    To begin using the library, refer to the Samples/ directory.

    1. Configure the required settings in init.php (server details can be obtained at https://www.fints.org after registration).
    2. Run tanModesAndMedia.php to test TAN modes.
    3. Run login.php to verify authentication.

    Once you can login without issues, you can proceed to other functional examples.

  10. How to handle asynchronous TAN and 2FA requests

    master

    Because PHP processes are typically short-lived, you often need to handle TAN (Transaction Authentication Number) or 2FA requests across different HTTP requests or processes. The library provides mechanisms to persist the state of a dialog and resume it later.

    1. Persisting State

    When an action requires a TAN (i.e., BaseAction::needsTan() returns true), call persist() to get a serialized string representing the current dialog state. This string contains necessary metadata like the dialogId and messageNumber but does not contain sensitive credentials like PINs.

    2. Resuming a Session

    In a new PHP process, use FinTs::new() and pass the serialized string to the $persistedInstance parameter to resume the dialog.

    3. Completing the Action

    Depending on the TanMode, use one of the following to finish the transaction:

    • Standard TAN (Synchronous/In-process): Use submitTan($action, $tan) to send the TAN entered by the user.
    • Decoupled TAN (Asynchronous/Out-of-process): If using a decoupled mode (where the user confirms on a separate device), call checkDecoupledSubmission($action) repeatedly. This method returns true if the authentication is complete and false if it is still outstanding.
    // Process 1: Start action
    $action = $fints->execute($transferAction);
    if ($action->needsTan()) {
        $state = $fints->persist(true); // Save state to DB/Session
    }
    
    // Process 2: User provides TAN later
    $fints = FinTs::new($options, $credentials, $state);
    $fints->submitTan($action, '123456');
  11. Understand the FinTS Message structure

    master

    A Fhp\Protocol\Message object represents a FinTS/HBCI message. It distinguishes between two types of segments:

    1. Plain Segments ($plainSegments): The actual functional data segments (e.g., transaction details, account info) before they are wrapped in the protocol's security envelope.
    2. Wrapper Segments ($wrapperSegments): The segments that form the protocol's "encrypted" structure. This includes the message header (HNHBK), encryption header (HNVSK), the wrapped content (HNVSD), and the message footer (HNHBS).

    When a message is "wrapped" (secured), the plainSegments are placed inside the HNVSD segment, and signature segments (HNSHK and HNSHA) are added to the beginning and end of the plain segment list respectively.

  12. Initialize a FinTs instance

    master

    Use the FinTs::new() factory method to create a new instance. You must provide FinTsOptions for connection configuration and Credentials for authentication. If you are resuming a session from a previous PHP process, you can pass a string returned by a previous call to persist() as the $persistedInstance argument.

    $options = new FinTsOptions(/* ... */);
    $credentials = new Credentials(/* ... */);
    $fints = FinTs::new($options, $credentials);