Bagaimana cara melarikan diri dari string di SQL Server menggunakan PHP?


89

Saya mencari alternatif mysql_real_escape_string()untuk SQL Server. Apakah addslashes()pilihan terbaik saya atau ada fungsi alternatif lain yang dapat digunakan?

Sebuah alternatif mysql_error()juga akan berguna.


2
Bagi saya ini bukan pertanyaan duplikat karena ini menyangkut kasus MSSQL tertentu yang tidak memiliki PDO resmi terkait
Pierre de LESPINAY

Jawaban:


74

addslashes()tidak sepenuhnya memadai, tetapi paket mssql PHP tidak memberikan alternatif yang layak. Solusi yang jelek tapi sepenuhnya umum adalah mengkodekan data sebagai hex bytestring, yaitu

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

Diabstraksi, itu akan menjadi:

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()setara mssql_get_last_message().


1
Ups, SELECT SCOPE_IDENTITY ()!
Bryan Rehbein

4
@genio: Mmm, bagus, kecuali sebenarnya. Saya kira Anda tidak akan menjelaskan apa yang Anda anggap sebagai masalah?
kekacauan

3
Sudahkah Anda mencoba ini dengan kolom tanggal waktu? Saya mendapatkan kesalahan ini: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.Saya yakin metode ini bisa benar hanya jika bekerja dengan setiap tipe data MSSQL.
Alejandro García Iglesias

1
Konten dari mssql_escape()fungsi yang dikembalikan tidak melakukannya untuk saya. Tampilan teks setelah melakukan pemilihan terlihat seperti ini 0x4a2761696d65206269656e206c652063686f636f6c6174sehingga tidak dapat dibaca.
Jeff Noel

3
@JeffNoel Anda mungkin membungkus string tanda kutip tunggal atau tanda kutip ganda. Karena item di-escape ke hex, tanda kutip tidak diperlukan. SQL Server seharusnya mengubah nilai hex menjadi sesuatu yang dipahami db.
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;
    }

Beberapa kode di sini diambil dari CodeIgniter. Bekerja dengan baik dan merupakan solusi yang bersih.

EDIT: Ada banyak masalah dengan cuplikan kode di atas. Tolong jangan gunakan ini tanpa membaca komentar untuk mengetahui apa itu. Lebih baik lagi, tolong jangan gunakan ini sama sekali. Permintaan parameterized adalah teman Anda: http://php.net/manual/en/pdo.prepared-statements.php


1
Mengapa Anda membutuhkannya preg_replace? Bukankah str_replacecukup?
Gabe

gabe: Preg_replace dalam kasus ini adalah untuk memungkinkan saya menggunakan rentang yang diberikan kepada saya dalam kelas karakter ekspresi reguler. Akan ada lebih banyak string yang diganti dalam hal ini sebaliknya.
genio

7
-1. Fungsi kutipan tidak bertanggung jawab untuk mengacaukan data - yang harus dilakukan hanyalah memastikan string dalam format sedemikian rupa sehingga dapat ditambahkan ke pernyataan SQL dan bertahan tanpa modifikasi.
cHao

6
Maaf, ini salah dari baris kode pertama - empty($value)akan mengembalikan truetidak hanya untuk '', tetapi juga untuk null,0 dan '0'! Anda akan mengembalikan string kosong dalam semua kasus tersebut.
Nux

Saya menaikkan suara ini, menurut saya ini berfungsi dengan baik selama Anda sepenuhnya menyadari masalah di atas. Saya akan menyebutnya ms_escape_and_strip_string, jadi siapa pun yang mengerjakannya akan melihatnya melakukan kedua tugas itu. Memiliki string kosong yang dikembalikan dalam banyak kasus tidak masalah selama Anda memperhitungkannya, kecuali saya kehilangan poin yang lebih besar di sini. Jika ini tidak sesuai dengan kebutuhan Anda, Anda selalu dapat mengambil baris itu dan menggantinya dengan logika yang sesuai dengan kebutuhan Anda.
NateDSaint

16

Mengapa Anda repot-repot melarikan diri jika Anda dapat menggunakan parameter dalam kueri Anda ?!

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

Ini berfungsi dengan benar dalam memilih, menghapus, memperbarui terlepas dari apakah parameter nilai Anda nullatau tidak. Buat masalah prinsip - Jangan menggabungkan SQL dan Anda selalu aman dan kueri Anda terbaca jauh lebih baik.

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


Ini adalah pendekatan yang benar. Anda harus selalu menggunakan parameter sebagai kebalikan dari kueri ad hoc. Namun, OP tidak menggunakan driver sqlsrv. Dia menggunakan driver mssql. jadi tautan yang akan digunakan bagi Anda yang terjebak menggunakan driver sqlsrv adalah http://php.net/manual/en/function.mssql-query.php .
smulholland2

