正确获取预准备语句的语法

时间:2012-02-24 04:28:52

标签: mysql mysqli

我发现有必要在一个我知之甚少的领域工作。我必须确保一个网站数据库,它使用大约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变量?

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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?

  4. 您可以将预备语句视为与函数类似。使用函数,您可以获取一段代码,对其中的一部分进行参数化并打包。函数可以多次调用,但只需要定义一次。准备好的陈述也是如此。由于值与代码分开,因此在预准备语句的参数中无法进行注入(注入是confusing data with code的结果)。

    与函数一样,您不能随意用参数替换语句的某些部分。一方面,您需要尊重语法。另一个限制是只能对某些事物进行参数化。功能和参数通常只允许您参数化值,但在某些语言中,值作为值是相当宽泛的。在SQL中,重要的是一个非常狭窄的值。标识符(数据库,表,列,存储过程和& c的名称)不是值。值列表(例如IN运算符的右参数)本身不是值。

    在一个精心设计的项目中扩展了1.中的一点,代码根据它实现的功能划分为不同的模块。这被称为“separation of concerns”,并导致诸如MVC和多层体系结构之类的东西。 “single responsibility principle是相关的(它可以被认为是一个子原则)。将这些应用于手头的情况,你应该有一个独特的data access layer负责数据库访问。有各种{{3您可以申请实现这一点,但基本方面只是DAL应该访问数据库,或者受到更改数据持久性的影响.DAL本身可以处理某些错误(部分或全部),但它不应该'关注用户交互或显示数据。