GPC export z Fio banky: Porovnání verzí
(Založena nová stránka: ==Vnější odkazy== * [http://sworktech.com/blog/index.php?/archives/190-Parsovani-GPC-souboru-v-PHP.html Parsování GPC souborů v PHP] Kategorie:Programování) |
Bez shrnutí editace |
||
(Není zobrazeno 11 mezilehlých verzí od stejného uživatele.) | |||
Řádek 1: | Řádek 1: | ||
==Úvod== |
|||
Existuje mnoho druhů formátů umožňujících export dat z internetového bankovnictví. Ne každý formát má natolik pevnou strukturu, aby jej bylo možné snadno a spolehlivě zpracovávat pomocí programových prostředků. Česká banka Fio nabízí jako jednu z možností exportu formát GPC. Pokud potřebujete provádět automatické stahování dat v tomto formátu z internetového bankovnictví u zmíněné banky, tak můžete použít zde prezentované již hotové třídy. Pomocí nich lze snadno vyčítat periodicky informace o nových pohybech na účtu. |
|||
==Třída GPC v gpc.php== |
|||
Tato třída slouží pro dekódování GPC formátu na asociativní pole, s kterým se pak už snadno pracuje v PHP. |
|||
<source lang="php"> |
|||
<?php |
|||
define('GPC_TYPE_REPORT', '074'); |
|||
define('GPC_TYPE_ITEM', '075'); |
|||
class GPC |
|||
{ |
|||
function ParseLine(string $Line): array |
|||
{ |
|||
$Line = ' '.$Line; |
|||
$Type = substr($Line, 1, 3); |
|||
if ($Type == GPC_TYPE_REPORT) |
|||
{ |
|||
$GPCLine = array |
|||
( |
|||
'Type' => GPC_TYPE_REPORT, |
|||
'AccountNumber' => substr($Line, 4, 16), |
|||
'AccountName' => trim(substr($Line, 20, 20)), |
|||
'OldBalanceDate' => mktime(0, 0, 0, substr($Line, 42, 2), substr($Line, 40, 2), '20'.substr($Line, 44, 2)), |
|||
'OldBalanceValue' => (substr($Line, 60, 1).substr($Line, 46, 14)) / 100, |
|||
'NewBalanceValue' => (substr($Line, 75, 1).substr($Line, 61, 14)) / 100, |
|||
'DebitValue' => (substr($Line, 90, 1).substr($Line, 76, 14)) / 100, |
|||
'CreditValue' => (substr($Line, 105, 1).substr($Line, 91, 14)) / 100, |
|||
'SequenceNumber' => intval(substr($Line, 106, 3)), |
|||
'Date' => mktime(0, 0, 0, substr($Line, 111, 2), substr($Line, 109, 2), '20'.substr($Line, 113, 2)), |
|||
//'DataAlignment' => substr($Line, 115, 14), |
|||
'CheckSum' => sha1(md5($Line).$Line), |
|||
); |
|||
} else |
|||
if ($Type == GPC_TYPE_ITEM) |
|||
{ |
|||
$GPCLine = array |
|||
( |
|||
'Type' => GPC_TYPE_ITEM, |
|||
'AccountNumber' => substr($Line, 4, 16), |
|||
'OffsetAccount' => substr($Line, 20, 16), |
|||
'RecordNumber' => substr($Line, 36, 13), |
|||
'Value' => substr($Line, 49, 12) / 100, |
|||
'Code' => substr($Line, 61, 1), |
|||
'VariableSymbol' => intval(substr($Line, 62, 10)), |
|||
'BankCode' => substr($Line, 74, 4), |
|||
'ConstantSymbol' => intval(substr($Line, 78, 4)), |
|||
'SpecificSymbol' => intval(substr($Line, 82, 10)), |
|||
'Valut' => substr($Line, 92, 6), |
|||
'ClientName' => substr($Line, 98, 20), |
|||
//'Zero' => substr($Line, 118, 1), |
|||
'CurrencyCode' => substr($Line, 119, 4), |
|||
'DueDate' => mktime(0, 0, 0, substr($Line, 125, 2), substr($Line, 123, 2), substr($Line, 127, 2)), |
|||
'CheckSum' => sha1(md5($Line).$Line), |
|||
); |
|||
} else $GPCLine = NULL; |
|||
return $GPCLine; |
|||
} |
|||
}</source> |
|||
==Přístup přes bankovní API== |
|||
Fio banka od 6.11.2012 [http://www.fio.cz/spolecnost-fio/media/tiskove-zpravy/122142-fio-banka-nabizi-bezpecne-automatizovane-ziskavani-dat-z-uctu zprovoznila své bankovní API], díky kterému je možné standardizovanou formou vyčítat informace o pohybech na účtech. Export lze provést do formátů XML, OFX, GPC, CSV, HTML, JSON a MT940. Zde je použit formát GPC. Detailní popis API najdete v [http://www.fio.cz/docs/cz/API_Bankovnictvi.pdf API_Bankovnictvi.pdf]. |
|||
* Pro přístup přes API je nutno si vygenerovat v internetovém bankovnictví pro každý účet unikátní token. |
|||
* Kódování GPC exportu je Windows-1250, takže se provádí konverze kódování na UTF-8 |
|||
===Třída Fio v fio_api.php=== |
|||
<source lang="php"> |
|||
<?php |
|||
include('gpc.php'); |
|||
class FioAPI |
|||
{ |
|||
public string $Token; |
|||
public string $Encoding; |
|||
function __construct() |
|||
{ |
|||
$this->Encoding = 'utf-8'; |
|||
} |
|||
function Import($TimeFrom, $TimeTo) |
|||
{ |
|||
if ($this->Token == '') throw new Exception('Missing value for Token property.'); |
|||
$fp = fsockopen('ssl://www.fio.cz', 443, $errno, $errstr, 30); |
|||
if (!$fp) |
|||
{ |
|||
throw new Exception('Connection error: '.$errstr); |
|||
} else |
|||
{ |
|||
// Send request |
|||
$RequestURL = '/ib_api/rest/periods/'.$this->Token.'/'. |
|||
date('Y-m-d', $TimeFrom).'/'.date('Y-m-d', $TimeTo).'/transactions.gpc'; |
|||
$Request = "GET ".$RequestURL." HTTP/1.1\r\n"; |
|||
$Request .= "Host: www.fio.cz\r\n"; |
|||
$Request .= "User-Agent: PHP Script\r\n"; |
|||
$Request .= "Content-Type: text/html\r\n"; |
|||
$Request .= "Connection: Close\r\n\r\n"; |
|||
fwrite($fp, $Request); |
|||
// Read response |
|||
$Response = array(); |
|||
while (!feof($fp)) |
|||
{ |
|||
$Response .= trim(fgets($fp, 1024))."\n"; |
|||
} |
|||
fclose($fp); |
|||
$Response = iconv('windows-1250', $this->Encoding, $Response); |
|||
$Response = explode("\n", $Response); |
|||
// Strip HTTP header |
|||
while ($Response[0] != '') array_shift($Response); |
|||
array_shift($Response); // Remove empty line |
|||
// Parse all GPC lines |
|||
$GPC = new GPC(); |
|||
$Result = array(); |
|||
foreach ($Response as $Index => $Line) |
|||
{ |
|||
if (($Index == 0) and (substr($Line, 0, strlen(GPC_TYPE_REPORT)) != GPC_TYPE_REPORT)) $this->NoValidDataError($Response); |
|||
$GPCLine = $GPC->ParseLine($Line); |
|||
if ($GPCLine != NULL) $Result[] = $GPCLine; |
|||
} |
|||
return $Result; |
|||
} |
|||
} |
|||
function NoValidDataError(array $Response) |
|||
{ |
|||
// Try to get error message |
|||
// If something go wrong fio show HTML login page and display error message |
|||
$Response = implode('', $Response); |
|||
$ErrorMessageStart = '<div id="oldform_warning">'; |
|||
if (strpos($Response, $ErrorMessageStart) !== false) |
|||
{ |
|||
$Response = substr($Response, strpos($Response, $ErrorMessageStart) + strlen($ErrorMessageStart)); |
|||
$ErrorMessage = trim(substr($Response, 0, strpos($Response, '</div>'))); |
|||
} else $ErrorMessage = ''; |
|||
throw new Exception('No valid GPC data: '.$ErrorMessage); |
|||
} |
|||
}</source> |
|||
===Ukázka použití v demo_fio_api.php=== |
|||
<source lang="php"> |
|||
<?php |
|||
include('fio_api.php'); |
|||
$Fio = new FioAPI(); |
|||
$Fio->Token = 'unikátní vygenerovaný token'; |
|||
$Records = $Fio->Import(time() - 3600 * 24 * 31 * 2, time()); |
|||
echo('<!DOCTYPE html>'); |
|||
echo('<html><head><meta charset="utf-8"></head><body>'); |
|||
echo('<table border="1">'); |
|||
foreach ($Records as $Record) |
|||
{ |
|||
echo('<tr>'); |
|||
if ($Record['Type'] == GPC_TYPE_REPORT) |
|||
{ |
|||
echo('<td>Jméno účtu: '.$Record['AccountName'].'</td>'); |
|||
echo('<td>Číslo účtu: '.$Record['AccountNumber'].'</td>'); |
|||
echo('<td>Ke dni '.date('j.n.Y', $Record['OldBalanceDate']).' je stav účtu '.$Record['OldBalanceValue'].' Kč</td>'); |
|||
echo('<td>Ke dni '.date('j.n.Y', $Record['Date']).' je stav účtu '.$Record['NewBalanceValue'].' Kč</td>'); |
|||
echo('<td>Suma příjmů: '.$Record['CreditValue'].' Kč</td>'); |
|||
echo('<td>Suma výdajů: '.$Record['DebitValue'].' Kč</td>'); |
|||
echo('</tr></table><br><br>'); |
|||
echo('<table border="1"><tr>'); |
|||
echo('<th>Datum</th>'); |
|||
echo('<th>Částka</th>'); |
|||
echo('<th>Účet protistrany</th>'); |
|||
echo('<th>Kód banky</th>'); |
|||
echo('<th>KS</th>'); |
|||
echo('<th>VS</th>'); |
|||
echo('<th>SS</th>'); |
|||
echo('<th>Uživatelská identifikace</th>'); |
|||
} else |
|||
if ($Record['Type'] == GPC_TYPE_ITEM) |
|||
{ |
|||
echo('<td>'.date('j.n.Y', $Record['DueDate']).'</td>'); |
|||
echo('<td>'.$Record['Value'].'</td>'); |
|||
echo('<td>'.$Record['OffsetAccount'].'</td>'); |
|||
echo('<td>'.$Record['BankCode'].'</td>'); |
|||
echo('<td>'.$Record['ConstantSymbol'].'</td>'); |
|||
echo('<td>'.$Record['VariableSymbol'].'</td>'); |
|||
echo('<td>'.$Record['SpecificSymbol'].'</td>'); |
|||
echo('<td>'.$Record['ClientName'].'</td>'); |
|||
} |
|||
echo('</tr>'); |
|||
} |
|||
echo('</table>'); |
|||
echo('</body></html>'); |
|||
</source> |
|||
==Přístup přes přímé webové rozhraní== |
|||
Přímý přístup byla jediná použitelná metoda v době, kdy neexistovalo samostatné bankovní API rozhraní. Data bylo možné získat ve formátu GPC, CSV nebo přímým rozkládáním HTML. Zde je použit export do formátu GPC. |
|||
* Kódování webu Fio je Windows-1250, takže se provádí konverze kódování na UTF-8 |
|||
* Při zasílání formuláře se generuje aktuální čas pomocí funkce time() v parametru LOGIN_TIME podle času počítače, na kterém běží skript. Čas na vašem počítači musí být blízký času na Fio serveru. Tedy synchronizovaný přes NTP z internetu. Pokud je čas zpožděn o více než asi 3-5 minut, dojde ke zobrazení hlášení "Přihlašovací formulář byl již neplatný. Zkuste se přihlásit znovu". |
|||
===Třída Fio v fio.php=== |
|||
<source lang="php"> |
|||
<?php |
|||
include('gpc.php'); |
|||
class Fio |
|||
{ |
|||
public string $UserName; |
|||
public string $Password; |
|||
public string $Account; |
|||
public string $Encoding; |
|||
function __construct() |
|||
{ |
|||
$this->Encoding = 'utf-8'; |
|||
} |
|||
function Import($TimeFrom, $TimeTo) |
|||
{ |
|||
if ($this->UserName == '') throw new Exception('Missing value for UserName property.'); |
|||
if ($this->Password == '') throw new Exception('Missing value for Password property.'); |
|||
if (!is_numeric($this->Account)) throw new Exception('Missing or not numeric value for Account property.'); |
|||
$fp = fsockopen('ssl://www.fio.cz', 443, $errno, $errstr, 30); |
|||
if (!$fp) |
|||
{ |
|||
throw new Exception('Connection error: '.$errstr); |
|||
} else |
|||
{ |
|||
// Send request |
|||
$RequestURL = "/scgi-bin/hermes/dz-pohyby.cgi?ID_ucet=".$this->Account. |
|||
"&LOGIN_USERNAME=".$this->UserName."&SUBMIT=Odeslat&LOGIN_TIME=".time(). |
|||
"&LOGIN_PASSWORD=".$this->Password."&pohyby_DAT_od=".date('d.m.Y', $TimeFrom). |
|||
"&pohyby_DAT_do=".date('d.m.Y', $TimeTo)."&export_gpc=1"; |
|||
$Request = "GET ".$RequestURL." HTTP/1.1\r\n"; |
|||
$Request .= "Host: www.fio.cz\r\n"; |
|||
$Request .= "User-Agent: PHP Script\r\n"; |
|||
$Request .= "Content-Type: text/html\r\n"; |
|||
$Request .= "Connection: Close\r\n\r\n"; |
|||
fwrite($fp, $Request); |
|||
// Read response |
|||
$Response = array(); |
|||
while (!feof($fp)) |
|||
{ |
|||
$Response .= trim(fgets($fp, 1024))."\n"; |
|||
} |
|||
fclose($fp); |
|||
$Response = iconv('windows-1250', $this->Encoding, $Response); |
|||
$Response = explode("\n", $Response); |
|||
// Strip HTTP header |
|||
while ($Response[0] != '') array_shift($Response); |
|||
array_shift($Response); // Remove empty line |
|||
// Parse all GPC lines |
|||
$GPC = new GPC(); |
|||
$Result = array(); |
|||
foreach ($Response as $Index => $Line) |
|||
{ |
|||
if (($Index == 0) and (substr($Line, 0, strlen(GPC_TYPE_REPORT)) != GPC_TYPE_REPORT)) $this->NoValidDataError($Response); |
|||
$GPCLine = $GPC->ParseLine($Line); |
|||
if ($GPCLine != NULL) $Result[] = $GPCLine; |
|||
} |
|||
return $Result; |
|||
} |
|||
} |
|||
function NoValidDataError(array $Response) |
|||
{ |
|||
// Try to get error message |
|||
// If something go wrong Fio show HTML login page and display error message |
|||
$Response = implode('', $Response); |
|||
$ErrorMessageStart = '<div id="oldform_warning">'; |
|||
if (strpos($Response, $ErrorMessageStart) !== false) |
|||
{ |
|||
$Response = substr($Response, strpos($Response, $ErrorMessageStart) + strlen($ErrorMessageStart)); |
|||
$ErrorMessage = trim(substr($Response, 0, strpos($Response, '</div>'))); |
|||
} else $ErrorMessage = ''; |
|||
throw new Exception('No valid GPC data: '.$ErrorMessage); |
|||
} |
|||
}</source> |
|||
===Ukázka použití v demo_fio.php=== |
|||
<source lang="php"> |
|||
<?php |
|||
include('fio.php'); |
|||
$Fio = new Fio(); |
|||
$Fio->Account = '123456789'; |
|||
$Fio->UserName = 'user'; |
|||
$Fio->Password = 'pass'; |
|||
$Records = $Fio->Import(time() - 3600 * 24 * 31 * 2, time()); |
|||
echo('<!DOCTYPE html>'); |
|||
echo('<html><head><meta charset="utf-8"></head><body>'); |
|||
echo('<table border="1">'); |
|||
foreach ($Records as $Record) |
|||
{ |
|||
echo('<tr>'); |
|||
if ($Record['Type'] == GPC_TYPE_REPORT) |
|||
{ |
|||
echo('<td>Jméno účtu: '.$Record['AccountName'].'</td>'); |
|||
echo('<td>Číslo účtu: '.$Record['AccountNumber'].'</td>'); |
|||
echo('<td>Ke dni '.date('j.n.Y', $Record['OldBalanceDate']).' je stav účtu '.$Record['OldBalanceValue'].' Kč</td>'); |
|||
echo('<td>Ke dni '.date('j.n.Y', $Record['Date']).' je stav účtu '.$Record['NewBalanceValue'].' Kč</td>'); |
|||
echo('<td>Suma příjmů: '.$Record['CreditValue'].' Kč</td>'); |
|||
echo('<td>Suma výdajů: '.$Record['DebitValue'].' Kč</td>'); |
|||
echo('</tr></table><br><br>'); |
|||
echo('<table border="1"><tr>'); |
|||
echo('<th>Datum</th>'); |
|||
echo('<th>Částka</th>'); |
|||
echo('<th>Účet protistrany</th>'); |
|||
echo('<th>Kód banky</th>'); |
|||
echo('<th>KS</th>'); |
|||
echo('<th>VS</th>'); |
|||
echo('<th>SS</th>'); |
|||
echo('<th>Uživatelská identifikace</th>'); |
|||
} else |
|||
if ($Record['Type'] == GPC_TYPE_ITEM) |
|||
{ |
|||
echo('<td>'.date('j.n.Y', $Record['DueDate']).'</td>'); |
|||
echo('<td>'.$Record['Value'].'</td>'); |
|||
echo('<td>'.$Record['OffsetAccount'].'</td>'); |
|||
echo('<td>'.$Record['BankCode'].'</td>'); |
|||
echo('<td>'.$Record['ConstantSymbol'].'</td>'); |
|||
echo('<td>'.$Record['VariableSymbol'].'</td>'); |
|||
echo('<td>'.$Record['SpecificSymbol'].'</td>'); |
|||
echo('<td>'.$Record['ClientName'].'</td>'); |
|||
} |
|||
echo('</tr>'); |
|||
} |
|||
echo('</table>'); |
|||
echo('</body></html>'); |
|||
</source> |
|||
==Pokud něco nefunguje jak má== |
|||
* Třídy jsou navrženy tak, aby při výskytu chyby vyvolaly výjimku. Pokud z popisu chyby není zřejmá příčina, je potřeba chybu ladit a do kódu přidávat dočasně ladící výpisy. Především ze zobrazení obsahu načítané stránky z webu Fio by mělo vyplynout odkud vítr vane. |
|||
==Vnější odkazy== |
==Vnější odkazy== |
||
* [http://www.fio.cz/docs/cz/struktura-gpc.pdf Struktura GPC formátu] |
|||
* [http://www.fio.cz/docs/cz/API_Bankovnictvi.pdf Specifikace Fio API] |
|||
* [http://sworktech.com/blog/index.php?/archives/190-Parsovani-GPC-souboru-v-PHP.html Parsování GPC souborů v PHP] |
* [http://sworktech.com/blog/index.php?/archives/190-Parsovani-GPC-souboru-v-PHP.html Parsování GPC souborů v PHP] |
||
* [http://www.fio.cz Fio banka] |
|||
[[Kategorie:Programování]] |
[[Kategorie:Programování]] |
Aktuální verze z 4. 6. 2024, 12:49
Úvod
Existuje mnoho druhů formátů umožňujících export dat z internetového bankovnictví. Ne každý formát má natolik pevnou strukturu, aby jej bylo možné snadno a spolehlivě zpracovávat pomocí programových prostředků. Česká banka Fio nabízí jako jednu z možností exportu formát GPC. Pokud potřebujete provádět automatické stahování dat v tomto formátu z internetového bankovnictví u zmíněné banky, tak můžete použít zde prezentované již hotové třídy. Pomocí nich lze snadno vyčítat periodicky informace o nových pohybech na účtu.
Třída GPC v gpc.php
Tato třída slouží pro dekódování GPC formátu na asociativní pole, s kterým se pak už snadno pracuje v PHP.
<?php
define('GPC_TYPE_REPORT', '074');
define('GPC_TYPE_ITEM', '075');
class GPC
{
function ParseLine(string $Line): array
{
$Line = ' '.$Line;
$Type = substr($Line, 1, 3);
if ($Type == GPC_TYPE_REPORT)
{
$GPCLine = array
(
'Type' => GPC_TYPE_REPORT,
'AccountNumber' => substr($Line, 4, 16),
'AccountName' => trim(substr($Line, 20, 20)),
'OldBalanceDate' => mktime(0, 0, 0, substr($Line, 42, 2), substr($Line, 40, 2), '20'.substr($Line, 44, 2)),
'OldBalanceValue' => (substr($Line, 60, 1).substr($Line, 46, 14)) / 100,
'NewBalanceValue' => (substr($Line, 75, 1).substr($Line, 61, 14)) / 100,
'DebitValue' => (substr($Line, 90, 1).substr($Line, 76, 14)) / 100,
'CreditValue' => (substr($Line, 105, 1).substr($Line, 91, 14)) / 100,
'SequenceNumber' => intval(substr($Line, 106, 3)),
'Date' => mktime(0, 0, 0, substr($Line, 111, 2), substr($Line, 109, 2), '20'.substr($Line, 113, 2)),
//'DataAlignment' => substr($Line, 115, 14),
'CheckSum' => sha1(md5($Line).$Line),
);
} else
if ($Type == GPC_TYPE_ITEM)
{
$GPCLine = array
(
'Type' => GPC_TYPE_ITEM,
'AccountNumber' => substr($Line, 4, 16),
'OffsetAccount' => substr($Line, 20, 16),
'RecordNumber' => substr($Line, 36, 13),
'Value' => substr($Line, 49, 12) / 100,
'Code' => substr($Line, 61, 1),
'VariableSymbol' => intval(substr($Line, 62, 10)),
'BankCode' => substr($Line, 74, 4),
'ConstantSymbol' => intval(substr($Line, 78, 4)),
'SpecificSymbol' => intval(substr($Line, 82, 10)),
'Valut' => substr($Line, 92, 6),
'ClientName' => substr($Line, 98, 20),
//'Zero' => substr($Line, 118, 1),
'CurrencyCode' => substr($Line, 119, 4),
'DueDate' => mktime(0, 0, 0, substr($Line, 125, 2), substr($Line, 123, 2), substr($Line, 127, 2)),
'CheckSum' => sha1(md5($Line).$Line),
);
} else $GPCLine = NULL;
return $GPCLine;
}
}
Přístup přes bankovní API
Fio banka od 6.11.2012 zprovoznila své bankovní API, díky kterému je možné standardizovanou formou vyčítat informace o pohybech na účtech. Export lze provést do formátů XML, OFX, GPC, CSV, HTML, JSON a MT940. Zde je použit formát GPC. Detailní popis API najdete v API_Bankovnictvi.pdf.
- Pro přístup přes API je nutno si vygenerovat v internetovém bankovnictví pro každý účet unikátní token.
- Kódování GPC exportu je Windows-1250, takže se provádí konverze kódování na UTF-8
Třída Fio v fio_api.php
<?php
include('gpc.php');
class FioAPI
{
public string $Token;
public string $Encoding;
function __construct()
{
$this->Encoding = 'utf-8';
}
function Import($TimeFrom, $TimeTo)
{
if ($this->Token == '') throw new Exception('Missing value for Token property.');
$fp = fsockopen('ssl://www.fio.cz', 443, $errno, $errstr, 30);
if (!$fp)
{
throw new Exception('Connection error: '.$errstr);
} else
{
// Send request
$RequestURL = '/ib_api/rest/periods/'.$this->Token.'/'.
date('Y-m-d', $TimeFrom).'/'.date('Y-m-d', $TimeTo).'/transactions.gpc';
$Request = "GET ".$RequestURL." HTTP/1.1\r\n";
$Request .= "Host: www.fio.cz\r\n";
$Request .= "User-Agent: PHP Script\r\n";
$Request .= "Content-Type: text/html\r\n";
$Request .= "Connection: Close\r\n\r\n";
fwrite($fp, $Request);
// Read response
$Response = array();
while (!feof($fp))
{
$Response .= trim(fgets($fp, 1024))."\n";
}
fclose($fp);
$Response = iconv('windows-1250', $this->Encoding, $Response);
$Response = explode("\n", $Response);
// Strip HTTP header
while ($Response[0] != '') array_shift($Response);
array_shift($Response); // Remove empty line
// Parse all GPC lines
$GPC = new GPC();
$Result = array();
foreach ($Response as $Index => $Line)
{
if (($Index == 0) and (substr($Line, 0, strlen(GPC_TYPE_REPORT)) != GPC_TYPE_REPORT)) $this->NoValidDataError($Response);
$GPCLine = $GPC->ParseLine($Line);
if ($GPCLine != NULL) $Result[] = $GPCLine;
}
return $Result;
}
}
function NoValidDataError(array $Response)
{
// Try to get error message
// If something go wrong fio show HTML login page and display error message
$Response = implode('', $Response);
$ErrorMessageStart = '<div id="oldform_warning">';
if (strpos($Response, $ErrorMessageStart) !== false)
{
$Response = substr($Response, strpos($Response, $ErrorMessageStart) + strlen($ErrorMessageStart));
$ErrorMessage = trim(substr($Response, 0, strpos($Response, '</div>')));
} else $ErrorMessage = '';
throw new Exception('No valid GPC data: '.$ErrorMessage);
}
}
Ukázka použití v demo_fio_api.php
<?php
include('fio_api.php');
$Fio = new FioAPI();
$Fio->Token = 'unikátní vygenerovaný token';
$Records = $Fio->Import(time() - 3600 * 24 * 31 * 2, time());
echo('<!DOCTYPE html>');
echo('<html><head><meta charset="utf-8"></head><body>');
echo('<table border="1">');
foreach ($Records as $Record)
{
echo('<tr>');
if ($Record['Type'] == GPC_TYPE_REPORT)
{
echo('<td>Jméno účtu: '.$Record['AccountName'].'</td>');
echo('<td>Číslo účtu: '.$Record['AccountNumber'].'</td>');
echo('<td>Ke dni '.date('j.n.Y', $Record['OldBalanceDate']).' je stav účtu '.$Record['OldBalanceValue'].' Kč</td>');
echo('<td>Ke dni '.date('j.n.Y', $Record['Date']).' je stav účtu '.$Record['NewBalanceValue'].' Kč</td>');
echo('<td>Suma příjmů: '.$Record['CreditValue'].' Kč</td>');
echo('<td>Suma výdajů: '.$Record['DebitValue'].' Kč</td>');
echo('</tr></table><br><br>');
echo('<table border="1"><tr>');
echo('<th>Datum</th>');
echo('<th>Částka</th>');
echo('<th>Účet protistrany</th>');
echo('<th>Kód banky</th>');
echo('<th>KS</th>');
echo('<th>VS</th>');
echo('<th>SS</th>');
echo('<th>Uživatelská identifikace</th>');
} else
if ($Record['Type'] == GPC_TYPE_ITEM)
{
echo('<td>'.date('j.n.Y', $Record['DueDate']).'</td>');
echo('<td>'.$Record['Value'].'</td>');
echo('<td>'.$Record['OffsetAccount'].'</td>');
echo('<td>'.$Record['BankCode'].'</td>');
echo('<td>'.$Record['ConstantSymbol'].'</td>');
echo('<td>'.$Record['VariableSymbol'].'</td>');
echo('<td>'.$Record['SpecificSymbol'].'</td>');
echo('<td>'.$Record['ClientName'].'</td>');
}
echo('</tr>');
}
echo('</table>');
echo('</body></html>');
Přístup přes přímé webové rozhraní
Přímý přístup byla jediná použitelná metoda v době, kdy neexistovalo samostatné bankovní API rozhraní. Data bylo možné získat ve formátu GPC, CSV nebo přímým rozkládáním HTML. Zde je použit export do formátu GPC.
- Kódování webu Fio je Windows-1250, takže se provádí konverze kódování na UTF-8
- Při zasílání formuláře se generuje aktuální čas pomocí funkce time() v parametru LOGIN_TIME podle času počítače, na kterém běží skript. Čas na vašem počítači musí být blízký času na Fio serveru. Tedy synchronizovaný přes NTP z internetu. Pokud je čas zpožděn o více než asi 3-5 minut, dojde ke zobrazení hlášení "Přihlašovací formulář byl již neplatný. Zkuste se přihlásit znovu".
Třída Fio v fio.php
<?php
include('gpc.php');
class Fio
{
public string $UserName;
public string $Password;
public string $Account;
public string $Encoding;
function __construct()
{
$this->Encoding = 'utf-8';
}
function Import($TimeFrom, $TimeTo)
{
if ($this->UserName == '') throw new Exception('Missing value for UserName property.');
if ($this->Password == '') throw new Exception('Missing value for Password property.');
if (!is_numeric($this->Account)) throw new Exception('Missing or not numeric value for Account property.');
$fp = fsockopen('ssl://www.fio.cz', 443, $errno, $errstr, 30);
if (!$fp)
{
throw new Exception('Connection error: '.$errstr);
} else
{
// Send request
$RequestURL = "/scgi-bin/hermes/dz-pohyby.cgi?ID_ucet=".$this->Account.
"&LOGIN_USERNAME=".$this->UserName."&SUBMIT=Odeslat&LOGIN_TIME=".time().
"&LOGIN_PASSWORD=".$this->Password."&pohyby_DAT_od=".date('d.m.Y', $TimeFrom).
"&pohyby_DAT_do=".date('d.m.Y', $TimeTo)."&export_gpc=1";
$Request = "GET ".$RequestURL." HTTP/1.1\r\n";
$Request .= "Host: www.fio.cz\r\n";
$Request .= "User-Agent: PHP Script\r\n";
$Request .= "Content-Type: text/html\r\n";
$Request .= "Connection: Close\r\n\r\n";
fwrite($fp, $Request);
// Read response
$Response = array();
while (!feof($fp))
{
$Response .= trim(fgets($fp, 1024))."\n";
}
fclose($fp);
$Response = iconv('windows-1250', $this->Encoding, $Response);
$Response = explode("\n", $Response);
// Strip HTTP header
while ($Response[0] != '') array_shift($Response);
array_shift($Response); // Remove empty line
// Parse all GPC lines
$GPC = new GPC();
$Result = array();
foreach ($Response as $Index => $Line)
{
if (($Index == 0) and (substr($Line, 0, strlen(GPC_TYPE_REPORT)) != GPC_TYPE_REPORT)) $this->NoValidDataError($Response);
$GPCLine = $GPC->ParseLine($Line);
if ($GPCLine != NULL) $Result[] = $GPCLine;
}
return $Result;
}
}
function NoValidDataError(array $Response)
{
// Try to get error message
// If something go wrong Fio show HTML login page and display error message
$Response = implode('', $Response);
$ErrorMessageStart = '<div id="oldform_warning">';
if (strpos($Response, $ErrorMessageStart) !== false)
{
$Response = substr($Response, strpos($Response, $ErrorMessageStart) + strlen($ErrorMessageStart));
$ErrorMessage = trim(substr($Response, 0, strpos($Response, '</div>')));
} else $ErrorMessage = '';
throw new Exception('No valid GPC data: '.$ErrorMessage);
}
}
Ukázka použití v demo_fio.php
<?php
include('fio.php');
$Fio = new Fio();
$Fio->Account = '123456789';
$Fio->UserName = 'user';
$Fio->Password = 'pass';
$Records = $Fio->Import(time() - 3600 * 24 * 31 * 2, time());
echo('<!DOCTYPE html>');
echo('<html><head><meta charset="utf-8"></head><body>');
echo('<table border="1">');
foreach ($Records as $Record)
{
echo('<tr>');
if ($Record['Type'] == GPC_TYPE_REPORT)
{
echo('<td>Jméno účtu: '.$Record['AccountName'].'</td>');
echo('<td>Číslo účtu: '.$Record['AccountNumber'].'</td>');
echo('<td>Ke dni '.date('j.n.Y', $Record['OldBalanceDate']).' je stav účtu '.$Record['OldBalanceValue'].' Kč</td>');
echo('<td>Ke dni '.date('j.n.Y', $Record['Date']).' je stav účtu '.$Record['NewBalanceValue'].' Kč</td>');
echo('<td>Suma příjmů: '.$Record['CreditValue'].' Kč</td>');
echo('<td>Suma výdajů: '.$Record['DebitValue'].' Kč</td>');
echo('</tr></table><br><br>');
echo('<table border="1"><tr>');
echo('<th>Datum</th>');
echo('<th>Částka</th>');
echo('<th>Účet protistrany</th>');
echo('<th>Kód banky</th>');
echo('<th>KS</th>');
echo('<th>VS</th>');
echo('<th>SS</th>');
echo('<th>Uživatelská identifikace</th>');
} else
if ($Record['Type'] == GPC_TYPE_ITEM)
{
echo('<td>'.date('j.n.Y', $Record['DueDate']).'</td>');
echo('<td>'.$Record['Value'].'</td>');
echo('<td>'.$Record['OffsetAccount'].'</td>');
echo('<td>'.$Record['BankCode'].'</td>');
echo('<td>'.$Record['ConstantSymbol'].'</td>');
echo('<td>'.$Record['VariableSymbol'].'</td>');
echo('<td>'.$Record['SpecificSymbol'].'</td>');
echo('<td>'.$Record['ClientName'].'</td>');
}
echo('</tr>');
}
echo('</table>');
echo('</body></html>');
Pokud něco nefunguje jak má
- Třídy jsou navrženy tak, aby při výskytu chyby vyvolaly výjimku. Pokud z popisu chyby není zřejmá příčina, je potřeba chybu ladit a do kódu přidávat dočasně ladící výpisy. Především ze zobrazení obsahu načítané stránky z webu Fio by mělo vyplynout odkud vítr vane.