PHP kullanarak SQL Server'da dizelerden nasıl çıkılır?


89

mysql_real_escape_string()SQL Server'ın alternatifini arıyorum . Mı addslashes()benim en iyi seçenek veya kullanılabilecek başka alternatif fonksiyon var mı?

İçin bir alternatif mysql_error()de faydalı olacaktır.


2
Benim için yinelenen bir soru değil çünkü ilgili resmi bir
PDO'su

Yanıtlar:


74

addslashes()tam olarak yeterli değildir, ancak PHP'nin mssql paketi iyi bir alternatif sağlamaz. Çirkin ama tamamen genel çözüm, verileri hex bytestring olarak kodlamaktır.

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

Soyutlanmış, bu şöyle olur:

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()eşdeğerdir mssql_get_last_message().


1
Hata, SELECT SCOPE_IDENTITY ()!
Bryan Rehbein

4
@genio: Mmm, harika, aslında olması dışında. Problem olduğunu düşündüğün şeyi açıklayacağını sanmıyorum?
kaos

3
Bunu tarih saat sütunlarıyla denediniz mi? Şu hatayı alıyorum: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.Bu yöntemin ancak her MSSQL veri türü ile çalışıyorsa doğru olabileceğine inanıyorum.
Alejandro García Iglesias

1
mssql_escape()Döndürülen işlevin içeriği bunu benim için yapmıyor. Bir seçim yaptıktan sonra metin görüntüsü bu 0x4a2761696d65206269656e206c652063686f636f6c6174nedenle okunamaz görünüyor.
Jeff Noel

3
@JeffNoel Muhtemelen dizeyi tek tırnak veya çift tırnak içine alıyorsunuz. Öğe onaltılık alana kaçtığından tırnak işaretleri gerekli değildir. SQL Server'ın hex değerini db'nin anladığı bir şeye dönüştürmesi beklenir.
danielson317

41
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;
    }

Buradaki kodun bir kısmı CodeIgniter'dan koparıldı. İyi çalışıyor ve temiz bir çözüm.

DÜZENLEME: Yukarıdaki kod pasajıyla ilgili pek çok sorun var. Lütfen bunların ne olduğunu öğrenmek için yorumları okumadan kullanmayın. Daha da iyisi, lütfen bunu hiç kullanmayın. Parametreli sorgular arkadaşlarınızdır: http://php.net/manual/en/pdo.prepared-statements.php


1
Neden ihtiyacın var preg_replace? str_replaceYeterli değil mi?
Gabe

gabe: Bu durumda preg_replace, normal ifadeler karakter sınıflarında bana verilen aralıkları kullanmama izin vermekti. Aksi takdirde bunda çok daha fazla dizge ikamesi olurdu.
genio

7
-1. Verileri karıştırmak bir alıntı işlevinin sorumluluğu değildir - tek yapması gereken, dizenin bir SQL deyimine eklenebilecek ve değiştirilmeden hayatta kalabileceği bir formatta olduğundan emin olmaktır.
cHao

6
- Maalesef bu kodunun ilk satırından yanlış empty($value)dönecektir truedeğil sadece '', aynı zamanda için null, 0ve '0'! Tüm bu durumlarda boş bir dize döndürürsünüz.
Nux

Buna oy verdim, yukarıdaki sorunların tamamen farkında olduğunuz sürece bunun mükemmel bir işlev olduğunu düşünüyorum. Buna ms_escape_and_strip_string adını verirdim, bu yüzden üzerinde çalışan herhangi biri bu iki görevi de yaptığını görecekti. Burada daha büyük bir noktayı kaçırmadığım sürece, birden fazla durumda boş bir dizeye sahip olmak, onu hesaba kattığınız sürece sorun değil. Bu ihtiyaçlarınıza uymuyorsa, her zaman bu satırı çıkarabilir ve ihtiyaçlarınıza uygun mantıkla değiştirebilirsiniz.
NateDSaint

16

Sorgunuzda parametreleri kullanabilecekken neden herhangi bir şeyden kaçmakla uğraşasınız ki ?!

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

Değer parametrelerinizin olup olmadığına bakılmaksızın doğrudan seçmelerde, silmelerde, güncellemelerde çalışır null. Prensip meselesi yapın - SQL'i birleştirmeyin ve her zaman güvendesiniz ve sorgularınız çok daha iyi okunur.

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


Doğru yaklaşım budur. Geçici sorguların aksine her zaman parametreleri kullanmalısınız. Ancak OP, sqlsrv sürücülerini kullanmıyor. Mssql sürücüleri kullanıyor. bu nedenle, sqlsrv sürücüleri kullanarak takılanlarınız için kullanabileceğiniz bağlantı http://php.net/manual/en/function.mssql-query.php'dir .
smulholland2

