2016-07-22 48 views
1

Wie Sie im folgenden Skript sehen können, verwende ich mehrere if-Anweisungen beim Überprüfen der Registrierungseingaben. Gibt es einen leichteren, weniger Spaghetti?Was kann ich anstelle von mehreren If-Anweisungen tun? PHP Register Script

Das Skript funktioniert wie es ist, aber ich möchte es sauberer sein.

<?php 

if (isset($_POST['register'])) { 

    $uname = trim($_POST['uName']); 
    $email = trim($_POST['email']); 
    $pass = trim($_POST['pass']); 
    $passCon = trim($_POST['passCon']); 

    $uname = strip_tags($uname); 
    $email = strip_tags($email); 
    $pass = strip_tags($pass); 
    $passCon = strip_tags($passCon); 

    if (!empty($pass)) { 
     if (!empty($email)) { 
      if (!empty($uname)) { 
       if ($pass == $passCon) { 

        $query = "SELECT username FROM users WHERE username='$uname'"; 
        $result = mysqli_query($conn, $query); 
        $checkUsername = mysqli_num_rows($result); 

        if ($checkUsername == 0) { 

         $query = "SELECT email FROM users WHERE email='$email'"; 
         $result = mysqli_query($conn, $query); 
         $count = mysqli_num_rows($result); 

         if ($count == 0) { 

          $password = hash('sha256', $pass); 
          $queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')"; 
          $res = mysqli_query($conn, $queryInsert); 

          if ($res) { 
           $errTyp = "success"; 
           $errMsg = "successfully registered, you may login now"; 
          } 
         } else { 
          $errTyp = "warning"; 
          $errMsg = "Sorry Email already in use"; 
         } 
        } else { 
         $errTyp = "warning"; 
         $errMsg = "Sorry Username already in use"; 
        } 
       } else { 
        $errTyp = "warning"; 
        $errMsg = "Passwords didn't match"; 
       } 
      } else { 
       $errTyp = "warning"; 
       $errMsg = "You didn't enter a Username"; 
      } 
     } else { 
      $errTyp = "warning"; 
      $errMsg = "You didn't enter an email address"; 
     } 
    } else { 
     $errTyp = "warning"; 
     $errMsg = "You didn't enter a password"; 
    } 
} 

Danke, Jay

+0

Ist das überhaupt eine korrekte Syntax? Hart verstehen ohne richtige Einrückung. –

+0

Ja. Es ist richtig .. Wie es funktioniert. – JayLewis

+0

Ich bin gerne "zurück früh" Methode für shortand code, lesen Sie mehr darüber hier: http://programmers.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or -use-an-if-statement –

Antwort

0

Das Problem Sie konfrontiert sind, nicht ungewöhnlich ist. Viele Programmierer haben sich diesem Problem gestellt. Lassen Sie mich Ihnen auf dem Weg helfen, Ihr Skript zu restrukturieren.

Zunächst einmal loslassen wir die verschachtelten if-else Aussagen. Sie verwirren und verschleiern, was wirklich vor sich geht.

Version 1:

if (!isset($_POST['register'])) 
    redirect('register.php'); // Let's assume that redirect() redirects the user to a different web page and exit()s the script. 

$uname = $_POST['uName']; 
$email = $_POST['email']; 
$pass = $_POST['pass']; 
$passRepeat = $_POST['passRepeat']; 

if (empty($pass)) { 
    $errorMessage = "You didn't enter a password"; 
} 

if (empty($email)) { 
    $errorMessage = "You didn't enter an email address"; 
} 

if (empty($uname)) { 
    $errorMessage = "You didn't enter a Username"; 
} 

if ($pass !== $passRepeat) { 
    $errMsg = "Passwords didn't match"; 
} 

$query = "SELECT username FROM users WHERE username='$uname'"; 
$result = mysqli_query($conn, $query); 
$checkUsername = mysqli_num_rows($result); 

if ($checkUsername !== 0) { 
    $errMsg = 'Sorry Username already in use'; 
} 

$query = "SELECT email FROM users WHERE email='$email'"; 
$result = mysqli_query($conn, $query); 
$count = mysqli_num_rows($result); 

if ($count !== 0) { 
    $errMsg = 'Sorry Email already in use'; 
} 

$password = hash('sha256', $pass); 
$queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')"; 
$res = mysqli_query($conn, $queryInsert); 

