Обнуляющие смайлики (или почему minishop2 отправляет заказы без товаров)

Всем привет.
Буквально вчера, словил неприятную багу.

(P.S. вполне возможно что многие знают об этой баге. Но ради интереса решил воспроизвести данную багу на других сайтах — в 90% случаев ошибка воспроизводится).

Имеется сайт на MODX Revolution 2.7.3 в связке с miniShop2 2.5.0.
Бага заключалась в том, что пришёл «пустой» заказ. Т.е. все реквизиты клиента в письме и заказе есть, а вот товаров в этом заказе нет.

Долго и упорно не мог понять в чём же проблема. Благо есть вебвизор и он таки помог воспроизвести ошибку.

Дело оказалось в смайликах. Которые были вставлены в комментарий к заказу.

Как воспроизвести ошибку:
1. Кладём товар в корзину, идём в оформление заказа, заполняем поля которые надо заполнить и в комментарий к заказу вставляем любой Emoji смайлик.
Например такой: 🙏🏻
1.1 Тыкаем в любое место страницы чтобы убрать фокус с поля комментария и жмём на F5.
Убеждаемся что корзина стала пустой и бага таки присутствует =)

Причина данного явления:
1. minishop2 — никак не обрабатывает поле comment. Т.е. сохраняет его «как есть».
2. Все заполненные поля заказа, minishop2 сохраняет в сессию. В том числе и комментарий.
3. MODX дублирует сессию в базу данных. Т.е. каждая сессия — это отдельная запись в базе данных (таблица: modx_session).
4. В 99% случаев, ваша база данных имеет кодировку utf8_general_ci (особо отчаянные имеют кодировку CP1251).
5. Смайлики — это какой-то там 4-х битный набор символов. Данный набор символов поддерживает кодировка utf8mb4_unicode_ci (данную кодировку разработала команда разработчиков MySQL и была специально создана для поддержки смайликов).
6. Если вы сохраните смайлик в базе данных с кодировкой utf8_general_ci, то весь текст который будет идти после смайлика — затрется.
7. Как мы уже знаем, MODX дублирует все сессии в базу. В базу записывается и сессия минишопа. Если в этой записи имеется смайлик — то такая запись 100% «грохнется» и MODX не сможет её прочитать, т.к. текст банально затрется. Если MODX не может прочитать запись — то он обнуляет сессию и создаёт новую запись.
Таким образом мы имеем обнулённую корзину.

Решение проблемы:
Самое минимальное, это нужно сделать следующее:
0. Сделать бэкап базы данных.
1. Открыть базу данных (через phpmyadmin, Navicat и т.п.) и найти таблицу: modx_session (где modx — это ваш префикс).
1.1. В данной таблице необходимо поменять кодировку у поля «data» на utf8mb4_unicode_ci
2. На сервере найти и открыть файл ../core/config/config.inc.php
2.1. И установить кодировку:
9-я строка:
$database_connection_charset = 'utf8mb4';
12-я строка:
$database_dsn = 'mysql:host=localhost;dbname=mydbname;charset=utf8mb4';
Ну а по хорошему, нужно конечно же перевести всю базу в кодировку utf8mb4_unicode_ci
Но и минимальное решение — тоже заработает.
Дмитрий Танцирев
18 июля 2020, 08:46
modx.pro
5
915
+8

Комментарии: 5

Василий Наумкин
18 июля 2020, 08:55
+7
На всякий случай напомню, что MODX по умолчанию использует utf8mb4 с версии 2.6.0, которая вышла в 2017 году.
    Руслан Алеев
    21 августа 2020, 10:32
    0
    А где это прописано? В процессе установки можно выбрать любую кодировку. А, к примеру, у меня config.inc.php выглядит так:
    $database_connection_charset = 'utf8';
    ...
    $database_dsn = 'mysql:host=localhost;dbname=DB_NAME;charset=utf8';
    Не пойму где именно MODX использует utf8mb4 по умолчанию, и использует ли вообще.
      Василий Наумкин
      22 августа 2020, 03:59
      0
      Ну ок, поддерживает utf8mb4 с версии 2.6.0, которая вышла в 2017 году.

      А если ты её не используешь — то сам себе злобный буратино. На modhost.pro она ставится для всех новых сайтов на MODX по умолчанию, так что я и забыл уже о подобных проблемах.
    ElenaLelo
    21 июля 2020, 23:00
    0
    Спасибо, как раз такая проблема
      Andrey Burym
      28 июля 2020, 15:45
      +2
      буквально сегодня всплыла проблема ) Хотел писать заметку про вашего
      В общем, дело не только в «самайликах». Можно «проще».
      Открываем два окна/вкладки корзины, во втором оформляем заказ, доставка, оплата, адрес.
      Перед последним кликом на «Отправить» переключаемся в первую вкладку и очищаем корзину.
      Затем возвращаемся на вторую вкладку и отправляем форму. Получаем заказ без товаров.


      На minishop2.com воспроизводится, лечится… не знаю как правильно, я залечил
      case 'msOnSubmitOrder':
              $cart = $order->ms2->cart->status();
              if($cart['total_count'] < 1) {
      ....
      Согласен, что последовательность действий несколько идиотичная,
      но таких людей уже как минимум двое (я — вынужденно, за покупателя ничего не скажу ))
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        5