Подтвердить что ты не робот

"установить имена" и mysqli_set_charset - кроме того, что они влияют на mysqli_escape_string, они идентичны?

Это кажется общеизвестным для использования mysql_set_charset/mysqli::set_charset вместо прямого запроса MySQL set names.

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

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

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

4b9b3361

Ответ 1

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


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

Пропустите исходный код:

  • Функции Userland mysql_set_charset и mysqli_set_charset call...
  • Функция двигателя mysql_set_character_set вызывает...
  • Макрос двигателя mysqlnd_set_character_set, который определяется как:

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

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

  • 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. Это может быть полезно при просмотре того, как ваш код проходит через этот блок.

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

Вкратце:

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

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

  • или - конечно - используйте PDO и его методы.

Ответ 4

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

Оператор

A 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 выполняют обе вещи.