Я пытаюсь сделать валидатор регулярных выражений даты. Проблема, с которой я сталкиваюсь, заключается в том, что я использую поле ввода с типом "date"
, которое работает как шарм в Chrome; он открывает календарь в Chrome, но в остальном он ничего не делает, поэтому я решил пойти на ручной ввод даты для остальных.
Это мое сообщение с ошибкой (я ищу формат YYYY-MM-DD):
$date_regex ='#^(19|20)\d\d[\- /.](0[1-9]|1[012])[\- /.](0[1-9]|[12][0-9]|3[01])$#'; $hiredate = $_POST['hiredate']; if (!preg_match($date_regex, $hiredate)){ $errors[] = 'Your hire date entry does not match the YYYY-MM-DD required format.'; }
Я знаю, что есть много примеров об этом, но я пробовал уже 20, и я не мог его решить. Может быть, я что-то упустил.
Вот поле ввода, если оно имеет несколько значение:
<input type="date" name="hiredate" />
Ваше регулярное выражение не сработало, потому что у вас был unescaped /
delimiter.
Регулярное выражение, которое будет проверять дату в формате YYYY-MM-DD
следующим образом:
^(19|20)\d\d[\-\/.](0[1-9]|1[012])[\-\/.](0[1-9]|[12][0-9]|3[01])$
Он подтвердит, что год начинается с 19
или 20
, что месяц не превышает 12
и не равен 0
и что день не больше 31
и не равен 0
.
Пример онлайн
Используя ваш первоначальный пример, вы можете протестировать его следующим образом:
$date_regex = '/^(19|20)\d\d[\-\/.](0[1-9]|1[012])[\-\/.](0[1-9]|[12][0-9]|3[01])$/'; $hiredate = '2013-14-04'; if (!preg_match($date_regex, $hiredate)) { echo '<br>Your hire date entry does not match the YYYY-MM-DD required format.<br>'; } else { echo '<br>Your date is set correctly<br>'; }
Пример онлайн
Не используйте regex для этого, вы можете получить тот же результат, используя DateTime::createFromFormat
// specify your date's original format, in this example m/d/Y (eg 08/31/2013) $format = "m/d/Y"; $hireDate = DateTime::createFromFormat($format, $_POST['hiredate']); if(!$hireDate) { // createFromFormat returns false if the format is invalid; } else { //change it to any format you want with format() (eg 2013-08-31) echo $hireDate->format("Ymd"); }
Вы можете прочитать больше здесь:
http://php.net/manual/en/datetime.createfromformat.php
Однако, похоже, проблема совершенно не связана с PHP.
PHP работает на задней панели, и кажется, что у вас проблема с интерфейсом.
Я также сомневаюсь, что проблема заключается в типе ввода, который вы используете. Если один браузер не поддерживает указанный тип ввода, он по умолчанию использует текст. Смотрите здесь:
Мой браузер не знает, что такое <input type="whatever" />
, поэтому он по умолчанию вводит тип "text". Если я упакую эти 4 входа в <form action="myForm.php" method="POST"></form>
, браузер отправляет входы на сервер, потому что сервер не заботится / знает, были ли входы скрытые, переключатели, выбор, текст или пароль. Серверы получают только исходные данные.
Скорее всего, ваша проблема связана с вашим Javascript, а не с вашим PHP. Попробуйте проверить, не показывает ли браузер, который не отображает ваш виджет, что на вашей странице есть какая-то ошибка.
У Safari и Firefox есть инструменты для разработки / отладки, которые не настолько уверены в IE.
Проверка и проверка YYYY-MM-DD
в одной строке
function isValidDate($date) { return preg_match("/^(\d{4})-(\d{1,2})-(\d{1,2})$/", $date, $m) ? checkdate(intval($m[2]), intval($m[3]), intval($m[1])) : false; }
Подробности см. В моем ответе.
Не используйте слепое DateTime::createFromFormat
для проверки дат. Давайте возьмем несуществующую дату 2018-02-30
и посмотрим:
$d = DateTime::createFromFormat("Ymd", "2018-02-30"); var_dump((bool) $d); // bool(true)
Да, он возвращает true
, а не false
как вы могли ожидать. Интереснее:
$d = DateTime::createFromFormat("Ymd", "2018-99-99"); var_dump((bool) $d); // bool(true)
Также true
… Итак, он проверяет только количество цифр. Еще одна попытка:
$d = DateTime::createFromFormat("Ymd", "ABCD-99-99"); var_dump($d); // bool(false)
Наконец, false
.
Что здесь происходит, мы можем видеть из этого фрагмента:
$d = DateTime::createFromFormat("Ymd", "2018-02-30"); var_dump($d); // var_dump OUTPUT object(DateTime)#1 (3) { ["date"]=> string(26) "2018-03-02 16:41:34.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }
Как вы можете видеть, когда мы пропускаем несуществующий 2018-02-30
, объект DateTime
содержит 2018-03-02
. Я предполагаю, что это потому, что февраль 2018 года составляет 28 дней, то есть максимальная дата 2018-02-28
, а когда мы проходим день 30
, createFromFormat просто добавляет 30 дней к 2018-02-01
и создает новую дату без предшествующей даты Проверка.