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.

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?
Podnikatel.cz: Kauza z Vinohrad pokračuje. Policie se omlouvá

Kauza z Vinohrad pokračuje. Policie se omlouvá

Podnikatel.cz: Youtuber? Za 15 tisíc dělat nebude

Youtuber? Za 15 tisíc dělat nebude

Lupa.cz: Co vzal čas: internetové kavárny a herny

Co vzal čas: internetové kavárny a herny

Měšec.cz: Investiční pasti. Děláte to, co ostatní, ale proděláváte

Investiční pasti. Děláte to, co ostatní, ale proděláváte

Root.cz: Tor možná 1. září zažije stávku

Tor možná 1. září zažije stávku

Měšec.cz: Udali ho na nelegální software a přišla Policie

Udali ho na nelegální software a přišla Policie

Měšec.cz: Se stavebkem k soudu už (většinou) nemusíte

Se stavebkem k soudu už (většinou) nemusíte

Měšec.cz: Kurzy platebních karet: vyplatí se platit? (TEST)

Kurzy platebních karet: vyplatí se platit? (TEST)

Vitalia.cz: Za její cukrovkou stojí rodiče

Za její cukrovkou stojí rodiče

Podnikatel.cz: Novela zákoníku práce. Řeší homeworking

Novela zákoníku práce. Řeší homeworking

Měšec.cz: Co s reklamací, když e-shop krachuje?

Co s reklamací, když e-shop krachuje?

Vitalia.cz: Je bílý kokos fakt tak úžasný? Ano, je!

Je bílý kokos fakt tak úžasný? Ano, je!

Měšec.cz: Platíme NFC mobilem. Konečně to funguje!

Platíme NFC mobilem. Konečně to funguje!

Lupa.cz: Samořídicí taxíky jsou tu. Začíná s nimi Uber

Samořídicí taxíky jsou tu. Začíná s nimi Uber

120na80.cz: Kam umístit silikony?

Kam umístit silikony?

120na80.cz: Víte, co je svobodná menstruace?

Víte, co je svobodná menstruace?

Měšec.cz: Do ostravské MHD bez jízdenky. Stačí karta

Do ostravské MHD bez jízdenky. Stačí karta

Podnikatel.cz: OSA zdraží, ale taky přidá nový poplatek

OSA zdraží, ale taky přidá nový poplatek

Lupa.cz: Elektronika tajemství zbavená. Jak s ní začít?

Elektronika tajemství zbavená. Jak s ní začít?

Vitalia.cz: Koukám, co bych dobrého snědla, abych zhubla

Koukám, co bych dobrého snědla, abych zhubla