Làm cách nào để thoát chuỗi trong SQL Server bằng PHP?


89

Tôi đang tìm giải pháp thay thế mysql_real_escape_string()cho SQL Server. Là addslashes()lựa chọn tốt nhất của tôi hoặc có một chức năng thay thế khác có thể được sử dụng?

Một thay thế cho mysql_error()cũng sẽ hữu ích.


2
Đối với tôi nó không phải là một câu hỏi trùng lặp vì nó liên quan đến trường hợp cụ thể MSSQL mà không có một quan chức PDO liên quan
Pierre de LESPINAY

Câu trả lời:


74

addslashes()không hoàn toàn phù hợp, nhưng gói mssql của PHP không cung cấp bất kỳ giải pháp thay thế phù hợp nào. Giải pháp xấu nhưng đầy đủ chung chung là mã hóa dữ liệu dưới dạng chuỗi kiểm tra hex, tức là

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

Tóm tắt, đó sẽ là:

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()tương đương là mssql_get_last_message().


1
Rất tiếc, SELECT SCOPE_IDENTITY () của nó!
Bryan Rehbein

4
@genio: Mmm, tuyệt, ngoại trừ thực tế là như vậy. Tôi không cho là bạn sẽ giải thích những gì bạn cho là vấn đề?
hỗn loạn

3
Bạn đã thử điều này với cột ngày giờ chưa? Tôi gặp lỗi này: SQLSTATE[22007]: Invalid datetime format: 210 [Microsoft][ODBC SQL Server Driver][SQL Server]Conversion failed when converting datetime from binary/varbinary string.Tôi tin rằng phương pháp này chỉ có thể đúng nếu nó hoạt động với mọi kiểu dữ liệu MSSQL.
Alejandro García Iglesias

1
Nội dung của mssql_escape()hàm trả về không làm việc đó cho tôi. Màn hình hiển thị văn bản sau khi thực hiện lựa chọn trông như thế này, 0x4a2761696d65206269656e206c652063686f636f6c6174do đó không thể đọc được.
Jeff Noel

3
@JeffNoel Có thể bạn gói chuỗi dấu ngoặc kép đơn hoặc dấu ngoặc kép. Vì mục được thoát thành hex nên các dấu ngoặc kép không cần thiết. SQL Server phải chuyển đổi giá trị hex thành một thứ mà db hiểu được.
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;
    }

Một số mã ở đây đã bị tách khỏi CodeIgniter. Hoạt động tốt và là một giải pháp sạch.

CHỈNH SỬA: Có rất nhiều vấn đề với đoạn mã ở trên. Vui lòng không sử dụng điều này mà không đọc các bình luận để biết đó là những gì. Tốt hơn hết, vui lòng không sử dụng cái này. Các truy vấn được tham số hóa là bạn của bạn: http://php.net/manual/en/pdo.prepared-statements.php


1
Tại sao bạn cần preg_replace? Không phải là str_replaceđủ?
Gabe

gabe: Preg_replace trong trường hợp này là để cho phép tôi sử dụng các phạm vi dành cho tôi trong các lớp ký tự biểu thức chính quy. Sẽ có nhiều chuỗi thay thế hơn trong cái này nếu không.
genio

7
-1. Hàm trích dẫn không có trách nhiệm xử lý dữ liệu - tất cả những gì nó nên làm là đảm bảo rằng chuỗi có định dạng sao cho nó có thể được thêm vào câu lệnh SQL và tồn tại không bị sửa đổi.
cHao

6
Xin lỗi, điều này sai từ dòng mã đầu tiên - empty($value)sẽ trả về truekhông chỉ cho '', mà còn cho null, 0'0'! Bạn sẽ trả về một chuỗi trống trong tất cả các trường hợp đó.
Nux

Tôi đã ủng hộ điều này, tôi nghĩ rằng nó là một chức năng hoàn toàn tốt miễn là bạn nhận thức đầy đủ về các vấn đề ở trên. Tôi sẽ gọi nó là ms_escape_and_strip_string, vì vậy bất kỳ ai khác làm việc trên nó sẽ thấy nó thực hiện cả hai nhiệm vụ đó. Có một chuỗi trống được trả về trong nhiều trường hợp là tốt miễn là bạn tính đến nó, trừ khi tôi chỉ thiếu một điểm lớn hơn ở đây. Nếu điều này không phù hợp với nhu cầu của bạn, bạn luôn có thể lấy dòng đó ra và thay thế nó bằng logic phù hợp với nhu cầu của bạn.
NateDSaint

16

Tại sao bạn lại muốn thoát khỏi bất cứ thứ gì khi bạn có thể sử dụng các tham số trong truy vấn của mình ?!

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

Nó hoạt động ngay trong việc chọn, xóa, cập nhật bất kể tham số giá trị của bạn có nullhay không. Thực hiện một vấn đề về nguyên tắc - Không nối SQL và bạn luôn an toàn và các truy vấn của bạn đọc tốt hơn nhiều.

http://php.net/manual/en/ Chức năng.sqlsrv-query.php


Đây là cách tiếp cận chính xác. Bạn nên luôn sử dụng các tham số trái ngược với các truy vấn đặc biệt. Tuy nhiên, OP không sử dụng trình điều khiển sqlsrv. Anh ấy đang sử dụng trình điều khiển mssql. vì vậy liên kết để sử dụng cho những người bạn bị kẹt khi sử dụng trình điều khiển sqlsrv là http://php.net/manual/en/ Chức năng.mssql-query.php .
smulholland

1
@ smulholland2 Ý của bạn là "hoặc những người trong số bạn bị mắc kẹt khi sử dụng trình điều khiển MSSQL "
Konstantin

