Mysql экранирование символов. И наименьшая помощь была бы от той функции, которую вы разработали

(PHP 4 >= 4.3.0, PHP 5)

mysql_real_escape_string — Escapes special characters in a string for use in an SQL statement

Description

mysql_real_escape_string (string $unescaped_string [, resource $link_identifier = NULL ]) : string

Escapes special characters in the unescaped_string , taking into account the current character set of the connection so that it is safe to place it in a mysql_query() . If binary data is to be inserted, this function must be used.

mysql_real_escape_string() calls MySQL"s library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00 , \n , \r , \ , " , " and \x1a .

This function must always (with few exceptions) be used to make data safe before sending a query to MySQL.

Caution

Security: the default character set

The character set must be set either at the server level, or with the API function mysql_set_charset() for it to affect mysql_real_escape_string() . See the concepts section on character sets for more information.

Parameters

unescaped_string

The string that is to be escaped.

Link_identifier

The MySQL connection. If the link identifier is not specified, the last link opened by mysql_connect() is assumed. If no such link is found, it will try to create one as if mysql_connect() had been called with no arguments. If no connection is found or established, an E_WARNING level error is generated.

Return Values

Returns the escaped string, or FALSE on error.

Errors/Exceptions

Executing this function without a MySQL connection present will also emit E_WARNING level PHP errors. Only execute this function with a valid MySQL connection present.

Examples

Example #1 Simple mysql_real_escape_string() example

// Connect
$link = mysql_connect ("mysql_host" , "mysql_user" , "mysql_password" )
OR die(mysql_error ());

// Query
$query = sprintf ("SELECT * FROM users WHERE user="%s" AND password="%s"" ,
mysql_real_escape_string ($user ),
mysql_real_escape_string ($password ));
?>

Example #2 mysql_real_escape_string() requires a connection example

This example demonstrates what happens if a MySQL connection is not present when calling this function.

The above example will output something similar to:

Warning: mysql_real_escape_string(): No such file or directory in /this/test/script.php on line 5 Warning: mysql_real_escape_string(): A link to the server could not be established in /this/test/script.php on line 5 bool(false) string(41) "SELECT * FROM actors WHERE last_name = """

Example #3 An example SQL Injection Attack

// We didn"t check $_POST["password"], it could be anything the user wanted! For example:
$_POST [ "username" ] = "aidan" ;
$_POST [ "password" ] = "" OR ""="" ;

// Query database to check if there are any matching users
$query = { $_POST [ "username" ]} " AND password=" { $_POST [ "password" ]} "" ;
mysql_query ($query );

// This means the query sent to MySQL would be:
echo $query ;
?>

The query sent to MySQL:

This would allow anyone to log in without a valid password.

Notes

A MySQL connection is required before using mysql_real_escape_string() otherwise an error of level E_WARNING is generated, and FALSE is returned. If link_identifier isn"t defined, the last MySQL connection is used.

Note : mysql_real_escape_string() does not escape % and _ . These are wildcards in MySQL if combined with LIKE , GRANT , or REVOKE .

8 years ago

Just a little function which mimics the original mysql_real_escape_string but which doesn"t need an active mysql connection. Could be implemented as a static function in a database class. Hope it helps someone.

function mysql_escape_mimic ($inp ) {
if(is_array ($inp ))
return array_map (__METHOD__ , $inp );

If(!empty($inp ) && is_string ($inp )) {
return str_replace (array("\\" , "\0" , "\n" , "\r" , """ , """ , "\x1a" ), array("\\\\" , "\\0" , "\\n" , "\\r" , "\\"" , "\\"" , "\\Z" ), $inp );
}

Return $inp ;
}
?>

13 years ago

Note that mysql_real_escape_string doesn"t prepend backslashes to \x00, \n, \r, and and \x1a as mentionned in the documentation, but actually replaces the character with a MySQL acceptable representation for queries (e.g. \n is replaced with the "\n" litteral). (\, ", and " are escaped as documented) This doesn"t change how you should use this function, but I think it"s good to know.

6 years ago

No discussion of escaping is complete without telling everyone that you should basically never use external input to generate interpreted code. This goes for SQL statements, or anything you would call any sort of "eval" function on.

So, instead of using this terribly broken function, use parametric prepared statements instead.

Honestly, using user provided data to compose SQL statements should be considered professional negligence and you should be held accountable by your employer or client for not using parametric prepared statements.

What does that mean?

It means instead of building a SQL statement like this:

"INSERT INTO X (A) VALUES(".$_POST["a"].")"

You should use mysqli"s prepare() function () to execute a statement that looks like this:

"INSERT INTO X (A) VALUES(?)"

NB: This doesn"t mean you should never generate dynamic SQL statements. What it means is that you should never use user-provided data to generate those statements. Any user-provided data should be passed through as parameters to the statement after it has been prepared.

So, for example, if you are building up a little framework and want to do an insert to a table based on the request URI, it"s in your best interest to not take the $_SERVER["REQUEST_URI"] value (or any part of it) and directly concatenate that with your query. Instead, you should parse out the portion of the $_SERVER["REQUEST_URI"] value that you want, and map that through some kind of function or associative array to a non-user provided value. If the mapping produces no value, you know that something is wrong with the user provided data.

Failing to follow this has been the cause of a number of SQL-injection problems in the Ruby On Rails framework, even though it uses parametric prepared statements. This is how GitHub was hacked at one point. So, no language is immune to this problem. That"s why this is a general best practice and not something specific to PHP and why you should REALLY adopt it.

