Topic: Guide: Getting up and running with PHP, cURL, and OFX

Hello all, i'd like to share some of my personal 3-day-long torturous experience and the result so other don't have to suffer. In particular this involved with Bank of America. Obvious prerequisites are having an account and you MUST also enroll here to be able to connect via OFX:

https://sitekey.bankofamerica.com/sas/p … mp;req=QKN

I will say this: the most difficult part of the whole thing is getting your damn bank info correct, after a successful logon, the rest should be easy to do from the well documented ofx spec. To come up with this, the road was long and twisted involving GNUcash, Quicken's OFX logs, downloading OFX/QIF files from the BoA transaction lists, and lots of research and sifting through data from conflicting sources. In the end, the most accurate source of info was the OFX exported file from BoA and the Quicken OFX logs, (for some reason i could not get the logs to output with GNU cash)

i actually hex edited the gnucash ofxlib dll file myself before realizing there was a tip about it at the bottom to change the APPVER so that BoA would stop complaining about incompatible software version, thats what got GNUcash up and running.

A few fun facts:
the websites below list the BoA as FID=6812 or 6805, depending on the site (and this may be true for actual original BoA accounts. However, after googling the routing number on the voided BoA check, LaSalle came up on this site: gregthatcher.com (then of course i remembered that BoA absorbed Lasalle). This was step one.

next, i looked at the exported ofx files from BoA and got the correct FID for the bank as (5959) and BANKID (081904808). however, this file showed the ORG as "Bank of America" which did not work. The quicken OFX log files as well as OFXblog showed the ORG as "HAN", which did work.

In summary, if you have Quicken or GNUcash, set them up and look at the logfiles, if they work, then all the info in them is correct.

Also, the routing/ABA number actually was not used at all, to log on or get transaction lists, it's probably used during setup to get the bankid.

Most of the valuable info came from a physical VOIDed check and these pages:
http://fi.intuit.com/support/logfileslocation.cfm
http://www.gregthatcher.com/FINANCIAL/D … &arg=L
http://wiki.gnucash.org/wiki/Setting_up … _GnuCash_2
http://wiki.gnucash.org/wiki/OFX_Direct … k_Settings
http://ofxblog.wordpress.com/2008/10/16 … -ca-wa-id/

// this function is just used to generate a random transaction id below
function getRandomString($length = 40, $charset = 'alphanum') {
    $alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $num = '0123456789';
    switch ($charset) {
        case 'alpha':
            $chars = $alpha;
            break;
        case 'alphanum':
            $chars = $alpha . $num;
            break;
        case 'num':
            $chars = $num;
            break;            
    }
    
    $randstring='';
    $maxvalue=strlen($chars)-1;
    for ($i = 0; $i < $length; $i++)
      $randstring .= substr($chars, rand(0, $maxvalue), 1);
    return $randstring;
}

// user login info
$user = 'username';
$pass = 'password';

// account info
$accnt_num = '0000000000';
$accnt_type = 'CHECKING';

// date and a random unique transaction id
$txn_id = getRandomString(6);
$tz_offset = date('Z')/3600;
$date = date("YmdHis[$tz_offset:T]");

// Bank of America info
$org = 'HAN';
$fid = '5959';
$bank_id = '081904808';

// transaction retrieval date range
$start_date = '20090101000000';        // from date, to..
$end_date = date('YmdHis');        // now

$xml = "
<OFX>
    <SIGNONMSGSRQV1>
        <SONRQ>
            <DTCLIENT>$date</DTCLIENT>
            <USERID>$user</USERID>
            <USERPASS>$pass</USERPASS>
            <LANGUAGE>ENG</LANGUAGE>
            <FI>
                <ORG>$org</ORG>
                <FID>$fid</FID>
            </FI>
            <APPID>QWIN</APPID>
            <APPVER>1800</APPVER>
        </SONRQ>
    </SIGNONMSGSRQV1>
    
    <BANKMSGSRQV1>
        <STMTTRNRQ>
            <TRNUID>$txn_id</TRNUID>
            <STMTRQ>
                <BANKACCTFROM>
                    <BANKID>$bank_id</BANKID>
                    <ACCTID>$accnt_num</ACCTID>
                    <ACCTTYPE>$accnt_type</ACCTTYPE>
                </BANKACCTFROM>
                <INCTRAN>
                    <DTSTART>$start_date</DTSTART>
                    <DTEND>$end_date</DTEND>
                    <INCLUDE>Y</INCLUDE>
                </INCTRAN>
            </STMTRQ>
        </STMTTRNRQ>
    </BANKMSGSRQV1>
</OFX>";

$ch = curl_init();
$ch1 = curl_setopt($ch, CURLOPT_URL, 'https://ofx.bankofamerica.com/cgi-forte/fortecgi?servicename=ofx_2-3&pagename=ofx');
$ch2 = curl_setopt($ch, CURLOPT_POST, 1);
$ch3 = curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
$ch4 = curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$ch5 = curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$ch6 = curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$result = curl_exec($ch);
if ($result) {
    $correctedXML = preg_replace('/<([A-Za-z]*?)>(?![\s\S]*?<\/\1>)(.+)/m', '<\1>\2</\1>', $result);
    $x = new SimpleXMLElement($correctedXML);
}
else
    echo "<pre>CURL ERROR: " . curl_error($ch) . "</pre>";
curl_close ($ch);

And to conclude, Quicken sends XML-invalid requests and BoA returns data in an INVALID XML format as well, (why? i dont know) so it took me almost 3 hours to come up with the proper Regex to reformat and create a valid XML string from the response. Consider it icing on the cake : )

Hope this helps someone, i would have killed for this info just a few days go, heh.
Leon

2 (edited by Eirikr 2009-10-22 21:59:01)

Re: Guide: Getting up and running with PHP, cURL, and OFX

A few thoughts and comments:

Leeoniya wrote:

And to conclude, Quicken sends XML-invalid requests and BoA returns data in an INVALID XML format as well, (why? i dont know)

Older apps use the older OFX spec, which was based not on XML, but on SGML, which didn't require closing tags.  Anyone with experience dealing with markup will understand why XML came as an improvement.  smile

Here's own working configuration, nothing in code, just the settings in GnuCash. 

Note that my accounts are with Bank of America, in California.

---------------
AqBanking Settings: "General" tab

User Settings
User Name = anything
User ID = Bank of America online login ID

Bank Settings
Country: US
Bank ID: routing number from my checkbook

AqBanking Settings: "OFX" tab

Bank Settings
FID = 6805
ORG = HAN

Connection Settings
Server URL = https://ofx.bankofamerica.com/cgi-forte … ename=bofa

Server Options
Supports Account List Download
Supports Statement Download
Supports Bill Pay

Expert Settings
APPID = QWIN
APPVER = 1800
---------------

Until I read Leeoniya's post here and worked through the included OFX internals and saw the APPID and APPVER values, I simply could not get any usable reply from the bank.  I have online banking turned on with BofA, so that wasn't the issue.  Once I added the two Expert Settings though, things work a charm -- the AqBanking backend correctly downloaded the account info for all five of my accounts: one checking, two credit, and two savings.  Thanks, Leeoniya!

Cheers,

-- Eir