Як уникнути спеціальних символів у MySQL?


78

Наприклад:

select * from tablename where fields like "%string "hi"  %";

Помилка:

У вас є помилка у вашому синтаксисі SQL; перевірте посібник, який відповідає версії вашого сервера MySQL, на правильний синтаксис, який слід використовувати поблизу 'hi ""' у рядку 1

Як побудувати цей запит?


Це може бути обмануто. Як я можу запобігти введенню SQL у PHP? ... (я не кажу, що це повинно чи правильно робити - лише те, що може статися.)
Пітер Мортенсен

Відповіді:


115

Інформація, наведена у цій відповіді, може призвести до небезпечної практики програмування.

Надана тут інформація сильно залежить від конфігурації MySQL, включаючи (але не обмежуючись) версію програми, клієнт бази даних та кодування символів.

Див. Http://dev.mysql.com/doc/refman/5.0/en/string-literals.html

MySQL розпізнає наступні екранні послідовності.
\ 0 Символ ASCII NUL (0x00).
\ 'Одинарні лапки (“'”).
\ "Символ подвійних лапок (" "").
\ b Символ зворотного простору.
\ n Символ нового рядка (подача рядка).
\ r Символ повернення каретки.
\ t Символ табуляції.
\ Z ASCII 26 (Control-Z). Див. Примітку за таблицею.
\\ Символ зворотної косої риски ("\").
\% Символ "%". Див. Примітку за таблицею.
\ _ Символ "_". Див. Примітку за таблицею.

Тож вам потрібно

select * from tablename where fields like "%string \"hi\" %";

Хоча, як зазначає нижче Білл Карвін , використання подвійних лапок для роздільників рядків не є стандартним SQL, тому корисною практикою є використання одинарних лапок. Це спрощує речі:

select * from tablename where fields like '%string "hi" %';

3
Чому невпевнено рятуватися від персонажа?
Пітер Мортенсен

@PeterMortensen, тому що ви не можете повністю покладатися на нього, щоб дезінфікувати ненадійні дані. Це залежить від того, що ви уникаєте всього, що сервер інтерпретує по-різному, і, як зазначається в зауваженні, це залежить від конфігурації, версій та використовуваних кодувань. Нова версія може запросто ввести щось нове, про що ви не розглядали, або ви можете легко забути деяких персонажів, або зловмисники можуть знайти деякі крайні випадки. Нарешті, escapng відганяє вас від належної практики: використовуйте параметри для всього ненадійного, який гарантовано працює так, як очікує механізм БД.
Алехандро

35

Я розробив власний метод втечі MySQL на Java (якщо корисний для когось).

Дивіться код класу нижче.

Попередження: неправильно, якщо ввімкнено режим SQL_BACKSLASH_ESCAPES.

private static final HashMap<String,String> sqlTokens;
private static Pattern sqlTokenPattern;

static
{           
    //MySQL escape sequences: http://dev.mysql.com/doc/refman/5.1/en/string-syntax.html
    String[][] search_regex_replacement = new String[][]
    {
                //search string     search regex        sql replacement regex
            {   "\u0000"    ,       "\\x00"     ,       "\\\\0"     },
            {   "'"         ,       "'"         ,       "\\\\'"     },
            {   "\""        ,       "\""        ,       "\\\\\""    },
            {   "\b"        ,       "\\x08"     ,       "\\\\b"     },
            {   "\n"        ,       "\\n"       ,       "\\\\n"     },
            {   "\r"        ,       "\\r"       ,       "\\\\r"     },
            {   "\t"        ,       "\\t"       ,       "\\\\t"     },
            {   "\u001A"    ,       "\\x1A"     ,       "\\\\Z"     },
            {   "\\"        ,       "\\\\"      ,       "\\\\\\\\"  }
    };

    sqlTokens = new HashMap<String,String>();
    String patternStr = "";
    for (String[] srr : search_regex_replacement)
    {
        sqlTokens.put(srr[0], srr[2]);
        patternStr += (patternStr.isEmpty() ? "" : "|") + srr[1];            
    }
    sqlTokenPattern = Pattern.compile('(' + patternStr + ')');
}


public static String escape(String s)
{
    Matcher matcher = sqlTokenPattern.matcher(s);
    StringBuffer sb = new StringBuffer();
    while(matcher.find())
    {
        matcher.appendReplacement(sb, sqlTokens.get(matcher.group(1)));
    }
    matcher.appendTail(sb);
    return sb.toString();
}

Використовував таблицю заміни пошуку у процедурі mysql, де мені потрібно було уникнути роздільника табуляції, щоб правильно вставити в базу даних, наприклад '\ t'. thx
Ерік Черпняк,

Мені дуже корисно! З повагою!
Paul Vargas

У вас є версія C #?
Нгуєн

28

Для роздільників рядків слід використовувати одинарні лапки. Одинарні лапки - це стандартний роздільник рядків SQL, а подвійні лапки - це роздільники ідентифікаторів (тому ви можете використовувати спеціальні слова або символи в іменах таблиць або стовпців).

У MySQL подвійні лапки працюють (нестандартно) як роздільник рядків за замовчуванням (якщо ви не встановили ANSIрежим SQL). Якщо ви коли-небудь будете використовувати іншу марку баз даних SQL, ви отримаєте перевагу від звички використовувати стандартні лапки.

Ще однією корисною перевагою використання одинарних лапок є те, що буквальні символи подвійних лапок у вашому рядку не потрібно уникати:

select * from tablename where fields like '%string "hi" %';

Я погоджуюся з ідеєю з одинарними лапками, тому що якщо ви перейдете, скажімо, на PostgresSQL, він вперто відмовиться від ваших запитів, і ви повинні використовувати одинарні лапки. Це хороша практика.
kovacsbv

Це обробляє приклад, але як щодо більш загального випадку? Наприклад, зворотну скісну риску, `\`.
Пітер Мортенсен

@PeterMortensen Використовуйте подвійну косу риску, щоб отримати один буквальний символ зворотної риски. Це те саме, що практично у кожній мові програмування. Дивіться також: dev.mysql.com/doc/refman/8.0/en/string-literals.html
Білл

12

MySQL має рядкову функцію QUOTE , і вона повинна вирішити цю проблему:


1
Крім цього не процитувати LIKE«s %характер, так що це досить марно
Пітер В. Мерк

Також зверніть увагу, що QUOTEдодаються оточуючі одиночні кави для рядкових значень
FlameStorm


8

Для таких рядків для мене найзручнішим способом зробити це подвоєння знака 'або ", як пояснюється в посібнику MySQL:

Є кілька способів включити символи лапок у рядок:

A “'” inside a string quoted with'” may be written as “''”.

A “"” inside a string quoted with “"” may be written as “""”.

Precede the quote character by an escape character (“\”).

A “'” inside a string quoted with"” needs no special treatment and need not be doubled or escaped. In the same way, “"” inside a

Струни, позначені символом "'", не потребують особливого ставлення.

Це з http://dev.mysql.com/doc/refman/5.0/en/string-literals.html .


1

Для перевірки того, як вставити подвійні лапки в MySQL за допомогою терміналу, ви можете скористатися таким способом:

TableName (Name, DString) ->
Вставка схеми у значення TableName ("Name", "My QQDoubleQuotedStringQQ")

Після вставки значення ви можете оновити значення в базі даних подвійними або одинарними лапками:

update table TableName replace(Dstring, "QQ", "\"")

0

Якщо ви використовуєте змінну під час пошуку в рядку, mysql_real_escape_string()це добре для вас. Лише моя пропозиція:

$char = "and way's 'hihi'";
$myvar = mysql_real_escape_string($char);

select * from tablename where fields like "%string $myvar  %";

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