【问题标题】:Using PDO query, without prepared statements, with multiple LIKE statements from multiple HTML input fields使用 PDO 查询,没有准备好的语句,来自多个 HTML 输入字段的多个 LIKE 语句
【发布时间】:2013-04-09 18:49:45
【问题描述】:

我已成功获取要在 PDO 中执行和打印的查询,但我在这里做错了。这个问题的代码的重要部分在最后几块代码中;为了清楚起见,我将第一部分包括在内。

此代码连接到具有多个输入字段的 HTML 表单。 PHP 通过在 WHERE 语句中使用 AND 附加来自每个字段的数据来构造查询。

这让我很困惑:我回显了 $query 变量,我可以看到查询的格式正确,但是当我尝试打印查询结果时,没有打印任何结果。

我在这里与使用准备好的语句搏斗,并决定尝试让代码在没有它们的情况下首先工作,因为未能构造具有不同数量参数的准备好的语句。在这篇文章的帮助下,我确实尝试过:LIKE query using multiple keywords from search field using PDO prepared statement

所以,暂时搁置准备好的陈述,谁能告诉我我在这里做错了什么?任何帮助将不胜感激。

<?php
if(isset($_POST['submit'])) {

// define the list of fields
$fields = array('titleSearch', 'keywordSearch', 'fullSearch', 'fromYear', 'toYear', 
    'fromSeconds', 'toSeconds', 'withSound', 'withColor');
$conditions = array();

// loop through the defined fields
foreach($fields as $field){
    // if the field is set and not empty
    if(isset($_POST[$field]) && $_POST[$field] != '') {
        // create a new condition, using a prepared statement
        $conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";
    }
}

// build the query
$query = "SELECT keyframeurl, videoid, title, creationyear, sound, color, 
     duration, genre FROM openvideo ";

// if there are conditions defined, append them to the query
if(count($conditions) > 0) {
    $query .= "WHERE " . implode(' AND ', $conditions);
}

//confirm that query formed correctly
echo $query; 

//print query results
foreach ($dbh->query($query) as $row){
   print $row['videoid'].' - '.$row['title'].'<br />';
}
}
?>

【问题讨论】:

标签: php pdo


【解决方案1】:

您忘记了直接插入到查询中的 $_POST 值的引号:

$conditions[] = "$field LIKE CONCAT ('%', '$_POST[$field]', '%')";
                                          ^--            ^--

因此,虽然这将解决您眼前的问题,但您仍然很容易受到 sql 注入攻击。

【讨论】:

  • 谢谢!这绝对是一个需要修复的问题,尽管我的代码在添加单引号后仍然没有执行查询。澄清一下,我打算最终使用准备好的语句,我只是遇到了麻烦,想尝试让一个更简单的版本工作。这是在将单引号添加到“$_POST[$field]”后打印的查询示例:SELECT keyframeurl、videoid、title、creationyear、sound、color、duration、genre FROM openvideo WHERE titleSearch LIKE CONCAT ('% ', 'future', '%') AND withSound LIKE CONCAT ('%', 'withSound', '%')
  • 然后进行一些适当的错误处理。例如$res = $db-&gt;query($sql) or die($db-&gt;errorInfo());.
【解决方案2】:

您必须运行它而不是发布您的查询。
这是解决问题的唯一方法

  • Stack Overflow 路人的头脑中没有数据库服务器来运行您的查询。
  • Stack Overflow 路人的头脑中没有您的特定数据库服务器来运行您的查询。

所以,您是唯一可以对您的数据库运行查询并询问它出了什么问题的人。

  1. Turn on error reporting. 确保您可以看到发生的错误。尝试添加故意错误,看看它是否有效。
  2. 仔细检查您的数据库数据是否确实包含所需的值。
  3. 仔细检查您的输入数据,如果它真的与数据库值匹配。
  4. 在控制台或 phpadmin 中针对数据库运行组装查询。

挖掘一些特定的问题。不要只是坐着等待。问一个问题“我有一个不起作用的代码”没有什么意义。代码必须运行,而不是盯着看。

【讨论】:

  • 感谢有关检查错误的建议。我是初学者,还没有开发出好的调试工具包,所以这很有帮助。
【解决方案3】:
$conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";

是罪魁祸首:为标题发送“某事”最终会变成类似

WHERE titleSearch LIKE CONCAT('%', something, '%')

但你想要

WHERE titleSearch LIKE CONCAT('%', 'something', '%')

有更多的报价。

但请务必不要将其推广到生产中,因为您最终可能会发布“xxx') OR 1=1; --”只是为了表现乐趣,或者更糟糕的是,取决于他们的心情。

【讨论】:

  • 谢谢!我添加了单引号,虽然代码仍然没有执行查询,所以肯定有一些额外的问题。不用担心,我确实打算最终使用准备好的语句,我只是想让代码的更简单版本首先工作。这是此代码打印的查询示例:SELECT keyframeurl, videoid, title, creationyear, sound, color, duration,genre FROM openvideo WHERE titleSearch LIKE CONCAT ('%', 'future', '%') AND withSound LIKE CONCAT ('%', 'withSound', '%')
【解决方案4】:

您甚至不需要CONCAT 内置函数,您可以将整个字符串建模为$conditions[] = "{$field} LIKE '%{$_POST[$field]}%'"。但是如果你不想在短期内面临严重的 SQL 注入攻击,你应该使用准备好的语句。

你为什么不尝试这样的事情呢? (以PDO为例):

if ($pdo = new \PDO("mysql:host=localhost;dbname=testdb;charset=utf8", "user", "password")) {
    $fields = ["titleSearch","keywordSearch","fullSearch","fromYear","toYear","fromSeconds","toSeconds","withSound","withColor"];
    $parameters = array_map(function ($input) { return filter_var($input, FILTER_SANITIZE_STRING); }, $fields)
    $conditions = array_map(function ($input) { return (!empty($_POST[$input]) ? "{$input} LIKE ?" : null); }, $fields);
    $query = "SELECT `keyframeurl`,`videoid`,`title`,`creationyear`,`sound`,`color`,`duration`,`genre` FROM `openvideo`" . (sizeof($conditions) > 0 ? " " . implode(" AND ", $conditions) : null);

    if ($statement = $pdo->prepare($query, [\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY])) {
        if ($statement->execute((!empty($parameters) ? $parameters : null))) {
            $result = $statement->fetchAll(\PDO::FETCH_ASSOC);
        }
    }
}

还没有测试过(我现在才想到),但它应该设置 PDO,根据您似乎要寻找的条件准备一个语句,在 execute() 方法中添加参数(预过滤,尽管有 FAR 更好的过滤技术)并返回与您的查询相关的所有结果。

即使您决定不使用它,也至少要考虑一下...这是 PDO 的一个很好的起点,当然,还有一个很好的 GET/POST 变量过滤教程(或使用 3rd-party像 HTML Purifier 这样的工具)。

希望有所帮助;)

【讨论】:

    猜你喜欢
    • 2010-12-19
    • 1970-01-01
    • 2012-10-24
    • 2010-11-21
    • 2012-08-12
    相关资源
    最近更新 更多