So überprüfen Sie eine E-Mail-Adresse in PHP

218

Ich habe diese Funktion, um eine E-Mail-Adresse zu validieren:

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

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

Ist dies in Ordnung, um zu überprüfen, ob die E-Mail-Adresse gültig ist oder nicht?

Cameron
quelle
1
Wenn es funktioniert, funktioniert es. Man kann es nicht wirklich besser machen, es ist zu klein. Das einzige, was nicht gut ist, ist Stil. validateEmailwäre Corret, sowie vorbei $email, nicht $EMAIL.
Stan
Ich wollte nur sicherstellen, dass ich keine größeren Probleme mit dem Code hatte, der alles ist :)
Cameron
Weitere Informationen dazu, wie und wie reguläre Ausdrücke zum Überprüfen von E-Mail-Adressen verwendet werden, finden Sie unter stackoverflow.com/questions/201323/… .
Legoscia
5
Dadurch könnten viele gültige E-Mail-Adressen nicht überprüft werden. Zum Beispiel *@example.com oder'@example.com oder ich @ [127.0.0.1] oder Sie @ [ipv6: 08B0: 1123: AAAA :: 1234]
jcoder
7
@jcoder, nicht, dass ich diese Regex empfehle, aber zumindest können wir hoffen, dass sich jeder, der solche Adressen zum
Halil Özgür

Antworten:

568

Der einfachste und sicherste Weg, um zu überprüfen, ob eine E-Mail-Adresse korrekt ist, ist die Verwendung der folgenden filter_var()Funktion:

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

Zusätzlich können Sie überprüfen, ob die Domain einen MXDatensatz definiert :

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

Dies garantiert jedoch immer noch nicht, dass die E-Mail vorhanden ist. Der einzige Weg, dies herauszufinden, ist das Senden einer Bestätigungsmail.


Nachdem Sie Ihre einfache Antwort erhalten haben, können Sie sich gerne über die Validierung von E-Mail-Adressen informieren, wenn Sie etwas lernen oder auf andere Weise einfach die schnelle Antwort verwenden und fortfahren möchten. Keine harten Gefühle.

Der Versuch, eine E-Mail-Adresse mit einem regulären Ausdruck zu überprüfen, ist eine "unmögliche" Aufgabe. Ich würde sogar sagen, dass der von Ihnen erstellte Regex nutzlos ist. Es gibt drei RFCs in Bezug auf E-Mail-Adressen und das Schreiben eines regulären Ausdrucks, um falsche E-Mail-Adressen abzufangen und gleichzeitig keine falschen Positiven zu haben, ist etwas, was kein Sterblicher tun kann. In dieser Liste finden Sie Tests (sowohl fehlgeschlagen als auch erfolgreich) des von der PHP- filter_var()Funktion verwendeten regulären Ausdrucks .

Selbst die integrierten PHP-Funktionen, E-Mail-Clients oder Server machen es nicht richtig. Trotzdem ist in den meisten Fällen filter_vardie beste Option.

Wenn Sie wissen möchten, welches Regex-Muster PHP (derzeit) zur Überprüfung von E-Mail-Adressen verwendet, lesen Sie die PHP-Quelle .

Wenn Sie mehr über E-Mail-Adressen erfahren möchten, empfehle ich Ihnen, mit dem Lesen der technischen Daten zu beginnen, aber ich muss Sie warnen, dass dies in keiner Weise einfach zu lesen ist:

Beachten Sie, dass dies filter_var()wie bereits erwähnt nur ab PHP 5.2 verfügbar ist. Wenn Sie möchten, dass es mit früheren Versionen von PHP funktioniert, können Sie den in PHP verwendeten regulären Ausdruck verwenden:

<?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 Ein Hinweis zum oben verwendeten Regex-Muster (von der PHP-Quelle). Es sieht so aus, als ob Michael Rushton ein Urheberrecht daran hat . Wie bereits erwähnt: "Sie können diesen Code gerne verwenden und weitergeben. Bitte bewahren Sie diesen Copyright-Hinweis auf."

