จะหลีกเลี่ยงสตริงใน SQL Server โดยใช้ PHP ได้อย่างไร


89

ฉันกำลังมองหาทางเลือกอื่นmysql_real_escape_string()สำหรับ SQL Server เป็นaddslashes()ตัวเลือกที่ดีที่สุดของฉันหรือมีฟังก์ชันทางเลือกอื่นที่สามารถใช้ได้หรือไม่?

อีกทางเลือกหนึ่งmysql_error()ก็จะมีประโยชน์เช่นกัน


2
สำหรับฉันมันไม่ใช่คำถามที่ซ้ำกันเพราะเกี่ยวข้องกับกรณี MSSQL เฉพาะที่ไม่มี PDO อย่างเป็นทางการที่เกี่ยวข้อง
Pierre de LESPINAY

คำตอบ:


74

addslashes()ยังไม่เพียงพอ แต่แพ็คเกจ mssql ของ PHP ไม่มีทางเลือกที่ดี วิธีแก้ปัญหาที่น่าเกลียด แต่ทั่วไปอย่างสมบูรณ์คือการเข้ารหัสข้อมูลเป็นฐานสิบหก bytestring เช่น

$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 ()!
Bryan Rehbein

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
Alejandro García Iglesias

1
เนื้อหาของmssql_escape()ฟังก์ชันที่ส่งกลับไม่ได้ทำเพื่อฉัน การแสดงข้อความหลังจากทำการเลือกดูเหมือนว่า0x4a2761696d65206269656e206c652063686f636f6c6174จะไม่สามารถอ่านได้
Jeff Noel

3
@JeffNoel คุณอาจจะตัดสตริงอัญประกาศเดี่ยวหรืออัญประกาศคู่ เนื่องจากรายการถูกหลบหนีเป็นเลขฐานสิบหกจึงไม่จำเป็นต้องมีเครื่องหมายคำพูด SQL Server ควรจะแปลงค่าฐานสิบหกเป็นสิ่งที่ฐานข้อมูลเข้าใจ
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;
    }

รหัสบางส่วนที่นี่ถูกคัดลอกมาจาก CodeIgniter ใช้ได้ดีและเป็นน้ำยาที่สะอาด

แก้ไข: มีปัญหามากมายเกี่ยวกับข้อมูลโค้ดด้านบน โปรดอย่าใช้สิ่งนี้โดยไม่อ่านความคิดเห็นเพื่อทราบว่าสิ่งเหล่านี้คืออะไร ยังดีกว่าโปรดอย่าใช้สิ่งนี้เลย คำถามที่เป็นพารามิเตอร์คือเพื่อนของคุณ: http://php.net/manual/en/pdo.prepared-statements.php


1
ทำไมคุณถึงต้องการpreg_replace? ไม่str_replaceเพียงพอหรือ?
Gabe

gabe: preg_replace ในกรณีนี้คืออนุญาตให้ฉันใช้ช่วงที่ฉันจ่ายให้ในคลาสอักขระนิพจน์ทั่วไป จะมีสตริงแทนที่มากขึ้นในอันนี้
genio

7
-1. ไม่ใช่หน้าที่ของฟังก์ชัน quoting ในการยุ่งเกี่ยวกับข้อมูลสิ่งที่ควรทำคือตรวจสอบให้แน่ใจว่าสตริงอยู่ในรูปแบบที่สามารถเพิ่มลงในคำสั่ง SQL และอยู่รอดโดยไม่ได้แก้ไข
cHao

6
ขออภัย แต่นี้เป็นธรรมจากบรรทัดแรกของรหัส - empty($value)จะกลับมาtrueไม่เพียง แต่สำหรับ''แต่ยังสำหรับnull, 0และ'0'! คุณจะส่งคืนสตริงว่างในทุกกรณี
Nux

ฉันเพิ่มคะแนนสิ่งนี้ฉันคิดว่ามันเป็นฟังก์ชั่นที่ดีอย่างสมบูรณ์ตราบเท่าที่คุณตระหนักดีถึงปัญหาข้างต้น ฉันจะเรียกมันว่า 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

1
@ smulholland2 คุณหมายถึง "หรือพวกคุณติดใช้ไดรเวอร์MSSQL "
Konstantin

สถานการณ์หนึ่งอาจเป็นไปได้ว่าคุณต้องการสร้างไฟล์คำสั่ง INSERT เพื่อใช้ในสถานการณ์จำลองการย้ายข้อมูล
Gary Reckard

11

คุณสามารถมองเข้าไปในห้องสมุด PDO คุณสามารถใช้คำสั่งที่เตรียมไว้กับ PDO ซึ่งจะหลีกเลี่ยงอักขระที่ไม่ถูกต้องในสตริงของคุณโดยอัตโนมัติหากคุณทำงบที่เตรียมไว้อย่างถูกต้อง สำหรับ PHP 5 เท่านั้นที่ฉันคิด


ด้วยพฤติกรรมการแบ่งครึ่งหนึ่งที่ฉันเคยเห็นจาก PDO ฉันต้องทำการทดสอบอย่างจริงจังก่อนที่ฉันจะเชื่อถือได้เพื่อหลีกเลี่ยงข้อมูลทั้งหมดอย่างถูกต้อง
ความวุ่นวาย

@ วุ่นวายจริงเหรอ? ฉันไม่รู้เรื่องนี้ .. คุณมีลิงค์ไปยังบทความหรือไม่?
alex

