4

Столкнулся со следующей проблемой. Имеем текст

<p><strong><span style="font-size: medium;">
Текст Текст Текст Текст
<img class="emoji" src="http://vk.com/images/emoji/D83DDCB2.png" alt="" />
</p>

При вставке в базу MySQL текст обрезается по символ , то есть остается

<p><strong><span style="font-size: medium;">
Текст Текст Текст Текст <img class="emoji"
src="http://vk.com/images/emoji/D83DDCB2.png" alt="

Вставка происходит в коде php:

$text = PHP_slashes($text); // экранируем кавычки
$sql = "INSERT INTO `{$this->table}` (`text`) VALUE ('$text')";
$this->db->execute($sql);

Попробовал вставить вручную в базу это сообщение - все сработало, только заменился на ?. Такое поведение вполне устраивает, можно бы и вовсе удалить такие символы из сообщения.

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

P.S.: Больше интересует не конкретное решение замены символов в строке, а настройки на все случаи - чтобы база не резала текст, а как-то его сохраняла, заменяя непонятные ей символы.

Update: строка запроса

INSERT INTO `mails` (`text`) VALUE ('<p><strong><span style=\"font-size: medium;\">Текст Текст Текст Текст <img class=\"emoji\" src=\"http://vk.com/images/emoji/D83DDCB2.png\" alt=\"\" /></p>')

Только вместо в текстовом файле отображается квадратик с вопросом

RussCoder
  • 3,481
  • 2
  • 20
  • 42
  • странно, что у вас вообще хоть что-то попадает в базу данных. надо ведь как минимум «заэскейпить» символы кавычек: \". – aleksandr barakin Sep 01 '15 at 10:07
  • @alexanderbarakin они у меня экранированы, я просто не привел весь код - счел, что он не относится к делу. Update: добавил соответствующую строку в код – RussCoder Sep 01 '15 at 10:10
  • а содержимое строки $sql вы не пробовали проконтролировать? – aleksandr barakin Sep 01 '15 at 10:25
  • Да, покажите строку запроса как она выглядит уходя на выполнения. И надеюсь вы работает в кодировке utf-8? Включу режим телепата и предположу, что вам надо для всех таблиц в базе включить сравнение utf8mb4_general_ci. – Visman Sep 01 '15 at 10:30
  • @Visman дополнил вопрос – RussCoder Sep 01 '15 at 10:51
  • 1
    Про кодировку, которую используете и сравнение в базе, что ответите? – Visman Sep 01 '15 at 11:04
  • У вас на этот символ `` аж 6 байтов на хранение отводится O_o – Visman Sep 01 '15 at 11:05
  • 1
    @Visman utf8_general_ci в базе, кодировка UTF-8 – RussCoder Sep 01 '15 at 11:10
  • Если ваша версия mysql позволяет включите сравнение utf8mb4_general_ci в таблицах и в самой базе. Если нет, нужно mysql обновить. – Visman Sep 01 '15 at 11:11
  • @Visman там есть такой пункт, однако он автоматически изменяет его на utf8_general_ci , Пробовал utf8_unicode_ci - не помогло – RussCoder Sep 01 '15 at 11:25
  • MySQL какой версии? – Visman Sep 01 '15 at 11:28
  • @Visman версия 5.6.25 – RussCoder Sep 01 '15 at 11:34
  • Странно, через Операции в phpmyadmin изменяется сравнение без проблем. – Visman Sep 01 '15 at 11:40
  • @Visman я делал через heidisql, но не думаю что это поможет, ибо utf8mb4_unicode_ci не помогло – RussCoder Sep 01 '15 at 11:43
  • После коннекта к базе у вас наверное запрос уходит вида SET NAMES 'utf8' замените его на SET NAMES 'utf8mb4' или даже на SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci' – Visman Sep 01 '15 at 11:46
  • @Visman это надо просто выполнить как sql-запрос ? – RussCoder Sep 01 '15 at 11:58
  • Да, Обычно уже в движке этот запрос выполняется сразу после подключения к безе. Если у вас такого SET NAMES 'utf8' запроса ни где нет в коде, то можете выполнить один из предложенных мной вариантов сразу после подключения к бд. – Visman Sep 01 '15 at 12:00
  • @Visman SET NAMES 'utf8' не работает. SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci' и SET NAMES 'utf8mb4' работает - в базе ? вместо символов фигурных. Теперь распишите в ответе что эта опция делает, почему просто SET NAMES 'utf8' не работает и я приму ваш ответ – RussCoder Sep 01 '15 at 12:13
  • Что значит SET NAMES 'utf8' не работает? :) Запрос этот работает и указывает, что соединение с базой идет в кодировке utf-8 с максимальной длиной символов 3 байта. SET NAMES 'utf8mb4' же указывает на ту же кодировку, но максимальную длину символов в 4 байта. Вот эти фигуристы символы, как и символы китайского и японского языков кодируются 4 байтами в кодировке utf-8. – Visman Sep 01 '15 at 12:19
  • @Visman а COLLATE 'utf8mb4_general_ci' что значит? – RussCoder Sep 01 '15 at 12:21
  • Сравнение задает, то которое я выше вручную предлагал для базы установить. – Visman Sep 01 '15 at 12:22
  • @Visman понятно. Для всей базы кстати я его теперь установил, для 1 таблицы не получалось – RussCoder Sep 01 '15 at 12:28
  • С использованием запроса SET NAMES 'utf8mb4'... должно корректно работать и в таком случае. – Visman Sep 01 '15 at 12:30
  • @Visman ну вы оформите ответ. Меня теперь еще интересует, что надо сделать, чтобы эти символы не в ? превращались, а так и сохранялись в БД – RussCoder Sep 01 '15 at 12:33
  • То есть символы все равно нормально не отображаются? Значит надо таблицы и все столбцы в них с текстовой информацией конвертировать в сравнение utf8mb4_general_ci. – Visman Sep 01 '15 at 12:40
  • Комментарии не предназначены для расширенной дискуссии; разговор перемещен в чат. – Nicolas Chabanovsky Sep 01 '15 at 13:36

3 Answers3

5

Ваша база сейчас работает в кодировке utf-8 в которой на 1 символ максимум выделяется 3 байта. Из-за этого ваши фигурные символы (а так же символы китайского и японского языков) не могут быть записаны в базу, так как имеют размер 4 байта.

Следует перевести базу данных на работу в кодировке utf-8 с поддержкой символов размером до 4 байт.

  1. Если MySQL имеет версию ниже 5.5.3, его следует обновить.
  2. Сделать полный бекап базы данных.
  3. Для перевода базы на 4-x байтный utf-8 нужно выполнить команду

    ALTER DATABASE название_базы CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
    
  4. Для каждой таблицы базы нужно выполнить команду такого вида

    ALTER TABLE название_таблицы CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    
  5. Для каждого поля содержащего текстовую информацию в каждой таблице нужно выполнить команду (примерный вид, зависит от структуры поля)

    ALTER TABLE название_таблицы CHANGE название_столбца название_столбца VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    

    Пункты 3-5 можно выполнить например через phpmyadmin.

  6. В код php нужно добавить сразу после коннекта к базе выполнение запроса вида

    SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci'
    

P.S. Про установку кодировки соединения https://ru.stackoverflow.com/a/726863/186083

Visman
  • 16,518
  • 8
  • 26
  • 56
0

Насколько я понимаю Вам вместо знака и других подобных необходимо использовать его код в html, если html код приходит извне то парсить регуляркой так же по коду...

0

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

function clearText($text) {
   $text = iconv('utf-8', 'windows-1251//IGNORE', $text);
   $text = iconv('windows-1251', 'utf-8//IGNORE', $text);
   return $text;
}

Эта функция убирает все "фигурные" символы из текста.

Решение типа

$text = iconv('utf-8', 'utf-8//IGNORE', $text);

не работает.

RussCoder
  • 3,481
  • 2
  • 20
  • 42
  • 1
    Вы таким способом не только фигурные символы уберете, но наверняка и символы отличающиеся от латиницы и кириллицы. – Visman Sep 01 '15 at 11:58
  • @Visman да, скорее всего. Поэтому такое решение не самое лучшее, но вообще работает для моего случая – RussCoder Sep 01 '15 at 12:00