From 287c8a86b4201322163ae6bae1d0fa2b21f349b1 Mon Sep 17 00:00:00 2001 From: Cody Mann Date: Sun, 6 Mar 2022 15:02:16 -0600 Subject: [PATCH 1/3] GH-7979: iterator advances when checking if valid --- ext/date/php_date.c | 32 +++++++----- .../tests/DatePeriod_no_advance_on_valid.phpt | 51 +++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 ext/date/tests/DatePeriod_no_advance_on_valid.phpt diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 2d5cffb9636..270d507a922 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -1451,16 +1451,6 @@ static int date_period_it_has_more(zend_object_iterator *iter) { date_period_it *iterator = (date_period_it *)iter; php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data); - timelib_time *it_time = object->current; - - /* apply modification if it's not the first iteration */ - if (!object->include_start_date || iterator->current_index > 0) { - it_time->have_relative = 1; - it_time->relative = *object->interval; - it_time->sse_uptodate = 0; - timelib_update_ts(it_time, NULL); - timelib_update_from_sse(it_time); - } if (object->end) { return object->current->sse < object->end->sse ? SUCCESS : FAILURE; @@ -1505,9 +1495,17 @@ static void date_period_it_current_key(zend_object_iterator *iter, zval *key) /* {{{ date_period_it_move_forward */ static void date_period_it_move_forward(zend_object_iterator *iter) { - date_period_it *iterator = (date_period_it *)iter; + date_period_it *iterator = (date_period_it *)iter; + php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data); + timelib_time *it_time = object->current; - iterator->current_index++; + it_time->have_relative = 1; + it_time->relative = *object->interval; + it_time->sse_uptodate = 0; + timelib_update_ts(it_time, NULL); + timelib_update_from_sse(it_time); + + iterator->current_index++; date_period_it_invalidate_current(iter); } /* }}} */ @@ -1525,7 +1523,17 @@ static void date_period_it_rewind(zend_object_iterator *iter) zend_throw_error(NULL, "DatePeriod has not been initialized correctly"); return; } + iterator->object->current = timelib_time_clone(iterator->object->start); + + if (!iterator->object->include_start_date) { + iterator->object->current->have_relative = 1; + iterator->object->current->relative = *iterator->object->interval; + iterator->object->current->sse_uptodate = 0; + timelib_update_ts(iterator->object->current, NULL); + timelib_update_from_sse(iterator->object->current); + } + date_period_it_invalidate_current(iter); } /* }}} */ diff --git a/ext/date/tests/DatePeriod_no_advance_on_valid.phpt b/ext/date/tests/DatePeriod_no_advance_on_valid.phpt new file mode 100644 index 00000000000..dce1e9f6eb7 --- /dev/null +++ b/ext/date/tests/DatePeriod_no_advance_on_valid.phpt @@ -0,0 +1,51 @@ +--TEST-- +Date Period iterators do not advance on `valid()` +--FILE-- +getIterator(); + +foreach ($iterator as $item) { + echo $item->format('Y-m-d') . "\n"; +} + +echo "---------STEP 2\n"; + +foreach ($iterator as $item) { + $iterator->valid(); + echo $item->format('Y-m-d') . "\n"; +} + +$period = new DatePeriod($start, $interval, $end, DatePeriod::EXCLUDE_START_DATE); +$iterator = $period->getIterator(); + +echo "---------STEP 3\n"; + +foreach ($iterator as $item) { + echo $item->format('Y-m-d') . "\n"; +} + +echo "---------STEP 4\n"; + +foreach ($iterator as $item) { + $iterator->valid(); + echo $item->format('Y-m-d') . "\n"; +} +--EXPECT-- +2022-01-01 +2022-01-02 +2022-01-03 +---------STEP 2 +2022-01-01 +2022-01-02 +2022-01-03 +---------STEP 3 +2022-01-02 +2022-01-03 +---------STEP 4 +2022-01-02 +2022-01-03 From 24085d0192240aa7102ca5e4cc5dfc2aecb2fa3c Mon Sep 17 00:00:00 2001 From: Cody Mann Date: Mon, 28 Mar 2022 17:05:44 -0500 Subject: [PATCH 2/3] style/readability updates --- ext/date/php_date.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 270d507a922..24b6b911368 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -1495,17 +1495,17 @@ static void date_period_it_current_key(zend_object_iterator *iter, zval *key) /* {{{ date_period_it_move_forward */ static void date_period_it_move_forward(zend_object_iterator *iter) { - date_period_it *iterator = (date_period_it *)iter; - php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data); - timelib_time *it_time = object->current; + date_period_it *iterator = (date_period_it *)iter; + php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data); + timelib_time *it_time = object->current; - it_time->have_relative = 1; - it_time->relative = *object->interval; - it_time->sse_uptodate = 0; - timelib_update_ts(it_time, NULL); - timelib_update_from_sse(it_time); + it_time->have_relative = 1; + it_time->relative = *object->interval; + it_time->sse_uptodate = 0; + timelib_update_ts(it_time, NULL); + timelib_update_from_sse(it_time); - iterator->current_index++; + iterator->current_index++; date_period_it_invalidate_current(iter); } /* }}} */ @@ -1526,13 +1526,16 @@ static void date_period_it_rewind(zend_object_iterator *iter) iterator->object->current = timelib_time_clone(iterator->object->start); - if (!iterator->object->include_start_date) { - iterator->object->current->have_relative = 1; - iterator->object->current->relative = *iterator->object->interval; - iterator->object->current->sse_uptodate = 0; - timelib_update_ts(iterator->object->current, NULL); - timelib_update_from_sse(iterator->object->current); - } + if (!iterator->object->include_start_date) { + timelib_time *it_time = iterator->object->current; + + it_time->have_relative = 1; + it_time->relative = *iterator->object->interval; + it_time->sse_uptodate = 0; + + timelib_update_ts(it_time, NULL); + timelib_update_from_sse(it_time); + } date_period_it_invalidate_current(iter); } From e38d300a70c66775e540a2e7a7e39b0f24c81dfa Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Thu, 14 Apr 2022 10:32:10 +0100 Subject: [PATCH 3/3] Refactor code to avoid duplication --- NEWS | 4 ++++ ext/date/php_date.c | 24 +++++++++---------- .../tests/DatePeriod_no_advance_on_valid.phpt | 3 ++- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 9645c031c61..79ff4202e2e 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed bug GH-8289 (Exceptions thrown within a yielded from iterator are not rethrown into the generator). (Bob) +- Date: + . Fixed bug GH-7979 (DatePeriod iterator advances when checking if valid). + (Derick, Cody Mann) + - FPM: . Fixed bug #76003 (FPM /status reports wrong number of active processe). (Jakub Zelenka) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 24b6b911368..5d0b57eab25 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -1492,6 +1492,15 @@ static void date_period_it_current_key(zend_object_iterator *iter, zval *key) } /* }}} */ +static void date_period_advance(timelib_time *it_time, timelib_rel_time *interval) +{ + it_time->have_relative = 1; + it_time->relative = *interval; + it_time->sse_uptodate = 0; + timelib_update_ts(it_time, NULL); + timelib_update_from_sse(it_time); +} + /* {{{ date_period_it_move_forward */ static void date_period_it_move_forward(zend_object_iterator *iter) { @@ -1499,11 +1508,7 @@ static void date_period_it_move_forward(zend_object_iterator *iter) php_period_obj *object = Z_PHPPERIOD_P(&iterator->intern.data); timelib_time *it_time = object->current; - it_time->have_relative = 1; - it_time->relative = *object->interval; - it_time->sse_uptodate = 0; - timelib_update_ts(it_time, NULL); - timelib_update_from_sse(it_time); + date_period_advance(it_time, object->interval); iterator->current_index++; date_period_it_invalidate_current(iter); @@ -1527,14 +1532,7 @@ static void date_period_it_rewind(zend_object_iterator *iter) iterator->object->current = timelib_time_clone(iterator->object->start); if (!iterator->object->include_start_date) { - timelib_time *it_time = iterator->object->current; - - it_time->have_relative = 1; - it_time->relative = *iterator->object->interval; - it_time->sse_uptodate = 0; - - timelib_update_ts(it_time, NULL); - timelib_update_from_sse(it_time); + date_period_advance(iterator->object->current, iterator->object->interval); } date_period_it_invalidate_current(iter); diff --git a/ext/date/tests/DatePeriod_no_advance_on_valid.phpt b/ext/date/tests/DatePeriod_no_advance_on_valid.phpt index dce1e9f6eb7..6a8a9d0f5d0 100644 --- a/ext/date/tests/DatePeriod_no_advance_on_valid.phpt +++ b/ext/date/tests/DatePeriod_no_advance_on_valid.phpt @@ -1,5 +1,5 @@ --TEST-- -Date Period iterators do not advance on `valid()` +Date Period iterators do not advance on valid() --FILE-- valid(); echo $item->format('Y-m-d') . "\n"; } +?> --EXPECT-- 2022-01-01 2022-01-02