Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -12,7 +12,7 @@
|
||||
namespace IPS\calendar\Icalendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -29,6 +29,7 @@ class _ICSParser
|
||||
*
|
||||
* @param string $rrule The ICS RRULE value
|
||||
* @param string $timezone Timezone to treat recurring end date as
|
||||
* @param NULL|\IPS\calendar\Date $startDate If supplied, we can use the start date to help convert certain repeat rules to make them simpler
|
||||
* @return array
|
||||
* @todo [Future] We do not support HOURLY, MINUTELY or SECONDLY "FREQ" values
|
||||
* @todo [Future] We do not support the properties BYSETPOS, BYYEARDAY, BYMONTH, BYHOUR, BYMINUTE, BYSECOND, BYWEEKNO, WKST
|
||||
@@ -37,7 +38,7 @@ class _ICSParser
|
||||
* @throws \InvalidArgumentException
|
||||
* @note Some implementations separate with : and some with ; so we have to support both
|
||||
*/
|
||||
public static function parseRrule( $rrule, $timezone=NULL )
|
||||
public static function parseRrule( $rrule, $timezone=NULL, $startDate = NULL )
|
||||
{
|
||||
$rule = array_map( 'trim', explode( ';', str_replace( ':', ';', $rrule ) ) );
|
||||
$dayNames = array();
|
||||
@@ -65,10 +66,18 @@ class _ICSParser
|
||||
throw new \InvalidArgumentException( $_ruleData[0] );
|
||||
break;
|
||||
|
||||
case 'WKST':
|
||||
/* We can safely ignore this when it is set to the default value of MO. We can't make assumptions in other cases. */
|
||||
if( mb_strtolower( $_ruleData[1] ) != 'mo' )
|
||||
{
|
||||
throw new \InvalidArgumentException( $_ruleData[0] );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FREQ':
|
||||
$frequency = mb_strtolower( $_ruleData[1] );
|
||||
|
||||
if( in_array( $frequency, array( 'daily', 'weekly', 'monthly', 'yearly' ) ) )
|
||||
if( \in_array( $frequency, array( 'daily', 'weekly', 'monthly', 'yearly' ) ) )
|
||||
{
|
||||
$repeatData['event_repeats'] = $frequency;
|
||||
$repeatData['event_repeat'] = TRUE;
|
||||
@@ -110,7 +119,7 @@ class _ICSParser
|
||||
case 'BYMONTHDAY':
|
||||
$values = array_map( 'trim', explode( ',', $_ruleData[1] ) );
|
||||
|
||||
if( count( $values ) > 1 OR \stripos( $values[0], '-' ) !== FALSE )
|
||||
if( \count( $values ) > 1 OR \stripos( $values[0], '-' ) !== FALSE )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'BYMONTHDAY' );
|
||||
}
|
||||
@@ -136,6 +145,36 @@ class _ICSParser
|
||||
$repeatData['event_repeat_freq'] = 1;
|
||||
}
|
||||
|
||||
/* Try to make the returned rules a little "smarter" for efficiency reasons... */
|
||||
/* Convert "repeats every 14 days" into "2 weeks" */
|
||||
if( $repeatData['event_repeats'] == 'daily' AND $repeatData['event_repeat_freq'] % 7 == 0 )
|
||||
{
|
||||
$repeatData['event_repeats'] = 'weekly';
|
||||
$repeatData['event_repeat_freq'] = $repeatData['event_repeat_freq'] / 7;
|
||||
}
|
||||
|
||||
/* Convert "repeats every week on Tuesday" to just "repeats every week" if the start date was Tuesday */
|
||||
if( $repeatData['event_repeats'] == 'weekly' AND $startDate !== NULL )
|
||||
{
|
||||
$_repeatDays = array();
|
||||
|
||||
foreach( \IPS\calendar\Date::getDayNames() as $day )
|
||||
{
|
||||
if( $repeatData['repeat_freq_on_' . $day['ical'] ] == TRUE )
|
||||
{
|
||||
$_repeatDays[] = $day['english'];
|
||||
}
|
||||
}
|
||||
|
||||
if( ( \count( $_repeatDays ) == 1 AND $startDate->weekday == $_repeatDays[0] ) OR \count( $_repeatDays ) == 7 )
|
||||
{
|
||||
foreach( $dayNames as $day )
|
||||
{
|
||||
$repeatData['repeat_freq_on_' . $day ] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $repeatData;
|
||||
}
|
||||
|
||||
@@ -169,7 +208,7 @@ class _ICSParser
|
||||
|
||||
if( isset( $repeat['repeat_end_date'] ) AND $repeat['repeat_end_date'] )
|
||||
{
|
||||
$rrule[] = 'UNTIL=' . \IPS\calendar\Date::createFromForm( $repeat['repeat_end_date'], NULL, $repeat['event_timezone'] )->setTimezone( new \DateTimeZone( 'UTC' ) )->modifiedIso8601();
|
||||
$rrule[] = 'UNTIL=' . \IPS\calendar\Date::createFromForm( $repeat['repeat_end_date'], NULL, 'UTC' )->modifiedIso8601();
|
||||
}
|
||||
|
||||
/* By-day rule */
|
||||
@@ -183,7 +222,7 @@ class _ICSParser
|
||||
}
|
||||
}
|
||||
|
||||
if( count( $days ) )
|
||||
if( \count( $days ) )
|
||||
{
|
||||
$rrule[] = 'BYDAY=' . implode( ',', $days );
|
||||
}
|
||||
@@ -225,7 +264,7 @@ class _ICSParser
|
||||
$_raw = preg_replace( "#(\n\r|\r|\n){1,}#", "\n", $content );
|
||||
$_raw = explode( "\n", $_raw );
|
||||
|
||||
if( !count($_raw) )
|
||||
if( !\count($_raw) )
|
||||
{
|
||||
throw new \UnexpectedValueException( "NO_CONTENT" );
|
||||
}
|
||||
@@ -294,7 +333,7 @@ class _ICSParser
|
||||
}
|
||||
|
||||
/* Convert the raw ICS data to GMT now */
|
||||
if( count($this->_parsedIcsData) )
|
||||
if( \count($this->_parsedIcsData) )
|
||||
{
|
||||
$this->_parsedIcsData = $this->_convertToGmt( $this->_parsedIcsData );
|
||||
}
|
||||
@@ -308,7 +347,7 @@ class _ICSParser
|
||||
// Leave this here - useful for debugging
|
||||
// print_r($this->_parsedIcsData);exit;
|
||||
|
||||
if ( count( $this->_parsedIcsData ) and isset( $this->_parsedIcsData['events'] ) )
|
||||
if ( \count( $this->_parsedIcsData ) and isset( $this->_parsedIcsData['events'] ) )
|
||||
{
|
||||
usort( $this->_parsedIcsData['events'], function( $a, $b ) {
|
||||
if ( $a['start']['raw_ts'] == $b['start']['raw_ts'] )
|
||||
@@ -367,15 +406,15 @@ class _ICSParser
|
||||
if ( ! $event_unix_to AND isset( $event['duration'] ) AND $event['duration'] )
|
||||
{
|
||||
preg_match( "#(\d+?)H#is", $event['duration'], $match );
|
||||
$hour = $match[1] ? $match[1] : 0;
|
||||
$hour = isset( $match[1] ) ? $match[1] : 0;
|
||||
|
||||
preg_match( "#(\d+?)M#is", $event['duration'], $match );
|
||||
$minute = $match[1] ? $match[1] : 0;
|
||||
$minute = isset( $match[1] ) ? $match[1] : 0;
|
||||
|
||||
preg_match( "#(\d+?)S#is", $event['duration'], $match );
|
||||
$second = $match[1] ? $match[1] : 0;
|
||||
$second = isset( $match[1] ) ? $match[1] : 0;
|
||||
|
||||
$event_unix_to = $event_unix_from->add( new \DateIntveral( 'PT' . ( $hour * 3600 ) . 'H' . ( $minute * 60 ) . 'M' . $second . 'S' ) );
|
||||
$event_unix_to = $event_unix_from->add( new \DateInterval( 'PT' . ( $hour * 3600 ) . 'H' . ( $minute * 60 ) . 'M' . $second . 'S' ) );
|
||||
}
|
||||
|
||||
/* If this is an all day event, adjust the timestamps */
|
||||
@@ -401,7 +440,7 @@ class _ICSParser
|
||||
try
|
||||
{
|
||||
/* If we are importing an ICS file, feed here will be null. */
|
||||
if ( is_null( $this->feed ) )
|
||||
if ( \is_null( $this->feed ) )
|
||||
{
|
||||
/* Bubble up so we can create a new event */
|
||||
throw new \UnderflowException;
|
||||
@@ -451,7 +490,7 @@ class _ICSParser
|
||||
$newEvent->title = ( isset( $event['summary'] ) AND $event['summary'] ) ? $event['summary'] : mb_substr( strip_tags( $event['description'] ), 0, 100 );
|
||||
$content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
|
||||
$newEvent->content = \IPS\Text\Parser::parseStatic( $content, TRUE, NULL, $this->member );
|
||||
$newEvent->sequence = ( isset( $event['sequence'] ) ? intval( $event['sequence'] ) : 0 );
|
||||
$newEvent->sequence = ( isset( $event['sequence'] ) ? \intval( $event['sequence'] ) : 0 );
|
||||
|
||||
/* Times and dates */
|
||||
if( isset( $event['last_modified'] ) AND $event['last_modified'] AND $event['last_modified'] < time() )
|
||||
@@ -469,7 +508,7 @@ class _ICSParser
|
||||
$newEvent->end_date = $event_unix_to ? $event_unix_to->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ) : NULL;
|
||||
|
||||
/* Geolocation? */
|
||||
if( isset( $event['geo'] ) AND is_array( $event['geo'] ) AND count( $event['geo'] ) )
|
||||
if( isset( $event['geo'] ) AND \is_array( $event['geo'] ) AND \count( $event['geo'] ) )
|
||||
{
|
||||
/* If we are updating an event, don't pull geo data if we already have it and it hasn't changed */
|
||||
$update = TRUE;
|
||||
@@ -532,7 +571,7 @@ class _ICSParser
|
||||
}
|
||||
|
||||
/* Add any event attendees that are members of our installation */
|
||||
if( !$eventId AND isset($event['attendee']) AND count($event['attendee']) )
|
||||
if( !$eventId AND isset($event['attendee']) AND \count($event['attendee']) )
|
||||
{
|
||||
foreach( $event['attendee'] as $attendee )
|
||||
{
|
||||
@@ -647,7 +686,7 @@ class _ICSParser
|
||||
/* Get the years that all events span */
|
||||
$years = array();
|
||||
|
||||
if( count( $this->_events ) )
|
||||
if( \count( $this->_events ) )
|
||||
{
|
||||
foreach( $this->_events as $event )
|
||||
{
|
||||
@@ -727,7 +766,7 @@ class _ICSParser
|
||||
$output = '';
|
||||
|
||||
/* Loop over the events */
|
||||
if( count( $this->_events ) )
|
||||
if( \count( $this->_events ) )
|
||||
{
|
||||
foreach( $this->_events as $event )
|
||||
{
|
||||
@@ -744,7 +783,7 @@ class _ICSParser
|
||||
|
||||
preg_match_all( "/(http.+?attachment\.php\?id=(\d+))/i", $event->content, $matches );
|
||||
|
||||
if( is_array($matches) AND count($matches) )
|
||||
if( \is_array($matches) AND \count($matches) )
|
||||
{
|
||||
foreach( $matches[2] as $k => $v )
|
||||
{
|
||||
@@ -752,7 +791,7 @@ class _ICSParser
|
||||
}
|
||||
}
|
||||
|
||||
if( count( $attachments ) )
|
||||
if( \count( $attachments ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_attachments', 'attach_id IN(' . implode( ',', array_keys( $attachments ) ) . ')' ) as $attachment )
|
||||
{
|
||||
@@ -770,7 +809,7 @@ class _ICSParser
|
||||
if( $event->all_day )
|
||||
{
|
||||
$output .= "DTSTART;VALUE=DATE:" . $event->_start_date->modifiedIso8601( FALSE ) . "\r\n";
|
||||
$output .= "DTEND;VALUE=DATE:" . $event->_end_date->modifiedIso8601( FALSE ) . "\r\n";
|
||||
$output .= "DTEND;VALUE=DATE:" . $event->_end_date->add( new \DateInterval( 'P1D' ) )->modifiedIso8601( FALSE ) . "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1102,7 +1141,7 @@ class _ICSParser
|
||||
/* Loop over the lines */
|
||||
$_recid = null;
|
||||
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
for( $i = $start, $j = \count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get content */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
@@ -1115,7 +1154,7 @@ class _ICSParser
|
||||
$_type = $tmp['type'];
|
||||
$_data = $tmp['data'];
|
||||
|
||||
if( $this->currentlyParsing != 'EVENT' AND !in_array( $_type, array( 'END', 'BEGIN' ) ) )
|
||||
if( $this->currentlyParsing != 'EVENT' AND !\in_array( $_type, array( 'END', 'BEGIN' ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1218,7 +1257,7 @@ class _ICSParser
|
||||
break;
|
||||
|
||||
case 'SEQUENCE':
|
||||
$_event['sequence'] = intval($_data);
|
||||
$_event['sequence'] = \intval($_data);
|
||||
break;
|
||||
|
||||
case 'RRULE':
|
||||
@@ -1268,7 +1307,7 @@ class _ICSParser
|
||||
protected function _processVcalendarObject( $start )
|
||||
{
|
||||
/* Loop over the lines */
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
for( $i = $start, $j = \count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get the data */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
@@ -1342,7 +1381,7 @@ class _ICSParser
|
||||
protected function _convertToGmt( $data )
|
||||
{
|
||||
/* Fix events */
|
||||
if ( is_array( $data['events'] ) AND count( $data['events'] ) )
|
||||
if ( \is_array( $data['events'] ) AND \count( $data['events'] ) )
|
||||
{
|
||||
foreach( $data['events'] as $id => $event )
|
||||
{
|
||||
@@ -1352,16 +1391,15 @@ class _ICSParser
|
||||
if ( isset( $event[ $method ]['tzid'] ) AND $event[ $method ]['tzid'] )
|
||||
{
|
||||
/* Let's test it first... */
|
||||
if( in_array( $event[ $method ]['tzid'], \IPS\DateTime::getTimezoneIdentifiers() ) )
|
||||
$timezone = NULL;
|
||||
|
||||
if( \in_array( $event[ $method ]['tzid'], \IPS\DateTime::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone = new \DateTimeZone( $event[ $method ]['tzid'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$timezone = NULL;
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'], $timezone );
|
||||
|
||||
Reference in new issue
Block a user