Cara memvalidasi alamat email dalam PHP

218

Saya memiliki fungsi ini untuk memvalidasi alamat email:

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

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

Apakah ini boleh untuk memeriksa apakah alamat email itu valid atau tidak?

Cameron
sumber
1
Jika berhasil, itu akan berhasil. Anda tidak bisa benar-benar membuatnya lebih baik, terlalu kecil. Satu-satunya hal yang tidak baik adalah gaya. validateEmailakan corret, serta lewat $email, tidak $EMAIL.
Stan
Hanya ingin memastikan saya tidak memiliki masalah besar dalam kode itu saja :)
Cameron
Lihat juga stackoverflow.com/questions/201323/… untuk lebih lanjut tentang bagaimana dan bagaimana tidak menggunakan ekspresi reguler untuk memvalidasi alamat email.
legoscia
5
Itu akan gagal memvalidasi banyak alamat email yang valid. Misalnya *@example.com atau'@example.com atau saya @ [127.0.0.1] atau Anda @ [ipv6: 08B0: 1123: AAAA :: 1234]
jcoder
7
@ jcoder, bukan saya merekomendasikan regex itu, tapi setidaknya kita bisa berharap siapa pun menggunakan alamat seperti itu untuk bernyanyi dll tidak akan mengeluh ketika gagal :)
Halil Özgür

Jawaban:

568

Cara termudah dan teraman untuk memeriksa apakah alamat email terbentuk dengan baik adalah dengan menggunakan filter_var()fungsi ini:

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

Selain itu Anda dapat memeriksa apakah domain mendefinisikan MXcatatan:

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

Tetapi ini masih tidak menjamin bahwa surat itu ada. Satu-satunya cara untuk mengetahuinya adalah dengan mengirim surat konfirmasi.


Sekarang setelah Anda mendapatkan jawaban yang mudah, jangan ragu untuk membaca tentang validasi alamat email jika Anda ingin belajar atau cukup gunakan jawaban cepat dan lanjutkan. Tidak ada perasaan keras.

Mencoba memvalidasi alamat email menggunakan regex adalah tugas yang "mustahil". Saya akan mengatakan bahwa regex yang Anda buat tidak berguna. Ada tiga rfc mengenai alamat email dan menulis regex untuk menangkap alamat email yang salah dan pada saat yang sama tidak memiliki positif palsu adalah sesuatu yang tidak dapat dilakukan oleh manusia. Lihatlah daftar ini untuk tes (gagal dan berhasil) dari regex yang digunakan oleh filter_var()fungsi PHP .

Bahkan fungsi PHP bawaan, klien email atau server tidak dapat melakukannya dengan benar. Masih dalam banyak kasus filter_varadalah pilihan terbaik.

Jika Anda ingin tahu pola regex mana yang digunakan PHP (saat ini) untuk memvalidasi alamat email, lihat sumber PHP .

Jika Anda ingin mempelajari lebih lanjut tentang alamat email, saya sarankan Anda untuk mulai membaca spesifikasi, tetapi saya harus memperingatkan Anda bahwa itu tidak mudah dibaca oleh peregangan apa pun:

Perhatikan bahwa filter_var()sebagaimana telah dinyatakan hanya tersedia pada PHP 5.2. Jika Anda ingin bekerja dengan versi PHP yang lebih lama, Anda bisa menggunakan regex yang digunakan dalam PHP:

<?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 = '[email protected]';

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

PS Catatan tentang pola regex yang digunakan di atas (dari sumber PHP). Sepertinya ada beberapa hak cipta di atasnya dari Michael Rushton . Seperti yang dinyatakan: "Jangan ragu untuk menggunakan dan mendistribusikan kembali kode ini. Tetapi harap simpan pemberitahuan hak cipta ini."

PeeHaa
sumber
Jawaban yang bagus, tetapi menurut tautan ini: haacked.com/archive/2007/08/21/... nama pengguna o bagian lokal dapat dikutip-string, tetapi FILTER_VALIDATE_EMAIL tidak menerimanya.
Daniel De León
3
Ini tidak berfungsi untuk semua alamat email seperti yang dinyatakan. Lihat juga daftar tes gagal dalam jawaban saya untuk melihat bahwa beberapa string yang dikutip berfungsi dan yang lainnya tidak.
PeeHaa
4
Tidak, terlalu banyak tes gagal pada pola itu emailtester.pieterhordijk.com/test-pattern/MTAz :-)
PeeHaa
1
Pola ini sangat kompleks jika Anda perlu menggunakannya dengan fungsi seperti "preg_match_all" pada string teks besar dengan email di dalamnya. Jika ada di antara Anda yang lebih sederhana, silakan bagikan. Maksud saya jika Anda ingin: preg_match_all ($ pattern, $ text_string, $ cocok); maka pola yang rumit ini akan membebani server jika Anda perlu menguraikan teks yang sangat besar.
Vlado
4
@PeeHaa: Postfix 3.0 mendukungnya selama hampir dua tahun sekarang: postfix.org/SMTPUTF8_README.html , dan itu termasuk dalam Ubuntu 16.04 dan akan dimasukkan dalam rilis Debian berikutnya, misalnya. Exim memiliki dukungan eksperimental. Penyedia webmail seperti Gmail juga telah menambahkan dukungan untuk mengirim / menerima email semacam itu, walaupun Anda belum dapat membuat akun unicode. Penggunaan dan dukungan yang luas masih dalam jangkauan, dan filter_varakan tertinggal cukup lama, bahkan jika mereka mengubahnya sekarang (saya telah memposting laporan bug).
iquito
43

