2012-02-24 81 views
0

我發現有必要在一個我知之甚少的領域工作。我必須確保使用大約20個MySQL SELECT調用的網站數據庫爲網站訪問者提供信息。呼叫都採用的形式:準備語句的語法正確

$leadstory = "-1"; 
if (isset($_GET['leadstory'])) { 
    $leadstory = $_GET['leadstory']; 
} 

$query_News = "SELECT * FROM news WHERE lead_story = $leadstory"; 
$News = mysql_query($query_News, $HDAdave) or die(mysql_error()); 
$row_News = mysql_fetch_assoc($News); 
$totalRows_News = mysql_num_rows($News); 

在以前的文章中,我問,如果這些SELECT語句容易受到SQL注入攻擊。大家都知道答案是肯定的。我做了一些閱讀和理解,我需要使用mysqli和類似以下內容:

$statement = $db_connection->prepare("SELECT * FROM news WHERE lead_story = ?;';"); 
$statement->bind_param("s", $leadstory); 
$statement->execute(); 
$row_News = $statement->fetchAll(); 

我有幾個問題。

  1. 我需要一個「或死亡」型線,如果連接失敗?

  2. 我該如何分配$ totalRows_News

  3. 我還需要「乾淨$leadstory變量與mysql_real_escape_string

+0

切換到PDO,它是迄今爲止的更好的PHP數據庫庫 – Phil 2012-02-24 04:53:49

+0

可能重複[如果你總是最後的MySQL查詢與「完蛋了麼?」(http://stackoverflow.com/q/2130105/),[用PDO計數](http://stackoverflow.com/q/883365/),[在PHP中預先準備好的語句中引用時需要引用的時間](http:// stackoverflow。 com/q/2212097 /) – outis 2012-02-24 08:43:16

回答

1

使用PDO將使你的生活變得更輕鬆

$pdo = new PDO(...); 
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

$stmt = $pdo->prepare('SELECT * FROM news WHERE lead_story = ?'); 
$stmt->bindParam(1, $leadStory); 
$stmt->execute(); 

$allRows_News = $stmt->fetchAll(); 
$totalRows_News = count($allRows_News); 
+0

非常感謝Phil,現在我看到了正確的語法,我可以開始學習它是如何工作的。最好的問候,戴夫 – user1028866 2012-02-24 05:21:31

1
  1. 輸出HTML時不要使用or die。你會得到無效的HTML。通常,檢測到的錯誤處於較低水平,但只能在較高水平上處理。正確的錯誤處理涉及將錯誤傳遞給適當的處理。您可以使用返回值來保存錯誤(如果可以有不同的錯誤和非錯誤返回類型)或使用exceptions
  2. 您可以使用mysqli_result->num_rowsPDOStatement->rowCount獲得結果行數。請注意,後者不適用於PDO支持的所有數據庫,但適用於MySQL。但是,兩者都需要緩衝查詢,這是因爲查詢必須在程序可以繼續之前完成(即execute與查詢同步)並且整個結果集必須存儲在內存中,所以性能較低。 Phil展示的方法可以與其他數據庫一起工作,儘管它與緩衝查詢的性能成本相同。替代的,無緩衝的查詢(execute與查詢相比是異步的)是在行可用時使用,而忽略行的總數直到結束。 PDOStatement支持Traversable,這意味着你可以循環使用foreach循環,所以你不需要知道循環的總行數。

    ... 
    $query->execute(array(':after' => $date)); 
    foreach ($query as $row) { 
        ... 
    } 
    

    這使得其他模塊中的處理結果特別好,因爲它們不需要知道它們迭代的內容。您甚至可以將結果作爲給定類的實例返回。

    $query->execute(...); 
    /* assign properties after calling constructor, so default property 
        values set in constructor don't overwrite the values from the DB */ 
    $query->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Article'); 
    
    # elsewhere, $articles has been set to the value of $query 
    foreach ($articles as $article) { 
        # $article is an Article; do with it what you will. 
        ... 
    } 
    

    的一個缺點到使用PDOStatement直接是查詢結果通常具有一次性使用;除非你使用遊標,否則你只能循環一次。

  3. 這個問題已經被問(可能多次)之前:When is quoting necessary in prepared statements of pdo in PHP?

你可以把準備好的語句類似於功能。使用函數,你需要一段代碼,參數化它的一部分並打包它。一個函數可以多次調用,但只需要定義一次。準備好的陳述也是如此。由於值與代碼保持分開,所以在準備好的語句的參數中無法進行注入(注入是confusing data with code的結果)。

與函數一樣,不能用參數任意替換語句的某些部分。首先,您需要尊重語法。另一個限制是只有某些東西可以被參數化。函數和參數通常只允許您對參數化值進行設置,但在某些語言中,重要的值是相當寬泛的。在SQL中,什麼是一個值非常狹窄。標識符(數據庫,表格,列,存儲過程的名稱,& c)不是值。值列表(例如IN運算符的正確參數)不是它們自己的值。

在一個設計良好的項目中,稍微擴展一點,代碼根據其實現的功能劃分到不同的模塊中。這就是所謂的「separation of concerns」,並導致諸如MVC和多層體系結構之類的東西。 「single responsibility principle是相關的(它可以被認爲是一個子原則)。將這些應用到手頭的案例中,您應該有一個明確的data access layer負責數據庫訪問。您可以應用各種patterns來實現此目的,但必需的只不過DAL應該訪問數據庫,或者受到更改數據如何持久保存的影響,DAL可以自己處理某些錯誤(部分或全部),但不應該關注用戶交互或顯示數據。

+0

感謝您的豐富的信息outis。這是一場真正的教育。戴夫 – user1028866 2012-02-25 15:15:41