Kontakt na PC SERVIS:
EO Computers - EO.CZ
V. Kl. Klicpery 715
50401 Nový Bydžov

Telefon606 622 826

EET implementace v PHP

Rád bych se podělil o funkční PHP skript pro odeslání EET účtenky.

Použil jsem volně dostupnou ukázku od Davida Spilky, který udělal skutečně skvělou práci - odkaz, ale skript mi bohužel nefungoval. Několik hodin jsem bojoval s opakující se chybou: Chyba : 3 - XML zpráva nevyhověla kontrole XML schématu.

Další nevýhodou bylo, že skript požaduje mít převedené certifikáty na PEM a KEY. To mi přišlo zbytečně složité. Podařilo se mi tedy skript doplnit o převod z P12 a níže uvádím funkční verzi, která vrací FIK kód. Požaduje pouze p12 certifikát a jeho heslo.

Abyste si mohli ukázku vyzkoušet, pak si stáhněte sadu certifikátu z odkazu http://www.etrzby.cz/cs/technicka-specifikace (EET_CA1_Playground_v1.zip). Z tohoto souboru použijte certifikát EET_CA1_Playground-CZ1212121218.p12 (ten jsem si uložil do složky eet_cert/eet.p12), heslo  k němu je 'eet'.

Pozn.: na serveru potřebujete verzi PHP 5.4.4 a vyšší.

Celý skript si můžete zkopírovat zde:

<?
$certs = [];
$pkcs12 = file_get_contents("eet_cert/eet.p12");

if (!extension_loaded('openssl') || !function_exists('openssl_pkcs12_read')) {
echo("Rozsireni OpenSSL neni dostupne.");
exit;
}

$openSSL = openssl_pkcs12_read($pkcs12, $certs, 'eet'); //heslo
if(!$openSSL)
{
echo("Certifikat se nepodarilo vyexportovat.");
exit;
}

date_default_timezone_set("Europe/Prague");
$dir=dirname($_SERVER["SCRIPT_FILENAME"]);

$eet['url']='https://pg.eet.cz/eet/services/EETServiceSOAP/v3'; // playground
$eet['key']=$certs['pkey'];

$tmp=$certs['cert'];
$tmp=explode('CERTIFICATE-----',$tmp);
$tmp=explode('-----END',$tmp[1]);
$data["certb64"]=$tmp[0];

$bodyTemplate='<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="TheBody" xml:id="TheBody"><Trzba xmlns="http://fs.mfcr.cz/eet/schema/v3"><Hlavicka @{dat_odesl} @{overeni} @{prvni_zaslani} @{uuid_zpravy}></Hlavicka><Data @{celk_trzba} @{cerp_zuct} @{cest_sluz} @{dan1} @{dan2} @{dan3} @{dat_trzby} @{dic_popl} @{dic_poverujiciho} @{id_pokl} @{id_provoz} @{porad_cis} @{pouzit_zboz1} @{pouzit_zboz2} @{pouzit_zboz3} @{rezim} @{urceno_cerp_zuct} @{zakl_dan1} @{zakl_dan2} @{zakl_dan3} @{zakl_nepodl_dph}></Data><KontrolniKody><pkp cipher="RSA2048" digest="SHA256" encoding="base64">${pkp}</pkp><bkp digest="SHA1" encoding="base16">${bkp}</bkp></KontrolniKody></Trzba></soap:Body>';

$signatureTemplate='<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="soap"></ec:InclusiveNamespaces></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></ds:SignatureMethod><ds:Reference URI="#TheBody"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></ds:DigestMethod><ds:DigestValue>${digest}</ds:DigestValue></ds:Reference></ds:SignedInfo>';

$requestTemplate='<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="TheCert">${certb64}</wsse:BinarySecurityToken><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="TheSignature">'.$signatureTemplate.'<ds:SignatureValue>${signature}</ds:SignatureValue><ds:KeyInfo Id="TheKeyInfo"><wsse:SecurityTokenReference wsu:Id="TheSecurityTokenReference"><wsse:Reference URI="#TheCert" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature></wsse:Security></SOAP-ENV:Header>${soap_body}</soap:Envelope>';


// priprav si data pro uctenku
$data["dat_odesl"]='';
$data["prvni_zaslani"]='true';
$data["uuid_zpravy"]='';

$data["dic_popl"]='CZ1212121218'; //DIC ponechte, aby Vam ukazka s danym certifikatem fungovala.
$data["id_provoz"]='11';
$data["id_pokl"]='1';
$data["porad_cis"]='1';
$data["dat_trzby"]='';
$data["celk_trzba"]=price(100);
$data["rezim"]='0';
$data["pkp"]='';
$data["bkp"]='';

// generuj datumy
$data["dat_odesl"]=date("c");
if (empty($data["dat_trzby"])) $data["dat_trzby"]=date("c");

if (empty($data["uuid_zpravy"])) $data["uuid_zpravy"]=uuid_v4();// vypočti PKP a BKP
$pkpInput=$data["dic_popl"].'|'.$data["id_provoz"].'|'.$data["id_pokl"].'|'.$data["porad_cis"].'|'.$data["dat_trzby"].'|'.$data["celk_trzba"];
openssl_sign($pkpInput, $signature, $eet['key'], 'SHA256');
$data["pkp"]=base64_encode($signature);
$data["bkp"]=BKB(sha1($signature));