Anda dapat menggunakan filter_var untuk ini.

<?php
   function validateEmail($email) {
      return filter_var($email, FILTER_VALIDATE_EMAIL);
   }
?>
Cameron Martin
sumber
1
berhenti menambahkan fungsi ini karena ini tidak memvalidasi domain. jika Anda menambahkan beberapa alamat @ ini valid. dan itu tidak!
Herr Nentu '11
Ada apa dengan semua fungsi satu baris yang berisi fungsi satu baris? Saya melihat mereka di mana-mana. Kapan ini menjadi "benda"? (retoris). Ini harus dihentikan.
Blue Water
15

Dalam pengalaman saya, regexsolusi memiliki terlalu banyak positif palsu dan filter_var()solusi memiliki negatif palsu (terutama dengan semua TLD yang lebih baru ).

Alih-alih, lebih baik memastikan bahwa alamat tersebut memiliki semua bagian yang diperlukan dari alamat email (pengguna, "@" simbol, dan domain), lalu verifikasi bahwa domain itu sendiri ada.

Tidak ada cara untuk menentukan (sisi server) jika ada pengguna email untuk domain eksternal.

Ini adalah metode yang saya buat di kelas Utilitas:

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;
}
Jabari
sumber
Neverbounce mengklaim API mereka mampu memvalidasi pengiriman 97%. Tentu saja, selama Anda tidak keberatan menyerahkan basis data kontak Anda.
Tom Russell
stristrakan gagal mendapatkan domain jika ada beberapa tanda @. Lebih baik untuk explode('@',$email)memeriksa itusizeof($array)==2
Aaron Gillion
@ AaronGillion Meskipun Anda benar sejauh cara yang lebih baik untuk mendapatkan bagian-bagian domain, metode ini masih akan kembali salah karena checkdnsrr()akan kembali salah jika ada tanda @ di domain.
Jabari
11

Saya pikir Anda mungkin lebih baik menggunakan filter bawaan PHP - dalam kasus khusus ini:

Itu dapat mengembalikan benar atau salah ketika disertakan dengan FILTER_VALIDATE_EMAILparam.

Fluffeh
sumber
9

Ini tidak hanya akan memvalidasi email Anda, tetapi juga membersihkannya untuk karakter yang tidak terduga:

$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);
}
Excalibur
sumber
4

Menjawab ini dalam 'pertanyaan teratas' tentang verifikasi email https://stackoverflow.com/a/41129750/1848217

Bagi saya cara yang tepat untuk memeriksa email adalah:

  1. Periksa bahwa simbol @ ada, dan sebelum dan sesudahnya ada beberapa simbol non- @: /^[^@]+@[^@]+$/
  2. Cobalah mengirim email ke alamat ini dengan beberapa "kode aktivasi".
  3. Ketika pengguna "mengaktifkan" alamat emailnya, kita akan melihat bahwa semuanya benar.

Tentu saja, Anda dapat menunjukkan peringatan atau tooltip di front-end ketika pengguna mengetik "aneh" email untuk membantunya menghindari kesalahan umum, seperti tidak ada titik di bagian domain atau spasi dalam nama tanpa mengutip dan sebagainya. Tetapi Anda harus menerima alamat "hello @ world" jika pengguna benar-benar menginginkannya.

Selain itu, Anda harus ingat bahwa standar alamat email adalah dan dapat berkembang, jadi Anda tidak bisa mengetikkan regexp "valid-standar" sekali dan untuk selamanya. Dan Anda harus ingat bahwa beberapa server internet konkret dapat gagal beberapa detail dari standar umum dan bahkan bekerja dengan "standar modifikasi" sendiri.

Jadi, cukup periksa @, beri petunjuk pengguna di frontend dan kirim email verifikasi pada alamat yang diberikan.

