Č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:
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.
Diskuse je zrušena z důvodu spamu.