PHP okénko: Kontrola e-mailové adresy

Jakub Vrána 5. 5. 2006

Často po uživateli chceme, aby zadal svou e-mailovou adresu. Tuto adresu lze kontrolovat podle různých kritérií. Pro účely tohoto článku bude za e-mailovou adresu považován řetězec uživatel@doména, který obvykle chceme po uživateli zadat, a ne mnohem komplexnější řetězec, který lze zadat do hlaviček From, To a dalších.

Syntaktická kontrola

V první řadě tu máme syntaktickou kontrolu. Na webu najdete spoustu pokusů, jak tuto kontrolu provádět, já sám jsem se na jedné podílel (příklad), ale dodatečně jsem v ní stejně našel chybu. Proto uvádím řešení, o kterém si aktuálně myslím, že je správné:

<?php
/** Kontrola e-mailové adresy
* @param string $email e-mailová adresa
* @return bool syntaktická správnost adresy
*/
function check_email($email)
{
    $atom = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]'; // znaky tvořící uživatelské jméno
    $domain = '[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])'; // jedna komponenta domény
    return eregi("^$atom+(\\.$atom+)*@($domain?\\.)+$domain\$", $email);
}
?> 

Ověření, zda adresa přijímá zprávy

Dále je možné kontrolovat, zda uvedená doména přijímá e-maily, což zjistí třeba funkce checkdnsrr. Podle RFC 2821 sice doména může poštu přijímat i bez MX záznamu, ale nebývá to zvykem.

Dále je možné server oťukat a zjistit, zda e-mail přijme. To je asi nejdůkladnější automatické řešení:

<?php
/** Ověření funkčnosti e-mailu
* @param string $email adresa příjemce
* @param string $from adresa odesílatele
* @return bool na adresu lze doručit zpráva, null pokud nejde ověřit
*/
function try_email($email, $from)
{
    if (!function_exists('getmxrr')) {
        return null;
    }
    $domain = preg_replace('~.*@~', '', $email);
    getmxrr($domain, $mxs);
    if (!in_array($domain, $mxs)) {
        $mxs[] = $domain;
    }
    $commands = array(
        "HELO " . preg_replace('~.*@~', '', $from),
        "MAIL FROM: <$from>",
        "RCPT TO: <$email>",
    );
    foreach ($mxs as $mx) {
        $fp = @fsockopen($mx, 25);
        if ($fp && substr($s = fgets($fp), 0, 3) == '220') {
            while ($s{3} == '-') {
                $s = fgets($fp);
            }
            foreach ($commands as $command) {
                fwrite($fp, "$command\r\n");
                if (substr($s = fgets($fp), 0, 3) != '250') {
                    return false;
                }
                while ($s{3} == '-') {
                    $s = fgets($fp);
                }
            }
            return true;
        }
    }
    return false;
}
?> 

Toto řešení ale pochopitelně nebude fungovat u serverů aplikujících greylisting.

widgety

Ověření, zda má uživatel adresu pod kontrolou

Pokud zároveň chceme ověřit, že má uživatel adresu pod kontrolou, musíme mu poslat zprávu:

<?php
/** Vygenerování náhodného řetězce
* @param int [$count] délka vráceného řetězce
* @param int [$chars] použité znaky: <=10 číslice, <=36 +malá písmena, <=62 +velká písmena
* @return string náhodný řetězec
*/
function rand_chars($count = 8, $chars = 36) {
    $return = "";
    for ($i=0; $i < $count; $i++) {
        $rand = rand(0, $chars - 1);
        $return .= chr($rand + ($rand < 10 ? ord('0') : ($rand < 36 ? ord('a') - 10 : ord('A') - 36)));
    }
    return $return;
}

$rand_chars = rand_chars();
if (mysql_query("INSERT INTO emaily (email, rand_chars) VALUES ('$_POST[email]', '$rand_chars')")) {
    $zprava = "Pokud máte zájem o služby serveru $_SERVER[SERVER_NAME], tak prosím navštivte tento odkaz:
http://$_SERVER[SERVER_NAME]/email_overit.php?id=" . mysql_insert_id() . "&rand_chars=$rand_chars
Pokud o služby serveru zájem nemáte, tak tuto zprávu prosím ignorujte.";
    $hlavicky = "MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit";
    mail($_POST["email"], "Overeni adresy", $zprava, $hlavicky);
}

// email_overit.php:
mysql_query("UPDATE emaily SET overeno = 1 WHERE id = '$_GET[id]' AND rand_chars = '$_GET[rand_chars]'");
?> 

Závěr

Záleží jen na vás, jak moc důkladně chcete kontrolu e-mailové adresy provádět. Nejčastěji se používají krajní varianty – buď pouhá syntaktická kontrola, nebo ověření, zda má uživatel adresu pod kontrolou.

Našli jste v článku chybu?
Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

DigiZone.cz: Digi2GO u Alza.cz a s balíčkem Sport zdarma

Digi2GO u Alza.cz a s balíčkem Sport zdarma

Vitalia.cz: Voda z Vltavy před a po úpravě na pitnou

Voda z Vltavy před a po úpravě na pitnou

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

Podnikatel.cz: Znáte už 5 novinek k #EET

Znáte už 5 novinek k #EET

Podnikatel.cz: Dva měsíce na EET. Budou stačit?

Dva měsíce na EET. Budou stačit?

Lupa.cz: Hackeři mají data z půlmiliardy účtů Yahoo

Hackeři mají data z půlmiliardy účtů Yahoo

Vitalia.cz: 5 důvodů, proč jet na výlov rybníka

5 důvodů, proč jet na výlov rybníka

Lupa.cz: Aukro.cz mění majitele. Vrací se do českých rukou

Aukro.cz mění majitele. Vrací se do českých rukou

Vitalia.cz: Když všichni seli řepku, on vsadil na dýně

Když všichni seli řepku, on vsadil na dýně

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Podnikatel.cz: Kalousek chce odklad EET. Předvolební tah?

Kalousek chce odklad EET. Předvolební tah?

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

DigiZone.cz: Ginx TV: pořad o počítačových hráčích

Ginx TV: pořad o počítačových hráčích

Vitalia.cz: Muž, který miluje příliš. Ženám neimponuje

Muž, který miluje příliš. Ženám neimponuje

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

120na80.cz: Hrbatá prsa aneb mýty o implantátech

Hrbatá prsa aneb mýty o implantátech

Podnikatel.cz: Takhle se prodávají mražené potraviny

Takhle se prodávají mražené potraviny