Эта заметка относится к разряду технической. То есть уже требует небольшого погружения в код .
Дано: Сайт под управлением CMS WordPress.
Задача: Проверить на уровне сервера (на стороне back-end) данные приходящие извне, на корректный номер телефона.
Решение: Если у вас установлен плагин для электронной коммерции WooCommerce, то обращу внимание на то, что в нём уже существует специальный метод (функция) который позволяет осуществить проверку на корректный номере телефона, то есть исключить обработку данных, если в них содержаться какие то иные символы, например, буквы.
Давайте взглянет на класс WC_Validation. В нём мы увидим нужные нам методы для решения поставленной задачи:
- is_phone() — Проверяет номер телефона с помощью регулярного выражения.
- format_phone() — Позволяет отформатировать переданный номер телефона.
Давайте взглянем на этот метод из ядра плагина WooCommerce:
/**
* Validates a phone number using a regular expression.
*
* @param string $phone Phone number to validate.
* @return bool
*/
public static function is_phone( $phone ) {
if ( 0 < strlen( trim( preg_replace( '/[\s\#0-9_\-\+\/\(\)\.]/', '', $phone ) ) ) ) {
return false;
}
return true;
}
Очевидно, что метод реализует грамотную проверку на адекватный номер телефона.
Функция strlen() возвращает длину строки и тут же мы её проверяем , чтобы она не была меньше нуля. А функция trim() ещё раньше отрабатывает и её назначение — удалить пробелы из начала и конца строки. И в серединке мы видим функцию preg_replace(), которая осуществляет поиск и замену по регулярному выражению. Первый аргумент — это паттерн. Второй аргумент — это то, что функция получает, то есть наш номер телефона извне. Возвращает функция булев тип: true|false.
Применение:
В принципе, для того чтобы воспользоваться функцией можно просто вызвать её, передав ей данные на валидацию. Но я предлагаю другой подход. Мы её вынесем отдельно, как функцию-хелпер, но только с проверкой на объявление одноимённой функции (можно конечно просто переименовать произвольно и не заморачиваться, но я учёл, что может быть активирован плагин Woo и тогда выполнение вызова функции, будет уже на стороне Woo).
/**
* Validates a phone number using a regular expression.
*
* @param string $phone Phone number to validate.
* @return bool
*/
if (!function_exists('is_phone')) {
function is_phone( $phone ) {
if ( 0 < strlen( trim( preg_replace( '/[\s\#0-9_\-\+\/\(\)\.]/', '', $phone ) ) ) ) {
return false;
}
return true;
}
}
Предлагаю прибегнуть к помощи онлайн-инструмента PHP Online Compiler (Editor / Interpreter) и посмотреть наш код в действии.
Я специально подготовил данные с разными вариантами: слитно со знаком «плюс», с чёрточками и с пробелом (последний пример). Люди по разному могут указать номер телефона. Все примеры валидны.
А теперь давайте рассмотрим не валидный пример, в котором специально вместо нуля передал заглавную «O», а в двух следующих специальные символы, которые не учтены в паттерне регулярного выражения. В итоге получили false
Форматирование номера телефона
Вторая функция format_phone(), которая идёт «прицепом» к первой, является обёрткой функции wc_format_phone_number()
Обратите внимание, что внутри после проверки на пустую строку идёт проверка и привязка к ранее рассмотренной функции. Согласно коду — это метод класса WC_Validation и он должен быть не false. Тогда то и происходит магия при помощи регулярного выражения и другого паттерна. Задумка хорошая, но по большому счёту для нашего континента бесполезная 🙂
При желании можно конечно «допилить» это дело, например, оформить в отдельную функцию-хелпер или же дополнить код первой функции и получить полное решение валидации номера телефона с последующим форматированием при возврате функцией. Хорошей отправной точкой тут может послужить нативная функция PHP sscanf() — которая разбирает строку в соответствии с заданным форматом. Вот пример со страницы описания данной функции.
Естественно, что для начинающих пользователей это может показаться сложным решением, поэтому я предлагаю написать простенькую «функцию-прицеп» к нашей первой функции-валидатору, которая будет возвращать отформатированную строку.
/**
* Format phone numbers.
*
* @param string $phone Phone number.
* @return string
*/
function myFormatPhone( $phone ) {
$phone = $phone ?? '';
$count = iconv_strlen($phone, 'UTF-8');
if($count === 10){
$part_one = substr($phone, 0, 3); // 903
$part_two = substr($phone, 3, 3); // 000
$part_three = substr($phone, 6, 2); // 00
$part_four = substr($phone, 8, 2); // 00
$phone = "({$part_one}) {$part_two}-{$part_three}-{$part_four}";
}
return $phone;
}
Код не идеальный. Это просто импровизация для того чтобы показать, как просто на стороне «бэкэнд», на PHP можно сделать форматирование возвращаемой строки с номером телефона.
Здесь для демонстрации возможностей PHP для каких-то проверок/условий задействовал функцию iconv_strlen() — возвращает количество символов в строке, а не количество байт (как, например strlen()).
Если отталкиваться от этого кода, то тут нужно учесть, что первая наша функция разрешает символы «+» и «-» , а следовательно их подсчёт тоже будет учитываться и нас подстерегает неожиданность при форматировании 🙂 Поэтому, в этом случае имеет смысл передавать только цифры, а всё лишнее — вычищать. Следовательно, наше выражение может иметь в первой функции следующий вид:
preg_replace("/[^0-9]/","", $phone ........
Но тут опять много нюансов, например человек может начать запись с «8-ки», а может с «7-ки» 🙂 А в Казахстане формат встречается зачастую +7 (7xx) xxx-xx-xx
Поэтому можно сохранять в базу значение до форматирования, а потом ещё и после и в случае каких-то непонятных ситуаций исследовать эти значения.
В общем, если подытожить, то на мой взгляд первой функции вполне достаточно. Главную задачу она выполняет — чистка пробелов и прочих лишних символов, которые никак не ассоциируются с записью телефонного номера.
Но, если вы всё-таки намерены делать форматирование, то я предлагаю реализовать его на стороне клиента и для этого можно задействовать изящное решение под WooCommerce, при помощи которого мы можем задать нужную маску для ввода номера телефона пользователем перед тем, как он будет передаваться функции-валидатору.
Как сделать маску при вводе номера телефона?