Also, you should still do some kind of validation of the data provided by users, even when using parametric prepared statements. This is because that user-provided data will often become part of some generated HTML, and you want to ensure that the user provided data isn"t going to cause security problems in the browser.

9 years ago

There"s an interesting quirk in the example #2 about SQL injection: AND takes priority over OR, so the injected query actually executes as WHERE (user="aidan" AND password="") OR ""="", so instead of returning a database record corresponding to an arbitrary username (in this case "aidan"), it would actually return ALL database records. In no particular order. So an attacker might be able to log in as any account, but not necessarily with any control over which account it is.

Of course a potential attacker could simply modify their parameters to target specific users of interest:

// E.g. attacker"s values
$_POST [ "username" ] = "" ;
$_POST [ "password" ] = "" OR user = "administrator" AND "" = "" ;

// Malformed query
$query = "SELECT * FROM users WHERE user=" $_POST [ username ] " AND password=" $_POST [ password ] "" ;

echo $query ;

// The query sent to MySQL would read:
// SELECT * FROM users WHERE user="" AND password="" OR user="administrator" AND ""="";
// which would allow anyone to gain access to the account named "administrator"

?>

1 year ago

@feedr
I elaborated his note as following:
$string = "asda\0sd\x1aas\\\\\\\\dasd\"asdasd\na\"\"sdasdad";
$array1 = array("\\\\\\\\", "\0", "\n", "\r", """, """, "\x1a");
$array2 = array("\\\\\\\\\\\\\\\\", "\\\0", "\\\n", "\\\r", "\\\"", "\\\"", "\\\Z");
echo($string);
echo(PHP_EOL);
for($i=0; $i if ($i==0)
$p = "/(? else
$p = "/(? echo($i);
echo($p);
echo($array2[$i]);
$string = preg_replace($p, $array2[$i], $string);
echo("\t");
echo($string);
echo(PHP_EOL);
}
echo(PHP_EOL);
echo($string);

2 years ago

To Quote Sam at Numb Safari

