【问题标题】:PHP PDO custom sql query preparationPHP PDO自定义sql查询准备
【发布时间】:2013-10-01 00:52:25
【问题描述】:

我在 PDO 上使用 prepare 获取 sql 查询时遇到了一点问题,我有以下代码:

$portfolio = $db->prepare("SELECT * FROM `news`, `:sub` WHERE `news`.`id` = `:sub`.`id_news` AND `page` = `:under` ORDER BY `date` DESC LIMIT :start, :limit");
$portfolio->bindParam(':under', $_GET['under'], PDO::PARAM_STR);
$portfolio->bindParam(':sub', $_GET['sub'], PDO::PARAM_STR);
$portfolio->bindParam(':start', $start, PDO::PARAM_INT);
$portfolio->bindParam(':limit', $limit, PDO::PARAM_INT);
$portfolio->execute();

但这并没有给出任何价值,而且我的数据库的值是正确的,有人知道为什么这不起作用吗? PS: var $start 和 $limit 没问题,因为它是分页脚本,在所有页面中都可以正常工作。

例如,我在网址中:mysite.com/index.php?sub=vid&under=info

所以查询应该是这样的:

"SELECT * FROM `news`, `vid` WHERE `news`.`id` = `vid`.`id_news` AND `page` = `info` ORDER BY `date` DESC LIMIT 0, 10"

因此,就我的理解而言,之前拥有此代码应该可以工作并且仍然安全吗?

switch($_GET['sub']){
    case "vid":
        $table = "vid";
        break;
    case "img":
        $table = "img";
        break;
}
$portfolio = $db->prepare("SELECT * FROM `news`, `$table` WHERE `news`.`id` = `$table`.`id_news` AND `page` = :under ORDER BY `date` DESC LIMIT :start, :limit");

【问题讨论】:

  • 为什么你有一个动态链接表?你的设计很糟糕,你知道的。
  • 您不能将表名与 PDO 绑定;检查stackoverflow.com/questions/182287/…
  • 不可能有动态表名,您需要采用不同的方式使这些表名动态化(但正如您的常识所说,最好查看您的数据库结构以及原因你首先需要这种方式。)

标签: php mysql pdo


【解决方案1】:

您不能将查询参数占位符用于表名或列名。

仅使用查询参数替换表达式中的文字值。 IE。带引号的字符串、带引号的日期或数值。

此外,即使您使用字符串或日期的参数,该参数也不会放在引号内。

要使表名或列名动态化,您必须将应用程序变量插入到 SQL 字符串中将字符串提交给 prepare()。

小心验证用户输入(例如 $_GET 变量),以避免 SQL 注入。例如,根据已知合法表名列表测试输入。

例子:

$subtables = array(
 "DEFAULT" => "text",
 "text" => "text",
 "vid" => "vid",
 "pic" => "pic"
);

// if the key exists, use the table name, else use the default table name
$subtable = $subtables[ $_GET["sub"] ] ?: $subtables[ "DEFAULT" ];

// now $subtable is effectively whitelisted, and it is safe to use
// without risk of SQL injection

$portfolio = $db->prepare("SELECT * 
  FROM news, `$subtable` AS sub 
  WHERE news.id = sub.id_news 
    AND page = :under 
  ORDER BY date DESC LIMIT :start, :limit");

【讨论】:

  • Bill 你能检查我的最终代码是否可以工作并且仍然安全吗?
  • 是的,您已将表名列入白名单。但是你仍然有 :under 引号内的参数,这是行不通的。我不知道您是否打算将 'info' 用作列名或字符串文字。
  • @HugoAlves,关于您的代码的另一条评论:如果 $_GET["sub"] 既不是 "vid" 也不是 "img",则 $table 未设置。 SQL会发生什么?您应该始终测试用户直接访问您的页面或手动输入 URL 的情况,而不仅仅是当他们从您的其他页面单击格式正确的链接时。
  • 在 .htaccess 中显示不存在页面(404 错误)的 php 代码中受到保护
【解决方案2】:

您不能将参数用于表和表对象(即字段)的名称。请参阅此问题。

Can PHP PDO Statements accept the table or column name as parameter?

【讨论】:

    【解决方案3】:
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
    

    这两条神奇的线将在您修复最大的一条 - 动态链接表之后解决您的所有小问题。

    它必须是一个单个表,其中“sub”是用于区分类别的字段名称

    SELECT * FROM news n, subnews s 
    WHERE n.id = id_news AND s.sub =:sub AND `page` = :under 
    ORDER BY `date` DESC LIMIT :start, :limit
    

    你还必须改掉用反引号包裹所有移动的习惯。

    【讨论】:

      猜你喜欢
      • 2015-12-08
      • 2010-12-19
      • 2012-06-02
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 1970-01-01
      相关资源
      最近更新 更多