Есть массив гороскопов. Пользователь вводит дату своего рождения в инпут и после отправки формы должен определиться его знак зодиака и выводится предсказание для его знака на текущий день. PHP: <?php error_reporting(-1); // №11 echo '<form action="" method="GET">'; echo '<input type="date" name="birthday">'; echo '<input type="submit" value="отправить">'; echo '</form>'; $horoscopes = [ 'Овны' => 'найдите в себе желание радоваться этой жизни, даже если не очень хочется.', 'Тельцы' => 'сегодня даже работа ответит вам взаимностью.', 'Близнецы' => 'умерьте аппетиты и не выходите за рамки разумного.', 'Раки' => 'вы в отличной физической форме и преодолеете все препятствия.', 'Львы' => 'у вас есть тактика, вот её и придерживайтесь.', 'Девы' => 'кто-то захочет совершить нападение на ваше сердце.', 'Весы' => 'настроение будет на высоте, а этого уже достаточно.', 'Скорпионы' => 'все бонусы этого дня будут поджидать вас вечером.', 'Стрельцы' => 'наслаждайтесь моментом, а о будущем вы ещё успеете подумать.', 'Козероги' => 'соблюдайте сегодня максимально дружелюбный вид.', 'Водолеи' => 'впечатлений, полученых сегодня вам хватит надолго.', 'Рыбы' => 'звёзды дают зелёный свет на новые знакомства.', ]; if (isset($_GET['birthday'])) { if ($_GET['birthday'] === '') { echo 'Вы не выбрали дату рождения!'; } else { $currentYear = date('Y'); // Порядковый номер дня рождения в году $birthday = (int)date('z', strtotime($_GET['birthday'])) + 1; switch ($birthday) { case ($birthday >= (int)date('z', mktime(0, 0, 0, 3, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 4, 19, $currentYear))): echo "Овны: $horoscopes[Овны]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 4, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 5, 20, $currentYear))): echo "Тельцы: $horoscopes[Тельцы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 5, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 6, 20, $currentYear))): echo "Близнецы: $horoscopes[Близнецы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 6, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 7, 22, $currentYear))): echo "Раки: $horoscopes[Раки]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 7, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 8, 22, $currentYear))): echo "Львы: $horoscopes[Львы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 8, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 9, 22, $currentYear))): echo "Девы: $horoscopes[Девы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 9, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 10, 22, $currentYear))): echo "Весы: $horoscopes[Весы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 10, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 11, 21, $currentYear))): echo "Скорпионы: $horoscopes[Скорпионы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 11, 22, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 12, 21, $currentYear))): echo "Стрельцы: $horoscopes[Стрельцы]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 12, 22, $currentYear)) || $birthday <= (int)date('z', mktime(0, 0, 0, 1, 19, $currentYear))): echo "Козероги: $horoscopes[Козероги]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 1, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 2, 18, $currentYear))): echo "Водолеи: $horoscopes[Водолеи]"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 2, 19, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 3, 20, $currentYear))): echo "Рыбы: $horoscopes[Рыбы]"; break; } } } У Козерога указаны даты с 22 декабря до 19 января. Но 19 января почему-то выводится гороскоп для водолея. У Водолея с 20 января по 18 февраля. Но 18 февраля уже выводится гороскоп для Рыб. Получается что в январе и феврале дни смещены.
Проблема здесь в том, как интерпретируются диапазоны дней для знаков, которые пересекают начало и конец года, как у Козерога и Водолея. В этих случаях сравнение дней в году (z — порядковый номер дня) требует особого подхода, потому что date('z') для 19 января (примерно 19-й день в году) будет меньше, чем для 31 декабря (примерно 365-й день). Чтобы правильно интерпретировать такие знаки, стоит сделать отдельные условия для знаков, диапазон которых включает конец года или начало нового. Можно, например, использовать дополнительные проверки для таких случаев, либо упростить код с учетом таких границ. Обновим условие для Козерога и Водолея, а также добавим проверку для тех, кто родился на пограничных датах: PHP: <?php // ... if (isset($_GET['birthday'])) { if ($_GET['birthday'] === '') { echo 'Вы не выбрали дату рождения!'; } else { $currentYear = date('Y'); $birthday = (int)date('z', strtotime($_GET['birthday'])) + 1; switch (true) { case ($birthday >= (int)date('z', mktime(0, 0, 0, 3, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 4, 19, $currentYear))): echo "Овны: {$horoscopes['Овны']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 4, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 5, 20, $currentYear))): echo "Тельцы: {$horoscopes['Тельцы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 5, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 6, 20, $currentYear))): echo "Близнецы: {$horoscopes['Близнецы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 6, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 7, 22, $currentYear))): echo "Раки: {$horoscopes['Раки']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 7, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 8, 22, $currentYear))): echo "Львы: {$horoscopes['Львы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 8, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 9, 22, $currentYear))): echo "Девы: {$horoscopes['Девы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 9, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 10, 22, $currentYear))): echo "Весы: {$horoscopes['Весы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 10, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 11, 21, $currentYear))): echo "Скорпионы: {$horoscopes['Скорпионы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 11, 22, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 12, 21, $currentYear))): echo "Стрельцы: {$horoscopes['Стрельцы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 12, 22, $currentYear)) || $birthday <= (int)date('z', mktime(0, 0, 0, 1, 19, $currentYear))): echo "Козероги: {$horoscopes['Козероги']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 1, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 2, 18, $currentYear))): echo "Водолеи: {$horoscopes['Водолеи']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 2, 19, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 3, 20, $currentYear))): echo "Рыбы: {$horoscopes['Рыбы']}"; break; } } } В этом варианте знак Козерога определяется корректно: сначала проверяется, попадает ли день в диапазон с 22 декабря по 31 декабря, либо с 1 по 19 января. Водолей тоже определяется корректно. Ввот основные изменения: Замена условий на switch (true): Вместо switch ($birthday), используется switch (true), что позволяет делать проверки с логическими выражениями (условиями) внутри каждого case, а не только на равенство значений. Корректировка условий для Козерога и Водолея: В случае Козерога: проверяется, находится ли день рождения в диапазоне с 22 декабря по 31 декабря или с 1 по 19 января: PHP: case ($birthday >= (int)date('z', mktime(0, 0, 0, 12, 22, $currentYear)) || $birthday <= (int)date('z', mktime(0, 0, 0, 1, 19, $currentYear))): echo "Козероги: {$horoscopes['Козероги']}"; break; Здесь используется оператор || (логическое ИЛИ), чтобы охватить оба периода (конец и начало года). В случае Водолея: знак определяется, если день рождения находится в интервале с 20 января по 18 февраля. Так как даты не пересекают границы года, условие для Водолея остается стандартным: PHP: case ($birthday >= (int)date('z', mktime(0, 0, 0, 1, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 2, 18, $currentYear))): echo "Водолеи: {$horoscopes['Водолеи']}"; break; Эти изменения позволяют правильно интерпретировать дни рождения, которые лежат на границе года, как в случае с Козерогом и Водолеем. --- Добавлено --- Замена switch ($birthday) на switch (true) — это ключевое изменение. Оно позволяет проверять логические выражения внутри каждого case, а не только точное соответствие значению переменной $birthday. В итоге, весь блок switch начинает работать как цепочка if...else if, что позволяет корректно обрабатывать диапазоны дат и решает проблему с Козерогом и Водолеем.
Ты проверял? У тебя правильно работает? Я скопировал твой код и у меня как показывал водолея с 19 января, так и показывает. В моем коде у козерога тоже стоит логическое || ИЛИ.
Добрый день! Посмотрите моё решение. Оставил, то что было для сравнения результата. Выберите какое понравится. PHP: <?php error_reporting(-1); // №11 echo '<form action="" method="GET">'; echo '<input type="date" name="birthday" required >'; echo '<input type="submit" value="отправить">'; echo '</form>'; $horoscopes = [ 'Овны' => 'найдите в себе желание радоваться этой жизни, даже если не очень хочется.', 'Тельцы' => 'сегодня даже работа ответит вам взаимностью.', 'Близнецы' => 'умерьте аппетиты и не выходите за рамки разумного.', 'Раки' => 'вы в отличной физической форме и преодолеете все препятствия.', 'Львы' => 'у вас есть тактика, вот её и придерживайтесь.', 'Девы' => 'кто-то захочет совершить нападение на ваше сердце.', 'Весы' => 'настроение будет на высоте, а этого уже достаточно.', 'Скорпионы' => 'все бонусы этого дня будут поджидать вас вечером.', 'Стрельцы' => 'наслаждайтесь моментом, а о будущем вы ещё успеете подумать.', 'Козероги' => 'соблюдайте сегодня максимально дружелюбный вид.', 'Водолеи' => 'впечатлений, полученых сегодня вам хватит надолго.', 'Рыбы' => 'звёзды дают зелёный свет на новые знакомства.', ]; $horoscopesInd = array_keys($horoscopes); $horoscopesDate = [ ["3-21","4-19"], ["4-20","5-20"], ["5-21","6-20"], ["6-21","7-22"], ["7-23","8-22"], ["8-23","9-22"], ["9-23","10-22"], ["10-23","11-21"], ["11-22","12-21"], ["12-22","1-19"], ["1-20","2-18"], ["2-19","3-20"] ]; function getTs($md, $Y){ $md = str_pad($md, 4, "0", STR_PAD_LEFT); return strtotime("$Y-$md"); } if (isset($_GET['birthday'])) { $currentYear = $Y = date('Y'); $mdBd = substr($_GET['birthday'], 5); foreach($horoscopesDate as $i => $interval) { $begin = getTs($interval[0], $Y); $tsBd = getTs($mdBd, $Y); if($i==9) $Y++; $end = getTs($interval[1], $Y); if(in_array($tsBd, range($begin,$end))) { echo $interval[0]," ", $interval[1],"<br>"; $zName = $horoscopesInd[$i]; echo $zName, " ", $horoscopes[$zName]; break; } } ######################################################################### # Для сранения резeльтата оcтавил Ваш код echo "<hr>"; $currentYear = date('Y'); $birthday = (int)date('z', strtotime($_GET['birthday'])) + 1; switch (true) { case ($birthday >= (int)date('z', mktime(0, 0, 0, 3, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 4, 19, $currentYear))): echo "Овны: {$horoscopes['Овны']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 4, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 5, 20, $currentYear))): echo "Тельцы: {$horoscopes['Тельцы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 5, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 6, 20, $currentYear))): echo "Близнецы: {$horoscopes['Близнецы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 6, 21, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 7, 22, $currentYear))): echo "Раки: {$horoscopes['Раки']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 7, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 8, 22, $currentYear))): echo "Львы: {$horoscopes['Львы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 8, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 9, 22, $currentYear))): echo "Девы: {$horoscopes['Девы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 9, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 10, 22, $currentYear))): echo "Весы: {$horoscopes['Весы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 10, 23, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 11, 21, $currentYear))): echo "Скорпионы: {$horoscopes['Скорпионы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 11, 22, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 12, 21, $currentYear))): echo "Стрельцы: {$horoscopes['Стрельцы']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 12, 22, $currentYear)) || $birthday <= (int)date('z', mktime(0, 0, 0, 1, 19, $currentYear))): echo "Козероги: {$horoscopes['Козероги']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 1, 20, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 2, 18, $currentYear))): echo "Водолеи: {$horoscopes['Водолеи']}"; break; case ($birthday >= (int)date('z', mktime(0, 0, 0, 2, 19, $currentYear)) && $birthday <= (int)date('z', mktime(0, 0, 0, 3, 20, $currentYear))): echo "Рыбы: {$horoscopes['Рыбы']}"; break; } ################################################################################ } Удачи!
Ну, изначально вы сделали неверный выбор что с чем сравнивать. Порядковый номер дня в году с интервалом дат знаков Зодиака чисто логически неудобно. В PHP наиболее удобным является сравнение дат в Юникс формате Отсюда наиболее удобным будет привести даты интервалов и дня рождения к одному году, взяв например 1970 Ну, тогда уже и моё. Вспомню, помнят ли ручки PHP: <?php date_default_timezone_set('UTC'); $birthday = '02-29'; // m-d function ret_udate($d) { $date = date_create('1970-'.$d); return date_format($date, 'U'); } function ret_zodiac($bd) { $ubd = ret_udate($bd); $horoscope = array ( array ('Козероги', '01-01', '01-19'), array ('Водолеи', '01-20', '02-18'), array ('Рыбы', '02-19', '03-20'), array ('Овны', '03-21', '04-19'), array ('Тельцы', '04-20', '05-20'), array ('Близнецы', '05-21', '06-20'), array ('Раки', '06-21', '07-22'), array ('Львы', '07-23', '08-22'), array ('Девы', '08-23', '09-22'), array ('Весы', '09-23', '10-22'), array ('Скорпионы', '10-23', '11-21'), array ('Стрельцы', '11-22', '12-21'), array ('Козероги', '12-22', '12-31'), ); foreach ($horoscope as $zodiac) { if(ret_udate($zodiac[1]) <= $ubd && $ubd <= ret_udate($zodiac[2])) { return $zodiac[0]; } } } $zodiac_sign = ret_zodiac($birthday); $horoscopes = array ( 'Овны' => 'найдите в себе желание радоваться этой жизни, даже если не очень хочется.', 'Тельцы' => 'сегодня даже работа ответит вам взаимностью.', 'Близнецы' => 'умерьте аппетиты и не выходите за рамки разумного.', 'Раки' => 'вы в отличной физической форме и преодолеете все препятствия.', 'Львы' => 'у вас есть тактика, вот её и придерживайтесь.', 'Девы' => 'кто-то захочет совершить нападение на ваше сердце.', 'Весы' => 'настроение будет на высоте, а этого уже достаточно.', 'Скорпионы' => 'все бонусы этого дня будут поджидать вас вечером.', 'Стрельцы' => 'наслаждайтесь моментом, а о будущем вы ещё успеете подумать.', 'Козероги' => 'соблюдайте сегодня максимально дружелюбный вид.', 'Водолеи' => 'впечатлений, полученых сегодня вам хватит надолго.', 'Рыбы' => 'звёзды дают зелёный свет на новые знакомства.' ); echo $zodiac_sign . ' : ' . $horoscopes[$zodiac_sign]; ?>
Добрый день! Всё ещё на PHP 5.3 ? Вы таже сравниваете не порядковый номер дня в году, а timestamp. Это правильное решение. Мне не понравилось, что Вы для того чтобы не прописовать логику повторили в массиве $horoscopes запись для 'Козероги' с разными датами. Это в данном случае лишнее PHP: date_default_timezone_set('UTC'); Удачи!