【问题标题】:How to escape strings in SQL Server using PHP?如何使用 PHP 转义 SQL Server 中的字符串?
【发布时间】:2023-03-03 23:50:01
【问题描述】:

我正在为 SQL Server 寻找 mysql_real_escape_string() 的替代品。 addslashes() 是我的最佳选择还是可以使用其他替代功能?

mysql_error() 的替代方案也很有用。

【问题讨论】:

标签: php sql-server escaping input-sanitization


【解决方案1】:

addslashes() 还不够,但是 PHP 的 mssql 包没有提供任何不错的替代方案。丑陋但完全通用的解决方案是将数据编码为十六进制字节串,即

$unpacked = unpack('H*hex', $data);
mssql_query('
    INSERT INTO sometable (somecolumn)
    VALUES (0x' . $unpacked['hex'] . ')
');

抽象,那就是:

function mssql_escape($data) {
    if(is_numeric($data))
        return $data;
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

mssql_query('
    INSERT INTO sometable (somecolumn)
    VALUES (' . mssql_escape($somevalue) . ')
');

mysql_error() 等效于 mssql_get_last_message()

【讨论】:

  • 糟糕,它的 SELECT SCOPE_IDENTITY()!
  • @genio:嗯,很好,但实际上是这样。我不认为你会解释你认为是什么问题?
  • 您是否尝试过使用日期时间列?我收到了这个错误:SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string. 我相信这个方法只有在适用于所有 MSSQL 数据类型时才是正确的。
  • mssql_escape() 函数返回的内容不是为我做的。进行选择后的文本显示看起来像这样0x4a2761696d65206269656e206c652063686f636f6c6174 因此不可读。
  • @JeffNoel 您可能将字符串换成了单引号或双引号。由于该项目已转义为十六进制,因此不需要引号。 SQL Server 应该将十六进制值转换为 db 可以理解的值。
【解决方案2】:
function ms_escape_string($data) {
        if ( !isset($data) or empty($data) ) return '';
        if ( is_numeric($data) ) return $data;

        $non_displayables = array(
            '/%0[0-8bcef]/',            // url encoded 00-08, 11, 12, 14, 15
            '/%1[0-9a-f]/',             // url encoded 16-31
            '/[\x00-\x08]/',            // 00-08
            '/\x0b/',                   // 11
            '/\x0c/',                   // 12
            '/[\x0e-\x1f]/'             // 14-31
        );
        foreach ( $non_displayables as $regex )
            $data = preg_replace( $regex, '', $data );
        $data = str_replace("'", "''", $data );
        return $data;
    }

这里的一些代码是从 CodeIgniter 中抄袭而来的。效果很好,是一个干净的解决方案。

编辑: 上面的代码 sn-p 有很多问题。请不要在未阅读 cmets 了解它们是什么的情况下使用它。更好的是,请不要使用它。参数化查询是你的朋友:http://php.net/manual/en/pdo.prepared-statements.php

【讨论】:

  • 为什么需要preg_replacestr_replace 还不够吗?
  • gabe:在这种情况下,preg_replace 是为了允许我使用在正则表达式字符类中提供给我的范围。否则会有更多的字符串替换。
  • -1。引用函数不负责破坏数据——它应该做的只是确保字符串的格式可以添加到 SQL 语句中并且不加修改地继续存在。
  • 抱歉,这在第一行代码中是错误的 - empty($value) 将返回 true 不仅适用于 '',而且适用于 null0'0' !在所有这些情况下,您都将返回一个空字符串。
  • 我对此表示赞同,我认为这是一个非常好的功能,只要您完全了解上述问题。不过我会称它为 ms_escape_and_strip_string,所以其他任何在它上面工作的人都会看到它同时完成了这两项任务。只要您考虑到它,在多种情况下返回一个空字符串就可以了,除非我在这里错过了更重要的一点。如果这不符合您的需求,您可以随时删除该行并用适合您需求的逻辑替换它。
【解决方案3】:

当您可以在查询中使用参数时,为什么还要费心转义任何内容?!

sqlsrv_query(
    $connection, 
    'UPDATE some_table SET some_field = ? WHERE other_field = ?', 
    array($_REQUEST['some_field'], $_REQUEST['id'])
)

无论您的值参数是否为null,它都适用于选择、删除、更新。 做一个原则问题 - 不要连接 SQL,你总是安全的,你的查询读起来更好。

http://php.net/manual/en/function.sqlsrv-query.php

【讨论】:

  • 这是正确的做法。您应该始终使用参数而不是临时查询。但是,OP 没有使用 sqlsrv 驱动程序。他正在使用 mssql 驱动程序。因此,对于那些使用 sqlsrv 驱动程序的人来说,使用的链接是 http://php.net/manual/en/function.mssql-query.php
  • @smulholland2 你的意思是“或者你们中的那些人坚持使用 MSSQL 驱动程序”
  • 一种情况可能是,如果您想生成一个 INSERT 语句文件以在数据迁移方案中使用。
【解决方案4】:

您可以查看PDO Library。您可以将预准备语句与 PDO 一起使用,如果您正确执行预准备语句,它将自动转义字符串中的任何坏字符。我认为这仅适用于 PHP 5。

【讨论】:

  • 由于我在 PDO 中看到的一些半途而废的行为,在我相信它能够正确转义所有数据之前,我必须进行一些认真的测试。
  • @Chaos 真的吗?我不知道这个..你有文章的链接吗?
  • 我想到的是这个家伙昨天在 PDO 上遇到的麻烦。不相关的交易的东西,但不起眼。结合 PHP 中数据转义不足的所有历史(php.net 告诉人们使用 addlashes()!),我非常怀疑。
  • 我喜欢 PDO 并首先尝试过,但是用于 MSSQL(在 Unix 上,基于 dblib)的那个有时会在我身上失败(分段错误),这就是我求助于上面定义的 mssql_escape 的原因。跨度>
  • 感谢您的评论,@Iapo。我正在考虑为 mssql 项目切换到 PDO - 特别是为了逃避 - 但你已经为我省去了麻烦。
【解决方案5】:

处理单引号和双引号的另一种方法是:

function mssql_escape($str)
{
    if(get_magic_quotes_gpc())
    {
        $str = stripslashes($str);
    }
    return str_replace("'", "''", $str);
}

【讨论】:

【解决方案6】:

为了转义单引号和双引号,您必须将它们加倍:

$value = 'This is a quote, "I said, 'Hi'"';

$value = str_replace( "'", "''", $value ); 

$value = str_replace( '"', '""', $value );

$query = "INSERT INTO TableName ( TextFieldName ) VALUES ( '$value' ) ";

等等……

和署名:Escape Character In Microsoft SQL Server 2000

【讨论】:

    【解决方案7】:

    在为此苦苦挣扎了几个小时后,我想出了一个感觉几乎是最好的解决方案。

    Chaos 将值转换为十六进制字符串的答案不适用于每种数据类型,尤其是日期时间列。

    我使用 PHP 的 PDO::quote(),但由于 PHP 自带,PDO::quote() 不支持 MS SQL Server 并返回 FALSE。它的工作解决方案是下载一些 Microsoft 捆绑包:

    之后,您可以使用 DSN 在 PHP 中连接 PDO,如下例所示:

    sqlsrv:Server=192.168.0.25; Database=My_Database;
    

    在 DSN 中使用 UIDPWD 参数不起作用,因此在创建连接时,用户名和密码作为 PDO 构造函数的第二个和第三个参数传递。 现在你可以使用 PHP 的PDO::quote()。享受吧。

    【讨论】:

      【解决方案8】:

      警告:此函数已在 PHP 7.0.0 中删除。

      http://php.net/manual/en/function.mssql-query.php

      对于仍在使用这些 mssql_* 函数的任何人,请记住,从 v7.0.0 开始,它们已从 PHP 中删除。因此,这意味着您最终必须重写模型代码以使用 PDO 库、sqlsrv_* 等。如果您正在寻找具有“引用/转义”方法的东西,我会推荐 PDO。

      此函数的替代方法包括:PDO::query()、sqlsrv_query() 和 odbc_exec()

      【讨论】:

        【解决方案9】:

        An answer from 2009-02-22T121000 by user chaos 不适合所有查询。

        例如,“CREATE LOGIN [0x6f6c6f6c6f] FROM WINDOWS”会给你一个例外。

        PS:查看 PHP 的 SQL Server 驱动程序,http://msdn.microsoft.com/library/cc296181%28v=sql.90%29.aspx 和 sqlsrv_prepare 函数,它可以绑定参数。

        PSS:上面的查询也没有帮助您;)

        【讨论】:

          【解决方案10】:

          如果您使用的是 PDO,则可以使用 PDO::quote 方法。

          【讨论】:

            【解决方案11】:

            为了将 SQL 中的十六进制值转换回 ASCII,这是我得到的解决方案(使用the function from user chaos 编码为十六进制)

            function hexEncode($data) {
                if(is_numeric($data))
                    return $data;
                $unpacked = unpack('H*hex', $data);
                return '0x' . $unpacked['hex'];
            }
            
            function hexDecode($hex) {
                $str = '';
                for ($i=0; $i<strlen($hex); $i += 2)
                    $str .= chr(hexdec(substr($hex, $i, 2)));
                return $str;
            }
            
            $stringHex = hexEncode('Test String');
            var_dump($stringHex);
            $stringAscii = hexDecode($stringHex);
            var_dump($stringAscii);
            

            【讨论】:

              【解决方案12】:

              最好也转义 SQL 保留字。例如:

              function ms_escape_string($data) {
                  if (!isset($data) or empty($data))
                      return '';
              
                  if (is_numeric($data))
                      return $data;
              
                  $non_displayables = array(
                      '/%0[0-8bcef]/',        // URL encoded 00-08, 11, 12, 14, 15
                      '/%1[0-9a-f]/',         // url encoded 16-31
                      '/[\x00-\x08]/',        // 00-08
                      '/\x0b/',               // 11
                      '/\x0c/',               // 12
                      '/[\x0e-\x1f]/',        // 14-31
                      '/\27/'
                  );
                  foreach ($non_displayables as $regex)
                      $data = preg_replace( $regex, '', $data);
                  $reemplazar = array('"', "'", '=');
                  $data = str_replace($reemplazar, "*", $data);
                  return $data;
              }
              

              【讨论】:

                【解决方案13】:

                我一直使用它作为mysql_real_escape_string() 的替代品:

                function htmlsan($htmlsanitize){
                    return $htmlsanitize = htmlspecialchars($htmlsanitize, ENT_QUOTES, 'UTF-8');
                }
                $data = "Whatever the value's is";
                $data = stripslashes(htmlsan($data));
                

                【讨论】:

                  【解决方案14】:

                  您可以使用以下正则表达式滚动您自己的mysql_real_escape_string 版本(并对其进行改进):[\000\010\011\012\015\032\042\047\134\140]。这会处理以下字符:null、退格、水平制表符、换行符、回车、替换、双引号、单引号、反斜杠、重音符。 mysql_real_escape_string 不支持退格和水平制表符。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2010-11-28
                    • 2011-07-05
                    • 2013-05-02
                    • 2011-10-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-02-15
                    相关资源
                    最近更新 更多