Обнуляющие смайлики (или почему 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-я строка:
Но и минимальное решение — тоже заработает.
Буквально вчера, словил неприятную багу.
(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Но и минимальное решение — тоже заработает.
Комментарии: 14
На всякий случай напомню, что MODX по умолчанию использует utf8mb4 с версии 2.6.0, которая вышла в 2017 году.
А где это прописано? В процессе установки можно выбрать любую кодировку. А, к примеру, у меня config.inc.php выглядит так:
$database_connection_charset = 'utf8';
...
$database_dsn = 'mysql:host=localhost;dbname=DB_NAME;charset=utf8';
Не пойму где именно MODX использует utf8mb4 по умолчанию, и использует ли вообще.
Ну ок, поддерживает utf8mb4 с версии 2.6.0, которая вышла в 2017 году.
А если ты её не используешь — то сам себе злобный буратино. На modhost.pro она ставится для всех новых сайтов на MODX по умолчанию, так что я и забыл уже о подобных проблемах.
А если ты её не используешь — то сам себе злобный буратино. На modhost.pro она ставится для всех новых сайтов на MODX по умолчанию, так что я и забыл уже о подобных проблемах.
Спасибо, как раз такая проблема
буквально сегодня всплыла проблема ) Хотел писать заметку про вашего…
В общем, дело не только в «самайликах». Можно «проще».
Открываем два окна/вкладки корзины, во втором оформляем заказ, доставка, оплата, адрес.
Перед последним кликом на «Отправить» переключаемся в первую вкладку и очищаем корзину.
Затем возвращаемся на вторую вкладку и отправляем форму. Получаем заказ без товаров.
На minishop2.com воспроизводится, лечится… не знаю как правильно, я залечил
но таких людей уже как минимум двое (я — вынужденно, за покупателя ничего не скажу ))
В общем, дело не только в «самайликах». Можно «проще».
Открываем два окна/вкладки корзины, во втором оформляем заказ, доставка, оплата, адрес.
Перед последним кликом на «Отправить» переключаемся в первую вкладку и очищаем корзину.
Затем возвращаемся на вторую вкладку и отправляем форму. Получаем заказ без товаров.
На minishop2.com воспроизводится, лечится… не знаю как правильно, я залечил
case 'msOnSubmitOrder':
$cart = $order->ms2->cart->status();
if($cart['total_count'] < 1) {
....
Согласен, что последовательность действий несколько идиотичная, но таких людей уже как минимум двое (я — вынужденно, за покупателя ничего не скажу ))
буду третим кого это тревожит, можете на пальцах пожалуйста рассказать как запретить оформление пустых заказов, в каких файлах, какой код. Спасибо
Если нужна просто проверка кол-ва товаров в корзине, то решение дали выше.
Создаёте плагин, вешаете его на событие msOnSubmitOrder и делаете проверку.
Создаёте плагин, вешаете его на событие msOnSubmitOrder и делаете проверку.
Дмитрий, спасибо.
Но я новичок в освоении modx, и к сожалению «делаете проверку» не знаю собственно что писать.
где создать плагин, как его подключить и повесить на собитие уже освоил, а вот сам код к сожалению не знаю
Но я новичок в освоении modx, и к сожалению «делаете проверку» не знаю собственно что писать.
case 'msOnSubmitOrder':
$cart = $order->ms2->cart->status();
if($cart['total_count'] < 1) {
....
это ж не весь код плагина, вот вместо точек, что должно быть?где создать плагин, как его подключить и повесить на собитие уже освоил, а вот сам код к сожалению не знаю
<?php
/** Проверка наличия товара в корзине */
switch ($modx->event->name) {
case 'msOnSubmitOrder':
$cart = $order->ms2->cart->status();
if($cart['total_count'] < 1) {
Здесь что?
}
break;
/** Проверка наличия товара в корзине */
switch ($modx->event->name) {
case 'msOnSubmitOrder':
$cart = $order->ms2->cart->status();
if($cart['total_count'] < 1) {
Здесь что?
}
break;
Здесь что?так как оформление заказа у меня несколько нестандартное (можете протестировать на kaolin-shop.ru), то для моих нужд было достаточно
if($cart['total_count'] < 1) {
$modx->event->output('Ваша корзина пуста, оформление заказа невозможно');
$modx->event->returnedValues = 'Ваша корзина пуста, оформление заказа невозможно';
exit( json_encode( array('onorder' => 'error', 'message' => 'Ваша корзина пуста, оформление заказа невозможно') ) );
}
а так-то можете разместить любую логику.зы: подобную правку я сделал на единственном сайте – прочие магазины претензий не предъявляли.
Супер, спасибо, сейчас попробую сделать, о результате отпишусь
Статья как это делал
Всё получилось, прекрасно отрабатывает.
Написал статью пошагово как это делал, вдруг кому пригодится)))
Всё получилось, прекрасно отрабатывает.
Написал статью пошагово как это делал, вдруг кому пригодится)))
статья – это хорошо. Только exit( json_encode – мой частный случай достойный критики. И вообще-то существует $modx->toJson (если уж по-феншую))
Спасибо, подправил.
Есть телеграмм для связи?
Есть телеграмм для связи?
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.