Beachten Sie, dass, obwohl dies die verschachtelte if-Anweisungen vermeidet, ist dies nicht der gleiche wie der ursprüngliche Code ist, da die Fehler durch fallen. Lasst uns das beheben. Wenn wir gerade dabei sind, warum sollten wir nach dem ersten Fehler zurückkehren wollen? Lassen Sie uns alle Fehler auf einmal zurückgeben!

Version 2:

$errors = array(); 

if (empty($pass)) { 
    $errors[] = "You didn't enter a password"; 
} 

if (empty($email)) { 
    $errors[] = "You didn't enter an email address"; 
} 

if (empty($uname)) { 
    $errors[] = "You didn't enter a username"; 
} 

if ($pass !== $passRepeat) { 
    $errors[] = "Passwords didn't match"; 
} 

$query = "SELECT username FROM users WHERE username='$uname'"; 
$result = mysqli_query($conn, $query); 
$usernameExists = mysqli_num_rows($result) > 0; 

if ($usernameExists) { 
    $errors[] = 'Sorry Username already in use'; 
} 

$query = "SELECT email FROM users WHERE email='$email'"; 
$result = mysqli_query($conn, $query); 
$emailExists = mysqli_num_rows($result) > 0; 

if ($emailExists) { 
    $errors[] = 'Sorry Email already in use'; 
} 

if (count($errors) === 0) { 
    $password = hash('sha256', $pass); 
    $queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')"; 
    $res = mysqli_query($conn, $queryInsert); 

    redirect('register_success.php'); 
} else { 
    render_errors($errors); 
} 

recht sauber, so weit! Beachten Sie, dass wir die if (empty($var))-Anweisungen durch eine for-Schleife ersetzen könnten. Ich denke jedoch, dass das in dieser Situation übertrieben ist.

Als eine Randnotiz, bitte beachten Sie, dass dieser Code anfällig für SQL injection ist. Die Behebung dieses Problems würde den Rahmen der Frage sprengen.

0

Weniger Spaghetti? Beginnen Sie mit der funktionalen Zerlegung und arbeiten Sie dann daran, die Aufgabe der Sanierung von der der Validierung zu trennen. Ich werde viele Schritte weglassen, die ich nehme (wie die Überprüfung der Form/$ _POST/filter_input_array() hat die richtige Anzahl von Eingaben, und die richtigen Schlüssel sind in der $ _POST superglobal/INPUT_POST, etc, möchten Sie vielleicht darüber nachdenken Das.). Ändern Sie einige meiner Techniken für Ihre genauen Bedürfnisse. Ihr Programm sollte danach weniger Spaghetti haben. :-)

Sanitize dann validieren. Du musst sie getrennt halten, sozusagen. ;-)

mit Funktionale Dekomposition

seinen eigenen Codeblock Erstellen Sie eine einzelne Aufgabe Sanitizing.

Wenn alle Schritte zur Bereinigung (trim(), strip_tags() usw.) für alle Ihre Formularfelder identisch sind, erstellen Sie eine Sanitizer-Funktion, um diese Aufgabe zu erledigen. Beachten Sie, dass das einmalige Trimmen und Entfernen von Tags einfach durch Verwendung einer Schleife verbessert werden kann. Speichern Sie den ursprünglichen Wert in einer Variablen, dann trim(), strip_tags() usw. innerhalb einer while-Schleife. Vergleichen Sie die Ergebnisse mit dem Original. Wenn sie gleich sind, brechen Sie ab. Wenn sie sich unterscheiden, speichern Sie den aktuellen Wert des Formularfelds in Ihrer Variablen erneut und lassen Sie die Schleife erneut laufen.

function sanitize($formValue) 
{ 
    $oldValue = $formValue; 

    do 
    { 
     $formValue = trim($formValue); 
     $formValue = strip_tags($formValue); 

     //Anything else you want to do. 

     $formValue = trim($formValue); 

     if($formValue === $oldValue) 
     { 
      break; 
     } 

     $oldValue = $formValue; 
    } 
    while(1); //Infinite loop 

    return $formValue; 
} 

Dann einfach diese Funktion in einer Schleife ausführen.

$sanitized = []; 

foreach($_POST as $key => $value) 
{ 
    $sanitized[$key] = sanitize($value); 
} 

/* You can keep track your variable anyway you want.*/ 

