在 php 中转换为十六进制与 MSSQL 不同


Converting to hex in php not the same as MSSQL

从这个问题的答案中,我试图通过将字符串转换为十六进制并比较这些值来使我的程序更安全,而不是直接和危险地使用来自用户的字符串。 我修改了该问题的代码以添加转换:

function mssql_escape($data) {
    if(is_numeric($data))
        return $data;
    $data = iconv("ISO-8859-1", "UTF-16", $data);
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

我这样做是因为在我的数据库中我使用的是 nvarchar 而不是 varchar。 现在当我在 php 端运行它时,它提出了

0xfeff00680065006c006c006f00200077006f0072006c00640021

然后我运行以下查询:

 declare @test nvarchar(100);
 set @test = 'hello world!';
 select CONVERT(VARBINARY(MAX), @test);

它导致:

0x680065006C006C006F00200077006F0072006C0064002100

现在你会注意到这些数字几乎相同。 除了尾随零,唯一的区别是 feff00。 为什么会这样呢? 我意识到我所要做的就是转移,但我真的很想知道为什么它在那里,而不仅仅是做出假设。 谁能向我解释为什么 php 决定在我的十六进制前面扔 feff00(黄色!(?

好吧,安德鲁,我似乎回答了你的很多问题。 此链接解释:

于是人们被迫想出了一个奇怪的惯例在每个 Unicode 字符串的开头存储一个 FE FF;这是称为 Unicode 字节顺序标记,如果您要交换高点和低字节,它看起来像FF FE和读取字符串的人将知道他们必须每隔一个字节交换一次。唷。并非每个野外的 Unicode 字符串在开头有一个字节顺序标记。

维基百科解释说:

如果 16 位单位以大端字节顺序表示,则此 BOM字符将按字节序列显示,后跟 0xFE0xFF. 此序列在文本中显示为 ISO-8859-1 字符 þÿ显示,期望文本为 ISO-8859-1。

如果 16 位单元使用小端序,字节序列将遵循0xFF由0xFE。此序列显示为 ISO-8859-1 字符 ÿþ文本显示,要求文本为 ISO-8859-1。

因此,您用 FEFF 显示的代码,这意味着它是大端表示法。 将 UTF-16LE 用于小端序,SQL 会理解这一点。 只要您只使用两个字节,移动前六个十六进制数字只会巧合地起作用。