Viewing file: DTA.php (19.55 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
// +----------------------------------------------------------------------+ // | PHP Version 4 | // +----------------------------------------------------------------------+ // | Copyright (c) 2003-2005 Hermann Stainer, Web-Gear | // | http://www.web-gear.com/ | // | All rights reserved. | // +----------------------------------------------------------------------+ // | DTA is a class that provides functions to create DTA files used in | // | Germany to exchange informations about money transactions with banks | // | or online banking programs. | // | This LICENSE is in the BSD license style. | // | | // | Redistribution and use in source and binary forms, with or without | // | modification, are permitted provided that the following conditions | // | are met: | // | | // | Redistributions of source code must retain the above copyright | // | notice, this list of conditions and the following disclaimer. | // | | // | Redistributions in binary form must reproduce the above copyright | // | notice, this list of conditions and the following disclaimer in the | // | documentation and/or other materials provided with the distribution. | // | | // | Neither the name of Hermann Stainer, Web-Gear nor the names of his | // | contributors may be used to endorse or promote products derived from | // | this software without specific prior written permission. | // | | // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | // | POSSIBILITY OF SUCH DAMAGE. | // +----------------------------------------------------------------------+ // | Author: Hermann Stainer <hs@web-gear.com> | // +----------------------------------------------------------------------+ // // $Id: DTA.php,v 1.2.0 2005/01/25 15:00:00 hstainer Exp $
/** * Determines the type of the DTA file: * DTA file contains credit payments. * * @const DTA_CREDIT */ define("DTA_CREDIT", 0);
/** * Determines the type of the DTA file: * DTA file contains debit payments (default). * * @const DTA_DEBIT */ define("DTA_DEBIT", 1);
/** * Dta class provides functions to create and handle with DTA files * used in Germany to exchange informations about money transactions with * banks or online banking programs. * * @author Hermann Stainer <hs@web-gear.com> * @version $Revision: 0.81 $ * @since DTA 0.1 */ class DTA { /** * Type of DTA file, DTA_CREDIT or DTA_DEBIT. * * @var integer $type */ var $type;
/** * Account data for the file sender. * * @var integer $account_file_sender */ var $account_file_sender;
/** * Array of ASCII Codes of valid chars for DTA field data. * * @var array $validString_chars */ var $validString_chars;
/** * Current timestamp. * * @var integer $timestamp */ var $timestamp;
/** * Array of exchanges that the DTA file should contain. * * @var integer $exchanges */ var $exchanges;
/** * Constructor. The type of the DTA file must be set. One file can * only contain credits (DTA_CREDIT) OR debits (DTA_DEBIT). * This is a definement of the DTA format. * * @param integer $type Determines the type of the DTA file. Either DTA_CREDIT or DTA_DEBIT. Must be set. * @access public */ function DTA($type) { $this->type = $type;
$this->account_file_sender = array();
$this->validString_chars = array(32, 36, 37, 38, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 196, 214, 220, 223);
$this->timestamp = time();
$this->exchanges = array(); }
/** * Checks if the given string contains only chars valid for fields in DTA files. * * @param string $string String that is checked. * @access public * @return boolean */ function validString($string) { $occuring_chars = count_chars($string, 1);
$result = true;
foreach ($occuring_chars as $char_ord => $char_amount) { if (!in_array($char_ord, $this->validString_chars)) { $result = false; break; } }
return $result; }
/** * Makes the given string valid for DTA files. German umlauts become uppercase, * all other chars not allowed are replaced with space * * @param string $string String that should made valid. * @access public * @return string */ function makeValidString($string) {
$result = "";
if (strlen($string) > 0) { $search = array( "'Ä'", "'Ö'", "'Ü'", "'ä'", "'ö'", "'ü'", "'ß'" );
$replace = array( "Ae", "Oe", "Ue", "ae", "oe", "ue", "ss" );
$result = strtoupper(preg_replace ($search, $replace, $string));
for ($index = 0;$index < strlen($result);$index++) { if (!in_array(ord(substr($result, $index, 1)), $this->validString_chars)) { $result[$index] = " "; } } }
return $result; }
/** * Set the sender of the DTA file. Must be set for valid DTA file. * The given account data is also used as default sender's account. * Account data contains * name Sender's name. Maximally 27 chars are allowed. * bank_code Sender's bank code. * account_number Sender's account number. * additional_name If necessary, additional line for sender's name (maximally 27 chars).
* @param array $account Account data fot file sender. * @access public * @return boolean */ function setAccountFileSender($account) { if (strlen($account['name']) > 0 && is_numeric($account['bank_code']) && is_numeric($account['account_number'])) { if (empty($account['additional_name'])) { $account['additional_name'] = ""; }
$this->account_file_sender = array( "name" => substr($this->makeValidString($account['name']), 0, 27), "bank_code" => $account['bank_code'], "account_number" => $account['account_number'], "additional_name" => substr($this->makeValidString($account['additional_name']), 0, 27) );
$result = true; } else { $result = false; }
return $result; }
/** * Adds an exchange. First the account data for the receiver of the exchange is set. * In the case the DTA file contains credits, this is the payment receiver. In the other * case (the DTA file contains debits), this is the account, from which money is taken away. * If the sender is not specified, values of the file sender are used by default. * Account data for receiver and sender contain * name Name. Maximally 27 chars are allowed. * bank_code Bank code. * account_number Account number. * additional_name If necessary, additional line for name (maximally 27 chars). * * @param array $account_receiver Receiver's account data. * @param double $amount Amount of money in this exchange. Currency: EURO * @param array $purposes Array of up to 15 lines (maximally 27 chars each) for description of the exchange. * @param array $account_sender Sender's account data. * @access public * @return boolean */ function addExchange($account_receiver, $amount, $purposes, $account_sender = array()) { if (empty($account_receiver['additional_name'])) { $account_receiver['additional_name'] = ""; } if (empty($account_sender['name'])) { $account_sender['name'] = $this->account_file_sender['name']; } if (empty($account_sender['bank_code'])) { $account_sender['bank_code'] = $this->account_file_sender['bank_code']; } if (empty($account_sender['account_number'])) { $account_sender['account_number'] = $this->account_file_sender['account_number']; } if (empty($account_sender['additional_name'])) { $account_sender['additional_name'] = $this->account_file_sender['additional_name']; }
if (strlen($account_sender['name']) > 0 && is_numeric($account_sender['bank_code']) && is_numeric($account_sender['account_number']) && strlen($account_receiver['name']) > 0 && is_numeric($account_receiver['bank_code']) && is_numeric($account_receiver['account_number']) && is_numeric($amount) && $amount > 0 && ((is_array($purposes) && count($purposes) >= 1) || (is_string($purposes) && strlen($purposes) > 0))) {
$amount = round($amount * 100);
if (is_string($purposes)) { $purposes = array($purposes, ""); }
$purposes_data = $purposes; $purposes = array();
foreach ($purposes_data as $purpose) { $purposes[] = substr($this->makeValidString($purpose), 0, 27); }
$this->exchanges[] = array( "sender_name" => substr($this->makeValidString($account_sender['name']), 0, 27), "sender_bank_code" => $account_sender['bank_code'], "sender_account_number" => $account_sender['account_number'], "sender_additional_name" => substr($this->makeValidString($account_sender['additional_name']), 0, 27), "receiver_name" => substr($this->makeValidString($account_receiver['name']), 0, 27), "receiver_bank_code" => $account_receiver['bank_code'], "receiver_account_number" => $account_receiver['account_number'], "receiver_additional_name" => substr($this->makeValidString($account_receiver['additional_name']), 0, 27), "amount" => $amount, "purposes" => $purposes );
$result = true; } else { $result = false; }
return $result; }
/** * Returns the full content of the generated DTA file. All added exchanges are processed. * * @access public * @return string */ function getFileContent() { $content = "";
$sum_account_numbers = 0; $sum_bank_codes = 0; $sum_amounts = 0;
/** * data record A */
// record length (128 Bytes) $content .= str_pad ("128", 4, "0", STR_PAD_LEFT); // record type $content .= "A"; // file mode (credit or debit) $content .= ($this->type == DTA_CREDIT) ? "G" : "L"; // Customer File ("K") / Bank File ("B") $content .= "K"; // sender's bank code $content .= str_pad ($this->account_file_sender['bank_code'], 8, "0", STR_PAD_LEFT); // only used if Bank File, otherwise NULL $content .= str_repeat ("0", 8); // sender's name $content .= str_pad ($this->account_file_sender['name'], 27, " ", STR_PAD_RIGHT); // date of file creation $content .= strftime("%d%m%y", $this->timestamp); // free (bank internal) $content .= str_repeat (" ", 4); // sender's account number $content .= str_pad ($this->account_file_sender['account_number'], 10, "0", STR_PAD_LEFT); // sender's reference number (optional) $content .= str_repeat ("0", 10); // free (reserve) $content .= str_repeat (" ", 15); // execution date ("DDMMYYYY", optional) $content .= str_repeat (" ", 8); // free (reserve) $content .= str_repeat (" ", 24); // currency (1 = Euro) $content .= "1";
/** * data record(s) C */
foreach ($this->exchanges as $exchange) { $sum_account_numbers += $exchange['receiver_account_number']; $sum_bank_codes += $exchange['receiver_bank_code']; $sum_amounts += $exchange['amount'];
$additional_purposes = $exchange['purposes']; $first_purpose = array_shift($additional_purposes);
$additional_parts = array();
if (strlen($exchange['receiver_additional_name']) > 0) { $additional_parts[] = array("type" => "01", "content" => $exchange['receiver_additional_name'] ); }
foreach ($additional_purposes as $additional_purpose) { $additional_parts[] = array("type" => "02", "content" => $additional_purpose ); }
if (strlen($exchange['sender_additional_name']) > 0) { $additional_parts[] = array("type" => "03", "content" => $exchange['sender_additional_name'] ); }
$additional_parts_number = count($additional_parts); // record length (187 Bytes + 29 Bytes for each additional part) $content .= str_pad (187 + $additional_parts_number * 29, 4, "0", STR_PAD_LEFT); // record type $content .= "C"; // first involved bank $content .= str_pad ($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT); // receiver's bank code $content .= str_pad ($exchange['receiver_bank_code'], 8, "0", STR_PAD_LEFT); // receiver's account number $content .= str_pad ($exchange['receiver_account_number'], 10, "0", STR_PAD_LEFT); // internal customer number (11 chars) or NULL $content .= "0" . str_repeat ("0", 11) . "0"; // payment mode (text key) $content .= ($this->type == DTA_CREDIT) ? "51" : "05"; // additional text key $content .= "000"; // bank internal $content .= " "; // free (reserve) $content .= str_repeat ("0", 11); // sender's bank code $content .= str_pad ($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT); // sender's account number $content .= str_pad ($exchange['sender_account_number'], 10, "0", STR_PAD_LEFT); // amount $content .= str_pad ($exchange['amount'], 11, "0", STR_PAD_LEFT); // free (reserve) $content .= str_repeat (" ", 3); // receiver's name $content .= str_pad ($exchange['receiver_name'], 27, " ", STR_PAD_RIGHT); // delimitation $content .= str_repeat (" ", 8); // sender's name $content .= str_pad ($exchange['sender_name'], 27, " ", STR_PAD_RIGHT); // first line of purposes $content .= str_pad ($first_purpose, 27, " ", STR_PAD_RIGHT); // currency (1 = Euro) $content .= "1"; // free (reserve) $content .= str_repeat (" ", 2); // amount of additional parts $content .= str_pad ($additional_parts_number, 2, "0", STR_PAD_LEFT);
if (count($additional_parts) > 0) { for ($index = 1;$index <= 2;$index++) { if (count($additional_parts) > 0) { $additional_part = array_shift($additional_parts); } else { $additional_part = array("type" => " ", "content" => "" ); } // type of addional part $content .= $additional_part['type']; // additional part content $content .= str_pad ($additional_part['content'], 27, " ", STR_PAD_RIGHT); } // delimitation $content .= str_repeat (" ", 11); }
for ($part = 3;$part <= 5;$part++) { if (count($additional_parts) > 0) { for ($index = 1;$index <= 4;$index++) { if (count($additional_parts) > 0) { $additional_part = array_shift($additional_parts); } else { $additional_part = array("type" => " ", "content" => "" ); } // type of addional part $content .= $additional_part['type']; // additional part content $content .= str_pad ($additional_part['content'], 27, " ", STR_PAD_RIGHT); } // delimitation $content .= str_repeat (" ", 12); } } }
/** * data record E */
// record length (128 bytes) $content .= str_pad ("128", 4, "0", STR_PAD_LEFT); // record type $content .= "E"; // free (reserve) $content .= str_repeat (" ", 5); // number of records type C $content .= str_pad (count($this->exchanges), 7, "0", STR_PAD_LEFT); // free (reserve) $content .= str_repeat ("0", 13); // sum of account numbers $content .= str_pad ($sum_account_numbers, 17, "0", STR_PAD_LEFT); // sum of bank codes $content .= str_pad ($sum_bank_codes, 17, "0", STR_PAD_LEFT); // sum of amounts $content .= str_pad ($sum_amounts, 13, "0", STR_PAD_LEFT); // delimitation $content .= str_repeat (" ", 51);
return $content; }
/** * Writes the DTA file. * * @param string $filename Filename. * @access public * @return boolean */ function saveFile($filename) { $content = $this->getFileContent();
$Dta_fp = @fopen($filename, "w"); if (!$Dta_fp) { $result = false; } else { $result = @fwrite($Dta_fp, $content); @fclose($Dta_fp); }
return $result; } }
?>
|