PHPを使用してSQL Serverで文字列をエスケープする方法


89

mysql_real_escape_string()SQL Serverの代替を探しています。あるaddslashes()私の最良の選択肢を用いることができる別の代替機能はありますか?

の代替mysql_error()も役立ちます。


2
私にとっては、関連する公式のPDOを持たない特定のMSSQLケースに関係しているので、重複した質問ではありません
Pierre de LESPINAY

回答:


74

addslashes()十分ではありませんが、PHPのmssqlパッケージは適切な代替手段を提供していません。醜いが完全に一般的なソリューションは、データを16進バイト文字列としてエンコードすることです。

$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()!
ブライアンレーバイン2009年

4
@genio:うーん、素晴らしいですが、実際はそうです。あなたが問題であると考えるものを説明すると思いませんか?
混沌

3
日時列でこれを試しましたか?このエラーが発生します。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おそらく文字列の単一引用符または二重引用符をラップします。アイテムは16進数にエスケープされるため、引用符は必要ありません。SQL Serverは、16進値をデータベースが理解できるものに変換することになっています。
danielson317 2014

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/en/pdo.prepared-statements.php


1
なぜあなたは必要preg_replaceですか?str_replace十分ではありませんか?
Gabe

gabe:この場合のpreg_replaceは、正規表現の文字クラスで提供されている範囲を使用できるようにするためのものです。それ以外の場合は、この文字列でより多くの文字列が置き換えられます。
genio

7
-1。データをマングルするのは引用関数の責任ではありません-文字列がSQLステートメントに追加され、変更されずに存続できるような形式であることを確認するだけです。
cHao

6
申し訳ありませんが、これはコードの最初の行から間違っています- だけでなく、およびもempty($value)返されます!これらすべての場合に空の文字列を返します。true''null0'0'
木の実

私はこれを支持しました、あなたが上記の問題を完全に認識している限り、それは完全に素晴らしい機能だと思います。私はそれをms_escape_and_strip_stringと呼んでいるので、それに取り組んでいる誰もがそれが両方のタスクを実行するのを見るでしょう。空の文字列が複数のケースで返されることは、私がここでより大きなポイントを見逃していない限り、あなたがそれを説明する限りは問題ありません。これがニーズに合わない場合は、いつでもその行を取り出して、ニーズに合ったロジックに置き換えることができます。
NateDSaint

16

クエリでパラメーターを使用できるのに、なぜエスケープする必要があるのですか?

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 2017

1
@ smulholland2「MSSQLドライバを使用して立ち往生している」という意味ですか
Konstantin

1つのシナリオは、データ移行シナリオで使用するINSERTステートメントのファイルを生成する場合です。
ゲイリーレッカード

11

PDOライブラリを調べることができます。PDOで準備済みステートメントを使用できます。これは、準備済みステートメントを正しく実行すると、ストリング内の不良文字を自動的にエスケープします。これはPHP 5専用です。


PDOから見た中途半端な動作の一部では、すべてのデータを正しくエスケープするには、PDOを信頼する前にいくつかの真剣なテストを行う必要があります。
混乱

@カオス本当に?私はこれを知らない..記事へのリンクはありますか?
アレックス

私が考えていたのは、この男が昨日PDOで抱えていた問題でした。関連のないトランザクションのものですが、印象的ではありません。これを、PHPでエスケープされた不適切なデータのすべての履歴(php.netに、addslashes()を使用するように指示する!)と組み合わせると、非常に疑わしくなります。
混沌

2
私はPDOが大好きで、最初にそれを試しましたが、MSSQL(Unixではdblibに基づく)の場合、失敗することがあります(セグメンテーション違反)。そのため、上記で定義した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

何時間もこれに苦労した後、私はほとんど最高に感じられる解決策を思いつきました。

値を16進文字列に変換するというカオスの答えは、すべてのデータ型、特に日時列では機能しません。

PHPを使用していますPDO::quote()が、PHPに付属してPDO::quote()いるため、MS SQL Serverではサポートされておらず、が返されますFALSE。それが機能するための解決策は、いくつかのMicrosoftバンドルをダウンロードすることでした。

その後、次の例のようなDSNを使用してPDOでPHPに接続できます。

sqlsrv:Server=192.168.0.25; Database=My_Database;

DSNでパラメータUIDPWDパラメータを使用しても機能しなかったため、接続の作成時にPDOコンストラクタの2番目と3番目のパラメータとしてユーザー名とパスワードが渡されました。これで、PHPを使用できますPDO::quote()。楽しい。


1

ユーザーchaosによる2009-02-22T121000からの回答は、すべてのクエリに適合しません。

たとえば、「CREATE LOGIN [0x6f6c6f6c6f] FROM WINDOWS」とすると、例外が発生します。

PS:PHPのSQL Serverドライバー、http: //msdn.microsoft.com/library/cc296181%28v=sql.90%29.aspx、およびパラメーターをバインドできるsqlsrv_prepare関数を見てください。

PSS:これも上記のクエリでは役に立ちませんでした;)


0

警告:この関数は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()などがあります。



0

SQLの16進値をASCIIに戻す変換の場合、これは私がこれで得た解決策です(ユーザーカオスからの関数を使用して16進にエンコードします)。

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

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

-2

mysql_real_escape_string次の正規表現を使用して、独自のバージョンのを転がすことができます(それを改良することもできます)[\000\010\011\012\015\032\042\047\134\140]。これは、null、バックスペース、水平タブ、改行、復帰、置換、二重引用符、単一引用符、バックスラッシュ、アクサングラーブの文字を処理します。では、バックスペースと水平タブはサポートされていませんmysql_real_escape_string

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.