PDO没有正确替换参数

时间:2013-11-10 09:47:44

标签: php mysql pdo

我正在制作一个基于PHP和MySQL的博客(使用PDO进行连接)。我编写了一个函数(下面),它将检索博客文章并返回它们,但order by在我通过引用传递它时不起作用:

<?php
/**
 * Get blog posts, filtered and sorted to taste.
 * @return array Array of rows - each row is an array indexed by column name.
 * @param string $inFunction What to select posts by - id, date or tag(s).
 * @param string $inFilter Filter data to select posts by - id no., date(s) or tag(s). If you are filtering by date and only specify one, it will be taken to be the 'newer than' date.
 * @param string $inOrder How to sort posts. This parameter is fed directly into the query and therefore should be raw SQL.
 * @param object $inDatabase Database handle to pass to the SQL query.
 */

function getBlogPosts($inFunction, $inDatabase, $inFilter, $inOrder) {
    switch ($inFunction) {
        case "permalink": {
            $query = $inDatabase->prepare("select * from blog_posts where permalink = :permalink");
            $query->bindValue(":permalink", $inFilter);
            $query->execute();
            $result = $query->fetch();
            return new BlogPost($result["id"], $result["title"], $result["permalink"], $result["post_full"], $result["post_sample"], $result["tags"], $result["timestamp"]);
            break;
        }

        case "number": {
            $query = $inDatabase->prepare("select * from blog_posts 
                order by :order 
                limit :limit_start , :limit_end");
            $query->bindParam(":order", $inOrder);
            $splitLimits = explode(", ", $inFilter);
            if (sizeOf($splitLimits) === 1)
                $splitLimits[] = 1; // First post

            $limitEnd = $splitLimits[0] + $limitStart;
            $limitStart = $splitLimits[1] - 1;
            $query->bindValue(":limit_start", (int) $limitStart, PDO::PARAM_INT);
            $query->bindValue(":limit_end", (int) $limitEnd, PDO::PARAM_INT);
            $query->debugDumpParams();
            $query->execute();
            $results = $query->fetchAll(PDO::FETCH_ASSOC);
            $return = array();
            foreach ($results as $result) {
                $return[] = new BlogPost($result["id"], $result["title"], $result["permalink"], $result["post_full"], $result["post_sample"], $result["tags"], $result["timestamp"]);
            }
            return $return;
            break;
        }

        case "id": {
            $query = $inDatabase->prepare("select * from blog_posts where id = :id order by :order");
            $query->bindParam(":id", $inFilter);
            $query->bindParam(":order", $inOrder);
            $query->execute();
            return $query->fetchAll(PDO::FETCH_ASSOC); // Prevents duplicate results when using loops (foreach, while etc.)
            break;
        }

        case "date": {
            $splitdate = explode(", ", $inFilter);
            $query = $inDatabase->prepare("select * from blog_posts 
                where (date_posted > :newerthan_date) 
                and (date_posted <= :olderthan_date) 
                order by :order");
            if (sizeof($splitdate) === 1) {
                $splitdate[] = date("Y-m-d");
            }
            $query->bindParam(":newerthan_date", $splitdate[0]);
            $query->bindParam(":olderthan_date", $splitdate[1]);
            $query->bindParam(":order", $inOrder);
            $query->execute();
            return $query->fetchAll(PDO::FETCH_ASSOC);
            break;
        }

        case "tag": {
            $tags = explode(", ", $inFilter);
            $insert = "";
            foreach ($tags as $key => $tag) {
                if ($key === 0) {
                    $insert .= "where tags like :tag_{$key}";
                }
                else {
                    $insert .= " or tags like :tag_{$key}";
                }
            }

            $query = $inDatabase->prepare("select * from blog_posts
                {$insert} 
                order by :order");

            foreach ($tags as $key => $tag) {
                $query->bindValue(":tag_{$key}", '%^' . $tag . '^%');
            }

            $query->bindParam(":order", $inOrder);
            $query->execute();
            return $query->fetchAll(PDO::FETCH_ASSOC);
            break;
        }
    }
}

在主页面上,调用$results = getBlogPosts("number", $sql_conn, "10", "timestamp desc");并且foreach循环遍历帖子。问题是PDO似乎没有应用:order参数;无论我为$ inOrder投入什么,它总是有相同的顺序。如果我直接将getBlogPosts函数中的语句更改为order by timestamp desc而不是order by :order,则可以正常使用。

我很难过 - 有什么想法吗?

1 个答案:

答案 0 :(得分:1)

“此参数直接提供给查询,因此应该是原始SQL。” =&gt;评论是正确的,代码,修复此问题。原因是你可以指定字符串/数字/等。带参数,但不是标识符(列名等)。

您的查询是做什么的:

 SELECT ... FROM ... ORDER BY 'columnname';

而不是:

 SELECT ... FROM ... ORDER BY columnname;

因此。它按字符串'columnname'排序,而不是具有相同名称的字段中的值,每行都是相同的,因此不会进行排序(您也可以ORDER BY 1。这里的解决方案是将该order by子句作为原始MySQL添加为docblock注释状态。如果你想要更多地控制它/防止那里的肮脏,你可以通过子句提供允许顺序的白名单并拒绝其他人。