Eurotel SMS

Článek vyšel v rámci PHP okénka na serveru Root.cz.

Eurotel má na svých stránkách SMS bránu sloužící k posílání esemesek zdarma. Brána je kvůli případnému zneužití chráněna jednoduchým Turingovým testem – uživatel musí opsat text ze zobrazeného obrázku. Já bránu zneužívat nehodlám, ale otravuje mě opisování textu z obrázku a navíc na něj často zapomínám. Proto jsem si napsal skriptík, který text z obrázku opíše za mě.

Nejprve si ujasněme, jak celé rozhraní funguje:

  1. Při přístupu na stránku SMS brány se nastaví cookie.
  2. Na základě této cookie se stáhne obrázek.
  3. Při odeslání zprávy metodou POST se podle cookie ověří, jestli byl zadán správný kód.

Z toho plyne, že na vyřešení úkolu budeme potřebovat tři schopnosti: přijímat a odesílat cookies, odesílat formulářová data metodou POST a zpracovávat obrázky. S využitím funkce fsockopen se první dva problémy dají se znalostí protokolu HTTP vyřešit i v PHP 4, mnohem pohodlnější řešení ale nabízí PHP 5 díky podpoře kontextů. Načrtněme si tedy, jak bude kód vypadat:

<?php
/** Poslání SMS na Eurotel
* @param int devítimístné telefonní číslo
* @param string text zprávy dlouhý maximálně 60 znaků
* @return null vypíše stránku s informací o výsledku
*/
function eurotel_sms($cislo, $zprava) {
    // získání cookies
    $fp = fopen("http://www2.eurotel.cz/sms/SMSGWChargingClient?action=edit&lang=cs", "r");
    $cookies = array();
    $meta_data = stream_get_meta_data($fp);
    foreach ($meta_data["wrapper_data"] as $val) {
        if (preg_match('~Set-Cookie: ([^;]+)~i', $val, $matches)) {
            $cookies[] = $matches[1];
        }
    }
    fclose($fp);
    $context = stream_context_create(array('http' => array('header' => "Cookie: " . implode("; ", $cookies) . "\r\n")));
    
    // získání obrázku
    $soubor = tempnam($_ENV["TEMP"], "eurotel");
    $obrazek = file_get_contents("http://www2.eurotel.cz/sms/SMSGWChargingClient?action=image", false, $context);
    file_put_contents($soubor, $obrazek);
    $code = eurotel_code($soubor);
    unlink($soubor);
    
    // potvrzení zprávy
    $content = array(
        "action=confirm", "reply=0", "replyEmail=", "intruder=0", "lang=cs",
        "ccndc=". urlencode("+420") . substr($cislo, 0, 3),
        "sn=" . substr($cislo, 3),
        "code=$code",
        "msgText=". urlencode($zprava),
    );
    $context_post = $context;
    stream_context_set_option($context_post, 'http', 'method', 'POST');
    stream_context_set_option($context_post, 'http', 'content', implode("&", $content));
    $fp = fopen("http://www2.eurotel.cz/sms/SMSGWChargingClient", "r", false, $context_post);
    fclose($fp);
    
    // odeslání zprávy
    readfile("http://www2.eurotel.cz/sms/SMSGWChargingClient?action=send&lang=cs", false, $context);
}
?>

V kódu je použito hned několik zajímavých funkcí: stream_get_meta_data, stream_context_create nebo tempnam. Hlavním obratem je ale využití dalších parametrů u běžných funkcí fopen, file_get_contents a readfile.

K implementaci zbývá funkce eurotel_code, která přeloží obrázek na řetězec. Univerzální řešení by samozřejmě bylo přes OCR, to ale není úplně jednoduché. Protože brána používá pouze omezenou množinu znaků, přišlo mi jednodušší si je vyzobat do souboru a jako zdroj pro překlad používat tento soubor. abeceda.png tedy obsahuje všechny používané znaky – nejprve čísla, pak písmena. Funkce eurotel_code načte tento soubor do jednotlivých znaků a následně načte obrázek s kódem a hledá v něm jednotlivé znaky.

<?php
/** Překlad kontrolního obrázku služby Eurotel SMS na text
* @param string název souboru s obrázkem
* @return string kontrolní kód
*/
function eurotel_code($image) {
    $chars = array();
    $im = imagecreatefrompng("abeceda.png");
    for ($index=0; $index < 36; $index++) {
        $pixels = array();
        for ($x=0; $x < 8; $x++) {
            for ($y=0; $y < 15; $y++) {
                $pixels[$x][$y] = imagecolorat($im, $x + 8*$index, $y);
            }
        }
        $chars[$index] = $pixels;
    }
    imagedestroy($im);
    
    $return = "";
    $im = imagecreatefromgif($image);
    for ($index=0; $index < 5; $index++) {
        $pixels = array();
        for ($x=0; $x < 8; $x++) {
            for ($y=0; $y < 15; $y++) {
                $pixels[$x][$y] = imagecolorat($im, $x + 8*$index, $y);
            }
        }
        $i = array_search($pixels, $chars);
        $return .= ($i < 10 ? $i : chr($i - 10 + ord('a')));
    }
    imagedestroy($im);
    
    return $return;
}
?>

