在原始 sql 查询 Laravel 中插入变量

Posted

技术标签:

【中文标题】在原始 sql 查询 Laravel 中插入变量【英文标题】:Inserting a variable in a raw sql query Laravel 【发布时间】:2016-10-03 18:41:44 【问题描述】:

我在控制器的一个函数中。

所以从表单中,我得到一个变量的值,比如:

$x = "whatever";

然后我需要在 WHERE 语句中嵌入该变量(因此,它的值)。如果我对值进行硬编码,它会带来正确的结果,但我已经尝试了各种方式来插入该变量但没有成功。好吧,假设我设法使用该变量,那么我将不得不研究绑定以避免 sql 注入,但到目前为止,我会说,看看该变量是否可以在查询中使用。

我试过了,双引号,串联。 $vx 。 , 花括号 $x, 像这样的 $variable 变量,但在某些情况下会给出语法错误,(连接),或者如果我只是在 author = $x 的地方嵌入这样的变量,它告诉我它可以'找不到名为 $x 的列

$x = "whatever";
$results = DB::select(DB::raw('SELECT 
                           t.id, t.AvgStyle, r.RateDesc
                       FROM (
                           SELECT
                               p.id, ROUND(AVG(s.Value)) AS AvgStyle
                           FROM posts p

                           INNER JOIN styles s
                               ON s.post_id = p.id
                           WHERE author = $x    
                           GROUP BY p.id
                       ) t
                       INNER JOIN rates r
                           ON r.digit = t.AvgStyle'
                           ));

【问题讨论】:

所以让我们从简单的开始:除非您使用双引号,否则 php 不会进行变量插值。让我们从那个开始。更改您的 sql 语句以使用“SELECT ...”并报告正在发生的任何行为。 我看到的第二个明显的事情 --- 作者是 char/varchar 值吗?如果是这样,您的 sql 语法必须是 WHERE author = '$x' 。 RAW 方法的目的是注入原始 sql,所以它不会为你做任何魔术。您必须构建一个可以复制到命令行工具并运行它的字符串。 你解决了!请把它作为一个答案来获得你的信任。 6000多点的智商不是白给的。 好的,不用担心,很高兴能帮上忙。 我很感激,但如果我们不把它作为答案,每个人都会继续检查它,因为它仍然像未解决一样。 【参考方案1】:

这似乎是一个简单的 PHP 变量插值问题。

DB::raw() 想要 raw SQL。因此,您传递的 SQL 字符串中有几个问题需要修复。

    PHP 变量插值(将变量注入字符串)只有在字符串周围使用双引号时才会发生。使用单引号,它变成一个字符串常量。 如果 Author 是 char/varchar,则 SQL 语法需要在原始 SQL 语句中的字符串两边加上引号。查询构建器通常会为您解决这些问题,但您会绕过它们。

所以“固定”版本是:

$x = "whatever";
$results = DB::select(DB::raw("SELECT 
                       t.id, t.AvgStyle, r.RateDesc
                   FROM (
                       SELECT
                           p.id, ROUND(AVG(s.Value)) AS AvgStyle
                       FROM posts p

                       INNER JOIN styles s
                           ON s.post_id = p.id
                       WHERE author = '$x'    
                       GROUP BY p.id
                   ) t
                   INNER JOIN rates r
                       ON r.digit = t.AvgStyle"
                   ));

像所有插值一样,如果被插值的变量来自用户输入,这会为您带来 SQL 注入的可能性。从最初的问题来看,这是否是一个问题尚不清楚。

DB::select() 有一个选项,允许您传递一个对 SQL 注入本质上是安全的参数数组。在这种情况下,解决方案是:

$x = "whatever";
$results = DB::select(DB::raw("SELECT 
                       t.id, t.AvgStyle, r.RateDesc
                   FROM (
                       SELECT
                           p.id, ROUND(AVG(s.Value)) AS AvgStyle
                       FROM posts p

                       INNER JOIN styles s
                           ON s.post_id = p.id
                       WHERE author = :author
                       GROUP BY p.id
                   ) t
                   INNER JOIN rates r
                       ON r.digit = t.AvgStyle"
                   ),
                       array('author' => $x)
                   );

【讨论】:

旁注:这里没有参数绑定,也没有转义,所以使用此代码的读者应该确保$x不是来自用户输入。 @halfer 根据我的测试,该参数是安全的,因为我可以将where name = :name['name' => "o'brien"] 一起使用。如果它没有转义那个撇号,查询就会失败。 @halfer:您的评论与非参数传递版本有关,我个人不提倡也不会使用。如果您不需要转义,那么参数化查询就是您要走的路,这也会使您免受 SQL 注入的影响。 如果您在 select 方法中有多个值,则此方法不起作用 我不明白你的意思——“select 方法中有多个值”。【参考方案2】:

关于this tutorial

$results = DB::select( DB::raw("SELECT * FROM some_table WHERE some_col = :somevariable"), array(
   'somevariable' => $someVariable,
 ));

【讨论】:

如果您在 select 方法中有多个值,则此方法不起作用【参考方案3】:

这是一个在原始 sql laravel 中插入变量的示例

        $query_result = Event::select(
            DB::raw('(CASE WHEN status = "draft" THEN "draft" 
            WHEN events.end_time <= \''.$now.'\' THEN "closed"
            ELSE "available"
            END) AS status'))
            ->orderBy('status')
            ->get();

【讨论】:

请解释您的解决方案,而不是只显示代码。

以上是关于在原始 sql 查询 Laravel 中插入变量的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 6 中转换原始 sql 查询?

在 Laravel 5 Eloquent 中获取原始 SQL 查询的结果

如何在 Laravel 7 中使用原始 SQL 查询创建范围?

在 Laravel 4 中转义原始 SQL 查询

将原始 SQL 查询传递给 Laravel 上的查询构建器

用于原始查询的 Laravel 批量插入