«Установить имена» и mysqli_set_charset – кроме того, что они влияют на mysqli_escape_string, они идентичны?

Похоже, что использовать mysql_set_charset / mysqli::set_charset вместо прямых set names запросов MySQL.

Часто упоминаемая причина заключается в том, что set names небезопасны, потому что кодировка, используемая для mysql_real_escape_string / mysqli::real_escape_string будет установлена ​​только вызовом mysql_set_charset / mysqli::set_charset . (Другая причина, о которой идет речь, заключается в том, что в документах PHP говорится, что это «не рекомендуется».)

Однако можно ли использовать прямые set names запросов MySQL MySQL, если мы будем использовать подготовленные инструкции и другие способы экранирования, кроме mysql_real_escape_string / mysqli::real_escape_string / mysqli_escape_string ?

Помимо влияния на кодировку mysql_real_escape_string / mysqli::real_escape_string / mysqli_escape_string , существует ли разница между set names mysql_set_charset vs mysql_set_charset / mysqli::set_charset ?

Related of "«Установить имена» и mysqli_set_charset – кроме того, что они влияют на mysqli_escape_string, они идентичны?"

Вызов SET NAMES в соединении эквивалентен вызову set_charset , если вы не вызываете ни get_charset ни mysql_real_escape_string (и друзей).


Когда вы вызываете set_charset , PHP делает две вещи. Во-первых, он вызывает SET NAMES в соединении. Во-вторых, он помнит, какую кодировку вы задали. Эта информация о состоянии позже используется только в get_charset и mysql_real_escape_string (и друзей). Поэтому, если вы не используете эти функции, вы можете рассмотреть два эквивалента.

Пойдем по источнику:

  1. Пользовательские функции mysql_set_charset и mysqli_set_charset call …
  2. Функция mysql_set_character_set функции mysql_set_character_set
  3. Engine macro mysqlnd_set_character_set , который определяется как:

    #define mysqlnd_set_character_set(conn, cs) \ ((conn)->data)->m->set_charset((conn)->data, (cs)))

    и расширяется до …

  4. MYSQLND_METHOD(mysqlnd_conn_data, set_charset) который содержит следующий код (пронумерованный для обсуждения, это не фактические номера строк исходного кода):

  1 if (PASS == conn->m->local_tx_start(conn, this_func)) { 2 char * query; 3 size_t query_len = mnd_sprintf(&query, 0, "SET NAMES %s", csname); 4 5 if (FAIL == (ret = conn->m->query(conn, query, query_len))) { 6 php_error_docref(NULL, E_WARNING, "Error executing query"); 7 } else if (conn->error_info->error_no) { 8 ret = FAIL; 9 } else { 10 conn->charset = charset; 11 } 12 mnd_sprintf_free(query); 13 14 conn->m->local_tx_end(conn, this_func, ret); 15 } 

Как вы можете видеть, PHP вызывает SET NAMES на самом соединении (строка 3). PHP также отслеживает только набор символов (строка 10). Комментарии далее обсуждают, что происходит с conn->charset , но достаточно сказать, что это заканчивается только в get_charset и mysql_real_escape_string (и друзьях).

Итак, если вы не заботитесь об этом состоянии, и вы соглашаетесь использовать ни get_charset ни mysql_real_escape_string , вы можете называть SET NAMES на самом соединении без какого-либо плохого эффекта.

В стороне, и я никогда не делал этого, но похоже, что компиляция PHP с -DPHP_DEBUG=1 позволит обеспечить значительную отладку через различные макросы DBG . Это может быть полезно, когда вы видите, как ваш код проходит через этот блок.

Необходимо сделать две вещи (в этой области):

  • Выбери кавычки (и другие символы), прежде чем вводить их в кавычки. В противном случае кавычки дадут вам синтаксические ошибки.
  • Установите кодировку байтов в клиенте. Это значит, что INSERTs / SELECTs будут знать, как изменить байты во время записи / чтения.

Сначала нужно избегать апострофа и двойной кавычки, так как оба из них являются допустимыми метками кавычек для строк в синтаксисе MySQL. Тогда сам побеждающий символ нуждается в побеге. Эти 3 символа достаточны для обязательных приложений. Однако, если вы пытаетесь избежать BLOB (например, .jpg), различные управляющие символы могут вызвать проблемы. Вероятно, вам лучше конвертировать в hex, а затем использовать UNHEX() , чтобы избежать проблем. Примечание. Здесь ничего не сказано о наборах символов. Если вы не имеете дело с BLOBs , вы можете уйти с addslashes() .

Вторая цель заключается в том, чтобы сказать: «Этот поток байтов кодируется таким образом (utf8 / latin1 / etc)». Используется только для преобразования между CHARACTER SET столбца, который хранится / извлекается, и желаемой кодировкой в ​​вашем клиенте (PHP и т. Д.). На разных языках он обрабатывается различными способами. Для PHP:

  • mysql_* – Не используйте этот интерфейс; он устарел и вскоре будет удален.
  • mysqli_*mysqli::set_charset(...)
  • PDO – new PDO('...;charset=UTF8', ...)

Делает ли set_charset() что-то с real_escape_string? Я не знаю. Но это не должно иметь значения. SET NAMES явно не может, поскольку это команда MySQL, и ничего не знает о PHP.

htmlentities() – это еще одна функция PHP в этой области. Он превращает 8-битные коды в & сущности. Это не следует использовать в MySQL. Это замаскировало бы другие проблемы. Используйте его только в определенных ситуациях, связанных с HTML, а не с PHP или MySQL.

Единственными разумными CHARACTER SETs будут использоваться сегодня, являются ascii, latin1, utf8 и utf8mb4. У них нет «символов» в области «управления». Sjis и несколько других наборов символов. Эта путаница над управляющими символами может быть причиной существования real_escape_string.

Вывод:

Как я вижу, вам нужны два механизма: один для экранирования и один для установки кодировки в клиенте. Они отделены друг от друга.

Если они связаны друг с другом, руководство по PHP не предоставило каких-либо веских оснований для выбора одного метода над другим.

mysql: весь интерфейс устарел, поэтому не используйте его вообще (PHP 7 удаляет интерфейс).

mysqli (и PDO) подготовил операторы, которые не используют (и не хотят) использование real_escape_string . -> Итак, если вы используете только mysqli и только подготовленные инструкции: не стоит беспокоиться о том, как вы устанавливаете кодировку.

Поскольку вы заботитесь о безопасности: я не вижу смысла в том, чтобы не использовать подготовленные заявления.

После того, как вы используете подготовленные операторы mysqli, единственный путь вперед – использовать $mysqli->set_charset() поскольку вы не можете просто конкатенировать несколько операторов sql в одной строке.

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

В итоге:

  • mysql: не использовать вообще.

  • mysqli: использовать подготовленные операторы и, следовательно, метод set_charset()
    Также: вам больше не понадобится real_escape_string после использования подготовленных операторов.

  • или, конечно, использовать PDO и его методы.

SET NAMES ... – псевдоним удобства:

SET NAMES 'charset_name' эквивалентен этим трех операторам:

 SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; 

Установка character_set_connection в charset_name также неявно устанавливает collation_connection для сопоставления по умолчанию для charset_name .

… который предоставляет MySQL Server всю информацию о кодировании текста, необходимую для текущего соединения. Все идет нормально.

Но PHP также задействован, и он ничего не узнает отсюда, потому что это в основном случайный пользовательский запрос. Есть две вещи, которые PHP не будет делать по очевидным причинам производительности:

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

Короче: этот метод уведомляет сервер, но не клиент. Однако выделенные функции PHP выполняют обе вещи.