-1

我正在制作一个基于 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函数中的语句更改为 haveorder by timestamp desc而不是order by :order,它可以正常工作。

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

4

1 回答 1

1

"This parameter is fed directly into the query and therefore should be raw SQL." => the comment is correct, the code is not, fix this. The reason is you can specify strings/numbers/etc. with parameters, but not identifiers (column names etc.).

What your query does it this:

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

Rather then:

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

So. it sorts by the string 'columnname', not the value in the field with the same name, with is the same for every row, so no sorting takes place (you might as well ORDER BY 1. The solution here is to add that order by clause as raw MySQL as the docblock comment states. If you want more control over it / prevent nastiness there, you could provide a whitelist of allowable order by clauses and refuse others.

于 2013-11-10T09:54:22.157 回答