สิ่งที่ฉันคิดคือปัญหาที่ผู้ชายคนนี้กำลังมีกับ PDO เมื่อวานนี้ สิ่งที่ไม่เกี่ยวข้องกับธุรกรรม แต่ไม่น่าประทับใจ รวมกับประวัติทั้งหมดของข้อมูลที่ไม่เพียงพอใน PHP (php.net บอกให้คนอื่นใช้ addlashes ()!) และฉันก็สงสัยมาก
ความวุ่นวาย

2
ฉันชอบ PDO และลองใช้ก่อน แต่สำหรับ MSSQL (บน Unix อิงจาก dblib) บางครั้งก็ล้มเหลวกับฉัน (ความผิดพลาดในการแบ่งส่วน) นั่นเป็นเหตุผลที่ฉันใช้ mssql_escape ที่กำหนดไว้ข้างต้น
Lapo

ขอบคุณสำหรับความคิดเห็นของคุณ @Iapo ฉันกำลังพิจารณาที่จะเปลี่ยนไปใช้ PDO สำหรับโครงการ mssql - โดยเฉพาะเพื่อหนี - แต่คุณช่วยฉันแก้ปัญหา
Winfield Trail

4

อีกวิธีหนึ่งในการจัดการคำพูดเดี่ยวและคู่คือ:

function mssql_escape($str)
{
    if(get_magic_quotes_gpc())
    {
        $str = stripslashes($str);
    }
    return str_replace("'", "''", $str);
}

get_magic_quites_gpc ถูก DEPRECATED เป็น PHP 5.3.0 และ REMOVED เมื่อ PHP 5.4.0 ดูphp.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
ม.ค.

2

ในการหลีกเลี่ยงเครื่องหมายคำพูดเดี่ยวและคู่คุณต้องเพิ่มเป็นสองเท่า:

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

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

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

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

ฯลฯ ...

และการระบุแหล่งที่มา: Escape Character ใน Microsoft SQL Server 2000


2

หลังจากต่อสู้กับเรื่องนี้มาหลายชั่วโมงฉันได้หาวิธีแก้ปัญหาที่เกือบจะดีที่สุด

คำตอบของ Chaos ในการแปลงค่าเป็น hexstring ใช้ไม่ได้กับทุกประเภทข้อมูลโดยเฉพาะกับคอลัมน์วันที่และเวลา

ผมใช้ของ PHP PDO::quote()แต่มันมาพร้อมกับ PHP, PDO::quote()ไม่ได้รับการสนับสนุนสำหรับ MS SQL Server FALSEและผลตอบแทน วิธีแก้ปัญหาในการใช้งานคือดาวน์โหลดชุด Microsoft บางชุด:

  • Microsoft Drivers 3.0 สำหรับ PHP สำหรับ SQL Server (SQLSRV30.EXE): ดาวน์โหลดและทำตามคำแนะนำเพื่อติดตั้ง
  • Microsoft® SQL Server® 2012 Native Client : ค้นหาผ่านเพจที่ครอบคลุมสำหรับ Native Client แม้ว่าจะเป็นปี 2012 แต่ฉันก็ใช้มันเพื่อเชื่อมต่อกับ SQL Server 2008 (การติดตั้ง 2008 Native Client ไม่ทำงาน) ดาวน์โหลดและติดตั้ง

หลังจากนั้นคุณสามารถเชื่อมต่อใน PHP กับ PDO โดยใช้ DSN ดังตัวอย่างต่อไปนี้:

sqlsrv:Server=192.168.0.25; Database=My_Database;

การใช้พารามิเตอร์UIDand PWDใน DSN ไม่ได้ผลดังนั้นชื่อผู้ใช้และรหัสผ่านจึงถูกส่งไปเป็นพารามิเตอร์ที่สองและสามบนตัวสร้าง PDO เมื่อสร้างการเชื่อมต่อ ตอนนี้คุณสามารถใช้ PDO::quote()PHP สนุก.


1

คำตอบจาก 2009-02-22T121000 โดยความสับสนวุ่นวายของผู้ใช้ไม่ตรงกับข้อความค้นหาทั้งหมด

ตัวอย่างเช่น "CREATE LOGIN [0x6f6c6f6c6f] FROM WINDOWS" จะให้ข้อยกเว้น

PS: ดูที่ไดรเวอร์ SQL Server สำหรับ PHP 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_ * เหล่านี้โปรดทราบว่าพวกเขาถูกลบออกจาก PHP เมื่อ v7.0.0 นั่นหมายความว่าในที่สุดคุณต้องเขียนโค้ดโมเดลของคุณใหม่เพื่อใช้ไลบรารี PDO, sqlsrv_ * เป็นต้นหากคุณกำลังมองหาบางสิ่งที่มีวิธี "quoting / escape" ฉันขอแนะนำ PDO

ทางเลือกอื่นสำหรับฟังก์ชันนี้ ได้แก่ : PDO :: query (), sqlsrv_query () และ odbc_exec ()



0

สำหรับการแปลงเพื่อรับค่าฐานสิบหกใน SQL กลับไปเป็น ASCII นี่คือวิธีแก้ปัญหาที่ฉันได้รับจากสิ่งนี้ (โดยใช้ฟังก์ชันจากความสับสนวุ่นวายของผู้ใช้เพื่อเข้ารหัสเป็นเลขฐานสิบหก)

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, backspace, แท็บแนวนอน, บรรทัดใหม่, การคืนค่าขนส่ง, การแทนที่, เครื่องหมายอัญประกาศคู่, เครื่องหมายคำพูดเดี่ยว, แบ็กสแลช, การเน้นที่เจาะจง Backspace mysql_real_escape_stringและแท็บแนวนอนจะไม่ได้รับการสนับสนุนโดย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.