【问题标题】:single quotes in SQL QuerySQL 查询中的单引号
【发布时间】:2009-12-21 08:43:41
【问题描述】:

我正在编写一个用于更新数据库的 php 脚本,但是当我尝试运行查询时它会出错,它会返回类似于

的错误
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'id=15"' at line 1

在数据中有空格后,“To use near”似乎显示了部分查询。我假设我需要将单引号放在从 php 变量到查询的数据位置,但是当我尝试将它们放入(甚至转义引号)时,我会从脚本中得到解析错误

SQL 查询是

    mysql_query("UPDATE Videos SET Title=".$_POST['Title'].", Preacher=".$_POST['Preacher'].", Date=".$_POST['Date'].", Service=".$_POST['Service'].", File=".$_POST['File'].", Description=".$_POST['Description']."WHERE id=".$_GET['vid_id']."\"") or die(mysql_error());

提前感谢您的帮助

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    mysql_real_escape_string()sql injections 已经被提及。
    但是现在你的脚本(煞费苦心地)必须将 sql 语句与数据/参数混合在一起,下一步 MySQL 服务器必须将数据与语句分开。
    使用(服务器端)prepared statements 查询的两个“部分”是分别发送的,并且(您的 MySQL 服务器的)sql 解析器永远不会“混淆”语句的结束位置和数据的开始位置。

    php-mysql 模块不知道预准备语句,但 php-mysqliPDO 知道。

    $pdo = new PDO('mysql:host=localhost;dbname=test', '...', '...'); 
    $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    
    $stmt = $pdo->prepare('
      UPDATE
        Videos
      SET
        Title=:title ,
        Preacher=:preacher ,
        Date=:date ,
        Service=:service ,
        File=:file ,
        Description=:description
      WHERE
        id=:id
    ');
    $stmt->bindParam(':title', $_POST['title']);
    $stmt->bindParam(':preacher', $_POST['preacher']);
    $stmt->bindParam(':date', $_POST['date']);
    $stmt->bindParam(':service', $_POST['service']);
    $stmt->bindParam(':file', $_POST['file']);
    $stmt->bindParam(':description', $_POST['description']);
    $stmt->bindParam(':id', $_GET['id']); // really _GET?
    $stmt->execute();
    

    如果您仅将 $stmt 用于一项操作,可能会显得很臃肿。但请考虑,否则您必须为每个参数调用 mysql_real_escape_string()。

    【讨论】:

    • 对,但是您也为每个参数调用了 bindParm() :)
    • 是的,这就是我的观点——只是反过来 ;-) 整个 bindParm() 事情可能看起来像开销,但你必须调用 real_escape_string() 否则(或确保一个数字参数真的是数字)
    【解决方案2】:

    您需要正确地转义变量并用单引号将它们括起来:

    mysql_query("UPDATE
                    Videos
                SET
                    Title = '".mysql_real_escape_string($_POST['Title'])."',
                    Preacher = '".mysql_real_escape_string($_POST['Preacher'])."', 
                    Date = '".mysql_real_escape_string($_POST['Date'])."',
                    Service = '".mysql_real_escape_string($_POST['Service'])."',
                    File = '".mysql_real_escape_string($_POST['File'])."',
                    Description = '".mysql_real_escape_string($_POST['Description'])."'
                WHERE
                    id = '".mysql_real_escape_string($_GET['vid_id'])."'")
    or die(mysql_error());
    

    如果不正确地转义你的变量,你会让自己容易受到SQL injection attacks 的攻击。

    编辑

    为了简化上述内容,您可以做一些技巧:

    // Apply mysql_escape_string to every item in $_POST
    array_map('mysql_real_escape_string', $_POST);
    // Get rid of $_POST, $_POST['Title'] becomes $p_Title
    extract($_POST, EXTR_PREFIX_ALL, 'p_');
    
    // Use sprintf to build your query
    $query = sprintf("UPDATE
                    Videos
                SET
                    Title = '%s',
                    Preacher = '%s', 
                    Date = '%s',
                    Service = '%s',
                    File = '%s',
                    Description = '%s'
                WHERE
                    id = '%s'",
                $p_Title,
                $p_Preacher,
                $p_Service,
                $p_File,
                $p_Description,
                mysql_real_escape_string($_GET['vid_id']));
    
    mysql_query($query) or die(mysql_error());
    

    请注意,不鼓励混合使用 $_POST 和 $_GET 变量。您应该通过表单中的隐藏输入字段提供更新 ID。

    【讨论】:

    • 哇,接受 :) 我认为正确使用 sprintf() 会更好,无论是可读性还是性能
    【解决方案3】:

    当您直接使用 DB API(没有 DB 抽象级别)时,最好的解决方案是使用 DB 转义函数。

    只需使用mysql_real_escape_string()

    <?php
    // Your query
    $query = sprintf("UPDATE Videos SET Title='%s', preacher='%s', Date='%s', "
                         ."Service='%s', File='%s', Description='%s' WHERE id='%s'",
                     mysql_real_escape_string($_POST['Title']),
                     mysql_real_escape_string($_POST['Preacher']),
                     mysql_real_escape_string($_POST['Date']),
                     mysql_real_escape_string($_POST['Service']),
                     mysql_real_escape_string($_POST['File']),
                     mysql_real_escape_string($_POST['Description']),
                     mysql_real_escape_string(($_GET['vid_id']));
    ?>
    

    作为奖励,您将获得针对 SQL INJECTION attacs 的真正改进的安全性,您之前的代码很容易受到攻击。

    如果您只是转义斜线,那么再次使用 php/mysql 函数addslashes() 将在这种情况下完成这项工作。

    【讨论】:

      【解决方案4】:

      为什么你要在末尾添加一个\",这会将" 放在 SQL 的末尾,但开头却没有?

      试试这个:

      mysql_query("UPDATE Videos SET Title=".$_POST['Title'].", Preacher=".$_POST['Preacher'].", Date=".$_POST['Date'].", Service=".$_POST['Service'].", File=".$_POST['File'].", Description=".$_POST['Description']."WHERE id=".$_GET['vid_id']) or die(mysql_error());
      

      【讨论】:

        【解决方案5】:

        删除\",来自:

        id=".$_GET['vid_id']."\""
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多