mirror of
https://github.com/rlanvin/php-rrule.git
synced 2025-02-20 09:54:16 +01:00
Fix #25
- Fix parser handling of UNTIL when DTSTART is not provided - Accept invalid RFC strings generated by the JS lib but triggers a Notice message
This commit is contained in:
parent
26d147b729
commit
0b3a2c9a32
@ -6,6 +6,8 @@
|
||||
|
||||
- `RRule::offsetGet` and `RSet::offsetGet` throw `InvalidArgumentException` for illegal offset types [#22](https://github.com/rlanvin/php-rrule/issues/22)
|
||||
- Update exception message for UNTIL parse error [#23](https://github.com/rlanvin/php-rrule/pull/23)
|
||||
- Fix parser handling of UNTIL when DTSTART is not provided [#25](https://github.com/rlanvin/php-rrule/issues/25)
|
||||
- Accept invalid RFC strings generated by the JS lib but triggers a Notice message [#25](https://github.com/rlanvin/php-rrule/issues/25)
|
||||
|
||||
## [1.4.0] - 2016-11-11
|
||||
|
||||
|
@ -103,7 +103,8 @@ class RRule implements RRuleInterface
|
||||
* Frequency names.
|
||||
* Used internally for conversion but public if a reference list is needed.
|
||||
*
|
||||
* @todo should probably be protected, with a static getter instead.
|
||||
* @todo should probably be protected, with a static getter instead to avoid
|
||||
* unintended modification.
|
||||
*
|
||||
* @var array The name as the key
|
||||
*/
|
||||
@ -121,7 +122,8 @@ class RRule implements RRuleInterface
|
||||
* Weekdays numbered from 1 (ISO-8601 or `date('N')`).
|
||||
* Used internally but public if a reference list is needed.
|
||||
*
|
||||
* @todo should probably be protected, with a static getter instead.
|
||||
* @todo should probably be protected, with a static getter instead
|
||||
* to avoid unintended modification
|
||||
*
|
||||
* @var array The name as the key
|
||||
*/
|
||||
@ -653,9 +655,9 @@ class RRule implements RRuleInterface
|
||||
{
|
||||
$parts = array();
|
||||
|
||||
$string = trim($string);
|
||||
$string = strtoupper(trim($string));
|
||||
|
||||
$dtstart_type = 'date';
|
||||
$dtstart_type = null;
|
||||
$rfc_date_regexp = '/\d{6}(T\d{6})?Z?/'; // a bit loose
|
||||
|
||||
foreach ( explode("\n", $string) as $line ) {
|
||||
@ -681,7 +683,9 @@ class RRule implements RRuleInterface
|
||||
|
||||
switch ( $property_name ) {
|
||||
case 'DTSTART':
|
||||
case 'dtstart':
|
||||
$tmp = null;
|
||||
$dtstart_type = 'date';
|
||||
if ( ! preg_match($rfc_date_regexp, $property_value) ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid DTSTART property: date or date time format incorrect'
|
||||
@ -715,6 +719,7 @@ class RRule implements RRuleInterface
|
||||
$parts['DTSTART'] = new \DateTime($property_value, $tmp);
|
||||
break;
|
||||
case 'RRULE':
|
||||
case 'rrule':
|
||||
foreach ( explode(';',$property_value) as $pair ) {
|
||||
$pair = explode('=', $pair);
|
||||
if ( ! isset($pair[1]) || isset($pair[2]) ) {
|
||||
@ -751,9 +756,17 @@ class RRule implements RRuleInterface
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$value = new \DateTime($value);
|
||||
}
|
||||
elseif ( $key === 'DTSTART' ) {
|
||||
if ( isset($parts['DTSTART']) ) {
|
||||
throw new \InvalidArgumentException('DTSTART cannot be part of RRULE and has already been defined');
|
||||
}
|
||||
// this is an invalid rule, however we'll support it since the JS lib is broken
|
||||
// see https://github.com/rlanvin/php-rrule/issues/25
|
||||
trigger_error("This string is not compliant with the RFC (DTSTART cannot be part of RRULE). It is accepted as is for compability reasons only.", E_USER_NOTICE);
|
||||
}
|
||||
$parts[$key] = $value;
|
||||
}
|
||||
break;
|
||||
|
@ -1721,47 +1721,188 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
public function rfcStrings()
|
||||
{
|
||||
return array(
|
||||
// full RFC string
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=HOURLY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1;BYHOUR=1'),
|
||||
RRULE:FREQ=HOURLY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1;BYHOUR=1',
|
||||
null // todo
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=DAILY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1'),
|
||||
RRULE:FREQ=DAILY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1',
|
||||
null // todo
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=DAILY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1;BYHOUR=12;BYMINUTE=15,30'),
|
||||
RRULE:FREQ=DAILY;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1;BYHOUR=12;BYMINUTE=15,30',
|
||||
null
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR'),
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR',
|
||||
null // todo
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR'),
|
||||
RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR',
|
||||
null // todo
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1'),
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTH=1',
|
||||
array()
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15'),
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15',
|
||||
array(
|
||||
date_create('1997-09-01 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-09-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-01 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-17 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-29 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-31 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-11-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-11-28 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-12-01 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-12-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-12-17 09:00:00', new DateTimeZone('America/New_York'))
|
||||
)
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15;BYSETPOS=-1'),
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15;BYSETPOS=-1',
|
||||
array(
|
||||
date_create('1997-09-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-31 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-11-28 09:00:00', new DateTimeZone('America/New_York')),
|
||||
)
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970901T090000
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15;BYSETPOS=-1,1'),
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15;BYSETPOS=-1,1',
|
||||
array(
|
||||
date_create('1997-09-01 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-09-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-01 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-10-31 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-11-05 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-11-28 09:00:00', new DateTimeZone('America/New_York')),
|
||||
date_create('1997-12-01 09:00:00', new DateTimeZone('America/New_York'))
|
||||
)
|
||||
),
|
||||
array(' DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;BYWEEKNO=20,30,40;BYDAY=MO'),
|
||||
RRULE:FREQ=YEARLY;BYWEEKNO=20,30,40;BYDAY=MO',
|
||||
null
|
||||
),
|
||||
array('DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;BYYEARDAY=1,-1,10,-50;BYDAY=MO'),
|
||||
RRULE:FREQ=YEARLY;BYYEARDAY=1,-1,10,-50;BYDAY=MO',
|
||||
null
|
||||
),
|
||||
array('DTSTART:19970512T090000Z
|
||||
RRULE:FREQ=YEARLY'),
|
||||
RRULE:FREQ=YEARLY',
|
||||
null
|
||||
),
|
||||
array('DTSTART:19970512T090000
|
||||
RRULE:FREQ=YEARLY'),
|
||||
RRULE:FREQ=YEARLY',
|
||||
null
|
||||
),
|
||||
array('DTSTART:19970512
|
||||
RRULE:FREQ=YEARLY'),
|
||||
RRULE:FREQ=YEARLY',
|
||||
null
|
||||
),
|
||||
|
||||
// case insensitive
|
||||
array("dtstart:19970902T090000\nrrule:freq=yearly;count=3",
|
||||
array(date_create('1997-09-02 09:00:00'),date_create('1998-09-02 09:00:00'),date_create('1999-09-02 09:00:00'))
|
||||
),
|
||||
|
||||
// empty lines
|
||||
array("\nDTSTART:19970512\nRRULE:FREQ=YEARLY;COUNT=3\n\n",
|
||||
array(date_create('1997-05-12'),date_create('1998-05-12'),date_create('1999-05-12'))
|
||||
),
|
||||
|
||||
// no DTSTART
|
||||
array("RRULE:FREQ=YEARLY;COUNT=3",
|
||||
null
|
||||
),
|
||||
array("RRULE:FREQ=YEARLY;UNTIL=20170202",
|
||||
null
|
||||
),
|
||||
array("RRULE:FREQ=YEARLY;UNTIL=20170202T090000",
|
||||
null
|
||||
),
|
||||
array("RRULE:FREQ=YEARLY;UNTIL=20170202T090000Z",
|
||||
null
|
||||
),
|
||||
|
||||
// just the RRULE property
|
||||
array('FREQ=DAILY',
|
||||
null
|
||||
),
|
||||
array("FREQ=YEARLY;UNTIL=20170202",
|
||||
null
|
||||
),
|
||||
array("FREQ=YEARLY;UNTIL=20170202T090000",
|
||||
null
|
||||
),
|
||||
array("FREQ=YEARLY;UNTIL=20170202T090000Z",
|
||||
null
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider rfcStrings
|
||||
*/
|
||||
public function testRfcStrings($str)
|
||||
public function testRfcStringParser($str, $occurrences)
|
||||
{
|
||||
$rule = new RRule($str);
|
||||
|
||||
// test that parsing the string produces the same result
|
||||
// as generating the string from a rule
|
||||
$this->assertEquals($rule, new RRule($rule->rfcString()));
|
||||
|
||||
if ( $occurrences ) {
|
||||
$this->assertEquals($occurrences, $rule->getOccurrences());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/rlanvin/php-rrule/issues/25
|
||||
*/
|
||||
public function quirkyRfcStrings()
|
||||
{
|
||||
return array(
|
||||
array('DTSTART=20160202T000000Z;FREQ=DAILY;UNTIL=20160205T000000Z',
|
||||
array(
|
||||
date_create('2016-02-02', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-03', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-04', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-05', new DateTimeZone('UTC'))
|
||||
)
|
||||
),
|
||||
array('RRULE:DTSTART=20160202T000000Z;FREQ=DAILY;UNTIL=20160205T000000Z',
|
||||
array(
|
||||
date_create('2016-02-02', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-03', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-04', new DateTimeZone('UTC')),
|
||||
date_create('2016-02-05', new DateTimeZone('UTC'))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider quirkyRfcStrings
|
||||
* @expectedException PHPUnit_Framework_Error_Notice
|
||||
*/
|
||||
public function testQuirkyRfcStringsParserNotice($str,$occurrences)
|
||||
{
|
||||
$rule = new RRule($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider quirkyRfcStrings
|
||||
*/
|
||||
public function testQuirkyRfcStringsParser($str,$occurrences)
|
||||
{
|
||||
$rule = @ new RRule($str);
|
||||
|
||||
if ( $occurrences ) {
|
||||
$this->assertEquals($occurrences, $rule->getOccurrences());
|
||||
}
|
||||
}
|
||||
|
||||
public function invalidRfcStrings()
|
||||
@ -1779,6 +1920,10 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
array('DTSTART:20060624
|
||||
RRULE:FREQ=DAILY;UNTIL=2006-06-24'),
|
||||
|
||||
// multiple dtstart
|
||||
array('DTSTART:20060624
|
||||
RRULE:DTSTART=20060630;FREQ=DAILY;UNTIL=20060624'),
|
||||
|
||||
// test combinations of DTSTART and UNTIL which are invalid
|
||||
array('DTSTART;TZID=Australia/Sydney:20160624
|
||||
RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20160628'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user