PeeHaa
quelle
Gute Antwort, aber laut diesem Link: haacked.com/archive/2007/08/21/… kann der Benutzername o lokaler Teil in Anführungszeichen gesetzt werden, aber die FILTER_VALIDATE_EMAIL akzeptieren ihn nicht.
Daniel De León
3
Es funktioniert nicht für alle angegebenen E-Mail-Adressen. Sehen Sie sich auch die Liste der fehlgeschlagenen Tests in meiner Antwort an, um festzustellen, dass einige Zeichenfolgen in Anführungszeichen funktionieren und andere nicht.
PeeHaa
4
Nein, zu viele fehlgeschlagene Tests mit diesem Muster emailtester.pieterhordijk.com/test-pattern/MTAz :-)
PeeHaa
1
Dieses Muster ist äußerst komplex, falls Sie es mit einer Funktion wie "preg_match_all" über einer großen Textzeichenfolge mit darin enthaltenen E-Mails verwenden müssen. Wenn einer von euch es einfacher hat, teilt es bitte mit. Ich meine, wenn Sie wollen: preg_match_all ($ pattern, $ text_string, $ match); Dann überlastet dieses komplexe Muster den Server, wenn Sie wirklich großen Text analysieren müssen.
Vlado
4
@PeeHaa: Postfix 3.0 unterstützt es seit fast zwei Jahren: postfix.org/SMTPUTF8_README.html . Es ist in Ubuntu 16.04 enthalten und wird beispielsweise in der nächsten Debian-Version enthalten sein. Exim hat experimentelle Unterstützung. Webmail-Anbieter wie Google Mail haben auch Unterstützung für das Senden / Empfangen solcher E-Mails hinzugefügt, obwohl Sie noch keine Unicode-Konten erstellen können. Die weit verbreitete Nutzung und Unterstützung ist in greifbarer Nähe und filter_varwird einige Zeit zurückbleiben, selbst wenn sie sich gerade ändern (ich habe einen Fehlerbericht veröffentlicht).
Iquito
43

Hierfür können Sie filter_var verwenden .

<?php
   function validateEmail($email) {
      return filter_var($email, FILTER_VALIDATE_EMAIL);
   }
?>
Cameron Martin
quelle
1
Beenden Sie das Hinzufügen dieser Funktion, da dadurch keine Domänen überprüft werden. Wenn Sie eine @ -Adresse hinzufügen, ist dies gültig. und es ist nicht!
Herr Nentu '11.
Was ist mit all den Einzeilenfunktionen, die Einzeilenfunktionen enthalten? Ich sehe sie überall. Wann wurde dies ein "Ding"? (rhetorisch). Das muss aufhören.
Blaues Wasser
15

Nach meiner Erfahrung haben regexLösungen zu viele falsch positive und filter_var()Lösungen falsch negative (insbesondere bei allen neueren TLDs ).

Stellen Sie stattdessen sicher, dass die Adresse alle erforderlichen Teile einer E-Mail-Adresse enthält (Benutzer, "@" - Symbol und Domäne), und überprüfen Sie dann, ob die Domäne selbst vorhanden ist.

Es gibt keine Möglichkeit (serverseitig) festzustellen, ob ein E-Mail-Benutzer für eine externe Domäne vorhanden ist.

Dies ist eine Methode, die ich in einer Utility-Klasse erstellt habe:

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
quelle
Neverbounce behauptet, dass seine API eine Lieferung von 97% validieren kann. Solange es Ihnen nichts ausmacht, Ihre Kontaktdatenbank zu übergeben, natürlich.
Tom Russell
stristrDie Domain wird nicht abgerufen, wenn mehrere @ -Zeichen vorhanden sind. Besser explode('@',$email)und überprüfen Sie dassizeof($array)==2
Aaron Gillion
@AaronGillion Obwohl Sie in Bezug auf einen besseren Weg zum Abrufen von Domänenteilen korrekt sind, würde die Methode immer noch false zurückgeben, ebenso checkdnsrr()wie false, wenn in der Domain ein @ -Zeichen vorhanden wäre.
Jabari
11

Ich denke, Sie sind möglicherweise besser dran, wenn Sie die in PHP integrierten Filter verwenden - in diesem speziellen Fall:

