我正在制作一个基于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
,则可以正常使用。
我很难过 - 有什么想法吗?
答案 0 :(得分:1)
“此参数直接提供给查询,因此应该是原始SQL。” =&gt;评论是正确的,代码不,修复此问题。原因是你可以指定字符串/数字/等。带参数,但不是标识符(列名等)。
您的查询是做什么的:
SELECT ... FROM ... ORDER BY 'columnname';
而不是:
SELECT ... FROM ... ORDER BY columnname;
因此。它按字符串'columnname'
排序,而不是具有相同名称的字段中的值,每行都是相同的,因此不会进行排序(您也可以ORDER BY 1
。这里的解决方案是将该order by子句作为原始MySQL添加为docblock注释状态。如果你想要更多地控制它/防止那里的肮脏,你可以通过子句提供允许顺序的白名单并拒绝其他人。