& quot; задавать имена & quot; vs 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 написано, что это «не рекомендуется» §.)

Однако безопасно ли использовать прямой запрос 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 против mysql_set_charset/mysqli::set_charset?

12

Решение

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


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

Давайте пройдемся по источнику:

  1. Пользовательские функции mysql_set_charset а также mysqli_set_charset вызов…
  2. Функция двигателя mysql_set_character_set звонки …
  3. Макрос двигателя 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 макросы. Это может быть полезно, чтобы увидеть, как ваш код проходит через этот блок.

6

Другие решения

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

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

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

1

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 делают обе вещи.

1
По вопросам рекламы [email protected]