PHP'de bir e-posta adresi nasıl doğrulanır


218

Bir e-posta adreslerini doğrulamak için bu işlevi var:

function validateEMAIL($EMAIL) {
    $v = "/[a-zA-Z0-9_-.+]+@[a-zA-Z0-9-]+.[a-zA-Z]+/";

    return (bool)preg_match($v, $EMAIL);
}

E-posta adresinin geçerli olup olmadığını kontrol etmek uygun mudur?


1
Çalışırsa çalışır. Gerçekten daha iyisini yapamazsın, çok küçük. İyi olmayan tek şey stil. validateEmailcorret olurdu, geçerken $emaildeğil $EMAIL.
Stan

Sadece kodda herhangi bir büyük sorun yoktu emin olmak istedim :)
Cameron

Ayrıca bkz stackoverflow.com/questions/201323/... hakkında daha fazla bilgi için nasıl ve ne kadar değil doğrulamak e-posta adreslerine normal ifadeler kullanmak.
legoscia

5
Bu, birçok geçerli e-posta adresini doğrulayamaz. Örneğin *@example.com veya'@example.com veya ben @ [127.0.0.1] veya siz [[ipv6: 08B0: 1123: AAAA :: 1234]
jcoder 28:12

7
@jcoder, o regex tavsiye ediyorum, ama :) başarısız olduğunda şikayet olmaz yukarı vb sing için en azından böyle adreslerini kullanan herkesin umut değil
Halil Özgür

Yanıtlar:


569

Bir e-posta adresinin iyi biçimlendirilmiş olup olmadığını kontrol etmenin en kolay ve en güvenli yolu bu filter_var()işlevi kullanmaktır :

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    // invalid emailaddress
}

Ayrıca, alan adının bir MXkayıt tanımlayıp tanımlamadığını da kontrol edebilirsiniz :

if (!checkdnsrr($domain, 'MX')) {
    // domain is not valid
}

Ancak bu hala postanın var olduğunu garanti etmez. Bunu öğrenmenin tek yolu bir onay postası göndermektir.


Artık kolay cevabınız var, öğrenmeye ya da sadece hızlı cevabı kullanmaya devam ederseniz e-posta adresi doğrulaması hakkında okumaktan çekinmeyin. Alınmadım.

Normal ifade kullanarak bir e-posta adresini doğrulamaya çalışmak "imkansız" bir iştir. Yaptığınız regex'in işe yaramaz olduğunu söyleyecek kadar ileri gideceğim. E-posta adresleri ve yanlış e-posta adreslerini yakalamak için bir regex yazmakla ilgili üç rfc vardır ve aynı zamanda yanlış pozitifleri yoktur, hiçbir ölümcül yapamaz. PHP'nin işlevi tarafından kullanılan normal ifadenin testleri (başarısız ve başarılı) için bu listeye göz atın filter_var().

Yerleşik PHP işlevleri, e-posta istemcileri veya sunucuları bile doğru yapmaz. Yine de çoğu durumda filter_varen iyi seçenektir.

PHP'nin (şu anda) e-posta adreslerini doğrulamak için hangi normal ifade modelini kullandığını bilmek istiyorsanız PHP kaynağına bakın .

E-posta adresleri hakkında daha fazla bilgi edinmek istiyorsanız, özellikleri okumaya başlamanızı öneririm, ancak sizi uyarmak zorundayım, herhangi bir streçle kolay bir okuma değil:

filter_var()Zaten belirtildiği gibi sadece PHP 5.2'den beri mevcut olduğunu unutmayın . PHP'nin önceki sürümleriyle çalışmasını istiyorsanız, PHP'de kullanılan normal ifadeyi kullanabilirsiniz:

<?php

$pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';

$emailaddress = 'test@gmail.com';

if (preg_match($pattern, $emailaddress) === 1) {
    // emailaddress is valid
}

PS Yukarıda kullanılan normal ifade modeliyle ilgili bir not (PHP kaynağından). Görünüşe göre Michael Rushton'ın üzerinde bazı telif hakları var . Belirtildiği gibi: "Bu kodu kullanmaktan ve yeniden dağıtmaktan çekinmeyin. Lütfen bu telif hakkı bildirimini saklayın."


İyi cevap, ancak bu bağlantıya göre: haacked.com/archive/2007/08/21/… yerel olarak bir parçanın kullanıcı adı tırnak içine alınabilir, ancak FILTER_VALIDATE_EMAIL bunu kabul etmez.
Daniel De León

