2016-07-22 38 views
1

正如您在下面的腳本中看到的,在檢查註冊輸入時,我使用了多個if語句。有沒有更簡單,意大利麪條少?我可以做什麼而不是多個陳述? PHP註冊腳本

的腳本是利國利民的,但我想它是整潔。

<?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"; 
    } 
} 

謝謝 周杰倫

+0

即使是一個正確的語法?如果沒有正確的縮進,努力就會明白。 –

+0

是的。這是正確的。因爲它的工作。 – JayLewis

+0

我想短期和代碼的「返回早期」的方法,在這裏閱讀更多關於它:http://programmers.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or -use-an-if-statement –

回答

0

你面對的問題是不是在所有少見。許多程序員都面臨這個問題。讓我在改編劇本的過程中幫助你。

首先,讓我們擺脫了嵌套if-else語句。他們混淆並混淆了真正發生的事情。

版本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); 

注意的是,雖然這避免嵌套if語句,這是不一樣的原代碼,因爲這些錯誤都將落空。我們來解決這個問題。當我們處於這個狀態時,爲什麼我們想在第一個錯誤發生後返回?讓我們一次返回所有的錯誤!

版本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); 
} 

很乾淨爲止!請注意,我們可以用for循環替換if (empty($var))語句。不過,我認爲這在這種情況下是矯枉過正的。

作爲一個側面說明,請記住,這個代碼很容易受到SQL injection。解決這個問題超出了問題的範圍。

0

意大利麪條較少? 從功能分解開始,然後努力將衛生任務與驗證任務分開。我將省去許多步驟(例如驗證表單/ $ _POST/filter_input_array()具有正確的輸入數量,並且正確的鍵位於$ _POST超全局/ INPUT_POST等中,您可能需要考慮那。)。改變我的一些技巧,以滿足您的確切需求。之後你的程序應該不那麼細意大利麪。 :-)

Sanitize然後驗證。 可以這麼說,你必須保持它們分開。 ;-)

與功能分解

消毒使一個單一的任務它自己的代碼塊。

如果您所有的消毒步驟(TRIM(),用strip_tags()等)爲您的所有表單域相同,則使消毒劑函數來完成這項工作。請注意,通過簡單地使用循環,可以改善您修剪和剝離標籤的一次性方法。將原始值保存在變量中,然後在while循環中修剪(),strip_tags()等。 的結果與原始對比。如果他們是一樣的,就休息一下。如果它們不同,請再次將變量字段的當前值保存在變量中,並讓循環再次運行。

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); 
} 

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

進一步展望未來,是次這樣的地方制定的輸入源($ _ POST,$ _ GET,$ _SESSION,$ _FILES,$ _COOKIE,等..)基於消毒,類hierarcy其實就是派上用場。而且,基於filter_input_array()的類層次結構真的讓你成爲遊戲的主角。驗證呢?

與功能分解

你可以看看每個表單字段爲需要其自身的驗證功能驗證。然後,只有檢查一個表單域所需的邏輯將包含在該塊內。關鍵是通過驗證器函數返回測試結果(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. 
} 

在PHP中,您可以使用變量函數來爲您的函數命名與他們正在檢查的字段相同的名稱。所以,要執行這些驗證器,只需執行此操作。

$errorMsgs = []; 

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

然後,一般來說,您只需要查看$ errorMsgs數組中是否有任何錯誤。通過處理$ errorMsgs數組來執行此操作

$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 .... 

進一步,您可以創建一個通用的Validator超類。

這一切雖這麼說。我以面向對象的方式進行所有的清理和驗證,以減少代碼重複。 Sanitizer超級班有孩子(PostSanitizer,GetSanitizer,....)。 Validator超類具有可能對字符串,整數或浮點數執行的所有測試。 Validator超類的孩子是頁面/表單特定的。但是,當需要類似表單令牌的東西時,它的驗證方法可以在Validator超類中找到,因爲它可以用於任何形式。

好的確認例程跟蹤:

1)的輸入值中的關聯數組..

2)試驗結果(布爾)中的關聯數組。測試結果(真/假)可以轉換爲CSS類或JSON字符串'1'和'0'。

3)關聯數組的錯誤消息。

..then做什麼用基於測試結果(通過鍵)輸入值和/或錯誤信息做最後的決定。如果存在錯誤(假設測試結果數組中的值爲假),請使用具有相應鍵的錯誤消息。

我以前的例子冷凝最終錯誤檢查和錯誤信息的數據結構具有一個陣列,但使用不同的數據結構允許更大的靈活性(從檢測到的錯誤解耦錯誤消息)。只需將每個驗證變量函數的結果存儲到$testResults這樣的數組中即可。

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). 

然後,只需檢查的false$testResults陣列中的存在。使用相應的$key從$ errorMsgs獲取相應的錯誤消息。通過使用這個通用的最終存根,您可以創建一個強大的整理和驗證例程,尤其是在面向對象的情況下。最終,你會開始看到,在各種驗證變量函數中重複進行相同類型的測試:數據類型,長度,正則表達式,完全匹配,必須是集合內的值等。因此,驗證變量函數之間的主要區別是最小和最大字符串長度,正則表達式模式等......如果您精明,可以創建一個關聯數組,用於使用其驗證集「編程」每個變量函數參數。這已經超出了範圍,但這就是我所做的。因此,我所有的變量函數都通過分類邏輯使用名爲validateInput()的類Validator方法執行相同的基本測試。此方法收到以下參數

1)要測試的值。 2)測試參數的關聯數組(可指定數據類型) 3)作爲變量(通過引用)傳入的數組元素,對應於正在測試的將保存錯誤消息的字段(如果有)。

有趣的是,我使用了兩步消毒和兩步驗證。我使用PHP函數的自定義過濾器算法,然後使用PECL過濾器函數(filter_input_array())。如果在這些步驟中有任何失敗,我會拋出一個SecurityException(因爲我擴展了RuntimeException)。

只有在這些過濾器通過後,纔會嘗試使用PHP/PECL過濾器閾值函數。然後,我使用驗證,可變函數運行我自己的驗證例程。是的,只有當前面的測試通過爲真(避免覆蓋以前的失敗和相應的錯誤信息)時纔會運行。

這完全是面向對象的。 希望我幫忙。