-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 ループが投稿を反復処理します。:order問題は、PDO がパラメーターを適用していないように見えることです。$inOrder に何を入れても、常に同じ順序になります。getBlogPosts関数内のステートメントを のorder by timestamp desc代わりに直接変更すると、正常にorder by :order動作します。

私は困惑しています - 何かアイデアはありますか?

4

1 に答える 1

1

「このパラメーターはクエリに直接入力されるため、未加工の SQL である必要があります。」=> コメントは正しく、コードは正しくありません。これを修正してください。その理由は、文字列/数字/などを指定できるからです。パラメーターを使用しますが、 識別子 (列名など)は使用しません。

あなたのクエリはこれを何をしますか:

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

むしろその後:

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

そう。同じ名前のフィールドの値ではなく、文字列でソートし、'columnname'すべての行で同じであるため、ソートは行われません (同様の場合もありますORDER BY 1。ここでの解決策は、その order by 句を生の MySQL として追加することです。 docblock コメントの状態. それをさらに制御したい場合/不快感を防止したい場合は、許容される order by 句のホワイトリストを提供し、他のものを拒否することができます。

于 2013-11-10T09:54:22.157 に答える