Một tình huống có thể xảy ra nếu bạn muốn tạo một tệp các câu lệnh INSERT để sử dụng trong kịch bản di chuyển dữ liệu.
Gary Reckard

11

Bạn có thể xem Thư viện PDO . Bạn có thể sử dụng các câu lệnh đã chuẩn bị sẵn với PDO, nó sẽ tự động thoát khỏi bất kỳ ký tự xấu nào trong chuỗi của bạn nếu bạn thực hiện đúng các câu lệnh đã chuẩn bị. Tôi nghĩ điều này chỉ dành cho PHP 5.


Với một số hành vi nửa vời mà tôi đã thấy từ PDO, tôi sẽ phải thực hiện một số thử nghiệm nghiêm túc trước khi tin tưởng nó để thoát tất cả dữ liệu một cách chính xác.
hỗn loạn

@Chaos Thật không? Tôi không biết về điều này .. bạn có một liên kết đến một bài báo?
alex

Những gì tôi đang nghĩ đến là rắc rối mà anh chàng này ở đây đã gặp phải ngày hôm qua với PDO. Công cụ giao dịch không liên quan, nhưng không ấn tượng. Kết hợp điều đó với tất cả lịch sử thoát dữ liệu không đầy đủ trong PHP (php.net nói với mọi người sử dụng dấu gạch chéo ()!) Và tôi rất nghi ngờ.
hỗn loạn

2
Tôi thích PDO và đã thử điều đó đầu tiên, nhưng cái dành cho MSSQL (trên Unix, dựa trên dblib) đôi khi không thành công với tôi (lỗi phân đoạn), đó là lý do tại sao tôi sử dụng mssql_escape được định nghĩa ở trên.
lapo

Cảm ơn bình luận của bạn, @Iapo. Tôi đang xem xét chuyển sang PDO cho một dự án mssql - cụ thể là để thoát khỏi - nhưng bạn đã cứu tôi khỏi rắc rối.
Winfield Trail,


2

Để thoát khỏi dấu ngoặc kép và đơn, bạn phải nhân đôi chúng lên:

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

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

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

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

Vân vân...

và thuộc tính: Escape Character trong Microsoft SQL Server 2000


2

Sau khi vật lộn với điều này trong nhiều giờ, tôi đã đưa ra một giải pháp gần như tốt nhất.

Câu trả lời của Chaos về việc chuyển đổi giá trị thành chuỗi lục phân không hoạt động với mọi loại dữ liệu, đặc biệt với các cột ngày giờ.

Tôi sử dụng PHP PDO::quote(), nhưng vì nó đi kèm với PHP, PDO::quote()không được hỗ trợ cho MS SQL Server và trả về FALSE. Giải pháp để nó hoạt động là tải xuống một số gói Microsoft:

Sau đó, bạn có thể kết nối trong PHP với PDO bằng DSN như ví dụ sau:

sqlsrv:Server=192.168.0.25; Database=My_Database;

Sử dụng các tham số UIDPWDtrong DSN không hoạt động, vì vậy tên người dùng và mật khẩu được chuyển làm tham số thứ hai và thứ ba trên phương thức khởi tạo PDO khi tạo kết nối. Bây giờ bạn có thể sử dụng PHP PDO::quote(). Thưởng thức.


1

Một câu trả lời từ 2009-02-22T121000 bởi sự hỗn loạn của người dùng không phù hợp với tất cả các truy vấn.

Ví dụ: "TẠO ĐĂNG NHẬP [0x6f6c6f6c6f] TỪ WINDOWS" sẽ cung cấp cho bạn một ngoại lệ.

Tái bút: xem trình điều khiển SQL Server cho PHP, http://msdn.microsoft.com/library/cc296181%28v=sql.90%29.aspx bút và hàm sqlsrv_prepare, có thể liên kết các tham số.

PSS: Điều này cũng không giúp bạn với truy vấn ở trên;)


0

Cảnh báo: Chức năng này đã bị LOẠI BỎ trong PHP 7.0.0.

http://php.net/manual/en/ Chức năng.mssql-query.php

Đối với bất kỳ ai vẫn đang sử dụng các hàm mssql_ * này, hãy nhớ rằng chúng đã bị xóa khỏi PHP kể từ v7.0.0. Vì vậy, điều đó có nghĩa là cuối cùng bạn phải viết lại mã mô hình của mình để sử dụng thư viện PDO, sqlsrv_ *, v.v. Nếu bạn đang tìm kiếm thứ gì đó có phương pháp "trích dẫn / thoát", tôi khuyên bạn nên sử dụng PDO.

Các lựa chọn thay thế cho hàm này bao gồm: PDO :: query (), sqlsrv_query () và odbc_exec ()



0

Để chuyển đổi để lấy lại các giá trị thập lục phân trong SQL thành ASCII, đây là giải pháp mà tôi đã nhận được về việc này (sử dụng hàm từ hỗn loạn của người dùng để mã hóa thành thập lục phân)

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

Tốt hơn là cũng nên thoát khỏi các từ dành riêng cho SQL. Ví dụ:

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

Tôi đã sử dụng cái này thay thế cho 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

Bạn có thể cuộn phiên bản của riêng bạn mysql_real_escape_string, (và cải tiến nó) với biểu thức chính quy sau đây: [\000\010\011\012\015\032\042\047\134\140]. Điều đó sẽ xử lý các ký tự sau: null, backspace, ngang tab, dòng mới, xuống dòng, thay thế, dấu ngoặc kép, dấu nháy đơn, dấu gạch chéo ngược, dấu trọng âm. Backspace và tab ngang không được hỗ trợ bởi mysql_real_escape_string.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.