// sestav tělo soap zprávy
$data["soap_body"]=replaceData($bodyTemplate,$data);

// vypočti digest
$data["digest"] = base64_encode(hash('sha256',$data["soap_body"],true));

// sestav podpisovou část a podepiš
$signatureFinal=replaceData($signatureTemplate,$data);
openssl_sign($signatureFinal, $signature, $eet['key'], 'SHA256');
$data["signature"]=base64_encode($signature);

// sestav finální XML zprávu pro EET
$xmlFinal=replaceData($requestTemplate,$data);

// Odešli účtenku
$opts = array(
'http' => array(
'method' => 'POST',
'header' => "Content-Type: text/xml;charset=UTF-8\r\nSOAPAction: http://fs.mfcr.cz/eet/OdeslaniTrzby",
'content' => $xmlFinal
)
);
$context=stream_context_create($opts);
$result=file_get_contents($eet['url'], false, $context);


echo"<textarea rows=80 cols=160>$result</textarea>";


function uuid_v4(){
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0x0fff)|0x4000,mt_rand(0,0x3fff)|0x8000,mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff));
}

function price($value)
{
return number_format($value, 2, '.', '');
}

function BKB($code){
$r='';
for ($i=0;$i<40;$i++)
{
if ($i%8==0&&$i!=0) $r.= '-';
$r.=$code[$i];
}
return $r;
}

function replaceData($template,$data){
foreach ($data as $key => $value) {
$template=str_replace("\${".$key."}",$value,$template);
$template=str_replace("@{".$key."}","$key=\"$value\"",$template);
}
// odstraň prázdná pole
$template=preg_replace("/\\$\\{[a-z_0-9:]+\\}/","",$template);
$template=preg_replace("/ @\\{[a-z_0-9:]+\\}/","",$template);
return $template;
}

?>

Veškeré zásluhy budiž připsány výše zmíněnému Davidu Spilkovi, kterému tímto děkuji.

EO.CZ - nabízíme EET pokladny. Máme důkladně otestovanou a do malých provozoven doporučujeme jednoduchou pokladnu XPOS CHD 3050: https://www.eo.cz/RXEPR03001S-x-pos-registracni-pokladna-chd3050.html


Autor článku: Ing. Marián Hudec - EO Computers - EO.CZ

Zde můžete okomentovat článek nebo nám nechat vzkaz:

Další články

Bezplatný upgrade na Windows 10 Bezplatný upgrade na Windows 10

Modrá obrazovka (blue screen) chybové kódy Modrá obrazovka (blue screen) chybové kódy

Jak se připojit na router Jak se připojit na router

Jak nastavit domovskou stránku v prohlížeči Jak nastavit domovskou stránku v prohlížeči

Jak nastavit heslo na WiFi Jak nastavit heslo na WiFi

Jak odinstalovat Windows 10 Jak odinstalovat Windows 10

Jak otestovat baterii v notebooku Jak otestovat baterii v notebooku

Jak otestovat flash disk Jak otestovat flash disk

Jak otestovat HDD Jak otestovat HDD

Jak otestovat paměti Jak otestovat paměti

Jak otestovat grafickou kartu Jak otestovat grafickou kartu

Jak připojit tablet k internetu Jak připojit tablet k internetu

Jak rozbalit soubor RAR Jak rozbalit soubor RAR

Jak vytvořit recovery partition (záchranný oddíl) Jak vytvořit recovery partition (záchranný oddíl)

Jak zjistit heslo na WiFi (WEP, WPA) Jak zjistit heslo na WiFi (WEP, WPA)

Kabely USB Type-C - přehled Kabely USB Type-C - přehled

Výměna displeje Výměna displeje

LCD technologie (TN, IPS, MVA, PVA) LCD technologie (TN, IPS, MVA, PVA)

Nejlepší ATX zdroj do 700 Kč Nejlepší ATX zdroj do 700 Kč

Jak vypnout notifikaci "Stáhnout si Windows 10" Jak vypnout notifikaci "Stáhnout si Windows 10"

Odblokování telefonů (hard reset) Odblokování telefonů (hard reset)

Originální nebo repasované tonery? Originální nebo repasované tonery?

Politý notebook. Co dělat? Politý notebook. Co dělat?

Prasklý displej u tabletu Prasklý displej u tabletu

Jak prodloužit podporu XP do roku 2019? Jak prodloužit podporu XP do roku 2019?

Recenze na čtečku knih Amazon Kindle Paperwhite Recenze na čtečku knih Amazon Kindle Paperwhite

Obnova systému v notebooku pomocí recovery key Obnova systému v notebooku pomocí recovery key

Windows 8 start (jak přidat start menu) Windows 8 start (jak přidat start menu)

Jak zálohovat data? Zálohujte pomocí Cobian Backup. Jak zálohovat data? Zálohujte pomocí Cobian Backup.

Zapnutí NumLock při startu (LogOn) Zapnutí NumLock při startu (LogOn)


Pošlete nám dotaz:


TOPlist