[ "No discussion of escaping is complete without telling everyone that you should basically never use external input to generate interpreted code. This goes for SQL statements, or anything you would call any sort of "eval" function on.

So, instead of using this terribly broken function, use parametric prepared statements instead.

Honestly, using user provided data to compose SQL statements should be considered professional negligence and you should be held accountable by your employer or client for not using parametric prepared statements." ]

Sam is right........

However I do not think it is sensible to stop all sanitising and simply pass the task on to parametric prepared statements.

A particular developer working in a particular situation will always know more about valid input (specific to that context).

If you ask a user to pass in a value you have already given them and you know that all such values start AB****** and the string should be of length 7 or 11 but never any other length then you have the basis of a good pre-sanitiser - different allowable lengths of a string might indicate legacy data.

I would never want to simply pass the rubbish that a malicious user may have passed in through a form to the parametric prepared statements, I would always want to do my own sanity checks first and in some cases these may err on the side of caution and simply choose to abort the Database op completely.

That way my DB does not get clogged up with unsafe statements made safe - it simply does not get clogged up which is better.

Security in layers - sanitisation and validation should still be considered in every situation BEFORE using prepared statements.

In addition as far as I can read into the official doc
==============================================

"Escaping and SQL injection

Bound variables are sent to the server separately from the query and thus cannot interfere with it. The server uses these values directly at the point of execution, after the statement template is parsed. Bound parameters do not need to be escaped as they are never substituted into the query string directly"

That suggests to me that danger is avoided in the internals by alternative handling not by nullification.

This means that a large project with incomplete conversion to prepared statements, legacy code in different parts of an organisation or servers talking to one another could all pass on the bad news from an immune location or situation to one that is not immune.

As long as the sanitisation is competently performed without incurring additional risks then personally I would stick with certain layers of sanitisation and then call the prepared statements.

Поэтому в основном я копал глубоко в области MySQL и PHP … в частности, меры безопасности, которые я должен принимать при работе с базой данных и вводами форм. До сих пор я нашел, что настоятельно рекомендуется следующее:

  1. Подготовленные заявления
  2. Использование _real_escape_string ()
  3. НЕ используя магические кавычки, поскольку он сбивает базы данных и заканчивает тем, что дает вам такие вещи, как «Ты назвал это не …».

Все это здорово, и я слежу за ним. Тем не менее, мне было интересно, следует ли избегать символов, таких как знак доллара [$], знак процента [%] и, возможно, другие. Не мог ли запрос интерпретировать знак доллара как переменную PHP, возможно? Что о синтаксисе LIKE, который я слышал, использует символ% или даже знак подстановки? Подготовленные заявления должны технически позаботиться обо всем этом, но я просто хотел быть в безопасности и убедиться, что у меня все ускользнуло должным образом. В случае, когда я забываю использовать подготовленные заявления или просто пренебрегать ими, я надеялся, что эта вторая линия обороны может сказать мне, что я могу избавиться от головокружения.

Вот что я сейчас использую для экранирования:

Function escape($connection, $data){ $new_data = trim($data); $new_data = i_real_escape_string($connection, $new_data); $new_data = addcslashes($new_data, "%_$"); $new_data = htmlspecialchars($new_data, ENT_NOQUOTES); return $new_data; }

Так это правильно? Я делаю что-то ужасно неправильно? Обратите внимание, что при возврате данных базы данных мне придется удалить обратные косы перед символами $,% и _.

Я делаю что-то ужасно неправильно?

Сначала о ваших исследованиях.

Подготовленные заявления – единственная замечательная вещь, которую вы нашли.

Хотя использование mysqli_real_escape_string (при условии, что вы используете подготовленные инструкции) было бы бесполезным и вредным (создавая результат, который вы отметили сами: «Вы назвали isn \ t …»).

И Magic Quotes уже давно удалены с языка – таким образом, на самом деле ничего не стоит.

Таким образом, даже большинство ваших первоначальных помещений явно ошибочны.

Теперь на ваш вопрос.

Не мог ли запрос интерпретировать знак доллара как переменную PHP, возможно?

Что о синтаксисе LIKE, который я слышал, использует символ% или даже знак подстановки?

Да, вы слышали это правильно. Точная цель оператора LIKE – выполнить поиск по шаблону. Отключение этих символов в LIKE не имело бы ни малейшего смысла.

Каждый раз, когда вы собираетесь использовать LIKE-оператор, вы должны решить, какой конкретный символ использовать и который запретить. Нельзя использовать одноразовое решение. Не говоря уже о том, что во всех других взаимодействиях mysql знак% не имеет никакого особого значения.

Подготовленные заявления должны технически позаботиться обо всем этом

Подготовленные утверждения не имеют ничего общего ни с $, ни с знаками%. Подготовленные утверждения относятся к SQL-инъекциям, но ни один символ не может вызвать его (не могли бы вы назвать «инъекцию» надлежащим образом используемым оператором LIKE, не так ли?).

Наконец, к самой ужасной части.

В случае, если вы забудете использовать подготовленные заявления или просто пренебрегаете их выполнением,

ничто не спасет вас.

И наименьшая помощь была бы от той функции, которую вы разработали.

Подвести итог.

  1. Избавиться от этой функции.
  2. Используйте заполнители * для представления каждой отдельной переменной в запросе.
  3. Escape % и _ символы во входных данных, только если они будут использоваться в LIKE-операторе, и вы не хотите, чтобы их интерпретировали.
  4. Используйте htmlspecialchars () для вывода, а не для ввода mysql.

* прочитайте подготовленные заявления, если этот термин вам незнаком.

Вам не нужно избегать знака доллара. MySQL не рассматривает этот характер специально, и PHP только распознает его в исходном коде, а не в строковых значениях (если вы не вызываете eval в строке, но это целая другая червь из червей).

Вам нужно будет только избежать % и _ если вы использовали пользовательский ввод в качестве аргумента LIKE и вы не хотели, чтобы пользователь мог использовать подстановочные знаки. Это может возникнуть, если вы обрабатываете форму поиска. Вам не нужно использовать его при хранении в базе данных.

При доступе к базе данных вам не нужно использовать htmlspecialchars . Это следует использовать только при отображении данных пользователю на странице HTML, чтобы предотвратить внедрение XSS.

В зависимости от того, какие данные и для чего они используются.

Если вы обнаружите, что готовые заявления по умолчанию PHP слишком велики и сложны, я предлагаю взглянуть на некоторые классы, доступные на github, чтобы дать вам представление об упрощенных запросах.

Пример вставки запросов с этим классом

$data = Array ("login" => "admin", "active" => true, "firstName" => "John", "lastName" => "Doe", "password" => $db->func("SHA1(?)",Array ("secretpassword+salt")), // password = SHA1("secretpassword+salt") "createdAt" => $db->now(), // createdAt = NOW() "expires" => $db->now("+1Y") // expires = NOW() + interval 1 year // Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear); $id = $db->insert ("users", $data); if ($id) echo "user was created. Id=" . $id; else echo "insert failed: " . $db->getLastError();


Для начала - немного о том, почему вообще нужны эти слеши.
Если мы подставляем в запрос какие-либо данные, то, чтобы отличить эти данные от команд SQL, их надо брать в кавычки.
К примеру, если написать
SELECT * FROM table WHERE name = Bill
то база решит, что Bill - это имя другого поля, не найдёт его, и выдаст ошибку. Поэтому подставляемые данные (в данном случае имя Bill) надо заключать в кавычки - тогда база сочтет его строкой, значение которой надо присвоить полю name:
SELECT * FROM table WHERE name = "Bill"
Однако, и в самих данных могут встречаться кавычки тоже. К примеру,
SELECT * FROM table WHERE name = "Д"Артаньян"
Здесь база данных решит, что "Д" - это данные, а Артаньян - команда, которую она не знает, и тоже выдаст ошибку. Поэтому и надо прослешивать все данные, чтобы объяснить базе, что встречающиеся в них кавычки (и некоторые другие спецсимволы) относятся к данным.
В результате мы получим правильный запрос, который ошибок не вызовет:
SELECT * FROM table WHERE name = "Д\"Артаньян"

Таким образом, мы выяснили, что при подстановке данных в запрос, следует придерживаться двух правил:
- все вставляемые в запрос данные должны быть заключены в кавычки (одинарные или двойные, но удобнее и чаще используются одинарные).
- во всех строковых переменных должны быть экранированы слешами спецсимволы.

Следует специально отметить: добавленные слеши НЕ идут в базу. Они нужны только в запросе. При попадании в базу слеши отбрасываются. Соответственно, распространенной ошибкой является применение stripslashes при получении данных из базы.

На самом деле, всё вышесказанное относится к данным строкового типа и датам. Числа можно вставлять не прослешивая и не окружaя кавычками. Если вы так делаете, то ОБЯЗАТЕЛЬНО! насильно приводите данные к нужному типу перед вставкой в запрос, например:
$id = intval ($id );
Однако для простоты (и надёжности) можно и с числами работать, как со строками (проскольку mysql всё равно преобразует их к нужному типу). Соответственно, мы будем любые данные, вставляемые в запрос, прослешивать и заключать в кавычки.

Так же, есть ещё одно правило - необязательное, но его следует придерживаться во избежание появления ошибок:
Имена полей и таблиц следует заключать в обратные одинарные кавычки - "`" (клавиша с этим символом находится на стандартной клавиатуре слева от клавиши "1") Ведь имя поля может совпадать с ключевыми словами mysql, но если мы используем обратную кавычку, то MySQL поймёт всё правильно:
SELECT * FROM `table` WHERE `date` = "2006-04-04"
Следует различать эти кавычки и не путать одни с другими. Следует также помнить, что обратные кавычки слешами не экранируются.

Итак, мы научились правильно подставлять в запрос данные.
НО! Динамическое составление запросов не исчерпывается подстановкой данных. Часто нам приходится подставлять в запрос команды SQL и имена полей. И здесь мы уже переходим к теме безопасности:

SQL Injection - это способ хакерской атаки, когда передаваемые скрипту данные модифицируются таким образом, что запрос, формируемый в этом скрипте, начинает выполнять совсем не то, для чего он предназначался.
Правила защиты от таких атак можно разделить на два пункта:
1. Работа с данными.
2. Работа с управляющими элементами запроса.

Первый пункт мы подробно рассматривали выше. Он, можно сказать, и не является, собственно, защитой. Соблюдение правил добавления занных в запрос продиктовано, в первую очередь, требованиями СИНТАКСИСА SQL. А как побочный эффект мы имеем и защиту от взлома.

Второй пункт гораздо сложнее, поскольку не существует такого же единого универсального правила, как для данных - обратная кавычка никак не защитит имя поля от модификации хакером. Невозможно кавычками защитить имя таблицы, операторы SQL, параметры команды LIMIT, и другие операторы.
Поэтому основное правило при подстановке управляющих элементов в запрос такое:
Если требуется динамически подставлять в запрос операторы SQL или имена полей, баз данных, таблиц, то ни под каким видом не вставлять их в запрос напрямую.
Все варианты таких добавлений должны быть ЗАРАНЕЕ прописаны в вашем скрипте и выбираться на основании того, что ввёл пользователь.
К примеру, если надо передать имя поля в оператор order by, то ни в коем случае нельзя подставлять его напрямую. Надо сначала проверить его. К примеру, сделать массив допустимых значений, и подставлять в запрос только если переданный параметр в этом массиве присутствует:
$orders =array("name" , "price" , "qty" );
$key = array_search ($_GET [ "sort" ], $orders ));
$orderby = $orders [ $key ];
$query = "SELECT * FROM `table` ORDER BY $orderby" ;
Мы ищем в массиве заранее описанных вариантов введённое пользователем слово, и, если находим, то выбираем соответствующий элемент массива. Если совпадения не будет найдено, то будет выбран первый элемент массива.
Таким образом, в запрос подставляется не то, что ввёл пользователь, а то, что было прописано у нас в скрипте.
Точно так же надо поступать и во всех остальных случаях
К примеру, если динамически формируется оператор WHERE:
if (!empty($_GET [ "price" ])) $where .= "price="" . mysql_real_escape_string ($_GET [ "price" ]). """ ;
$query = "SELECT * FROM `table` WHERE $where" ;
Мне сложно представить себе случай, когда имя таблицы может подставляться в запрос динамически, но если такое случится, то имя тоже надо вставлять только из заранее прописанного в скрипте набора.
Параметры оператора LIMIT следует принудительно приводить к целочисленному типу с помощью арифметических операций или функции intval ().
Не следует думать, что перечисленными здесь примерами исчерпываются все варианты динамического составления запросов. Нужно просто понять принцип, и применять его во всех подобных случаях.

Особенности работы с оператором LIKE
Совершенно отдельный случай - оператор LIKE.
Во-первых, помимо обычного прослешивания, в переменных, которые подставляются в LIKE, надо удваивать слеши. То есть, если в переменной содержится символ \, то его надо удвоить, а после этого выполнить обычное прослешивание, через mysql_real_escape_string.
К примеру, если мы ищем строку
символ \ называется "backslash" и нам нужно точное совпадение, то мы просто применяем mysql_real_escape_string и запрос получается стандартный:
SELECT * FROM test WHERE field = "символ \\ называется \"backslash\"" Если же мы хотим подставить эту строку в LIKE, то сначала надо заменить каждый слеш на два, а потом применить mysql_real_escape_string. В результате получится
SELECT * FROM table WHERE field LIKE "%символ \\\\ называется \"backslash\"%"
Во-вторых, следует обратить внимание на то, что ни одна из функций, добавляющих слеши, не добавляет их к метасимволам поиска "%" и "_", используемым в операторе LIKE. Поэтому, если вы используете этот оператор, и не хотите, чтобы символы _ и % использовались, как маски, то добавляйте слеши вручную. Это можно сделать командой
$data = addCslashes ($data , "%_" ); Внимание - это не addslashes! В имени этой функции есть дополнительная буква "c".

Таким образом получается, что переменные, используемые в операторе LIKE мы должны обрабатывать отдельно.
сначала заменять один слеш на два, с помощью такого, к примеру, кода:
$var = str_replace ("\\" , "\\\\" , $var ); затем (можно наравне со всеми другими данными, идущими в запрос) прослешиваем:
$var = mysql_real_escape_string ($var ); а затем, если хотим, чтобы _ и % соответствовали точно самим себе, делаем
$var = addCslashes ($var , "_%" );
В результате, если мы будем искать, к примеру, такую строку
символ \ называется "backslash", а символ _ называется "underscore" то после обработки, в запросе она должна выглядеть так:
"%символ \\\\ называется \"backslash\", а символ \_ называется \"underscore\" То есть, слеш, который был в строке изначально - учетверился. Остальные символы прослешились, как обычно. Плюс - прослешился символ подчёркивания.

О слешах. Как от них избавиться
Слеш, или бэкслеш, от английского back slash - обратная косая черта ("\"), которая непонятным образом вдруг сама собой появляется в ваших переменных. Добавляется он к некоторым спецсимволам, но в основном его замечают из-за кавычек.
Происходит это из-за специальных настроек PHP, обычно включённых на хостинге по умолчанию. Теоретически, эти настройки могут повысить безопасность скриптов, работаюющих с БД. Практически же, от автоматического добавления слешей часто получается путаница и неудобство, как при работе с БД, так и при её отсутствии.
Ниже мы подробно разберём оба этих случая.

За автоматическое добавление слешей отвечают директивы php.ini, которые носят общее название "волшебные кавычки":
magic_quotes_gpc и magic_quotes_runtime Если включена первая, то PHP автоматически добавляет слеши к данным, пришедшим от пользователя - из POST, GET запросов и кук (а так же - к логину и паролю, полученным через HTTP Authorisation).
Если вторая, то слеши добавляются к данным, полученым во время исполнения скрипта - например, из файла или базы данных.

Если вы работаете без базы данных, или же работаете с БД правильно (о чём будет написано ниже), лишние слеши вам только мешают, и от них надо избавляться. Проще и правильнее всего отключить автоматическое добавление, в настройках PHP.
Это можно сделать либо поправив соответствующие директивы в php.ini, если у вас есть к нему доступ, либо создав в коневом каталоге сайта файл .htaccess , и добавив в него строчки
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0

Если отключить таким образом не получается, то придётся писать код разной степени сложности, чтобы очистить от слешей входящие данные. (Впрочем, если вы хотите написать переносимое приложение, не зависящее от настроек PHP, то написать его всё равно придётся. И включать отдельным блоком в начале ваших скриптов).

С данными, получаемыми во время работы, разобраться проще всего: достаточно в начале скрипта написать
set_magic_quotes_runtime(0); Для данных, полученных от пользователя, всё гораздо сложнее. Для этого кода нам потребуется две функции:

  • проверить, добавил ли PHP, можно с помощью функции get_magic_quotes_gpc .
  • удаляет слеши функция stripslashes .
    Соответственно, с помощью первой надо проверить, и, если PHP добавил, то перебрать все входящие переменные и очистить с помощью второй.
    Если вы работаете правильно, при register_globals = off , то достаточно применить stripslashes ко всем массивам, содержащим данные, приходящие из браузера.
    к примеру, можно включить во все скрипты сайта вот такой код:
    function strips (& $el ) {
    if (is_array ($el ))
    foreach($el as $k => $v )
    strips ($el [ $k ]);
    else $el = stripslashes ($el );
    }
    if (get_magic_quotes_gpc ()) {
    strips ($_GET );
    strips ($_POST );
    strips ($_COOKIE );
    strips ($_REQUEST );
    if (isset($_SERVER [ "PHP_AUTH_USER" ])) strips ($_SERVER [ "PHP_AUTH_USER" ]);
    if (isset($_SERVER [ "PHP_AUTH_PW" ])) strips ($_SERVER [ "PHP_AUTH_PW" ]);
    }
    В случае же неправильных настроек register_globals приемлемое решение и вовсе будет найти затруднительно, поэтому лучше - повторюсь - сразу работать при правильных настройках.

    Замечания

    • Среди причин, по которым не стоит полагаться на "волшебные кавычки", есть ещё одна. Весьма маловероятная, но всё же. К "волшебным кавычкам" относится на самом деле не две директивы, а три. Третья - magic_quotes_sybase . Мало того, что она вместо слеша добавляет кавычку - так она ещё и отменяет действие magic_quotes_gpc. Если каким-то чудом обе эти директивы имеют статус "on", то последняя не сработает! То есть, полагаясь на "волшебные кавычки", мы в этом случае получим все прелести неправильно составленных запросов. Вообще, чисто теоретически, надо учитывать наличие этой директивы, поскольку она преподносит ещё и такой сюрприз, как... изменение поведения функций addslashes и stripslashes! Если magic_quotes_sybase = on , то эти функции начинают вместо слеша добавлять и удалять одинарную кавычку соответственно.
    • Все приведенные примеры касаются только БД Mysql. Конкретные правила составления запросов могут отличаться для других СУБД, но общий принцип остается прежним:
      • если API для работы с БД или сторонняя библиотека предоставляет специальные функции для составления запросов , и есть возможность их использования, то пользоваться в первую очередь надо ими.
      • если таких функций нет, то следует искать в документации функции экранирования спецсимволов для этой СУБД.
    Примечание: формы
    При выводе value в тегах input форм, слеши не помогают.
    Чтобы текст в таком поле выводился целиком, value надо заключать в кавычки , а к выводимым данным применять функцию htmlspecialchars()
    Пример:

    Необходимо так же отметить (хоть это уже совсем не имеет отношения к кавычкам и слешам), что функцию htmlspecialchars следует применять при выводе в браузер вообще ко всем данным, которые получены от непроверенного пользователя. Почему это следует делать, можно почитать в гугле по запросу что такое XSS уязвимость
    by phpfaq.ru

  • Для начала - немного о том, почему вообще нужны эти слеши.
    Если мы подставляем в запрос какие-либо данные, то, чтобы отличить эти данные от команд SQL, их надо брать в кавычки.
    К примеру, если написать
    SELECT * FROM table WHERE name = Bill
    то база решит, что Bill - это имя другого поля, не найдёт его, и выдаст ошибку. Поэтому подставляемые данные (в данном случае имя Bill) надо заключать в кавычки - тогда база сочтет его строкой, значение которой надо присвоить полю name:
    SELECT * FROM table WHERE name = "Bill"
    Однако, и в самих данных могут встречаться кавычки тоже. К примеру,
    SELECT * FROM table WHERE name = "Д"Артаньян"
    Здесь база данных решит, что "Д" - это данные, а Артаньян - команда, которую она не знает, и тоже выдаст ошибку. Поэтому и надо прослешивать все данные, чтобы объяснить базе, что встречающиеся в них кавычки (и некоторые другие спецсимволы) относятся к данным.
    В результате мы получим правильный запрос, который ошибок не вызовет:
    SELECT * FROM table WHERE name = "Д\"Артаньян"

    Таким образом, мы выяснили, что при подстановке строковых данных в запрос, следует придерживаться двух правил:
    - все вставляемые строковые данные должны быть заключены в кавычки (одинарные или двойные, но удобнее и чаще используются одинарные).
    - в них должны быть экранированы слешами спецсимволы.

    Следует специально отметить: добавленные слеши НЕ идут в базу. Они нужны только в запросе. При попадании в базу слеши отбрасываются. Соответственно, распространенной ошибкой является применение stripslashes при получении данных из базы.

    Всё вышесказанное относится к данным строкового типа и датам. Числа можно вставлять не прослешивая и не окружaя кавычками. Если вы так делаете, то ОБЯЗАТЕЛЬНО! насильно приводите данные к нужному типу перед вставкой в запрос, например:
    $id = intval ($id );
    Однако для простоты (и надёжности) можно и с числами работать, как со строками (проскольку mysql всё равно преобразует их к нужному типу). Соответственно, мы будем любые данные, вставляемые в запрос, прослешивать и заключать в кавычки.

    Так же, есть ещё одно правило - необязательное, но его следует придерживаться во избежание появления ошибок:
    Имена полей и таблиц следует заключать в обратные одинарные кавычки - "`" (клавиша с этим символом находится на стандартной клавиатуре слева от клавиши "1") Ведь имя поля может совпадать с ключевыми словами mysql, но если мы используем обратную кавычку, то MySQL поймёт всё правильно:
    SELECT * FROM `table` WHERE `date` = "2006-04-04"
    Следует различать эти кавычки и не путать одни с другими. Следует также помнить, что обратные кавычки слешами не экранируются.

    Итак, мы научились правильно подставлять в запрос данные.
    НО! Динамическое составление запросов не исчерпывается подстановкой данных. Часто нам приходится подставлять в запрос команды SQL и имена полей. И здесь мы уже переходим к теме безопасности:

    SQL Injection - это способ хакерской атаки, когда передаваемые скрипту данные модифицируются таким образом, что запрос, формируемый в этом скрипте, начинает выполнять совсем не то, для чего он предназначался.
    Правила защиты от таких атак можно разделить на два пункта:
    1. Работа с данными.
    2. Работа с управляющими элементами запроса.

    Первый пункт мы подробно рассматривали выше. Он, можно сказать, и не является, собственно, защитой. Соблюдение правил добавления занных в запрос продиктовано, в первую очередь, требованиями СИНТАКСИСА SQL. А как побочный эффект мы имеем и защиту от взлома.

    Второй пункт гораздо сложнее, поскольку не существует такого же единого универсального правила, как для данных - обратная кавычка никак не защитит имя поля от модификации хакером. Невозможно кавычками защитить имя таблицы, операторы SQL, параметры команды LIMIT, и другие операторы.
    Поэтому основное правило при подстановке управляющих элементов в запрос такое:
    Если требуется динамически подставлять в запрос операторы SQL или имена полей, баз данных, таблиц, то ни под каким видом не вставлять их в запрос напрямую.
    Все варианты таких добавлений должны быть ЗАРАНЕЕ прописаны в вашем скрипте и выбираться на основании того, что ввёл пользователь.
    К примеру, если надо передать имя поля в оператор order by, то ни в коем случае нельзя подставлять его напрямую. Надо сначала проверить его. К примеру, сделать массив допустимых значений, и подставлять в запрос только если переданный параметр в этом массиве присутствует:
    $orders =array("name" , "price" , "qty" );
    $key = array_search ($_GET [ "sort" ], $orders ));
    $orderby = $orders [ $key ];
    $query = "SELECT * FROM `table` ORDER BY $orderby " ;

    Мы ищем в массиве заранее описанных вариантов введённое пользователем слово, и, если находим, то выбираем соответствующий элемент массива. Если совпадения не будет найдено, то будет выбран первый элемент массива.
    Таким образом, в запрос подставляется не то, что ввёл пользователь, а то, что было прописано у нас в скрипте.
    Точно так же надо поступать и во всех остальных случаях
    К примеру, если динамически формируется оператор WHERE:
    if (!empty($_GET [ "price" ])) $where .= "price="" . mysql_real_escape_string ($_GET [ "price" ]). """ ;
    $query = "SELECT * FROM `table` WHERE $where " ;

    Мне сложно представить себе случай, когда имя таблицы может подставляться в запрос динамически, но если такое случится, то имя тоже надо вставлять только из заранее прописанного в скрипте набора.
    Параметры оператора LIMIT следует принудительно приводить к целочисленному типу с помощью арифметических операций или функции intval ().
    Не следует думать, что перечисленными здесь примерами исчерпываются все варианты динамического составления запросов. Нужно просто понять принцип, и применять его во всех подобных случаях.

    кавычек строке (11)

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

    $query = "INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)";

    Кроме того, в приведенном выше примере рассмотрим, что "table," "col[n]," and "val[n]" могут быть переменными.

    Каков стандарт для этого? Чем ты занимаешься?

    Я читал ответы на подобные вопросы около 20 минут, но, похоже, нет окончательного ответа на этот вопрос.

    Answers

    Теперь предположим, что вы используете прямую переменную post в запросе MySQL, тогда используйте ее следующим образом:

    $query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (" ".$_POST["id"]." ", " ".$_POST["name"]." ", " ".$_POST["email"]." ")";

    Это наилучшая практика использования переменных PHP в MySQL.

    В основном в Mysql, эти типы идентификаторов используются в запросах ` , " , " и () .

      " или " использовать для включения строки как значения "26-01-2014 00:00:00" или "26-01-2014 00:00:00" . Этот идентификатор используется только для функции "26-01-2014 00:00:00" строки, например now() or sum ,max .

      ` использовать для включения таблицы таблицы или таблицы, например, select column_name из table_name где id = "2"

      () используются только для того, чтобы просто заключить части запроса, например, select column_name из table_name где (id = "2" и gender = "male") или name = "rakesh.

    Помимо всех (хорошо объясненных) ответов, не было упомянутых ниже, и я часто бываю в этом Q & A.

    В двух словах; MySQL думает, что вы хотите делать математику на своей собственной таблице / столбце и интерпретируете дефисы, такие как «электронная почта», как e mail .

    Отказ от ответственности. Поэтому я думал, что добавлю это как ответ типа «FYI» для тех, кто совершенно не знаком с работой с базами данных, и которые могут не понимать уже описанные технические термины.

    (Есть хорошие ответы выше, касающиеся характера вашего вопроса SQL, но это также может быть актуальным, если вы новичок в PHP.)

    Возможно, важно отметить, что PHP обрабатывает одиночные и двойные кавычки по-разному...

    Строки с одним кавычком - это «литералы» и представляют собой довольно много строк WYSIWYG. Строки с двойными кавычками интерпретируются PHP для возможной замены переменных (обратные ссылки в PHP не являются точно строками, они выполняют команду в оболочке и возвращают результат).

    $foo = "bar"; echo "there is a $foo"; // There is a $foo echo "there is a $foo"; // There is a bar echo `ls -l`; // ... a directory list

    Если таблицы cols и значения являются переменными, то существует два способа:

    С двойными кавычками "" полный запрос:

    $query = "INSERT INTO $table_name (id, $col1, $col2) VALUES (NULL, "$val1", "$val2")";

    $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") VALUES (NULL, "".$val1."", "".$val2."")";

    С одинарными кавычками "" :

    $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") VALUES (NULL, ".$val1.", ".$val2.")";

    Используйте обратные тики `` когда имя столбца / значения похоже на зарезервированное ключевое слово MySQL.

    Примечание. Если вы указываете имя столбца с именем таблицы, используйте обратные тики следующим образом:

    `table_name` . `column_name` <- Примечание: исключить. из задних клещей.

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

    Одинарные кавычки следует использовать для строковых значений, например, в списке VALUES() . Двойные кавычки поддерживаются MySQL также для строковых значений, но одинарные кавычки более широко принимаются другими РСУБД, поэтому неплохо использовать одинарные кавычки вместо двойных.

    MySQL также ожидает, что литеральные значения DATE и DATETIME будут иметь одинарные кавычки в виде строк, например "2001-01-01 00:00:00" . Для получения дополнительной информации см. Документацию по литературе даты и времени , в частности альтернативы использованию дефиса - в качестве разделителя сегментов в строках даты.

    Поэтому, используя ваш пример, я бы дважды привел строку PHP и использовал одинарные кавычки для значений "val1", "val2" . NULL - это ключевое слово MySQL и специальное (non) -значение, и поэтому оно не используется.

    Ни один из этих идентификаторов таблиц или столбцов не является зарезервированными словами или использует символы, требующие цитирования, но я все равно цитировал их с обратными выводами (подробнее об этом позже...).

    Функции, родственные RDBMS (например, NOW() в MySQL), не должны цитироваться, хотя их аргументы подчиняются тем же правилам или правилам цитирования, которые уже упоминались.

    Backtick (`) table & column ───────┬─────┬──┬──┬──┬────┬──┬────┬──┬────┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `updated`) VALUES (NULL, "val1", "val2", "2001-01-01", NOW()) "; Unquoted keyword ─────┴┴┴┘ │ │ │ │ │ │ │││││ Single-quoted (") strings ───────────┴────┴──┴────┘ │ │ │││││ Single-quoted (") DATE ───────────────────────────┴──────────┘ │││││ Unquoted function ─────────────────────────────────────────┴┴┴┴┘

    Переменная интерполяция

    Шаблоны цитирования для переменных не изменяются, хотя, если вы намерены интерполировать переменные непосредственно в строке, это должно быть двойным кавычком в PHP. Просто убедитесь, что вы правильно избежали переменных для использования в SQL. (Вместо этого рекомендуется использовать API, поддерживающий подготовленные инструкции, в качестве защиты от SQL-инъекции).

    // Same thing with some variable replacements // Here, a variable table name $table is backtick-quoted, and variables // in the VALUES list are single-quoted $query = "INSERT INTO `$table` (`id`, `col1`, `col2`, `date`) VALUES (NULL, "$val1" , "$val2" , "$date" )";

    Подготовленные заявления

    При работе с подготовленными заявлениями, проконсультируйтесь с документацией, чтобы определить, следует ли указывать заполнители заявления. Самые популярные API-интерфейсы, доступные в PHP, PDO и MySQLi, предполагают неавторизованные заполнители, как и большинство подготовленных API-интерфейсов инструкций на других языках:

    // PDO example with named parameters, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)"; // MySQLi example with ? parameters, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

    Символы, возвращающие обратную ссылку в идентификаторах:

    Например:

    То же самое можно сделать для имен таблиц и имен полей. Это очень хорошая привычка, если вы привязываете свой идентификатор базы данных обратными окнами.

    Проверьте this ответ, чтобы узнать больше об обратных выводах.

    Теперь о Double quotes & Single Quotes (Майкл уже упомянул об этом).

    Но, чтобы определить значение, вам нужно использовать одиночные или двойные кавычки. Давайте посмотрим другой пример.

    INSERT INTO `tablename` (`id, `title`) VALUES (NULL, title1);

    Здесь я сознательно забыл обернуть title1 кавычками. Теперь сервер примет title1 как имя столбца (то есть идентификатор). Итак, чтобы указать, что это значение, вам нужно использовать двойные или одинарные кавычки.

    INSERT INTO `tablename` (`id, `title`) VALUES (NULL, "title1");

    Теперь, в сочетании с PHP, двойные кавычки и одинарные кавычки значительно упрощают время написания запроса. Давайте посмотрим на измененную версию запроса в вашем вопросе.

    $query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2")";

    Теперь, используя двойные кавычки в PHP, вы сделаете переменные $val1 и $val2 чтобы использовать их значения, создав тем самым корректный запрос. подобно

    $val1 = "my value 1"; $val2 = "my value 2"; $query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2")";

    INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "my value 1", "my value 2")

    Здесь было много полезных ответов, в целом достигающих высшей точки в два пункта.

    1. BACKTICKS (`) используются вокруг имен идентификаторов.
    2. ОДНО ЦИТАТЫ (") используются вокруг значений.

    И как @MichaelBerkowski сказал

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

    Существует случай, когда идентификатор не может быть зарезервированным ключевым словом или содержать пробельные символы или символы, находящиеся за пределами ограниченного набора, но обязательно требуют обратных ссылок вокруг них.

    123E10 - это допустимое имя идентификатора, но также действительный литерал INTEGER .

    [Не вдаваясь в подробности, как вы получите такое имя идентификатора], Предположим, я хочу создать временную таблицу с именем 123456e6 .

    Нет ОШИБКИ на backticks.

    DB > create temporary table `123456e6` (`id` char (8)); Query OK, 0 rows affected (0.03 sec)

    ОШИБКА, если вы не используете обратные вызовы.

    DB > create temporary table 123451e6 (`id` char (8)); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near "123451e6 (`id` char (8))" at line 1

    Тем не менее, 123451a6 - это прекрасное имя идентификатора (без обратных тиков).

    DB > create temporary table 123451a6 (`id` char (8)); Query OK, 0 rows affected (0.03 sec)

    Это полностью потому, что 1234156e6 также является экспоненциальным числом.

    Одинарные кавычки следует использовать для строковых значений, например, в списке VALUES ().

    Backticks обычно используются для указания идентификатора, а также могут быть безопасными из-за случайного использования зарезервированных ключевых слов.

    В сочетании PHP и MySQL двойные кавычки и одинарные кавычки значительно упрощают время написания запросов.

    В MySQL есть два типа котировок:

    1. " для включения строковых литералов
    2. ` для включения идентификаторов, таких как имена таблиц и столбцов

    И тогда есть " это особый случай. Он может использоваться для одной из вышеупомянутых целей за раз в зависимости от sql_mode сервера sql_mode :

    1. По умолчанию " символ» можно использовать для вложения строковых литералов "
    2. В режиме ANSI_QUOTES " символ может использоваться для включения идентификаторов, ANSI_QUOTES

    Следующий запрос приведет к различным результатам (или ошибкам) ​​в зависимости от режима SQL:

    SELECT "column" FROM table WHERE foo = "bar"

    ANSI_QUOTES отключен

    Запрос будет выбирать строковый литерал "column" где столбец foo равен строке "bar"

    Включено ANSI_QUOTES

    Запрос будет выбирать столбец column где столбец foo равен столбцу

    Когда использовать

    • Я предлагаю вам избегать использования " чтобы ваш код не зависел от режимов SQL
    • Всегда указывайте идентификаторы, так как это хорошая практика (довольно много вопросов на SO обсуждают это)

    Существует четкое различие между использованием " " и " " .

    Когда " " используется во всем, нет «трансформации или перевода». Он печатается так, как есть.

    С " " , независимо от того, что он окружает, "переводится или преобразуется" в его ценность.

    Под трансляцией / преобразованием я имею в виду следующее: все, что содержится в одинарных кавычках, не будет «переведено» на их значения. Они будут приняты, поскольку они находятся внутри кавычек. Пример: a=23 , тогда echo "$a" будет генерировать $a на стандартном выходе. В то время как echo "$a" произведет 23 на стандартном выходе.



     

    Возможно, будет полезно почитать: