PHP implementácia TatraPay a CardPay

V dnešnom príspevku nájdete jednoduchú PHP implementáciu TatraPay a CardPay od TatraBanky.

Implementácia sa skladá z troch tried. Trieda TatraBanka obsahuje deklaráciou premenných a metódy GetSign() na výpočet bezpečnostného kľúča zo zadaného reťazca. Z tejto triedy su odvodené triedy TatraPay a CardPay, ktoré implementujú konštruktor a metódy GetUrl(), ktorá vracia URL pre vykonanie platby a VerifyReply(), ktorá slúži na overenie odpovede z banky.

Triedy boli implementované podľa technických príručiek od TatraBanky. Príručky si môžete stiahnuť tu: TatraPay, CardPay.

Použitie je veľmi jednoduché. Presmerovanie na stránku TB pre vykonanie platby:

require('TatraBanka.class.php');

// parametre: suma, mena, VS, návratová URL
$objTP = new TatraPay('123.4', '978', '1234', 'http://www.example.com/');

header('Location: ' . $objTP->GetUrl());
exit;

Overenie odpovede z banky:

require('TatraBanka.class.php');

$objTP = new TatraPay();

if($objTP->VerifyReply()) {
     echo "Odpoveď je OK";
} esle {
     echo "Pozor odpoveď nie je platná!";
}

Spomínané triedy sú tu:

<?php
/*
 * Zakladna trieda pre triedy TatraPay a CardPay
 */
class TatraBanka {
        const KEY = 'tajny_kluc';
        const MID = '1234';

        const RSMS = ''; // cislo kam sa maju posielat SMS notifikacie o platbe
        const REM = ''; // mail kam sa maju posielat notifikacie o platbe

        /**
         * Suma. Max 13+2 číslic. Desatinná čiarka musí byť '.'
         * @var Float
         */
        protected $strAMT;                                     

        /**
         * Mena transakcie. Kód 978 je pre EURO.
         * @var String
         */
        protected $strCURR;                     

        /**
         * Variabilný symbol. Max 10 číslic.
         * @var String
         */
        protected $strVS;                   

        /**
         * Špecifický symbol - nepovinný. Max 10 číslic.
         * @var String
         */
        protected $strSS;                               

        /**
         * Konštantný symbol. Max 4 číslice.
         * @var String
         */
        protected $strCS;                   

        /**
         * Návratová URL
         * @var String
         */
        protected $strRURL;

        /**
         * Bezpečnostný podpis
         * @var String
         */
        protected $strSIGN;   

        /**
         * GetSign vracia bezpečnostný podpis zo zadaného reťazca
         * @param $str reťazec z ktorého sa vypočíta podpis
         * @return string
         */
        public function GetSign($str) {
                $strSIGN = sha1($str, true);
                $strSIGN = substr($strSIGN, 0, 8);
                $des = mcrypt_module_open(MCRYPT_DES, "", MCRYPT_MODE_ECB, "");

                $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($des), MCRYPT_RAND);
                mcrypt_generic_init($des, self::KEY, $iv);                        

                $strSIGN = mcrypt_generic($des, substr($strSIGN, 0, 8));
                mcrypt_generic_deinit($des);
                mcrypt_module_close($des);                              

                $strSIGN = strtoupper(bin2hex($strSIGN));
                return $strSIGN;
        }                                                

        protected function SanitizeFloat($flt) {
                return str_replace(',', '.', sprintf('%.2f', $flt));
        }
}                                                                   

/**
*       Trieda pre CardPay
*/
class TatraPay extends TatraBanka {
        /**
         * Constructor
         * @param $AMT suma
         * @param $CURR mena
         * @param $VS variabilný symbol
         * @param $RURL návratová URL
         * @return New TatraPay object
         */
        public function __construct($AMT = null, $CURR = null, $VS = null, $RURL = null, $SS = null, $CS = '0308') {
                $this->strAMT = $this->SanitizeFloat($AMT);
                $this->strCURR = $CURR;
                $this->strVS = $VS;
                $this->strRURL = $RURL;
                $this->strSS = $SS;
                $this->strCS = $CS;
                $this->strSS = $SS;                                                                                 

                $strSIGN = $this->GetSign(self::MID . $this->strAMT . $CURR . $VS . $CS . $RURL);
                $this->strSIGN = $strSIGN;
        }                                                                                        