3
Belirtildiği gibi tüm e-posta adresleri için çalışmaz . Ayrıca, alıntı yapılan bazı dizelerin işe yaradığını ve diğerlerinin çalışmadığını görmek için cevabımdaki başarısız testlerin listesine bakın.
PeeHaa

4
Hayır, bu model üzerinde çok fazla başarısız test yapıldı emailtester.pieterhordijk.com/test-pattern/MTAz :-)
PeeHaa

1
Bu kalıp, içinde e-posta bulunan büyük metin dizesi üzerinde "preg_match_all" gibi bir işlevle kullanmanız gerektiğinde son derece karmaşıktır. İçinizden herhangi biri daha basitse lütfen paylaşın. Yani eğer isterseniz: preg_match_all ($ pattern, $ text_string, $ match); eğer gerçekten büyük metinleri ayrıştırmanız gerekirse bu karmaşık desen sunucuyu aşırı yükler.
Vlado

4
@PeeHaa: Postfix 3.0 neredeyse iki yıldır destekliyor: postfix.org/SMTPUTF8_README.html ve Ubuntu 16.04'e dahil edildi ve örneğin bir sonraki Debian sürümüne dahil edilecek. Exim'in deneysel desteği var. Gmail gibi web posta sağlayıcıları da henüz bu tür e-postaları gönderme / alma desteği eklemiştir, ancak henüz unicode hesaplar oluşturamazsınız. Yaygın kullanım ve destek erişilebilir ve filter_varşu anda değiştirseler bile oldukça uzun bir süre geride kalacak (bir hata raporu yayınladım).
iquito

43

Bunun için filter_var kullanabilirsiniz .

<?php
   function validateEmail($email) {
      return filter_var($email, FILTER_VALIDATE_EMAIL);
   }
?>

1
etki alanlarını doğrulamadığı için bu işlevi eklemeyi bırakın. @ adresi ekliyorsanız bu geçerlidir. ve değil!
Herr Nentu '11

Bir satır işlevi içeren tek satır işlevlerinin tümü nedir? Onları her yerde görüyorum. Bu ne zaman bir "şey" haline geldi? (söylem). Bunun durması gerekiyor.
Blue Water

15

