Skip to content

Commit 8e8a277

Browse files
committed
Slightly improve error handling in DatePeriod::__construct()
1 parent 46c0c82 commit 8e8a277

6 files changed

+70
-27
lines changed

ext/date/php_date.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "ext/standard/php_math.h"
2525
#include "php_date.h"
2626
#include "zend_interfaces.h"
27+
#include "zend_exceptions.h"
2728
#include "lib/timelib.h"
2829
#include "lib/timelib_private.h"
2930
#ifndef PHP_WIN32
@@ -4117,13 +4118,11 @@ PHP_METHOD(DatePeriod, __construct)
41174118
timelib_time *clone;
41184119
zend_error_handling error_handling;
41194120

4120-
zend_replace_error_handling(EH_THROW, NULL, &error_handling);
41214121
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
41224122
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) {
41234123
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s|l", &isostr, &isostr_len, &options) == FAILURE) {
4124-
php_error_docref(NULL, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
4125-
zend_restore_error_handling(&error_handling);
4126-
return;
4124+
zend_type_error("DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments");
4125+
RETURN_THROWS();
41274126
}
41284127
}
41294128
}
@@ -4132,15 +4131,30 @@ PHP_METHOD(DatePeriod, __construct)
41324131
dpobj->current = NULL;
41334132

41344133
if (isostr) {
4134+
zend_replace_error_handling(EH_THROW, NULL, &error_handling);
41354135
date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len);
4136+
zend_restore_error_handling(&error_handling);
4137+
if (EG(exception)) {
4138+
RETURN_THROWS();
4139+
}
4140+
41364141
if (dpobj->start == NULL) {
4137-
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
4142+
zend_string *func = get_active_function_or_method_name();
4143+
zend_throw_error(zend_ce_exception, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr);
4144+
zend_string_release(func);
4145+
RETURN_THROWS();
41384146
}
41394147
if (dpobj->interval == NULL) {
4140-
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
4148+
zend_string *func = get_active_function_or_method_name();
4149+
zend_throw_error(zend_ce_exception, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr);
4150+
zend_string_release(func);
4151+
RETURN_THROWS();
41414152
}
41424153
if (dpobj->end == NULL && recurrences == 0) {
4143-
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
4154+
zend_string *func = get_active_function_or_method_name();
4155+
zend_throw_error(zend_ce_exception, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr);
4156+
zend_string_release(func);
4157+
RETURN_THROWS();
41444158
}
41454159

41464160
if (dpobj->start) {
@@ -4179,7 +4193,10 @@ PHP_METHOD(DatePeriod, __construct)
41794193
}
41804194

41814195
if (dpobj->end == NULL && recurrences < 1) {
4182-
php_error_docref(NULL, E_WARNING, "The recurrence count '%d' is invalid. Needs to be > 0", (int) recurrences);
4196+
zend_string *func = get_active_function_or_method_name();
4197+
zend_throw_error(zend_ce_exception, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func));
4198+
zend_string_release(func);
4199+
RETURN_THROWS();
41834200
}
41844201

41854202
/* options */
@@ -4189,8 +4206,6 @@ PHP_METHOD(DatePeriod, __construct)
41894206
dpobj->recurrences = recurrences + dpobj->include_start_date;
41904207

41914208
dpobj->initialized = 1;
4192-
4193-
zend_restore_error_handling(&error_handling);
41944209
}
41954210
/* }}} */
41964211

ext/date/tests/DatePeriod_wrong_constructor.phpt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ Havard Eide <nucleuz@gmail.com>
77
date.timezone=UTC
88
--FILE--
99
<?php
10-
new DatePeriod();
10+
11+
try {
12+
new DatePeriod();
13+
} catch (TypeError $exception) {
14+
echo $exception->getMessage() . "\n";
15+
}
1116
?>
12-
--EXPECTF--
13-
Fatal error: Uncaught Exception: DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments. in %s:%d
14-
Stack trace:
15-
#0 %s(%d): DatePeriod->__construct()
16-
#1 {main}
17-
thrown in %s on line %d
17+
--EXPECT--
18+
DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments

ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ try {
99
}
1010

1111
try {
12-
new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'),-1);
12+
new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'), -1);
1313
} catch (Exception $exception) {
1414
echo $exception->getMessage(), "\n";
1515
}
16+
1617
?>
1718
--EXPECT--
18-
DatePeriod::__construct(): The recurrence count '0' is invalid. Needs to be > 0
19-
DatePeriod::__construct(): The recurrence count '-1' is invalid. Needs to be > 0
19+
DatePeriod::__construct(): Recurrence count must be greater than 0
20+
DatePeriod::__construct(): Recurrence count must be greater than 0

ext/date/tests/bug44562.phpt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@ Bug #44562 (Creating instance of DatePeriod crashes)
44
<?php
55
date_default_timezone_set('Europe/Oslo');
66

7-
try
8-
{
7+
try {
98
$dp = new DatePeriod('2D');
10-
}
11-
catch ( Exception $e )
12-
{
9+
} catch (Exception $e) {
1310
echo $e->getMessage(), "\n";
1411
}
1512

ext/date/tests/date_interval_bad_format_leak.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ DateInterval with bad format should not leak period
44
<?php
55

66
try {
7-
$interval = new DateInterval('P3"D');
7+
new DateInterval('P3"D');
88
} catch (Exception $e) {
99
echo $e->getMessage(), "\n";
1010
}
1111

1212
try {
13-
$perid = new DatePeriod('P3"D');
13+
new DatePeriod('P3"D');
1414
} catch (Exception $e) {
1515
echo $e->getMessage(), "\n";
1616
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Test bad ISO date formats passed to DatePeriod constructor
3+
--FILE--
4+
<?php
5+
6+
try {
7+
new DatePeriod("R4");
8+
} catch (Exception $e) {
9+
echo $e->getMessage(), "\n";
10+
}
11+
12+
try {
13+
new DatePeriod("R4/2012-07-01T00:00:00Z");
14+
} catch (Exception $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
18+
19+
try {
20+
new DatePeriod("2012-07-01T00:00:00Z/P7D");
21+
} catch (Exception $e) {
22+
echo $e->getMessage(), "\n";
23+
}
24+
25+
?>
26+
--EXPECT--
27+
DatePeriod::__construct(): ISO interval must contain a start date, "R4" given
28+
DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given
29+
DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given

0 commit comments

Comments
 (0)