1

この質問への回答から、文字列を16進数に変換し、ユーザーから直接文字列を直接危険に使用するのではなく、それらの値を比較することで、プログラムをより安全にしようとしました。その質問のコードを変更して、変換を追加しました。

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'];
}

これを行うのは、データベースでvarcharの代わりにnvarcharを使用しているためです。これで、php側で実行すると、次のようになります。

0xfeff00680065006c006c006f00200077006f0072006c00640021

次に、次のクエリを実行します。

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

結果は次のようになります。

0x680065006C006C006F00200077006F0072006C0064002100

これで、これらの数値がほぼ同じであることがわかります。末尾のゼロを除いて、唯一の違いはfeff00です。なんでそこにあるの?私がしなければならないのはシフトだけだと思いますが、単に仮定するのではなく、なぜそこにあるのかを知りたいのです。phpが私のヘクスの前にfeff00(黄色!)を投げることを決めた理由を誰かが私に説明できますか?

4

1 に答える 1

0

さて、アンドリュー、私はあなたの質問の多くに答えているようです。 このリンクは説明します:

そのため、人々はすべてのUnicode文字列の先頭にFEFFを格納するという奇妙な慣習を思い付く必要がありました。これはUnicodeバイト順マークと呼ばれ、上位バイトと下位バイトを交換する場合はFF FEのように見え、文字列を読み取る人は1バイトおきに交換する必要があることを認識します。ふぅ。野生のすべてのUnicode文字列の先頭にバイト順マークがあるわけではありません。

そしてウィキペディアは説明します:

16ビット単位がビッグエンディアンのバイトオーダーで表される場合、このBOM文字は、バイトのシーケンスで0xFEの後に0xFFとして表示されます。このシーケンスは、テキストがISO-8859-1であることを想定したテキスト表示では、ISO-8859-1文字þÿとして表示されます。

16ビットユニットがリトルエンディアンの順序を使用する場合、バイトのシーケンスは0xFFの後に0xFEが続きます。このシーケンスは、テキストがISO-8859-1であることを想定したテキスト表示では、ISO-8859-1文字ÿþとして表示されます。

つまり、FEFFで表示したコードは、ビッグエンディアン表記であることを意味します。リトルエンディアンにはUTF-16LEを使用すると、SQLがそれを理解します。最初の6桁の16進数のシフトは、2バイトしか使用していない限り、偶然に機能します。

于 2013-06-17T21:17:50.243 に答える