Deneyimlerime göre, regexçözümlerin çok fazla yanlış pozitifleri var ve filter_var()çözümlerin yanlış negatifleri var (özellikle tüm yeni TLD'lerde ).

Bunun yerine, adresin bir e-posta adresinin gerekli tüm parçalarına (kullanıcı, "@" sembolü ve etki alanı) sahip olduğundan emin olmak, ardından alan adının var olduğunu doğrulamak daha iyidir.

Harici bir etki alanı için bir e-posta kullanıcısının olup olmadığını belirlemenin (sunucu tarafı) bir yolu yoktur.

Bu, bir Utility sınıfında oluşturduğum bir yöntemdir:

public static function validateEmail($email)
{
    // SET INITIAL RETURN VARIABLES

        $emailIsValid = FALSE;

    // MAKE SURE AN EMPTY STRING WASN'T PASSED

        if (!empty($email))
        {
            // GET EMAIL PARTS

                $domain = ltrim(stristr($email, '@'), '@') . '.';
                $user   = stristr($email, '@', TRUE);

            // VALIDATE EMAIL ADDRESS

                if
                (
                    !empty($user) &&
                    !empty($domain) &&
                    checkdnsrr($domain)
                )
                {$emailIsValid = TRUE;}
        }

    // RETURN RESULT

        return $emailIsValid;
}

Neverbounce, API'larının% 97 oranında teslimatı doğrulayabildiğini iddia ediyor. Tabii ki kişiler veritabanınızı teslim etmenin sakıncası yoksa.
Tom Russell

stristrbirden fazla @ işareti varsa alan adını alamaz. Daha iyi explode('@',$email)ve kontrolsizeof($array)==2
Aaron Gillion

@AaronGillion Etki alanı parçalarını elde etmenin daha iyi bir yolu kadar doğru olsanız da checkdnsrr(), etki alanında bir @ işareti olsaydı yöntem yine de false döndürür.
Jabari

11

Bu özel durumda PHP'nin dahili filtrelerini kullanarak daha iyi olabileceğini düşünüyorum :

FILTER_VALIDATE_EMAILParam ile birlikte sağlandığında doğru veya yanlış döndürebilir .


9

Bu yalnızca e-postanızı doğrulamakla kalmaz, aynı zamanda beklenmedik karakterler için dezenfekte eder:

$email  = $_POST['email'];
$emailB = filter_var($email, FILTER_SANITIZE_EMAIL);

if (filter_var($emailB, FILTER_VALIDATE_EMAIL) === false ||
    $emailB != $email
) {
    echo "This email adress isn't valid!";
    exit(0);
}

4

Bunu e-posta doğrulaması hakkında 'en iyi soru' bölümünde yanıtladı https://stackoverflow.com/a/41129750/1848217

Benim için e-postaları kontrol etmenin doğru yolu:

  1. @ Simgesinin var olduğunu ve ondan önce ve sonra @ olmayan semboller olduğunu kontrol edin: /^[^@]+@[^@]+$/
  2. Bu adrese "etkinleştirme kodu" içeren bir e-posta göndermeyi deneyin.
  3. Kullanıcı e-posta adresini "etkinleştirdiğinde" her şeyin doğru olduğunu göreceğiz.

Tabii ki, kullanıcı "garip" e-posta yazdığında, alan adı bölümünde nokta veya isim vermeden boşluklar gibi yaygın hatalardan kaçınmasına yardımcı olmak için ön uçta bazı uyarı veya ipucu gösterebilirsiniz. Ancak kullanıcı gerçekten istiyorsa "merhaba @ dünya" adresini kabul etmelisiniz.

Ayrıca, e-posta adresi standardının olduğunu ve gelişebileceğini de unutmamalısınız, bu nedenle "standart-geçerli" normal ifadeyi bir kez ve her zaman yazamazsınız. Bazı somut internet sunucularının ortak standartların bazı detaylarında başarısız olabileceğini ve aslında kendi "değiştirilmiş standart" ile çalışabileceğini unutmamalısınız.

Yani, @ işaretleyin, ön uçtaki kullanıcıyı işaretleyin ve verilen adrese doğrulama e-postaları gönderin.


1
Normal ifadeniz bunu kontrol eder @, ancak e-postayı yöneten RFC'lerden herhangi biri için geçerli olup olmadığını gerçekten kontrol etmez. Yazıldığı gibi çalışmaz. Regex101.com üzerinden koştum ve geçerli adreslerle
eşleşemedi

Sadece normal ifadeyi mi yoksa yanıtın tamamını mı okuyorsunuz? Tamamen sana katılmıyorum. Sadece söyle lütfen, gmail.com sunucusu hangi RFC göre joe@gmail.com ve jo.e@gmail.com aynı adres olduğunu varsayar? Standartlara göre veya FRESH standartlarına göre çalışmayan birçok sunucu vardır. Ancak kullanıcılarına e-posta gönderir. Bir kez regexp yazarsanız ve yalnızca bununla doğrularsanız, gelecekte doğru kalacağını ve gelecekteki kullanıcılarınızın "yeni yol" e-postalarıyla başarısız olmayacağını garanti etmezsiniz. Yani, konumum aynı: e-posta adresini doğrulamak istiyorsanız ana nokta - sadece aktivasyon e-postası gönderin.
FlameStorm

@Machavity ama regexp içinde bugreport için teşekkürler, ben onu sabit /^[^@]+@[^@+]$/için/^[^@]+@[^@]+$/
FlameStorm

Normal ifadeyi düzeltmek için size yardımcı olur, ancak bu filter_varyöntem üzerinde nasıl gelişir ? Kötü biçimlendirilmiş adresleri kabul etme sorununu da gidermez. joe@domain
Normal ifadeniz

@Machavity, örneğin, sunucunuzda PHP'nin somut bir sürümü var ve bunu en yeni sürüme güncelleyemezsiniz. Örneğin, php 5.5.15 var. 2018 yılında geçerli e-postalar standardı genişletildi. Yakında php 7.3.10'da gerçekleşecek. Ve iyi çalışan bir işlev olacak filter_var($email, FILTER_VALIDATE_EMAIL, $newOptions). Ancak sunucuda eski işleviniz var, bazı durumlarda güncelleme yapamıyorsunuz. Bazı yeni geçerli e-postalarla müşterileri kaybedeceksiniz. Ayrıca, bir kez daha fark ettim ki, tüm e-posta hizmet sunucuları kesinlikle ortak ve modern e-posta adresleri standardına uygun değildir.
FlameStorm

3

E -posta adresinden sağlanan alan adının geçerli olup olmadığını kontrol etmek istiyorsanız , aşağıdakileri kullanın:

/*
* Check for valid MX record for given email domain
*/
if(!function_exists('check_email_domain')){
    function check_email_domain($email) {
        //Get host name from email and check if it is valid
        $email_host = explode("@", $email);     
        //Add a dot to the end of the host name to make a fully qualified domain name and get last array element because an escaped @ is allowed in the local part (RFC 5322)
        $host = end($email_host) . "."; 
        //Convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
        return checkdnsrr(idn_to_ascii($host), "MX"); //(bool)       
    }
}

Geçerli e-posta biçimi geçerli e-posta anlamına gelmediğinden , bu, birçok e-posta adresini standart e-posta doğrulamasıyla birlikte filtrelemenin kullanışlı bir yoludur .

O Not idn_to_ascii()(veya kardeşi fonksiyonu idn_to_utf8()) işlevi olmayabilir PHP kurulumda mevcuttur, bu uzantıları gerektirir PECL intl> = 1.0.2 ve PECL idn> = 0.1.

Ayrıca, e-postada alan adı parçası olarak IPv4 veya IPv6'nın (örneğin user@[IPv6:2001:db8::1]) doğrulanamayacağını, yalnızca adlandırılmış ana makinelerin doğrulanabileceğini unutmayın .

Daha fazlasını burada görün .


E-posta adresinin ana bilgisayar kısmı IPv6 biçiminde IP adresinde ise işe yarayacağını sanmıyorum
GordonM

2

Buradaki cevapları okuduktan sonra, ben de bununla sonuçlandım:

public static function isValidEmail(string $email) : bool
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return false;
    }

    //Get host name from email and check if it is valid
    $email_host = array_slice(explode("@", $email), -1)[0];

    // Check if valid IP (v4 or v6). If it is we can't do a DNS lookup
    if (!filter_var($email_host,FILTER_VALIDATE_IP, [
        'flags' => FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
    ])) {
        //Add a dot to the end of the host name to make a fully qualified domain name
        // and get last array element because an escaped @ is allowed in the local part (RFC 5322)
        // Then convert to ascii (http://us.php.net/manual/en/function.idn-to-ascii.php)
        $email_host = idn_to_ascii($email_host.'.');

        //Check for MX pointers in DNS (if there are no MX pointers the domain cannot receive emails)
        if (!checkdnsrr($email_host, "MX")) {
            return false;
        }
    }

    return true;
}

