Як уникнути рядків у SQL Server за допомогою PHP?


89

Я шукаю альтернативу mysql_real_escape_string() для SQL Server. Це addslashes()мій найкращий варіант або є інша альтернативна функція, яку можна використовувати?

Альтернатива для mysql_error()також була б корисною.


2
Для мене це не дублічне запитання, оскільки воно стосується конкретного випадку MSSQL, який не має відповідного офіційного PDO
П’єр де ЛЕСПІНЕЙ

Відповіді:


74

addslashes()не є повністю адекватним, але пакет PHP mssql не забезпечує жодної гідної альтернативи. Потворним, але повністю загальним рішенням є кодування даних у вигляді шістнадцяткового байтового тестування, тобто

$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 02.03.09

4
@genio: Ммм, чудово, за винятком того, що це насправді. Не думаю, що ви пояснили б, що, на вашу думку, є проблемою?
хаос

3
Ви пробували це зі стовпцями datetime? Я отримую цю помилку: 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 Ви, ймовірно, обертаєте рядок одинарними або подвійними лапками. Оскільки елемент переходить у шістнадцяткове, лапки не є необхідними. SQL Server повинен перетворити шістнадцяткове значення на щось, що розуміє 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;
    }

Частина коду тут була вирвана з CodeIgniter. Працює добре і є чистим рішенням.

РЕДАГУВАТИ: Є багато проблем із цим фрагментом коду вище. Будь ласка, не використовуйте це, не читаючи коментарів, щоб знати, що це таке. А ще краще, будь ласка, не використовуйте це взагалі. Параметризовані запити - ваші друзі: http://php.net/manual/en/pdo.prepared-statements.php


1
Навіщо вам preg_replace? Хіба не str_replaceдостатньо?
Гейб,

gabe: preg_replace у цьому випадку мав дозволити мені використовувати діапазони, надані мені в класах символів регулярних виразів. В іншому випадку було б набагато більше замінників рядків.
genio

7
-1. Функція цитування не несе відповідальності за обробку даних - все, що вона повинна зробити, це переконатися, що рядок у такому форматі, що його можна додати до оператора 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 "
Костянтин

Один із сценаріїв може бути, якщо ви хочете створити файл операторів INSERT для використання у сценарії міграції даних.
Gary

11

Ви можете заглянути в бібліотеку PDO . Ви можете використовувати підготовлені оператори з PDO, які автоматично уникнуть будь-яких поганих символів у ваших рядках, якщо ви правильно зробите підготовлені оператори. Це лише для PHP 5, я думаю.


З деякою непомітною поведінкою, яку я бачив поза PDO, мені довелося б провести серйозне тестування, перш ніж я довірив їй, щоб правильно вивести всі дані.
хаос

@Chaos Справді? Я цього не знаю .. у вас є посилання на статтю?
alex

Я думав про проблему, яку цей хлопець тут мав учора з PDO. Не пов’язані між собою операції, але не вражаючі. Поєднайте це з усією історією неадекватного виходу даних у PHP (php.net каже людям використовувати addlashes ()!), І я стає дуже підозрілим.
хаос

2
Я люблю PDO і спробував це спочатку, але той для MSSQL (на Unix, заснований на dblib) іноді не вдається мені (помилка сегментації), тому я вдався до mssql_escape, визначеного вище.
лапо

Дякуємо за ваш коментар, @Iapo. Я розглядав можливість переходу на PDO для проекту mssql - зокрема, щоб уникнути, - але ти врятував мене від проблем.
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

Поборвавшись із цим годинами, я придумав рішення, яке відчуває себе чи не найкращим.

Відповідь Хаосу на перетворення значень у шістнадцятковий рядок працює не з кожним типом даних, зокрема зі стовпцями дати та часу.

Я використовую PHP PDO::quote(), але, оскільки він поставляється з PHP, PDO::quote()не підтримується для MS SQL Server і повертається FALSE. Рішенням для його роботи було завантаження деяких пакетів Microsoft:

Після цього ви можете підключитися в PHP з PDO за допомогою DSN, як показано в наступному прикладі:

sqlsrv:Server=192.168.0.25; Database=My_Database;

Використання параметрів UIDі PWDв DSN не спрацювало, тому ім’я користувача та пароль передаються як другий та третій параметри конструктора PDO під час створення з’єднання. Тепер ви можете використовувати PHP PDO::quote(). Насолоджуйтесь


1

Відповідь хаосу користувача від 22.02.20091212000 не відповідає всім запитам.

Наприклад, "СТВОРИТИ ВХОД [0x6f6c6f6c6f] З ВІКН" дасть вам виняток.

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_ * тощо. Якщо ви шукаєте щось із методом "цитування / екранування", я б рекомендував PDO.

Альтернативи цієї функції включають: PDO :: query (), sqlsrv_query () та odbc_exec ()



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

-1

Для перетворення, щоб повернути шістнадцяткові значення в 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);

-2

Ви можете згорнути свою власну версію mysql_real_escape_string, (і поліпшити його) з наступним регулярним виразом: [\000\010\011\012\015\032\042\047\134\140]. Це піклується про такі символи: нуль, зворотний простір, горизонтальна вкладка, новий рядок, повернення каретки, заміна, подвійна лапка, одинарна лапка, коса коса риса, серйозний акцент. Пробіл і горизонтальна вкладка не підтримуються mysql_real_escape_string.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.