1
@ smulholland2 Apakah maksud Anda "atau Anda yang terjebak menggunakan driver MSSQL "
Konstantin

Satu skenario mungkin jika Anda ingin membuat file pernyataan INSERT untuk digunakan dalam skenario migrasi data.
Gary Reckard

11

Anda dapat melihat ke Perpustakaan PDO . Anda dapat menggunakan pernyataan yang telah disiapkan dengan PDO, yang secara otomatis akan menghilangkan karakter buruk apa pun dalam string Anda jika Anda melakukan pernyataan yang disiapkan dengan benar. Ini untuk PHP 5 saja menurut saya.


Dengan beberapa perilaku setengah-setengah yang telah saya lihat dari PDO, saya harus melakukan beberapa pengujian serius sebelum saya mempercayainya untuk menghindari semua data dengan benar.
kekacauan

@Chaos Benarkah? Saya tidak menyadarinya .. apakah Anda memiliki link ke artikel?
alex

Yang saya pikirkan adalah masalah yang dialami orang ini kemarin dengan PDO. Hal-hal transaksi yang tidak terkait, tetapi tidak mengesankan. Gabungkan itu dengan semua riwayat melarikan diri data yang tidak memadai dalam PHP (php.net memberitahu orang-orang untuk menggunakan addlashes ()!) Dan saya menjadi sangat curiga.
kekacauan

2
Saya suka PDO dan mencobanya terlebih dahulu, tetapi yang untuk MSSQL (di Unix, berdasarkan dblib) terkadang gagal pada saya (kesalahan segmentasi), itulah mengapa saya menggunakan mssql_escape yang ditentukan di atas.
lapo

Terima kasih atas komentar Anda, @Iapo. Saya sedang mempertimbangkan untuk beralih ke PDO untuk proyek mssql - khususnya untuk melarikan diri - tetapi Anda telah menyelamatkan saya dari masalah.
Winfield Trail


2

Untuk menghindari tanda kutip tunggal dan ganda, Anda harus menggandakannya:

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

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

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

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

dll ...

dan atribusi: Karakter Escape di Microsoft SQL Server 2000


2

Setelah bergumul dengan ini selama berjam-jam, saya telah menemukan solusi yang terasa hampir terbaik.

Jawaban kekacauan untuk mengonversi nilai menjadi hexstring tidak berfungsi dengan setiap tipe data, khususnya dengan kolom datetime.

Saya menggunakan PHP PDO::quote(), tetapi karena itu datang dengan PHP, PDO::quote()tidak didukung untuk MS SQL Server dan kembali FALSE. Solusi agar berfungsi adalah mengunduh beberapa bundel Microsoft:

Setelah itu Anda bisa terhubung di PHP dengan PDO menggunakan DSN seperti contoh berikut:

sqlsrv:Server=192.168.0.25; Database=My_Database;

Penggunaan parameter UIDdan PWDdi DSN tidak berfungsi, jadi nama pengguna dan sandi dikirimkan sebagai parameter kedua dan ketiga pada konstruktor PDO saat membuat koneksi. Sekarang Anda dapat menggunakan PHP PDO::quote(). Nikmati.



0

Peringatan: Fungsi ini DIHAPUS di PHP 7.0.0.

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

Bagi siapa pun yang masih menggunakan fungsi mssql_ * ini, perlu diingat bahwa fungsi tersebut telah dihapus dari PHP mulai v7.0.0. Jadi, itu berarti Anda pada akhirnya harus menulis ulang kode model Anda untuk menggunakan pustaka PDO, sqlsrv_ * dll. Jika Anda mencari sesuatu dengan metode "mengutip / keluar", saya akan merekomendasikan PDO.

Alternatif untuk fungsi ini termasuk: PDO :: query (), sqlsrv_query () dan odbc_exec ()



0

Untuk konversi untuk mendapatkan nilai heksadesimal dalam SQL kembali menjadi ASCII, berikut adalah solusi yang saya dapatkan untuk ini (menggunakan fungsi dari kekacauan pengguna untuk disandikan menjadi heksadesimal)

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

Lebih baik juga menghindari kata-kata khusus SQL. Sebagai contoh:

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

Saya telah menggunakan ini sebagai alternatif dari 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

Anda bisa roll versi Anda sendiri mysql_real_escape_string, (dan meningkatkan atasnya) dengan ekspresi reguler berikut: [\000\010\011\012\015\032\042\047\134\140]. Itu menangani karakter berikut: null, backspace, tab horizontal, baris baru, carriage return, pengganti, petik ganda, petik tunggal, garis miring terbalik, aksen kuburan. Tab spasi mundur dan horizontal tidak didukung oleh mysql_real_escape_string.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.