1

Sadece çeşitli noktalar, alt çizgiler ve tire sağlayan gerçek bir normal ifade arıyorsanız, aşağıdaki gibi [a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+. Bu, aptalca görünen bir e-postanın tom_anderson.1-neo@my-mail_matrix.comdoğrulanmasını ister.


0
/(?![[:alnum:]]|@|-|_|\.)./

Günümüzde, bir HTML5 formu kullanıyorsanız, type=emailtarayıcı motorlarının kendi doğrulayıcıları olduğundan zaten% 80 güvende olursunuz. Tamamlamak için bu normal preg_match_all()ifadeyi kendinize ekleyin ve reddedin:

if (!preg_match_all("/(?![[:alnum:]]|@|-|_|\.)./",$email)) { .. }

Doğrulama için HTML5 formları tarafından kullanılan normal ifadeyi bulun
https://regex101.com/r/mPEKmy/1


Açıklama yapmadan downvotes çok nefret ediyorum. Eh o söyleyebilirdi: Tarayıcı e-posta kontrolü (istemci tarafı) hiç güvenli değil. Herkes kodu değiştirerek sunucuya her şeyi gönderebilir. Bu yüzden kontrol (tekrar) sunucu tarafı yapmanın açık ve en güvenli yolu. Buradaki soru PHP'ye dayanıyor, bu yüzden bariz Cameron bir istemci çözümü değil bir sunucu çözümü arıyordu.
Jonny

Bu cevap tamamen PHP ile ilgili olmayabilir, ancak HTML önerisi sadece bir telefon / PC kullanan "standart" kullanıcıyı kapsar. Ayrıca kullanıcı siteyi kullanırken doğrudan "onun" tarayıcısında bir bilgi alır. Sunucu tarafındaki gerçek kontroller bununla sınırlı değil. Btw, @Thielicious bir PHP değişikliğinden bahsetti, bu yüzden yorumu IMHO ile ilgili.
k00ni

Muhtemelen "tarayıcı motorlarının kendi doğrulayıcısına sahip olduğundan% 80 güvende olduğunuz" varsayımı nedeniyle oyları düşürdü. Http isteklerini bir tarayıcıdan göndermenin başka birçok yolu vardır, bu nedenle herhangi bir isteğin güvenli olduğunu varsayamazsınız ... tarayıcı aracısını kontrol etseniz bile.
Jabari
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.