1
@ smulholland2 "veya MSSQL sürücülerini kullananlarınız" mı demek istediniz
Konstantin

Veri geçiş senaryosunda kullanmak için bir INSERT deyimleri dosyası oluşturmak istiyorsanız bir senaryo olabilir.
Gary Reckard

11

PDO Kitaplığına bakabilirsiniz . Hazırlanmış ifadeleri doğru yaparsanız dizelerinizdeki kötü karakterleri otomatik olarak atlayacak olan PDO ile kullanabilirsiniz. Bu sadece PHP 5 için olduğunu düşünüyorum.


PDO'da gördüğüm yarım kalmış davranışların bir kısmıyla, tüm verilerden doğru şekilde kaçmak için ona güvenmeden önce bazı ciddi testler yapmam gerekiyordu.
kaos

@Chaos Gerçekten mi? Bunun farkında değilim .. bir makale bağlantınız var mı?
alex

Düşündüğüm şey, bu adamın dün PDO ile yaşadığı sorundu. İlişkisiz işlem işleri, ancak etkileyici değil. Bunu PHP'de kaçan yetersiz veri geçmişiyle birleştirin (php.net insanlara addslashes () kullanmalarını söylüyor!) Ve çok şüpheleniyorum.
kaos

2
PDO'yu seviyorum ve ilk önce denedim, ancak MSSQL için olanı (Unix üzerinde, dblib tabanlı) bazen bende başarısız oluyor (segmentasyon hatası), bu yüzden yukarıda tanımlanan mssql_escape'e başvurdum.
lapo

Yorumunuz için teşekkürler, @Iapo. Bir mssql projesi için PDO'ya geçmeyi düşünüyordum - özellikle kaçmak için - ama beni bu sorundan kurtardınız.
Winfield Trail


2

Tek ve çift tırnak işaretlerinden kaçmak için onları ikiye katlamanız gerekir:

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

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

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

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

vb...

ve atıf: Microsoft SQL Server 2000'de Kaçış Karakteri


2

Bununla saatlerce uğraştıktan sonra, neredeyse en iyi hissettiren bir çözüm buldum.

Kaos'un değerleri onaltılık dizeye dönüştürme yanıtı her veri türü ile, özellikle tarih saat sütunlarıyla çalışmaz.

PHP kullanıyorum PDO::quote(), ancak PHP ile birlikte geldiği PDO::quote()için MS SQL Sunucusu için desteklenmiyor ve geri dönüyor FALSE. Çalışması için çözüm, bazı Microsoft paketlerini indirmekti:

Bundan sonra aşağıdaki örnekte olduğu gibi bir DSN kullanarak PDO ile PHP'ye bağlanabilirsiniz:

sqlsrv:Server=192.168.0.25; Database=My_Database;

Kullanılması UIDve PWDbağlantı oluştururken kullanıcı adı ve şifre PDO kurucusuna saniyede ve üçüncü parametre olarak geçirilir, böylece DSN parametreler çalıştı olmadı. Artık PHP'yi kullanabilirsiniz PDO::quote(). Zevk almak.



0

Uyarı: Bu işlev PHP 7.0.0'da KALDIRILDI.

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

Hala bu mssql_ * işlevlerini kullanan herkes için, bunların v7.0.0'dan itibaren PHP'den kaldırıldığını unutmayın. Bu, PDO kitaplığını, sqlsrv_ * vb. Kullanmak için model kodunuzu yeniden yazmanız gerektiği anlamına gelir. "Alıntı yapma / kaçma" yöntemiyle bir şey arıyorsanız, PDO'yu tavsiye ederim.

Bu işlevin alternatifleri şunları içerir: PDO :: query (), sqlsrv_query () ve odbc_exec ()



0

SQL'deki onaltılık değerleri ASCII'ye geri döndürmek için, işte bu konuda aldığım çözüm ( kullanıcı kaosundan onaltılı olarak kodlamak için işlevi kullanarak )

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

Ayrılmış SQL sözcüklerinden de kaçınmak daha iyidir. Örneğin:

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

Bunu alternatif olarak kullanıyorum 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

Sen kendi versiyonunu rulo olabilir mysql_real_escape_stringaşağıdaki normal ifade ile, (ve bunun üzerine geliştirmek): [\000\010\011\012\015\032\042\047\134\140]. Bu, aşağıdaki karakterleri dikkate alır: null, backspace, horizontal sekme, yeni satır, satır başı, ikame, çift tırnak, tek tırnak, ters eğik çizgi, ciddi vurgu. Backspace ve yatay sekme tarafından desteklenmez mysql_real_escape_string.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.