Как избежать строк в 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 ()!
Брайан Ребейн, 02

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 должен преобразовывать шестнадцатеричное значение в то, что понимает БД.
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: 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 для использования в сценарии переноса данных.
Гэри Рекард

11

Вы можете заглянуть в библиотеку PDO . Вы можете использовать подготовленные операторы с PDO, который автоматически исключит любые плохие символы в ваших строках, если вы правильно выполните подготовленные операторы. Думаю, это только для PHP 5.


С некоторыми из полуопределенного поведения, которое я видел в PDO, мне пришлось бы провести серьезное тестирование, прежде чем я доверял бы ему правильно экранировать все данные.
хаос,

@Chaos Правда? Я не в курсе .. у вас есть ссылка на статью?
Alex

Я думал о том, что вчера у этого парня была проблема с PDO. Несвязанные транзакции, но не впечатляющие. Добавьте к этому всю историю неадекватного экранирования данных в PHP (php.net говорит людям использовать addlashes ()!), И я становлюсь очень подозрительным.
хаос,

2
Мне нравится PDO, и я попробовал это первым, но тот, который предназначен для MSSQL (в Unix, на основе dblib), иногда дает сбой (ошибка сегментации), поэтому я прибегал к mssql_escape, определенному выше.
Lapo

Спасибо за комментарий, @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' ) ";

так далее...

и атрибуция: escape-символ в Microsoft SQL Server 2000


2

После нескольких часов борьбы с этим я нашел решение, которое кажется мне лучшим.

Ответ хаоса о преобразовании значений в шестнадцатеричную строку не работает с каждым типом данных, особенно со столбцами datetime.

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

  • Драйверы Microsoft 3.0 для PHP для SQL Server (SQLSRV30.EXE): загрузите и следуйте инструкциям по установке.
  • Microsoft® SQL Server® 2012 Native Client : Найдите на обширной странице собственный клиент. Несмотря на то, что сейчас 2012 год, я использую его для подключения к SQL Server 2008 (установка собственного клиента 2008 года не сработала). Загрузить и установить.

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

sqlsrv:Server=192.168.0.25; Database=My_Database;

Использование UIDи PWDпараметры в DSN не работал, поэтому имя пользователя и пароль передаются в качестве второго и третьего параметров на конструктору PDO при создании подключения. Теперь вы можете использовать PHP PDO::quote(). Наслаждаться.


1

Ответ от 22.02.2009 T121000 от user chaos не подходит для всех запросов.

Например, «СОЗДАТЬ ЛОГИН [0x6f6c6f6c6f] ИЗ 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 начиная с версии 7.0.0. Таким образом, это означает, что вам в конечном итоге придется переписать код модели, чтобы использовать библиотеку PDO, sqlsrv_ * и т. Д. Если вы ищете что-то с методом «цитирования / экранирования», я бы порекомендовал 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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.