        public function GetUrl() {
                $url = sprintf('https://moja.tatrabanka.sk/cgi-bin/e-commerce/start/e-commerce.jsp?PT=TatraPay&MID=%s&AMT=%s&CURR=%s&VS=%s&CS=%s&RURL=%s&SIGN=%s',
                        self::MID,
                        $this->strAMT,
                        $this->strCURR,
                        $this->strVS,
                        $this->strCS,
                        $this->strRURL,
                        $this->strSIGN
                );
                if(RSMS != '')
                        $url .= '&RSMS=' . self::RSMS;
                if(REM != '')
                        $url .= '&REM=' . self::REM;
                return $url;
        }                                                                                                                                                         

        public function VerifyReply() {
                if(!isset($_GET['VS']))
                        return false;
                if(!isset($_GET['RES']))
                        return false;
                if(!isset($_GET['SIGN']))
                        return false;
                $strToSign = $_GET['VS'] . $_GET['RES'];
                if($_GET['SIGN'] == $this->GetSign($strToSign)) {
                        return true;
                }
                return false;
        }
}                                                                

/**
 * Trieda pre CardPay
 */
class CardPay extends TatraBanka {
        /**
         * IP adresa klienta
         * @var String
         */
        protected $strIPC;        

        /**
         * Meno klienta
         * @var String
         */
        protected $strNAME;

        /**
         * Constructor
         * @param $AMT suma
         * @param $CURR mena
         * @param $VS variabilný symbol
         * @param $RURL návratová URL
         * @return new CardPay object
         */
        public function __construct($NAME = null, $AMT = null, $CURR = null, $VS = null, $RURL = null, $SS = null, $CS = '0308') {
                setlocale(LC_CTYPE, 'en_US.UTF-8');
                $this->strNAME = strtr(iconv('UTF-8', 'US-ASCII//TRANSLIT', $NAME), array("'" => ''));
                $this->strAMT = $this->SanitizeFloat($AMT);
                $this->strCURR = $CURR;
                $this->strVS = $VS;
                $this->strRURL = $RURL;
                $this->strSS = $SS;
                $this->strCS = $CS;                                                                                               

                if(array_key_exists('X_FORWARDED_FOR', $_SERVER)) {
                        $this->strIPC = $_SERVER['X_FORWARDED_FOR'];
                } else {
                        $this->strIPC = $_SERVER['REMOTE_ADDR'];
                }

                $strSIGN = $this->GetSign(self::MID . $this->strAMT . $this->strCURR . $this->strVS . $this->strCS . $RURL . $this->strIPC . $this->strNAME);
                $this->strSIGN = $strSIGN;
        }

        public function GetUrl() {
                $url = sprintf('https://moja.tatrabanka.sk/cgi-bin/e-commerce/start/e-commerce.jsp?PT=CardPay&MID=%s&AMT=%s&CURR=%d&VS=%s&CS=%s&RURL=%s&SIGN=%s&IPC=%s&NAME=%s',
                        self::MID,
                        $this->strAMT,
                        $this->strCURR,
                        $this->strVS,
                        $this->strCS,
                        $this->strRURL,
                        $this->strSIGN,
                        $this->strIPC,
                        urlencode($this->strNAME)
                );
                if(RSMS != '')
                        $url .= '&RSMS=' . self::RSMS;
                if(REM != '')
                        $url .= '&REM=' . self::REM;
                return $url;
        }

        public function VerifyReply() {
                if(!isset($_GET['VS']))
                        return false;
                if(!isset($_GET['RES']))
                        return false;
                if(!isset($_GET['SIGN']))
                        return false;
                if(!isset($_GET['AC']))
                        return false;
                $strToSign = $_GET['VS'] . $_GET['RES'] . $_GET['AC'];
                if($_GET['SIGN'] == $this->GetSign($strToSign)) {
                        return true;
                }
                return false;
        }
}

Ako vidíte tak implementácia je veľmi jednoduchá a nesnaží sa byť univerzálnym riešením. Ak by ste mali záujem o univerzálnu knižnicu a dokonca aj pre iné banky ako TatraBanka, tak môžete použiť knižnicu MONOGRAM EPayment.

Ak sa vám tento článok páčil, tak ho podporte na vybrali.sme.sk, alebo pozrisi.sk. Ďakujem.

Súvisiace články:

19 reakcií ku článku “PHP implementácia TatraPay a CardPay”

  1. Segey Says:

    Thank you, Man!
    Russian programmer =)

  2. JANATA Viktor Says:

    Naozaj slušný príspevok aj s dokumentáciou … čo na slovensku nebýva bežné :).

  3. misko Says:

    Ahoj,

    dakujem za uzitocnu kniznicu, no mam jednu otazku – pri implementacii ma po kliknuti na odkaz presmeruje na stranku TB kde je sprava

    Spojenie je zrušené. Maximálny čas nečinnosti (10 min.) bol prekročený.
    Session time-out.

    Podla overovacej stranky TB mam SIGN kluc vygenerovany spravne.. Nestretol si sa s podobnym problemom?

    A dalsia z mojich otazok je , na akej adrese je volany verify callback – ak som to spravne pochopil , RURL je stranka na ktoru bude uzivatel presmerovany po vykonani platby..

    Dakujem za odpoved,

    misko

  4. head Says:

    Cau,

    S tym timeoutom som sa nestretol. Nie som si isty preco ti to vyhadzuje. Bol si predtym ako si to testoval prihlaseny na stranke TB ? Sice by to na to asi nemalo mat vplyv, ale nic ine ma nenapada. Robi ti to pri oboch platbach, alebo len jednu z CardPay, alebo TatraPay ?

    Co sa tyka verifikacie, tak mas pravdu. RURL je stranka kam bude uzivatel presmerovany a na tej sa aj robi verifikacia. Tatrabanka ta presmeruje na RURL a ku nej prida parametre na overenie platby. Ty len vytvoris novu instanciu objektu podla typu platby a zavolas metodu VerifyReply().

  5. misko Says:

    Dakujem za rychlu odpoved – problem s timeoutom pravdepodobne spociva v case requestu, resp. ze tam existuje urcity offset v lokalnom case na strane TB voci mojmu serveru (to je take moje momentalne nepotvrdene podozrenie ktore potrebujem este overit), kedze web ktory vyvijam je hostovany v zahranici (USA).

    Co sa tyka callbacku – jedina informacia o spracovani platby je teda posielana len pri navrate na stranku merchanta? Tzn. ze info o platbe sa do systemu nedostane, pokial klient neklikne na “Pokracovat” na stranke TB? (ak teda nie je nastaveny automaticky redirect, alebo zavrie okno este pred redirectom)

    este raz dakujem za pomoc

  6. head Says:

    S časom by nemal byť problém, keďže sa nikde nepoužíva na generovanie SIGN… Tá chyba znamená, že predošlá session vytvorená pri návšteve stránky internet bankingu už nieje platná, ale prečo to robí to neviem.

    A s callbackom máš pravdu. Keď klient po zaplatení zavrie okno a nebude presmerovaný na tvoju stránku, tak ty sa nedozvieš (teda tvoj skript) o tom či prebehla platba. Preto je ešte vhodné nastaviť si SMS a mail notifikáciu.

  7. Marek Says:

    @misko: Tiež dostávam pri presmerovaní na cardpay/tatrapay session timeout aj napriek tomu že mám správne vypočítaný podpis. Podarilo sa Ti tento problém vyriešiť?

  8. head Says:

    Marek, dostavas ten timeout s mojou “kniznicou” ? Netusim kde by mohol byt problem a u mna to funguje…

  9. Marek Says:

    Nie, mám vlastnú implementáciu. Toto je jediný hit z googlu kde sa diskutuje o tejto chybe tak som dúfal že tu nájdem aj radu :) S tou session je to veľmi divné, určite som žiadnu session v internetbankingu nemal a nejde to ani v úplne novej session inej inštancie iného webbrowsera.

  10. stAn Says:

    Zdravim, mam ten isty problem “Spojenie je zrušené. Maximálny čas nečinnosti (10 min.) bol prekročený. Session time-out.” Pracujem s testovacimi udajmi, ale ani cez POST ani GET sa mi nedari dostat inu hlasku ako toto. Neupouzivam tb internet banking ani nic podobne, skusal som to vo vsetky prehliadacoch… vsetky vstupne data mam spravne. Vygeneroval som si SIGN a vytvoril formular v cistom html kode bez php a stale to iste… netusite nahodou kde je problem?

  11. Richard Says:

    Nazdar, mam ten isty problem Session time-out.

    Najde sa niekto, kto poradi ?

  12. Johny Says:

    Programoval som TatraPay a CardPay pre jeden e-commerce system, cize som nevychadzal z navodu vyssie, ale programoval som vlastne riesenie. Mozem iba potvrdit to, ze moduly sa spravaju na roznych domenach mojich klientov odlisne. Iba na jednom mi nabehne stranka pre vyzvu k uhrade. Na ostatnych “TatraPay Spojenie je zrušené. Maximálny čas nečinnosti (10 min.) bol prekročený.”

    Problem preto bude zreme na strane TB a asi ich tento problem nijako netrapi.

  13. general Says:

    Zdravim, potreboval by som pomoc s tym overenim pri navrate… Nerozumiem tej poslednej casti. Pouzivam CardPay a pri navrate mi banka vlastne posle SIGN a ta funkcia ho ma porovnat so SIGNom, ktory generovala moja stranka pri presmerovani na stranku TB? Nerozumiem co mam vlozit do tychto funkcii…

    $objTP = new CardPay();

    if($objTP->VerifyReply())
    {
    echo “Odpoveď je OK”;
    }
    else
    {
    echo “Pozor odpoveď nie je platná!”;
    }

  14. PrestaShop Plus Says:

    Hlasku
    “TatraPay Spojenie je zrušené. Maximálny čas nečinnosti (10 min.) bol prekročený.”
    obdrzite vzdy, ak skusate funkcnost modulu v ostrej prevadzke, avsak na strane banky este nebola sluzba pe dany obchod aktivovana.

    Treba sa najskor spojit s TB a nechat modul testovat pracovnikom Tatra banky. Po uspesnom teste banka aktivuje sluzbu pre dany obchod na svojej strane a vsetko zacne fungovat tak, ako ma.

  15. head Says:

    Vdaka za vysvetlenie. To je dovod, preco som ju nikdy nevidel… ;)

    Moze to niekto potvrdit, ze po aktivovani to uz funguje ok ?

  16. head Says:

    general: do tej funkcie netreba vkladat nic, ta funckia zoberie parametre z $_GET a verifikuje odpoved… to je vsetko

  17. general Says:

    Ano aj ja potvrdzujem, treba poziadat banku aby to pustila do ostrej prevadzky a potom to bude fungovat korektne. Vdaka head aj som si myslel :) len mi to pride take, ze keby to nebolo zabezpecne spojenie staci prepisat jednu premennu v url na OK…

  18. dendo Says:

    zdravim
    snazim sa o implementaciu podla navodu vytvoril som si jeden subor kde som vlozil to presmerovanie na banku.jeden soburo s tymi zakladnymi triedami ,len neviem kde mam umiestnit tu overenie odpovede z banky.
    mohli by ste mi nejako pomoct???
    dakujem

Reakcie z iných blogov

  1. Web stránka: kvety-online.sk – donáška kvetov a kytíc | Hlava bloguje -

Pridaj komentár