Blick weiter die Straße hinunter, es mal wie das ist, wo eine Eingangsquelle Ausarbeitung ($ _POST, $ _GET, $ _SESSION, $ _FILES, $ _COOKIE, etc ..) basiert Hygienisierung, wirklich Klasse hierarcy kommt praktisch. Darüber hinaus versetzt Sie diese Klassenhierarchie mit der Verwendung von filter_input_array() wirklich in die richtige Richtung. Was ist mit Validierung?

mit Funktionale Dekomposition Validieren

Sie auf jedes Formularfeld als um ihre eigene Validieren Funktion aussehen könnte. Dann wird nur die Logik, die erforderlich ist, um ein Formularfeld zu überprüfen, in dem Block enthalten sein. Der Schlüssel, behalte deine Boolesche Logik, indem die Validatorfunktionen die Ergebnisse eines Tests zurückgeben (true/false).

function uname($uname, &$error) 
{ 
    if(! /* Some test */) 
    { 
     $error = 'Totally wrong!' 
    } 
    elseif(! /* Another test */) 
    { 
     $error = 'Incredibly wrong!' 
    } 
    else 
    { 
     $error = NULL; 
    } 

    return !isset($error) //If error is set, then the test has failed. 
} 

function email($email, &$error) 
{ 
    if(! /* Some test */) 
    { 
     $error = 'Totally wrong!' 
    } 
    elseif(! /* Another test */) 
    { 
     $error = 'Incredibly wrong!' 
    } 
    else 
    { 
     $error = NULL; 
    } 

    return !isset($error) //If error is set, then the test has failed. 
} 

function pass($pass, &$error) 
{ 
    if(! /* Some test */) 
    { 
     $error = 'Totally wrong!' 
    } 
    elseif(! /* Another test */) 
    { 
     $error = 'Incredibly wrong!' 
    } 
    else 
    { 
     $error = NULL; 
    } 

    return !isset($error) //If error is set, then the test has failed. 
} 

function passCon($passCon, &$error) 
{ 
    if(! /* Some test */) 
    { 
     $error = 'Totally wrong!' 
    } 
    elseif(! /* Another test */) 
    { 
     $error = 'Incredibly wrong!' 
    } 
    else 
    { 
     $error = NULL; 
    } 

    return !isset($error) //If error is set, then the test has failed. 
} 

In PHP können Sie variable Funktionen verwenden, um Ihre Funktion genauso zu benennen wie die Felder, die sie prüfen. Um diese Validatoren auszuführen, tun Sie dies einfach.

$errorMsgs = []; 

foreach($sanitized as $key => $value) 
{ 
    $key($value, $errorMsgs[$key]) 
} 

Dann müssen Sie im Allgemeinen nur sehen, ob es Fehler im Array $ errorMsgs gibt. Tun Sie dies durch die Verarbeitung des $ errorMsgs Array

$error = false; 

foreach($errorMsgs as $key => $value) 
{ 
    if(isset($value)) 
    { 
     //There is an error in the $key field 
     $error = true; 
    } 
} 


..and then. 

if($error === true) 
{ 
    //Prompt user in some way and terminate processing. 
} 

// Send email, login, etc .... 

weiter genommen, könnten Sie eine generische, Validator, Superklasse erstellen.

All dies wird gesagt. Ich mache meine gesamte Bereinigung und Validierung in einer objektorientierten Weise, um die Code-Duplizierung zu reduzieren. Die Sanitizer-Superklasse hat Kinder (PostSanitizer, GetSanitizer, ....). Die Validator-Superklasse verfügt über alle Tests, die für eine Zeichenfolge, eine ganze Zahl oder einen Gleitkommawert ausgeführt werden können. Kinder der Validator-Oberklasse sind page/form-spezifisch. Wenn jedoch etwas wie ein Formular-Token benötigt wird, wird die Validierungsmethode in der Validator-Superklasse gefunden, da sie in jedem Formular verwendet werden kann.

Eine gute Validierungsroutine verfolgt:

1) Eingangswerte in einem assoziativen Array ..

2) Testergebnisse (Boolesche) in einem assoziativen Array. Testresultate (true/false) können in CSS-Klassen oder eine JSON-Zeichenfolge von "1" und "0" konvertiert werden.

3) Fehlermeldungen in einem assoziativen Array.