K celkové funkčnosti uvedeného kódu chybí již jen soubor abeceda.png. Nezlobte se na mě, že ho nedám volně k dispozici, přeci jen si nemohu být jist tím, že by to někdo nezneužil pro nevyžádané rozesílání zpráv. Jako příklad ne zcela tradičního využití PHP ale příklad myslím posloužil dobře.

Jakub Vrána, Řešení problému, 4.4.2005, on-line

Diskuse

pif:

dobry, zkousel jsem pitvat oskara, nicmene, ten ma daleko slozitejsi algoritmus na zjisteni :))) kdo ho udela, tak je u me borec nejvetsi.
15.4.2005 17:20:40

ikona Jakub Vrána:

Podívej se do diskuse u článku na Rootu.
15.4.2005 17:25:42

Passss:

Jakube smim se jenom zeptat, jak asi vypadá jenom ten soubor abeceda.png nebo co obsahuje ?
23.4.2005 12:29:14

ikona Jakub Vrána:

V článku je uvedeno "abeceda.png obsahuje všechny používané znaky - nejprve čísla, pak písmena." Ale teď už to je stejně jedno, protože Eurotel způsob generování kódu změnil.
24.4.2005 12:47:43

Veronika:

Nejde mi na eurotelu odeslat zprava. Co s tim? Potvrzovaci kod pisu urcite spravne, ale porad mi to oznamuje chybne cookies!
17.7.2005 23:10:42

Ninja:

v nastaveni internet /ovladaci panely / uber cookes na minimum
30.9.2005 10:23:45

janek:

Pane vrana, podle vas se da vlastne zneuzit vse, to bych podle vas nemoh koupit poradny kuchynsky nuz, jelikoz by vlastne prodejce nemohl zajistit to, ze vas tim nozem neprobodnu, prodat auto, jelikoz bych vas s nim mohl prejet atd. vlastne bychom skoncili u pazourku, ale vlastne tim bych vam moh zapalit barak v nemz zijete, jako vymluva dobry... ale jen tak pro 50% obyvatelstva ti chytrejsi vi, ze je to od vas tezka komerce... jen za hotove!!!  janek
18.7.2005 19:37:44

ikona Jakub Vrána:

Bohužel vám příliš nerozumím. Pravděpodobně narážíte na nezpřístupnění souboru abeceda.png, který ale neposkytuji ani za peníze. Navíc si ho s určitou pílí mohl každý sestavit sám, do té doby, než Eurotel kontrolu kódu o něco ztížil.

V tomto článku mi šlo hlavně o technologii a je to tedy jakýsi http://en.wikipedia.org/wiki/Proof_of_concept, rozhodně nechci někoho poškozovat.
19.7.2005 00:07:17

michal:

muzu vas poprosit?? nemuzu posilat sms! chce to abzch si nastavil cookies! jak to mam udelat??
30.8.2005 12:07:22

ikona Jakub Vrána:

V prohlížeči si povolte cookies, případně se obraťte na podporu Eurotelu.
30.8.2005 12:54:00

michal:

ahoj dekuju ale potrebuju to trochu lepe popsat ja nejsem moc dobrej na tyhle veci
9.9.2005 19:22:22

Karča:

Dobry den,chtela bych se zeptat,co mam delat,kdyz mi nejde posilat SMS?Kod vyplnuji spravne a kdyz chci napsanou SMS odeslat,pise mi to tam cervene: Chybna cookie nebo pouziti cookies je vypnuto,co delam spatne?Dekuji predem za odpoved
7.10.2005 18:13:57

EDDY:

musis si v prohlizeci zapnou cokiee
27.10.2005 22:30:42

ruda:

a jak to mám prosímtě udělat,poraď prosím!!!!
25.2.2006 12:19:57

Zdenek:

Přejdi na Firefox,ten má automaticky cookies aktivní.Z
28.10.2006 20:41:16

ŠUŠU:

a kde je prosímvás ten prohlížeč?????prosím odpovězte... díky
2.10.2007 20:54:47

Paulí:

podle mě není na eurotel problém napsat sms:

<?php
$cislo
="123456789"; // telefoní číslo
$zprava="zprava"; // zpráva

$to = "+420$cislo@sms.eurotel.cz";
$extra = "From: Reply-To: ";
$subject = "";
$mess = $zprava;
mail ($to, $subject, $mess, $extra);
echo(
"<script> alert('SMS zprava byla uspesne odeslana.'); </script>");
?>
8.4.2008 19:55:00

Kory:

to je aspon reseni:-)
17.3.2011 13:39:39
avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.