Es kann ein wahr oder falsch zurückgeben, wenn es mit dem FILTER_VALIDATE_EMAILParameter geliefert wird.

Fluffeh
quelle
9

Dadurch wird Ihre E-Mail nicht nur validiert, sondern auch auf unerwartete Zeichen überprüft:

$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
quelle
4

Beantwortete dies in der 'Top-Frage' zur E-Mail-Überprüfung https://stackoverflow.com/a/41129750/1848217

Für mich ist der richtige Weg zum Abrufen von E-Mails:

  1. Überprüfen Sie, ob das Symbol @ vorhanden ist, und davor und danach gibt es einige Nicht-@-Symbole: /^[^@]+@[^@]+$/
  2. Versuchen Sie, eine E-Mail mit einem "Aktivierungscode" an diese Adresse zu senden.
  3. Wenn der Benutzer seine E-Mail-Adresse "aktiviert" hat, werden wir sehen, dass alles in Ordnung ist.

Natürlich können Sie im Front-End eine Warnung oder einen Tooltip anzeigen, wenn der Benutzer "seltsame" E-Mails eingibt, um häufige Fehler zu vermeiden, z. B. keinen Punkt im Domain-Teil oder Leerzeichen im Namen ohne Anführungszeichen usw. Sie müssen jedoch die Adresse "hello @ world" akzeptieren, wenn der Benutzer dies wirklich möchte.

Außerdem müssen Sie sich daran erinnern, dass der Standard für E-Mail-Adressen entwickelt wurde und werden kann, sodass Sie nicht einfach ein für alle Mal einen "standardgültigen" regulären Ausdruck eingeben können. Und Sie müssen sich daran erinnern, dass einige konkrete Internet-Server einige Details des gemeinsamen Standards nicht erfüllen können und tatsächlich mit einem eigenen "modifizierten Standard" arbeiten.

Überprüfen Sie einfach @, geben Sie dem Benutzer im Frontend einen Hinweis und senden Sie Bestätigungs-E-Mails an die angegebene Adresse.

FlameStorm
quelle
1
Ihre Regex prüft zwar, ob @sie jedoch für einen der RFCs, die E-Mails regeln, gültig ist. Es funktioniert auch nicht wie geschrieben. Ich habe es über regex101.com ausgeführt und es konnte keine gültigen Adressen gefunden werden
Machavity
Lesen Sie nur Regex oder die ganze Antwort? Stimme dir überhaupt nicht zu. Sagen Sie mir bitte, gemäß welchem ​​RFC nimmt der gmail.com-Server an, dass [email protected] und [email protected] dieselbe Adresse haben? Es gibt viele Server, die nicht nach Standards oder nicht nach FRESH-Standards funktionieren. Aber sie dienen E-Mails ihrer Benutzer. Wenn Sie einen regulären Ausdruck einmal eingeben und nur dadurch validieren, können Sie nicht garantieren, dass er auch in Zukunft richtig bleibt und Ihre zukünftigen Benutzer nicht mit ihren "New-Way" -E-Mails versagen. Meine Position ist also dieselbe: Hauptpunkt, wenn Sie die E-Mail-Adresse überprüfen möchten - senden Sie einfach eine Aktivierungs-E-Mail.
FlameStorm
@Machavity aber danke für bugreport in regexp, fest ich es von /^[^@]+@[^@+]$/zu/^[^@]+@[^@]+$/
FlameStorm
Wir bitten Sie, den regulären Ausdruck zu korrigieren, aber wie verbessert sich das gegenüber der filter_varMethode? Es behebt auch nicht das Problem, dass schlecht formatierte Adressen akzeptiert werden. Ihre Regex wird gerne joe@domainals gültige E-Mail-Adresse akzeptiert , wenn dies nicht der
Fall ist
@Machavity, auf Ihrem Server befindet sich beispielsweise eine konkrete Version von PHP, die Sie nicht auf die neueste Version aktualisieren können. Zum Beispiel haben Sie PHP 5.5.15. Im Jahr 2018 wurde der Standard für gültige E-Mails erweitert. Es wird in Kürze in PHP 7.3.10 realisiert. Und es wird eine gut funktionierende Funktion geben filter_var($email, FILTER_VALIDATE_EMAIL, $newOptions). Sie haben jedoch eine alte Funktion auf dem Server und können in einigen Fällen nicht aktualisiert werden. Und Sie verlieren Kunden mit einigen neuen gültigen E-Mails. Außerdem stelle ich erneut fest, dass nicht alle E-Mail-Server streng nach dem üblichen und modernen Standard von E-Mail-Adressen funktionieren.
FlameStorm
3

