2012-10-31 64 views
0

下面的代碼表示我試圖嘗試並找出行中是否存在符合條件的條件。它默認爲else語句,正確,但如果if語句似乎爲真(沒有電子郵件爲[email protected]),則不會與'if'語句一起使用,而是代碼繼續。該代碼的後半部分主要是爲了擴展情況。該行只能存在或不存在,所以我不明白爲什麼它不嚴格執行其中一個。我正在轉換爲PDO進行網站安全,這就是爲什麼不是所有的都在PDO中。如果這個問題太侷限了,我很抱歉?檢查標準下是否存在行(PDO,準備???)

$stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?"); 
$stmt->execute(array("$email")); 
$row3 = $stmt->fetch(PDO::FETCH_ASSOC); 

while($row = $stmt->fetch()) { 

    if (! $row3) { 
    // Row3 doesn't exist -- this means no one in the database has this email, allow the person to join 
    $query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())"; 
    mysqli_query($dbc, $query); 
    $query = "SELECT * FROM table WHERE username = '$username'"; 
    $data2 = mysqli_query($dbc, $query); 
    while ($row = mysqli_fetch_array($data2)) { 

    $recipent = '' . $row['user_id'] . ''; 

    $query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')"; 
    mysqli_query($dbc, $query); 

    // Aftermath. 
    echo '<p>Your new account has been successfully created. You\'re now ready to <a href="game2.php" target="_blank">log in</a>. After this you should implement basic character-details on your users profile to begin the game.</p>'; 

    mysqli_close($dbc); 
    exit(); 
    } } 
    else { 
    // An account already exists for this email, so display an error message 
    echo '<p class="error">An account already exists for this e-mail.</p>'; 
    $email = ""; 
    } 
} 
+1

錯誤,如果'$ stmt-> fetch()'返回'false','while'循環已經退出,所以如果該行不存在,您將永遠不會輸入'if'語句。 'while'循環類似於'if($ row-> rowCount()> 0)' – dbf

+0

有沒有什麼特別的原因可以混合PDO和MySQLi? –

+0

他說他正在努力將其轉換爲按查詢查詢的PDO。我假設他不想一下子把它全部打破。他似乎還有另一個主要問題,所以混合可能不是一個大問題。 –

回答

2

+1從@Geoff_Montee回答,但這裏有幾個技巧:

  • 請務必檢查錯誤每次準備後()或執行()。報告錯誤(但不要將您的SQL暴露給用戶),並優雅地失敗。

  • 請注意,即使您檢查了是否存在與$ email匹配的行,也可以在檢查後和INSERT之前的短暫時間內創建此行。這是一個race condition。即使您選擇與$ email匹配的行,也應該在數據庫中使用UNIQUE約束,並且在UNIQUE約束因衝突而阻止插入時執行INSERT時捕獲錯誤。

  • SELECT email而不是SELECT *。如果您有電子郵件索引,則查詢運行效率更高,因爲它只能檢查給定值的索引,而不必在不需要時讀取表中的所有列。此優化稱爲僅索引查詢

  • 同樣使用SELECT user_id而不是SELECT *。僅當您確實需要獲取所有列時才使用SELECT *

  • Bcrypt is more secure than SHA for hashing passwords.

+0

您的觀點:通過列名選擇而不是*,我同意並且通常不會這樣做,我真的不知道*是如何結束的,因爲mysql(i)版本沒有它,我只能假設試圖添加COUNT(*)並刪除它放棄了它。關於SHA,是的,我正在看這個問題[在這裏]使用鹽,鑰匙等(http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-散列的口令功能於PHP)。通過檢查錯誤,你的意思是什麼時候行意味着要返回執行一個'關閉,如果行返回= 0'類錯誤停止? –

+1

@SamBowyer他意味着你沒有錯誤檢查你的原代碼。所以,如果查詢失敗(語法錯誤,服務器死亡,颶風吹走數據中心),代碼將繼續徘徊。查看我添加到我的代碼中的錯誤檢查。很多'if(!$ stmt-> prepare(...))'。 –

+0

另外,關於Bill關於競爭條件的觀點......一個好的解決方案是使用事務並選擇合適的事務隔離級別:http://dev.mysql.com/doc/refman/5.5/en/dynindex- isolevel.html –

2

if語句將永遠不會被執行。你需要檢查返回的行數。這是你想要的:

注:我原來用的是$stmt->rowCount(),但是OP說沒有爲他工作。但我很確定那個錯誤的原因是來自其他地方。

if (!($stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?"))) { 
    //error 
} 

if (!$stmt->execute(array("$email"))) { 
    //error 
} 
//The $row3 var you had was useless. Deleted that. 

$count = 0; 

while ($row = $stmt->fetch()) { 
    $count++; 
} 

//The query returned 0 rows, so you know the email doesn't exist in the DB 
if ($count== 0) { 

    $query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())"; 

    if (!mysqli_query($dbc, $query)) { 
     //error 
    } 

    $query = "SELECT * FROM table WHERE username = '$username'"; 

    if (!($data2 = mysqli_query($dbc, $query))) { 
     //error 
    } 

    while ($row = mysqli_fetch_array($data2)) { 

     $recipent = '' . $row['user_id'] . ''; 

     $query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')"; 

     if (!mysqli_query($dbc, $query)) { 
      //error 
     } 

     // Aftermath. 
     echo '<p>Your new account has been successfully created. You\'re now ready to <a href="game2.php" target="_blank">log in</a>. After this you should implement basic character-details on your users profile to begin the game.</p>'; 

     mysqli_close($dbc); 
     exit(); 
    } 
} 
//The query did not return 0 rows, so it does exist in the DB 
else { 
    // An account already exists for this email, so display an error message 
    echo '<p class="error">An account already exists for this e-mail.</p>'; 
    $email = ""; 
} 

而且您應完全轉換其餘查詢以使用PDO。

+0

我嘗試多次使用row_count(與COUNT(*)一起),它只是對我無效。錯誤是「調用一個非對象的成員函數rowCount()」。我讀了rowCount並不總是在SELECT查詢上工作。儘管非常感謝您的回答,但您是否知道爲什麼它將自己標識爲非對象?我認爲數組是對象。 –

+1

@SamBowyer「對非對象的調用」通常意味着還有其他問題。但是,我明白你的觀點。給我一點時間。 –

+0

@ Geoff_Montee - 這是我的錯。重新安排的代碼缺少一個}。我不知道爲什麼導致這個錯誤,但現在的代碼工作。非常感謝 - 以及其他答案,這爲PDO如何處理與mysqli的處理方式提供了深入的見解(並且僅在幾天前才提到PDO意味着我真的沒有學到這一點)。謝謝! –