如何使用PHP在SQL Server中转义字符串?


89

我正在寻找mysql_real_escape_string()SQL Server 的替代方案。是addslashes()我最好的选择,还是可以使用另一种替代功能?

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


2
对我来说,这不是一个重复的问题,因为它涉及没有相关官方PDO的特定MSSQL案例
Pierre de LESPINAY 2013年

Answers:


74

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()


1
糟糕,其SELECT SCOPE_IDENTITY()!
布赖恩·里贝因

4
@genio:嗯,太好了,除了实际上是这样。我不认为您会解释您认为是什么问题?
混乱

3
您是否使用datetime列尝试过此操作?我收到此错误:SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.我相信只有对每种MSSQL数据类型都可以使用此方法,它才是正确的。
亚历杭德罗·加西亚·伊格莱西亚斯

1
mssql_escape()返回的函数的内容不是为我做的。选择后的文本显示看起来像这样,0x4a2761696d65206269656e206c652063686f636f6c6174因此不可读。
杰夫·诺埃尔

3
@JeffNoel您可能将字符串用单引号或双引号引起来。由于该项目转义为十六进制,因此不需要引号。SQL Server应该将十六进制值转换为数据库可以理解的值。
danielson317

40
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剥离的。效果很好,是一个干净的解决方案。

编辑:上面的代码片段有很多问题。请不要在不阅读评论的情况下使用它,以了解它们是什么。更好的是,请不要使用此功能。参数化查询是您的朋友:http : //php.net/manual/zh/pdo.prepared-statements.php


1
为什么需要preg_replace?还str_replace不够吗?
加布

gabe:在这种情况下,preg_replace允许我在正则表达式字符类中使用提供给我的范围。否则,将有更多的字符串替换。
genio

7
-1。处理数据不是引用函数的责任,它要做的只是确保字符串的格式可以将其添加到SQL语句中,并且可以不修改地保存下来。
cHao 2010年

6
很抱歉,但是这是从第一行代码错误- empty($value)将返回true不仅'',而且对null0'0'!在所有这些情况下,您都将返回一个空字符串。
Nux 2010年

我对此表示赞同,只要您完全了解上述问题,它就是一个很好的功能。我将其称为ms_escape_and_strip_string,因此其他从事此工作的人都将看到它完成了这两项任务。只要您考虑它,多次返回一个空字符串就可以了,除非我在这里遗漏了一个更大的要点。如果这不符合您的需求,您可以随时删除该行,并用适合您需要的逻辑替换它。
NateDSaint 2011年

16

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

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

无论您的value参数是否正确,它都可以正确地进行选择,删除,更新null。原则上的问题-不要串联SQL,这样一来,您始终会很安全,并且查询效果会更好。

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


这是正确的方法。您应该始终使用参数,而不是临时查询。但是,OP没有使用sqlsrv驱动程序。他正在使用mssql驱动程序。因此,适合那些使用sqlsrv驱动程序的人的链接是http://php.net/manual/zh/function.mssql-query.php
smulholland2

1
@ smulholland2您的意思是“或者您那些被困使用MSSQL驱动程序的人”
Konstantin

一种情况可能是,如果您想生成一个INSERT语句文件以在数据迁移方案中使用。
加里·瑞卡德

11

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


鉴于我在PDO中看到的一些笨拙的行为,我必须做一些认真的测试,然后我相信它可以正确地转义所有数据。
混乱

@混沌真的吗?我没有意识到。.您是否有文章链接?
alex

我当时想到的是这个家伙昨天在PDO遇到的麻烦。不相关的交易内容,但效果不佳。将其与PHP中数据转义不足的所有历史结合起来(php.net告诉人们使用addlashes()!),我感到非常可疑。
混乱

2
我喜欢PDO并先尝试了该方法,但是有时MSSQL(在Unix上,基于dblib)在MSDO上失败(分段错误),这就是为什么我诉诸于上面定义的mssql_escape的原因。
lapo 2011年

感谢您的评论,@ Iapo。我当时正在考虑为mssql项目切换到PDO-特别是为了逃脱-但您为我省去了麻烦。
Winfield Trail


2

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

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

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

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

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

等等...

和属性: Microsoft SQL Server 2000中的转义字符


2

经过数小时的努力,我想出了一种感觉最好的解决方案。

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()。请享用。



0

警告:此功能已在PHP 7.0.0中删除。

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

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

此功能的替代方法包括:PDO :: query(),sqlsrv_query()和odbc_exec()



0

最好也转义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;
}

-1

我一直在用它作为替代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));

-1

为了将SQL中的十六进制值转换回ASCII,这是我得到的解决方案(使用用户混乱中的函数编码为十六进制)

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);

-2

你可以推出自己的版本mysql_real_escape_string具有以下的正则表达式,(和改进它)[\000\010\011\012\015\032\042\047\134\140]。这需要照顾以下字符:null,退格键,水平制表符,换行符,回车符,替换符,双引号,单引号,反斜杠,重音符。不支持退格和水平制表符mysql_real_escape_string

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.