Wenn Sie überprüfen möchten, ob die von der E-Mail-Adresse angegebene Domain gültig ist, verwenden Sie Folgendes:

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

Dies ist eine praktische Möglichkeit, viele ungültige E-Mail-Adressen zusammen mit der Standard-E-Mail-Validierung zu filtern, da ein gültiges E-Mail-Format keine gültige E-Mail bedeutet .

Beachten Sie, dass die Funktion idn_to_ascii()(oder seine Schwesterfunktion idn_to_utf8()) in Ihrer PHP-Installation möglicherweise nicht verfügbar ist. Sie erfordert die Erweiterungen PECL intl> = 1.0.2 und PECL idn> = 0.1.

Beachten Sie auch, dass IPv4 oder IPv6 als Domain-Teil in E-Mails (zum Beispiel user@[IPv6:2001:db8::1]) nicht validiert werden können, sondern nur benannte Hosts.

Sehen Sie hier mehr .

Bud Damyanov
quelle
Ich denke nicht, dass es funktionieren wird, wenn der Host-Teil der E-Mail-Adresse eine IP-Adresse im IPv6-Format hat
GordonM
2

Nachdem ich die Antworten hier gelesen hatte, kam ich zu folgendem Ergebnis:

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;
}
Pelmered
quelle
1

Wenn Sie nur nach einem tatsächlichen regulären Ausdruck suchen, der verschiedene Punkte, Unterstriche und Striche zulässt, gehen Sie wie folgt vor : [a-zA-z0-9.-]+\@[a-zA-z0-9.-]+.[a-zA-Z]+. Dadurch kann eine ziemlich dumm aussehende E-Mail tom_anderson.1-neo@my-mail_matrix.comvalidiert werden.

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

Wenn Sie heutzutage ein HTML5-Formular mit verwenden, sind type=emailSie bereits zu 80% sicher, da Browser-Engines über einen eigenen Validator verfügen. Um dies zu ergänzen, fügen Sie diesen regulären Ausdruck zu Ihrem hinzu preg_match_all()und negieren Sie ihn:

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

Suchen Sie den regulären Ausdruck, der von HTML5-Formularen zur Validierung verwendet wird:
https://regex101.com/r/mPEKmy/1

Thielicious
quelle
Ich hasse auch Abstimmungen ohne Erklärung. Nun, ich denke, er könnte sagen: Die E-Mail-Prüfung des Browsers (clientseitig) ist überhaupt nicht sicher. Jeder kann etwas an einen Server senden, indem er den Code ändert. Es ist also offensichtlich und der sicherste Weg, die Server-Seite (erneut) zu überprüfen. Die Frage hier basiert auf PHP, daher suchte Cameron offensichtlich nach einer Serverlösung und nicht nach einer Clientlösung.
Jonny
Diese Antwort ist möglicherweise nicht vollständig PHP-bezogen, aber der HTML-Vorschlag deckt den "Standard" -Benutzer ab, der nur ein Telefon / einen PC verwendet. Außerdem erhält der Benutzer während der Nutzung der Website Informationen direkt in "seinem" Browser. Echte Überprüfungen auf der Serverseite werden damit sicher nicht abgedeckt. Übrigens erwähnte @Thielicious eine PHP-Änderung, so dass sein Kommentar meiner Meinung nach verwandt ist.
k00ni
Es hat wahrscheinlich aufgrund der Annahme, dass Sie "80% sicher sind, da Browser-Engines einen eigenen Validator haben", negative Stimmen erhalten. Es gibt viele andere Möglichkeiten, http-Anfragen zu senden als über einen Browser. Sie können also nicht davon ausgehen, dass eine Anfrage sicher ist ... selbst wenn Sie den Browser-Agenten überprüfen.
Jabari