..und trifft dann endgültige Entscheidungen darüber, was mit den Eingabewerten und/oder Fehlermeldungen zu tun ist, basierend auf den Testergebnissen (per Schlüssel). Wenn Fehler vorhanden sind (falsche Werte in einem Array mit hypothetischen Testergebnissen), verwenden Sie die Fehlernachrichten mit dem entsprechenden Schlüssel.

Mein vorheriges Beispiel verdichtet die endgültigen Fehlerprüf- und Fehlermeldungsdatenstrukturen mit einem Array, aber die Verwendung separater Datenstrukturen ermöglicht mehr Flexibilität (entkoppelt Fehlermeldungen von den erkannten Fehlern). Speichern Sie einfach die Ergebnisse jeder validierenden Variablenfunktion in einem $testResults Array wie diesem.

function sanitize($formValue) 
{ 
    $oldValue = $formValue; 

    do 
    { 
     $formValue = trim($formValue); 
     $formValue = strip_tags($formValue); 

     //Anything else you want to do. 

     $formValue = trim($formValue); 

     if($formValue === $oldValue) 
     { 
      break; 
     } 

     $oldValue = $formValue; 
    } 
    while(1); //Infinite loop 

    return $formValue; 
} 

$sanitized = []; 

foreach($_POST as $key => $value) 
{ 
    $sanitized[$key] = sanitize($value); 
} 

$testResults = []; 
$errorMsgs = []; 

foreach($sanitized as $key => $value) 
{ 
    $testResults[$key] = $key($value, $errorMsgs[$key]) 
} 

if(!in_array(false, $testResults, true)) 
{ 
    return true //Assuming that, ultimately, you need to know if everything worked or not, and will take action on this elsewhere. It's up to you to make the correct functions/methods, but this general foundation can get you going. 
} 

return false; //Obviously. Do not submit the form. Show the errors (CSS and error messages). 

Dann überprüfen, einfach für die Existenz von false im $testResults Array. Erhalten Sie die entsprechende Fehlermeldung von $ errorMsgs mit dem entsprechenden $key. Mit diesem generischen, endgültigen Stub können Sie eine leistungsfähige Santisierungs- und Validierungsroutine erstellen, insbesondere wenn Sie objektorientiert vorgehen.

Schließlich werden Sie sehen, dass die gleichen Arten von Tests unter den verschiedenen Validierungsvariablenfunktionen wiederholt werden: Datentyp, Länge, regulärer Ausdruck, exakte Übereinstimmungen, müssen ein Wert innerhalb eines Satzes sein usw. Der Hauptunterschied zwischen den validierenden Variablenfunktionen besteht in den minimalen und maximalen String-Längen, Regex-Mustern usw. Wenn Sie versiert sind, können Sie ein assoziatives Array erstellen, mit dem jede Variable mit ihrer Validierungsgruppe "programmiert" wird Parameter. Das geht ein bisschen über den Rahmen hinaus, aber genau das tue ich.

So führen alle meine variablen Funktionen die gleichen grundlegenden Tests über faktorierte Logik mit einer Methode der Klasse Validator namens validateInput(). Diese Methode erhält folgende Argumente

1) Der zu testende Wert. 2) Ein assoziatives Array der Testparameter (die den Datentyp angeben können). 3) Ein Array-Element, das als Variable (durch Verweis) übergeben wird und dem Feld entspricht, das die Fehlermeldung enthält, falls vorhanden.

Was lustig ist, ist, dass ich eine zweistufige Hygienisierung und eine zweistufige Validierung verwende. Ich verwende einen benutzerdefinierten Filteralgorithmus mit PHP-Funktionen, dann benutze ich die PECL-Filterfunktionen (filter_input_array()). Wenn etwas während dieser Schritte fehlschlägt, werfe ich eine SecurityException (weil ich RuntimeException erweitern).

Erst nachdem diese Filter bestanden haben, versuche ich, die PHP/PECL-Filter Valiation-Funktionen zu verwenden. Dann führe ich meine eigene Validierungsroutine mit validierenden, variablen Funktionen aus. Ja, diese werden nur ausgeführt, wenn der vorherige Test als wahr übergeben wurde (um das Überschreiben vorheriger Fehler und die entsprechende Fehlermeldung zu vermeiden).

Dies ist vollständig objektorientiert. Ich hoffe, ich habe geholfen.