芝麻web文件管理V1.00
编辑当前文件:/home/strato/chroot/opt/RZphp5/includes/Payment/DTA.php
* @author Martin Schütte
* @copyright 2003-2005 Hermann Stainer, Web-Gear * @copyright 2008 Martin Schütte * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) * @version CVS: $Id: DTA.php,v 1.9 2009/06/04 21:20:54 mschuett Exp $ * @link http://pear.php.net/package/Payment_DTA */ /** * needs base class */ require_once 'DTABase.php'; /** * 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. * * Specifications: * - http://www.ebics-zka.de/dokument/pdf/Anlage%203-Spezifikation%20der%20Datenformate%20-%20Version%202.3%20Endfassung%20vom%2005.11.2008.pdf, * part 1.1 DTAUS0, p. 4ff * - http://www.bundesbank.de/download/zahlungsverkehr/zv_spezifikationen_v1_5.pdf * - http://www.hbci-zka.de/dokumente/aenderungen/DTAUS_2002.pdf * * @category Payment * @package Payment_DTA * @author Hermann Stainer
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) * @version Release: @package_version@ * @link http://pear.php.net/package/Payment_DTA */ class DTA extends DTABase { /** * Type of DTA file, DTA_CREDIT or DTA_DEBIT. * * @var integer $type */ var $type; /** * Sum of bank codes in exchanges; used for control fields. * * @var integer $sum_bankcodes * @access private */ var $sum_bankcodes; /** * Sum of account numbers in exchanges; used for control fields. * * @var integer $sum_accounts * @access private */ var $sum_accounts; /** * 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->DTABase(); $this->type = $type; $this->sum_bankcodes = 0; $this->sum_accounts = 0; } /** * 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 for file sender. * * @access public * @return boolean */ function setAccountFileSender($account) { $account['account_number'] = strval($account['account_number']); $account['bank_code'] = strval($account['bank_code']); if (strlen($account['name']) > 0 && strlen($account['bank_code']) > 0 && strlen($account['bank_code']) <= 8 && ctype_digit($account['bank_code']) && strlen($account['account_number']) > 0 && strlen($account['account_number']) <= 10 && ctype_digit($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 14 lines * (maximally 27 chars each) for * description of the exchange. * A string is accepted as well. * @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']; } $account_receiver['account_number'] = strval($account_receiver['account_number']); $account_receiver['bank_code'] = strval($account_receiver['bank_code']); $account_sender['account_number'] = strval($account_sender['account_number']); $account_sender['bank_code'] = strval($account_sender['bank_code']); $cents = (int)(round($amount * 100)); if (strlen($account_sender['name']) > 0 && strlen($account_sender['bank_code']) > 0 && strlen($account_sender['bank_code']) <= 8 && ctype_digit($account_sender['bank_code']) && strlen($account_sender['account_number']) > 0 && strlen($account_sender['account_number']) <= 10 && ctype_digit($account_sender['account_number']) && strlen($account_receiver['name']) > 0 && strlen($account_receiver['bank_code']) <= 8 && ctype_digit($account_receiver['bank_code']) && strlen($account_receiver['account_number']) <= 10 && ctype_digit($account_receiver['account_number']) && is_numeric($amount) && $cents > 0 && $cents <= PHP_INT_MAX && $this->sum_amounts <= (PHP_INT_MAX - $cents) && ( (is_string($purposes) && strlen($purposes) > 0) || (is_array($purposes) && count($purposes) >= 1 && count($purposes) <= 14) )) { $this->sum_amounts += $cents; $this->sum_bankcodes += $account_receiver['bank_code']; $this->sum_accounts += $account_receiver['account_number']; if (is_string($purposes)) { $filtered_purposes = str_split($this->makeValidString($purposes), 27); $filtered_purposes = array_slice($filtered_purposes, 0, 14); } else { $filtered_purposes = array(); foreach ($purposes as $purposeline) { $filtered_purposes[] = substr($this->makeValidString($purposeline), 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" => $cents, "purposes" => $filtered_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 */ // (field numbers according to ebics-zka.de specification) // A1 record length (128 Bytes) $content .= str_pad("128", 4, "0", STR_PAD_LEFT); // A2 record type $content .= "A"; // A3 file mode (credit or debit) // and Customer File ("K") / Bank File ("B") $content .= ($this->type == DTA_CREDIT) ? "G" : "L"; $content .= "K"; // A4 sender's bank code $content .= str_pad($this->account_file_sender['bank_code'], 8, "0", STR_PAD_LEFT); // A5 only used if Bank File, otherwise NULL $content .= str_repeat("0", 8); // A6 sender's name $content .= str_pad($this->account_file_sender['name'], 27, " ", STR_PAD_RIGHT); // A7 date of file creation $content .= strftime("%d%m%y", $this->timestamp); // A8 free (bank internal) $content .= str_repeat(" ", 4); // A9 sender's account number $content .= str_pad($this->account_file_sender['account_number'], 10, "0", STR_PAD_LEFT); // A10 sender's reference number (optional) $content .= str_repeat("0", 10); // A11a free (reserve) $content .= str_repeat(" ", 15); // A11b execution date ("DDMMYYYY", optional) $content .= str_repeat(" ", 8); // A11c free (reserve) $content .= str_repeat(" ", 24); // A12 currency (1 = Euro) $content .= "1"; assert(strlen($content) == 128); /** * data record(s) C */ foreach ($this->exchanges as $exchange) { $sum_account_numbers += $exchange['receiver_account_number']; $sum_bank_codes += (int) $exchange['receiver_bank_code']; $sum_amounts += (int) $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); assert($additional_parts_number <= 15); // C1 record length (187 Bytes + 29 Bytes for each additional part) $content .= str_pad(187 + $additional_parts_number * 29, 4, "0", STR_PAD_LEFT); // C2 record type $content .= "C"; // C3 first involved bank $content .= str_pad($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT); // C4 receiver's bank code $content .= str_pad($exchange['receiver_bank_code'], 8, "0", STR_PAD_LEFT); // C5 receiver's account number $content .= str_pad($exchange['receiver_account_number'], 10, "0", STR_PAD_LEFT); // C6 internal customer number (11 chars) or NULL $content .= "0" . str_repeat("0", 11) . "0"; // C7a payment mode (text key) $content .= ($this->type == DTA_CREDIT) ? "51" : "05"; // C7b additional text key $content .= "000"; // C8 bank internal $content .= " "; // C9 free (reserve) $content .= str_repeat("0", 11); // C10 sender's bank code $content .= str_pad($exchange['sender_bank_code'], 8, "0", STR_PAD_LEFT); // C11 sender's account number $content .= str_pad($exchange['sender_account_number'], 10, "0", STR_PAD_LEFT); // C12 amount $content .= str_pad($exchange['amount'], 11, "0", STR_PAD_LEFT); // C13 free (reserve) $content .= str_repeat(" ", 3); // C14a receiver's name $content .= str_pad($exchange['receiver_name'], 27, " ", STR_PAD_RIGHT); // C14b delimitation $content .= str_repeat(" ", 8); /* first part/128 chars full */ // C15 sender's name $content .= str_pad($exchange['sender_name'], 27, " ", STR_PAD_RIGHT); // C16 first line of purposes $content .= str_pad($first_purpose, 27, " ", STR_PAD_RIGHT); // C17a currency (1 = Euro) $content .= "1"; // C17b free (reserve) $content .= str_repeat(" ", 2); // C18 number of additional parts (00-15) $content .= str_pad($additional_parts_number, 2, "0", STR_PAD_LEFT); /* * End of the constant part (187 chars), * now up to 15 extensions with 29 chars each might follow. */ if (count($additional_parts) == 0) { // no extension, pad to fill the part to 2*128 chars $content .= str_repeat(" ", 256-187); } else { // The first two extensions fit into the current part: for ($index = 1;$index <= 2;$index++) { if (count($additional_parts) > 0) { $additional_part = array_shift($additional_parts); } else { $additional_part = array("type" => " ", "content" => "" ); } // C19/21 type of addional part $content .= $additional_part['type']; // C20/22 additional part content $content .= str_pad($additional_part['content'], 27, " ", STR_PAD_RIGHT); } // delimitation $content .= str_repeat(" ", 11); } // For more extensions add up to 4 more parts: 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" => "" ); } // C24/26/28/30 type of addional part $content .= $additional_part['type']; // C25/27/29/31 additional part content $content .= str_pad($additional_part['content'], 27, " ", STR_PAD_RIGHT); } // C32 delimitation $content .= str_repeat(" ", 12); } } // with 15 extensions there may be a 6th part if (count($additional_parts) > 0) { $additional_part = array_shift($additional_parts); // C24 type of addional part $content .= $additional_part['type']; // C25 additional part content $content .= str_pad($additional_part['content'], 27, " ", STR_PAD_RIGHT); // padding to fill the part $content .= str_repeat(" ", 128-27-2); } assert(count($additional_parts) == 0); assert(strlen($content) % 128 == 0); } /** * data record E */ assert($this->sum_amounts === $sum_amounts); assert($this->sum_bankcodes === $sum_bank_codes); assert($this->sum_accounts === $sum_account_numbers); // E1 record length (128 bytes) $content .= str_pad("128", 4, "0", STR_PAD_LEFT); // E2 record type $content .= "E"; // E3 free (reserve) $content .= str_repeat(" ", 5); // E4 number of records type C $content .= str_pad(count($this->exchanges), 7, "0", STR_PAD_LEFT); // E5 free (reserve) $content .= str_repeat("0", 13); // use number_format() to ensure proper integer formatting // E6 sum of account numbers $content .= str_pad(number_format($sum_account_numbers, 0, "", ""), 17, "0", STR_PAD_LEFT); // E7 sum of bank codes $content .= str_pad(number_format($sum_bank_codes, 0, "", ""), 17, "0", STR_PAD_LEFT); // E8 sum of amounts $content .= str_pad(number_format($sum_amounts, 0, "", ""), 13, "0", STR_PAD_LEFT); // E9 delimitation $content .= str_repeat(" ", 51); assert(strlen($content) % 128 == 0); return $content; } /** * Returns an array with information about the transactions. * Can be used to print an accompanying document (Begleitzettel) for disks. * * @access public * @return array Returns an array with keys: "sender_name", * "sender_bank_code", "sender_account", "sum_amounts", * "sum_bankcodes", "sum_accounts", "count", "date" */ function getMetaData() { $meta = parent::getMetaData(); $meta["sum_bankcodes"] = floatval($this->sum_bankcodes); $meta["sum_accounts"] = floatval($this->sum_accounts); return $meta; } }