«Ввёл все цифры, флаг — Россия, а мне пишут: введите корректный номер». Номер был правильный. Маска под флагом была правильная. Сервер проверял его по правилам другой страны.
Это 12-я часть цикла «WordPress на кэшируемом сайте».
Два источника правды
Сайт работал в нескольких странах. Страну на странице определяли два разных места:
| Что | Откуда берёт страну |
|---|---|
| маска поля и флаг | разметка страницы: <meta name="language"> |
| проверка номера на сервере | кука lang из запроса |
Обычно они совпадают. Но разметка приходит из кэша и живёт своей жизнью, а кука — общая для всех вкладок и меняется мгновенно. Расходятся они легко:
- страница открыта из истории браузера кнопкой «назад», а кука уже другая;
- в соседней вкладке сменили страну — кука сменилась у всех вкладок;
- страну переключили без перезагрузки страницы.
В итоге под флагом «Россия» сервер проверял номер по белорусскому шаблону и отвергал правильный +7.
Воспроизводится за минуту: поставить куку lang=by из консоли, не перезагружая страницу, и отправить корректный российский номер.
Вторая мина в том же коде
return preg_match($regExps[$lang], $phone); // $lang — из куки
Список стран задаёт контент-менеджер в настройках. Если в куке окажется страна, которой нет в списке шаблонов, — отвергаться будет каждый номер.
Решение: любой известный формат
Мы не стали чинить синхронизацию куки и разметки. Правило из прошлой части — форма должна отправиться всегда — подсказывает решение проще: номер принимается, если он подходит под шаблон любой из известных стран.
function validate_phone(string $phone, array $regExps): bool
{
foreach ($regExps as $regExp) {
if (preg_match($regExp, $phone)) {
return true;
}
}
return false;
}
- недозаполненный номер по-прежнему отвергается: он не подходит ни под один шаблон;
- передавать страну с клиента отдельным полем смысла нет — при проверке «любой известный» результат тот же;
- лишняя заявка с номером соседней страны дешевле потерянной.
Общий урок для кэшируемых сайтов
Если страница из кэша и сервер решают одно и то же по разным источникам, однажды они разойдутся. Разметка застыла на момент кэширования, кука — живая. Либо оба решения берут одно и то же (например, страна передаётся из разметки вместе с формой), либо сервер не должен зависеть от того, в чём они расходятся.
Как кука в разметке вообще ломает кэш — в девятой части цикла про кэш страниц.
Посетители не могут отправить форму с правильным телефоном?
Пришлите адрес — проверю, по каким правилам сервер проверяет номер и откуда их берёт.
// загружаю комментарии…