FlameStorm
sumber
1
Regex Anda mengecek @, tetapi tidak benar-benar memeriksa apakah itu valid untuk RFC yang mengatur email. Itu juga tidak berfungsi seperti yang tertulis. Saya menjalankannya melalui regex101.com dan gagal mencocokkan alamat yang valid
Machavity
Apakah Anda hanya membaca regex atau seluruh jawaban? Sepenuhnya tidak setuju dengan Anda. Katakan saja pada saya, menurut RFC apa server gmail.com menganggap bahwa [email protected] dan [email protected] adalah alamat yang sama? Ada banyak server yang bekerja tidak sesuai standar atau tidak dengan standar segar. Tapi mereka melayani email pengguna mereka. Jika Anda mengetik beberapa regexp sekali, dan hanya memvalidasi itu, Anda tidak memiliki jaminan bahwa itu akan tetap benar di masa depan dan pengguna masa depan Anda tidak akan gagal dengan email "cara baru" mereka. Jadi, posisi saya sama: poin utama jika Anda ingin memverifikasi alamat email - cukup kirim email aktivasi.
FlameStorm
@Machavity tetapi terima kasih untuk bugreport di regexp, saya memperbaikinya dari /^[^@]+@[^@+]$/ke/^[^@]+@[^@]+$/
FlameStorm
Alat peraga bagi Anda untuk memperbaiki regex, tetapi bagaimana cara meningkatkan filter_varmetode? Itu tidak memperbaiki masalah menerima alamat berformat buruk juga. Regex Anda akan dengan senang hati menerima joe@domainsebagai alamat email yang valid, padahal bukan
Machavity
@Machavity, well, misalnya, ada versi nyata PHP di server Anda dan Anda tidak dapat memperbaruinya ke yang terbaru. Misalnya, Anda memiliki php 5.5.15. Pada tahun 2018 standar email yang valid diperpanjang. Ini akan segera terealisasi di php 7.3.10. Dan akan ada fungsi kerja yang baik filter_var($email, FILTER_VALIDATE_EMAIL, $newOptions). Tetapi Anda memiliki fungsi lama di server, Anda tidak dapat memperbarui dalam beberapa kasus. Dan Anda akan kehilangan klien dengan beberapa email baru yang valid. Juga, sekali lagi saya perhatikan, bahwa tidak semua pengungkit penyajian email bekerja secara ketat sesuai dengan standar umum dan alamat email modern.
FlameStorm
3

Jika Anda ingin memeriksa apakah domain yang disediakan dari alamat email itu valid, gunakan sesuatu seperti:

/*
* 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)       
    }
}

Ini adalah cara praktis untuk memfilter banyak alamat email yang tidak valid, bersama dengan validasi email standar, karena format email yang valid tidak berarti email yang valid .

Perhatikan bahwa idn_to_ascii()(atau fungsi kakaknya idn_to_utf8()) fungsi mungkin tidak tersedia di instalasi PHP Anda, itu memerlukan ekstensi PECL intl> = 1.0.2 dan PECL idn> = 0.1.

Perlu diingat juga bahwa IPv4 atau IPv6 sebagai bagian domain dalam email (misalnya user@[IPv6:2001:db8::1]) tidak dapat divalidasi, hanya host yang bernama boleh.

Lihat lebih lanjut di sini .

Bud Damyanov
sumber
Saya tidak berpikir itu akan berhasil jika bagian host dari alamat email dalam alamat IP dalam format IPv6
GordonM
2

Setelah membaca jawaban di sini, inilah yang akhirnya saya dapatkan:

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;
}
Terlambat
sumber
1

Jika Anda hanya mencari regex yang sebenarnya yang memungkinkan untuk berbagai titik, garis bawah dan garis, sebagai berikut: [a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+. Itu akan memungkinkan email yang tampak bodoh seperti tom_anderson.1-neo@my-mail_matrix.comdivalidasi.

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

Saat ini, jika Anda menggunakan formulir HTML5 type=emailmaka Anda sudah 80% aman karena mesin peramban memiliki validator sendiri. Untuk melengkapinya, tambahkan regex ini ke Anda preg_match_all()dan negasikan:

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

Temukan regex yang digunakan oleh formulir HTML5 untuk validasi
https://regex101.com/r/mPEKmy/1

Sangat berbahaya
sumber
Aku benci downvotes juga tanpa penjelasan. Yah saya kira dia mungkin mengatakan: Pemeriksaan email browser (sisi klien) tidak aman sama sekali. Siapa pun dapat mengirim apa pun ke server dengan mengubah kode. Jadi sudah jelas dan cara paling aman untuk melakukan pengecekan (lagi) sisi server. Pertanyaan di sini didasarkan pada PHP, jadi Cameron yang jelas sedang mencari solusi server dan bukan solusi klien.
Jonny
Jawaban ini mungkin tidak sepenuhnya terkait dengan PHP, tetapi saran HTML mencakup pengguna "standar" hanya menggunakan telepon / PC. Pengguna juga mendapat info langsung di browser "nya" saat menggunakan situs. Pemeriksaan nyata di sisi server tidak tercakup dengan ini, tentu saja. Btw, @Thielicious menyebutkan perubahan PHP, jadi komentarnya terkait dengan IMHO.
k00ni
Mungkin menerima suara karena asumsi bahwa Anda "80% aman karena mesin peramban memiliki validator sendiri". Ada banyak cara lain untuk mengirim permintaan http daripada melalui browser, jadi Anda tidak dapat berasumsi bahwa permintaan apa pun aman ... bahkan jika Anda memeriksa agen browser.
Jabari